authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-03-11 16:11:09-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-03-11 16:11:09-04:00
log982c500be5285500a236ca01c2f66e8555647a52
tree070417adb81d973df463dd7f4adb40d175af453f
parentf66067546775a04ca0cda1c74cb9002d02dc49d5
parentcff90e3ae0b14da5163ea0c3283557f402001c67
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #23188 from jacobly0/fix-23143

x86_64: fix crashes with symbols

3 files changed, 212 insertions(+), 71 deletions(-)

src/arch/x86_64/CodeGen.zig+159-45
......@@ -97980,16 +97980,150 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
9798097980 switch (pred_mcv) {
9798197981 .register => |pred_reg| switch (pred_reg.class()) {
9798297982 .general_purpose => {},
97983 .sse => if (need_xmm0 and pred_reg.id() != comptime Register.xmm0.id()) {
97984 try self.register_manager.getKnownReg(.xmm0, null);
97985 try self.genSetReg(.xmm0, pred_ty, pred_mcv, .{});
97986 break :mask .xmm0;
97987 } else break :mask if (has_blend)
97988 pred_reg
97983 .sse => if (elem_ty.toIntern() == .bool_type)
97984 if (need_xmm0 and pred_reg.id() != comptime Register.xmm0.id()) {
97985 try self.register_manager.getKnownReg(.xmm0, null);
97986 try self.genSetReg(.xmm0, pred_ty, pred_mcv, .{});
97987 break :mask .xmm0;
97988 } else break :mask if (has_blend)
97989 pred_reg
97990 else
97991 try self.copyToTmpRegister(pred_ty, pred_mcv)
9798997992 else
97990 try self.copyToTmpRegister(pred_ty, pred_mcv),
97993 return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}),
9799197994 else => unreachable,
9799297995 },
97996 .register_mask => |pred_reg_mask| {
97997 if (pred_reg_mask.info.scalar.bitSize(self.target) != 8 * elem_abi_size)
97998 return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
97999
98000 const mask_reg: Register = if (need_xmm0 and pred_reg_mask.reg.id() != comptime Register.xmm0.id()) mask_reg: {
98001 try self.register_manager.getKnownReg(.xmm0, null);
98002 try self.genSetReg(.xmm0, ty, .{ .register = pred_reg_mask.reg }, .{});
98003 break :mask_reg .xmm0;
98004 } else pred_reg_mask.reg;
98005 const mask_alias = registerAlias(mask_reg, abi_size);
98006 const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg);
98007 defer self.register_manager.unlockReg(mask_lock);
98008
98009 const lhs_mcv = try self.resolveInst(extra.lhs);
98010 const lhs_lock = switch (lhs_mcv) {
98011 .register => |lhs_reg| self.register_manager.lockRegAssumeUnused(lhs_reg),
98012 else => null,
98013 };
98014 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
98015
98016 const rhs_mcv = try self.resolveInst(extra.rhs);
98017 const rhs_lock = switch (rhs_mcv) {
98018 .register => |rhs_reg| self.register_manager.lockReg(rhs_reg),
98019 else => null,
98020 };
98021 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
98022
98023 const order = has_blend != pred_reg_mask.info.inverted;
98024 const reuse_mcv, const other_mcv = if (order)
98025 .{ rhs_mcv, lhs_mcv }
98026 else
98027 .{ lhs_mcv, rhs_mcv };
98028 const dst_mcv: MCValue = if (reuse_mcv.isRegister() and self.reuseOperand(
98029 inst,
98030 if (order) extra.rhs else extra.lhs,
98031 @intFromBool(order),
98032 reuse_mcv,
98033 )) reuse_mcv else if (has_avx)
98034 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
98035 else
98036 try self.copyToRegisterWithInstTracking(inst, ty, reuse_mcv);
98037 const dst_reg = dst_mcv.getReg().?;
98038 const dst_alias = registerAlias(dst_reg, abi_size);
98039 const dst_lock = self.register_manager.lockReg(dst_reg);
98040 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
98041
98042 const mir_tag = @as(?Mir.Inst.FixedTag, if ((pred_reg_mask.info.kind == .all and
98043 elem_ty.toIntern() != .f32_type and elem_ty.toIntern() != .f64_type) or pred_reg_mask.info.scalar == .byte)
98044 if (has_avx)
98045 .{ .vp_b, .blendv }
98046 else if (has_blend)
98047 .{ .p_b, .blendv }
98048 else if (pred_reg_mask.info.kind == .all)
98049 .{ .p_, undefined }
98050 else
98051 null
98052 else if ((pred_reg_mask.info.kind == .all and (elem_ty.toIntern() != .f64_type or !self.hasFeature(.sse2))) or
98053 pred_reg_mask.info.scalar == .dword)
98054 if (has_avx)
98055 .{ .v_ps, .blendv }
98056 else if (has_blend)
98057 .{ ._ps, .blendv }
98058 else if (pred_reg_mask.info.kind == .all)
98059 .{ ._ps, undefined }
98060 else
98061 null
98062 else if (pred_reg_mask.info.kind == .all or pred_reg_mask.info.scalar == .qword)
98063 if (has_avx)
98064 .{ .v_pd, .blendv }
98065 else if (has_blend)
98066 .{ ._pd, .blendv }
98067 else if (pred_reg_mask.info.kind == .all)
98068 .{ ._pd, undefined }
98069 else
98070 null
98071 else
98072 null) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
98073 if (has_avx) {
98074 const rhs_alias = if (reuse_mcv.isRegister())
98075 registerAlias(reuse_mcv.getReg().?, abi_size)
98076 else rhs: {
98077 try self.genSetReg(dst_reg, ty, reuse_mcv, .{});
98078 break :rhs dst_alias;
98079 };
98080 if (other_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
98081 mir_tag,
98082 dst_alias,
98083 rhs_alias,
98084 try other_mcv.mem(self, .{ .size = self.memSize(ty) }),
98085 mask_alias,
98086 ) else try self.asmRegisterRegisterRegisterRegister(
98087 mir_tag,
98088 dst_alias,
98089 rhs_alias,
98090 registerAlias(if (other_mcv.isRegister())
98091 other_mcv.getReg().?
98092 else
98093 try self.copyToTmpRegister(ty, other_mcv), abi_size),
98094 mask_alias,
98095 );
98096 } else if (has_blend) if (other_mcv.isBase()) try self.asmRegisterMemoryRegister(
98097 mir_tag,
98098 dst_alias,
98099 try other_mcv.mem(self, .{ .size = self.memSize(ty) }),
98100 mask_alias,
98101 ) else try self.asmRegisterRegisterRegister(
98102 mir_tag,
98103 dst_alias,
98104 registerAlias(if (other_mcv.isRegister())
98105 other_mcv.getReg().?
98106 else
98107 try self.copyToTmpRegister(ty, other_mcv), abi_size),
98108 mask_alias,
98109 ) else {
98110 try self.asmRegisterRegister(.{ mir_tag[0], .@"and" }, dst_alias, mask_alias);
98111 if (other_mcv.isBase()) try self.asmRegisterMemory(
98112 .{ mir_tag[0], .andn },
98113 mask_alias,
98114 try other_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
98115 ) else try self.asmRegisterRegister(
98116 .{ mir_tag[0], .andn },
98117 mask_alias,
98118 if (other_mcv.isRegister())
98119 other_mcv.getReg().?
98120 else
98121 try self.copyToTmpRegister(ty, other_mcv),
98122 );
98123 try self.asmRegisterRegister(.{ mir_tag[0], .@"or" }, dst_alias, mask_alias);
98124 }
98125 break :result dst_mcv;
98126 },
9799398127 else => {},
9799498128 }
9799598129 const mask_reg: Register = if (need_xmm0) mask_reg: {
......@@ -98192,7 +98326,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
9819298326 const dst_lock = self.register_manager.lockReg(dst_reg);
9819398327 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
9819498328
98195 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.childType(zcu).zigTypeTag(zcu)) {
98329 const mir_tag = @as(?Mir.Inst.FixedTag, switch (elem_ty.zigTypeTag(zcu)) {
9819698330 else => null,
9819798331 .int => switch (abi_size) {
9819898332 0 => unreachable,
......@@ -98208,7 +98342,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
9820898342 null,
9820998343 else => null,
9821098344 },
98211 .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
98345 .float => switch (elem_ty.floatBits(self.target.*)) {
9821298346 else => unreachable,
9821398347 16, 80, 128 => null,
9821498348 32 => switch (vec_len) {
......@@ -98262,30 +98396,20 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
9826298396 try self.copyToTmpRegister(ty, lhs_mcv), abi_size),
9826398397 mask_alias,
9826498398 ) else {
98265 const mir_fixes = @as(?Mir.Inst.Fixes, switch (elem_ty.zigTypeTag(zcu)) {
98266 else => null,
98267 .int => .p_,
98268 .float => switch (elem_ty.floatBits(self.target.*)) {
98269 32 => ._ps,
98270 64 => ._pd,
98271 16, 80, 128 => null,
98272 else => unreachable,
98273 },
98274 }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
98275 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);
98399 try self.asmRegisterRegister(.{ mir_tag[0], .@"and" }, dst_alias, mask_alias);
9827698400 if (rhs_mcv.isBase()) try self.asmRegisterMemory(
98277 .{ mir_fixes, .andn },
98401 .{ mir_tag[0], .andn },
9827898402 mask_alias,
9827998403 try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
9828098404 ) else try self.asmRegisterRegister(
98281 .{ mir_fixes, .andn },
98405 .{ mir_tag[0], .andn },
9828298406 mask_alias,
9828398407 if (rhs_mcv.isRegister())
9828498408 rhs_mcv.getReg().?
9828598409 else
9828698410 try self.copyToTmpRegister(ty, rhs_mcv),
9828798411 );
98288 try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias);
98412 try self.asmRegisterRegister(.{ mir_tag[0], .@"or" }, dst_alias, mask_alias);
9828998413 }
9829098414 break :result dst_mcv;
9829198415 };
......@@ -100824,11 +100948,11 @@ const Temp = struct {
100824100948 const new_temp_index = cg.next_temp_index;
100825100949 cg.temp_type[@intFromEnum(new_temp_index)] = .usize;
100826100950 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
100827 switch (temp.tracking(cg).short) {
100828 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
100951 const mcv = temp.tracking(cg).short;
100952 switch (mcv) {
100953 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
100829100954 .register => |reg| {
100830 const new_reg =
100831 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100955 const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100832100956 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
100833100957 try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{
100834100958 .base = .{ .reg = reg.to64() },
......@@ -100836,33 +100960,22 @@ const Temp = struct {
100836100960 });
100837100961 },
100838100962 .register_offset => |reg_off| {
100839 const new_reg =
100840 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100963 const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100841100964 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
100842100965 try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{
100843100966 .base = .{ .reg = reg_off.reg.to64() },
100844100967 .mod = .{ .rm = .{ .disp = reg_off.off + off } },
100845100968 });
100846100969 },
100970 .load_symbol, .load_frame => {
100971 const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100972 new_temp_index.tracking(cg).* = .init(.{ .register_offset = .{ .reg = new_reg, .off = off } });
100973 try cg.genSetReg(new_reg, .usize, mcv, .{});
100974 },
100847100975 .lea_symbol => |sym_off| new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = .{
100848100976 .sym_index = sym_off.sym_index,
100849100977 .off = sym_off.off + off,
100850100978 } }),
100851 .load_frame => |frame_addr| {
100852 const new_reg =
100853 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
100854 new_temp_index.tracking(cg).* = .init(.{ .register_offset = .{
100855 .reg = new_reg,
100856 .off = off,
100857 } });
100858 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
100859 .base = .{ .frame = frame_addr.index },
100860 .mod = .{ .rm = .{
100861 .size = .qword,
100862 .disp = frame_addr.off,
100863 } },
100864 });
100865 },
100866100979 .lea_frame => |frame_addr| new_temp_index.tracking(cg).* = .init(.{ .lea_frame = .{
100867100980 .index = frame_addr.index,
100868100981 .off = frame_addr.off + off,
......@@ -101179,7 +101292,8 @@ const Temp = struct {
101179101292 => return temp.toRegClass(true, .general_purpose, cg),
101180101293 .lea_symbol => |sym_off| {
101181101294 const off = sym_off.off;
101182 if (off == 0) return false;
101295 // hack around linker relocation bugs
101296 if (false and off == 0) return false;
101183101297 try temp.toOffset(-off, cg);
101184101298 while (try temp.toRegClass(true, .general_purpose, cg)) {}
101185101299 try temp.toOffset(off, cg);
src/link/Dwarf.zig+33-26
......@@ -2008,9 +2008,9 @@ pub const WipNav = struct {
20082008 .decl_const_runtime_bits,
20092009 .decl_const_comptime_state,
20102010 .decl_const_runtime_bits_comptime_state,
2011 .decl_empty_func,
2011 .decl_nullary_func,
20122012 .decl_func,
2013 .decl_empty_func_generic,
2013 .decl_nullary_func_generic,
20142014 .decl_func_generic,
20152015 => false,
20162016 .generic_decl_var,
......@@ -2626,8 +2626,8 @@ pub fn finishWipNavFunc(
26262626 abbrev_code_buf,
26272627 try dwarf.refAbbrevCode(switch (abbrev_code) {
26282628 else => unreachable,
2629 .decl_func => .decl_empty_func,
2630 .decl_instance_func => .decl_instance_empty_func,
2629 .decl_func => .decl_nullary_func,
2630 .decl_instance_func => .decl_instance_nullary_func,
26312631 }),
26322632 );
26332633 }
......@@ -3012,29 +3012,34 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
30123012 if (nav_gop.found_existing) switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, nav_gop.value_ptr.*)) {
30133013 .null => {},
30143014 else => unreachable,
3015 .decl_empty_func, .decl_func, .decl_instance_empty_func, .decl_instance_func => return,
3016 .decl_empty_func_generic,
3015 .decl_nullary_func, .decl_func, .decl_instance_nullary_func, .decl_instance_func => return,
3016 .decl_nullary_func_generic,
30173017 .decl_func_generic,
3018 .decl_instance_empty_func_generic,
3018 .decl_instance_nullary_func_generic,
30193019 .decl_instance_func_generic,
30203020 => dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear(),
30213021 } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
30223022 wip_nav.entry = nav_gop.value_ptr.*;
30233023
30243024 const func_type = ip.indexToKey(func.ty).func_type;
3025 const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
3026 if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
3027 } else true;
30253028 const diw = wip_nav.debug_info.writer(dwarf.gpa);
3026 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
3027 .decl = .decl_func_generic,
3029 try wip_nav.declCommon(if (is_nullary) .{
3030 .decl = .decl_nullary_func_generic,
30283031 .generic_decl = .generic_decl_func,
3029 .decl_instance = .decl_instance_func_generic,
3032 .decl_instance = .decl_instance_nullary_func_generic,
30303033 } else .{
3031 .decl = .decl_empty_func_generic,
3034 .decl = .decl_func_generic,
30323035 .generic_decl = .generic_decl_func,
3033 .decl_instance = .decl_instance_empty_func_generic,
3036 .decl_instance = .decl_instance_func_generic,
30343037 }, &nav, inst_info.file, &decl);
30353038 try wip_nav.refType(.fromInterned(func_type.return_type));
3036 if (func_type.param_types.len > 0 or func_type.is_var_args) {
3039 if (!is_nullary) {
30373040 for (0..func_type.param_types.len) |param_index| {
3041 if (std.math.cast(u5, param_index)) |small_param_index|
3042 if (func_type.paramIsComptime(small_param_index)) continue;
30383043 try wip_nav.abbrevCode(.func_type_param);
30393044 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
30403045 }
......@@ -3568,12 +3573,14 @@ fn updateLazyType(
35683573 };
35693574 try diw.writeByte(@intFromEnum(cc));
35703575 try wip_nav.refType(.fromInterned(func_type.return_type));
3571 for (0..func_type.param_types.len) |param_index| {
3572 try wip_nav.abbrevCode(.func_type_param);
3573 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3576 if (!is_nullary) {
3577 for (0..func_type.param_types.len) |param_index| {
3578 try wip_nav.abbrevCode(.func_type_param);
3579 try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
3580 }
3581 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3582 try uleb128(diw, @intFromEnum(AbbrevCode.null));
35743583 }
3575 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
3576 if (!is_nullary) try uleb128(diw, @intFromEnum(AbbrevCode.null));
35773584 },
35783585 .error_set_type => |error_set_type| {
35793586 try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
......@@ -4787,9 +4794,9 @@ const AbbrevCode = enum {
47874794 decl_const_runtime_bits,
47884795 decl_const_comptime_state,
47894796 decl_const_runtime_bits_comptime_state,
4790 decl_empty_func,
4797 decl_nullary_func,
47914798 decl_func,
4792 decl_empty_func_generic,
4799 decl_nullary_func_generic,
47934800 decl_func_generic,
47944801 generic_decl_var,
47954802 generic_decl_const,
......@@ -4806,9 +4813,9 @@ const AbbrevCode = enum {
48064813 decl_instance_const_runtime_bits,
48074814 decl_instance_const_comptime_state,
48084815 decl_instance_const_runtime_bits_comptime_state,
4809 decl_instance_empty_func,
4816 decl_instance_nullary_func,
48104817 decl_instance_func,
4811 decl_instance_empty_func_generic,
4818 decl_instance_nullary_func_generic,
48124819 decl_instance_func_generic,
48134820 // the rest are unrestricted other than empty variants must not be longer
48144821 // than the non-empty variant, and so should appear first
......@@ -5019,7 +5026,7 @@ const AbbrevCode = enum {
50195026 .{ .ZIG_comptime_value, .ref_addr },
50205027 },
50215028 },
5022 .decl_empty_func = .{
5029 .decl_nullary_func = .{
50235030 .tag = .subprogram,
50245031 .attrs = decl_abbrev_common_attrs ++ .{
50255032 .{ .linkage_name, .strp },
......@@ -5044,7 +5051,7 @@ const AbbrevCode = enum {
50445051 .{ .noreturn, .flag },
50455052 },
50465053 },
5047 .decl_empty_func_generic = .{
5054 .decl_nullary_func_generic = .{
50485055 .tag = .subprogram,
50495056 .attrs = decl_abbrev_common_attrs ++ .{
50505057 .{ .type, .ref_addr },
......@@ -5167,7 +5174,7 @@ const AbbrevCode = enum {
51675174 .{ .ZIG_comptime_value, .ref_addr },
51685175 },
51695176 },
5170 .decl_instance_empty_func = .{
5177 .decl_instance_nullary_func = .{
51715178 .tag = .subprogram,
51725179 .attrs = decl_instance_abbrev_common_attrs ++ .{
51735180 .{ .linkage_name, .strp },
......@@ -5192,7 +5199,7 @@ const AbbrevCode = enum {
51925199 .{ .noreturn, .flag },
51935200 },
51945201 },
5195 .decl_instance_empty_func_generic = .{
5202 .decl_instance_nullary_func_generic = .{
51965203 .tag = .subprogram,
51975204 .attrs = decl_instance_abbrev_common_attrs ++ .{
51985205 .{ .type, .ref_addr },
test/behavior/select.zig+20
......@@ -66,3 +66,23 @@ fn selectArrays() !void {
6666 const xyz = @select(f32, x, y, z);
6767 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));
6868}
69
70test "@select compare result" {
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
74
75 const S = struct {
76 fn min(comptime V: type, lhs: V, rhs: V) V {
77 return @select(@typeInfo(V).vector.child, lhs < rhs, lhs, rhs);
78 }
79
80 fn doTheTest() !void {
81 try expect(@reduce(.And, min(@Vector(4, f32), .{ -1, 2, -3, 4 }, .{ 1, -2, 3, -4 }) == @Vector(4, f32){ -1, -2, -3, -4 }));
82 try expect(@reduce(.And, min(@Vector(2, f64), .{ -1, 2 }, .{ 1, -2 }) == @Vector(2, f64){ -1, -2 }));
83 }
84 };
85
86 try S.doTheTest();
87 try comptime S.doTheTest();
88}