authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-11-03 12:12:36-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-11-04 09:15:05-04:00
log095c4294aa8b275da0627adefad046923fcaae46
tree069ca321e822ea95d7265ece0b79173832a0745a
parent6553359f398ccc3be10a4975d99cb325a5b7c1fd

x86_64: fix miscompilations

Closes #17618

2 files changed, 102 insertions(+), 29 deletions(-)

lib/std/multi_array_list.zig+1-1
...@@ -106,7 +106,7 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -106,7 +106,7 @@ pub fn MultiArrayList(comptime T: type) type {
106 }106 }
107107
108 pub fn toMultiArrayList(self: Slice) Self {108 pub fn toMultiArrayList(self: Slice) Self {
109 if (self.ptrs.len == 0) {109 if (self.ptrs.len == 0 or self.capacity == 0) {
110 return .{};110 return .{};
111 }111 }
112 const unaligned_ptr = self.ptrs[sizes.fields[0]];112 const unaligned_ptr = self.ptrs[sizes.fields[0]];
src/arch/x86_64/CodeGen.zig+101-28
...@@ -2533,6 +2533,19 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2533,6 +2533,19 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2533 ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation);2533 ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation);
2534 for (deaths) |death| try self.processDeath(death);2534 for (deaths) |death| try self.processDeath(death);
25352535
2536 const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).Array.len]RegisterLock;
2537 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
2538 if (opts.update_tracking) ({}) else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
2539
2540 var reg_locks = if (opts.update_tracking) {} else try std.ArrayList(RegisterLock).initCapacity(
2541 stack.get(),
2542 @typeInfo(ExpectedContents).Array.len,
2543 );
2544 defer if (!opts.update_tracking) {
2545 for (reg_locks.items) |lock| self.register_manager.unlockReg(lock);
2546 reg_locks.deinit();
2547 };
2548
2536 for (0..state.registers.len) |index| {2549 for (0..state.registers.len) |index| {
2537 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))2550 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))
2538 null2551 null
...@@ -2549,11 +2562,8 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2549,11 +2562,8 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2549 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);2562 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
2550 }2563 }
2551 if (target_maybe_inst) |target_inst| {2564 if (target_maybe_inst) |target_inst| {
2552 try self.inst_tracking.getPtr(target_inst).?.materialize(2565 const target_tracking = self.inst_tracking.getPtr(target_inst).?;
2553 self,2566 try target_tracking.materialize(self, target_inst, state.reg_tracking[index]);
2554 target_inst,
2555 state.reg_tracking[index],
2556 );
2557 }2567 }
2558 }2568 }
2559 if (opts.update_tracking) {2569 if (opts.update_tracking) {
...@@ -2571,7 +2581,8 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt...@@ -2571,7 +2581,8 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
2571 state.reg_tracking[index],2581 state.reg_tracking[index],
2572 );2582 );
2573 }2583 }
2574 }2584 } else if (target_maybe_inst) |_|
2585 try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index)));
2575 }2586 }
2576 if (opts.emit_instructions) if (self.eflags_inst) |inst|2587 if (opts.emit_instructions) if (self.eflags_inst) |inst|
2577 try self.inst_tracking.getPtr(inst).?.spill(self, inst);2588 try self.inst_tracking.getPtr(inst).?.spill(self, inst);
...@@ -6746,6 +6757,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -6746,6 +6757,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
6746 .disp = val_byte_off,6757 .disp = val_byte_off,
6747 } },6758 } },
6748 });6759 });
6760 try self.spillEflagsIfOccupied();
6749 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));6761 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(val_bit_off));
6750 } else {6762 } else {
6751 const tmp_reg =6763 const tmp_reg =
...@@ -6768,6 +6780,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn...@@ -6768,6 +6780,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn
6768 .disp = val_byte_off + 1,6780 .disp = val_byte_off + 1,
6769 } },6781 } },
6770 });6782 });
6783 try self.spillEflagsIfOccupied();
6771 try self.asmRegisterRegisterImmediate(6784 try self.asmRegisterRegisterImmediate(
6772 .{ ._rd, .sh },6785 .{ ._rd, .sh },
6773 dst_alias,6786 dst_alias,
...@@ -6851,6 +6864,27 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -6851,6 +6864,27 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
6851 } else {6864 } else {
6852 try self.load(dst_mcv, ptr_ty, ptr_mcv);6865 try self.load(dst_mcv, ptr_ty, ptr_mcv);
6853 }6866 }
6867
6868 if (elem_ty.isAbiInt(mod) and elem_size * 8 > elem_ty.bitSize(mod)) {
6869 const high_mcv: MCValue = switch (dst_mcv) {
6870 .register => |dst_reg| .{ .register = dst_reg },
6871 .register_pair => |dst_regs| .{ .register = dst_regs[1] },
6872 else => dst_mcv.address().offset(@intCast((elem_size - 1) / 8 * 8)).deref(),
6873 };
6874 const high_reg = if (high_mcv.isRegister())
6875 high_mcv.getReg().?
6876 else
6877 try self.copyToTmpRegister(Type.usize, high_mcv);
6878 const high_lock = self.register_manager.lockReg(high_reg);
6879 defer if (high_lock) |lock| self.register_manager.unlockReg(lock);
6880
6881 try self.truncateRegister(elem_ty, high_reg);
6882 if (!high_mcv.isRegister()) try self.genCopy(
6883 if (elem_size <= 8) elem_ty else Type.usize,
6884 high_mcv,
6885 .{ .register = high_reg },
6886 );
6887 }
6854 break :result dst_mcv;6888 break :result dst_mcv;
6855 };6889 };
6856 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });6890 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -6996,6 +7030,11 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -6996,6 +7030,11 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
6996 } else {7030 } else {
6997 // TODO if the value is undef, don't lower this instruction7031 // TODO if the value is undef, don't lower this instruction
6998 }7032 }
7033
7034 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
7035 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
7036 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
7037
6999 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7038 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7000 const ptr_mcv = try self.resolveInst(bin_op.lhs);7039 const ptr_mcv = try self.resolveInst(bin_op.lhs);
7001 const ptr_ty = self.typeOf(bin_op.lhs);7040 const ptr_ty = self.typeOf(bin_op.lhs);
...@@ -7088,12 +7127,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7088,12 +7127,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7088 const dst_lock = self.register_manager.lockReg(dst_reg);7127 const dst_lock = self.register_manager.lockReg(dst_reg);
7089 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);7128 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
70907129
7091 if (field_off > 0) try self.genShiftBinOpMir(7130 if (field_off > 0) {
7092 .{ ._r, .sh },7131 try self.spillEflagsIfOccupied();
7093 Type.usize,7132 try self.genShiftBinOpMir(
7094 dst_mcv,7133 .{ ._r, .sh },
7095 .{ .immediate = field_off },7134 Type.usize,
7096 );7135 dst_mcv,
7136 .{ .immediate = field_off },
7137 );
7138 }
7097 if (abi.RegisterClass.gp.isSet(RegisterManager.indexOfRegIntoTracked(dst_reg).?) and7139 if (abi.RegisterClass.gp.isSet(RegisterManager.indexOfRegIntoTracked(dst_reg).?) and
7098 container_ty.abiSize(mod) * 8 > field_ty.bitSize(mod))7140 container_ty.abiSize(mod) * 8 > field_ty.bitSize(mod))
7099 try self.truncateRegister(field_ty, dst_reg);7141 try self.truncateRegister(field_ty, dst_reg);
...@@ -7128,12 +7170,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7128,12 +7170,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7128 defer for (dst_locks) |dst_lock| if (dst_lock) |lock|7170 defer for (dst_locks) |dst_lock| if (dst_lock) |lock|
7129 self.register_manager.unlockReg(lock);7171 self.register_manager.unlockReg(lock);
71307172
7131 if (field_off > 0) try self.genShiftBinOpMir(7173 if (field_off > 0) {
7132 .{ ._r, .sh },7174 try self.spillEflagsIfOccupied();
7133 Type.u128,7175 try self.genShiftBinOpMir(
7134 dst_mcv,7176 .{ ._r, .sh },
7135 .{ .immediate = field_off },7177 Type.u128,
7136 );7178 dst_mcv,
7179 .{ .immediate = field_off },
7180 );
7181 }
71377182
7138 if (field_bit_size <= 64) {7183 if (field_bit_size <= 64) {
7139 if (self.regExtraBits(field_ty) > 0)7184 if (self.regExtraBits(field_ty) > 0)
...@@ -7161,12 +7206,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7161,12 +7206,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7161 const dst_lock = self.register_manager.lockReg(dst_reg);7206 const dst_lock = self.register_manager.lockReg(dst_reg);
7162 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);7207 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
71637208
7164 if (field_off % 64 > 0) try self.genShiftBinOpMir(7209 if (field_off % 64 > 0) {
7165 .{ ._r, .sh },7210 try self.spillEflagsIfOccupied();
7166 Type.usize,7211 try self.genShiftBinOpMir(
7167 dst_mcv,7212 .{ ._r, .sh },
7168 .{ .immediate = field_off % 64 },7213 Type.usize,
7169 );7214 dst_mcv,
7215 .{ .immediate = field_off % 64 },
7216 );
7217 }
7170 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);7218 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
71717219
7172 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))7220 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
...@@ -7272,6 +7320,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7272,6 +7320,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7272 .disp = frame_addr.off + field_byte_off,7320 .disp = frame_addr.off + field_byte_off,
7273 } },7321 } },
7274 });7322 });
7323 try self.spillEflagsIfOccupied();
7275 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));7324 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, Immediate.u(field_bit_off));
7276 } else {7325 } else {
7277 const tmp_reg = registerAlias(7326 const tmp_reg = registerAlias(
...@@ -7300,6 +7349,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7300,6 +7349,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7300 .disp = frame_addr.off + field_byte_off + limb_abi_size,7349 .disp = frame_addr.off + field_byte_off + limb_abi_size,
7301 } },7350 } },
7302 });7351 });
7352 try self.spillEflagsIfOccupied();
7303 try self.asmRegisterRegisterImmediate(7353 try self.asmRegisterRegisterImmediate(
7304 .{ ._rd, .sh },7354 .{ ._rd, .sh },
7305 dst_alias,7355 dst_alias,
...@@ -7344,13 +7394,18 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -7344,13 +7394,18 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
7344fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {7394fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
7345 const mod = self.bin_file.options.module.?;7395 const mod = self.bin_file.options.module.?;
7346 const src_ty = self.typeOf(src_air);7396 const src_ty = self.typeOf(src_air);
7347 const src_mcv = try self.resolveInst(src_air);
7348 if (src_ty.zigTypeTag(mod) == .Vector)7397 if (src_ty.zigTypeTag(mod) == .Vector)
7349 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(mod)});7398 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(mod)});
73507399
7400 var src_mcv = try self.resolveInst(src_air);
7351 switch (src_mcv) {7401 switch (src_mcv) {
7352 .eflags => |cc| switch (tag) {7402 .eflags => |cc| switch (tag) {
7353 .not => return .{ .eflags = cc.negate() },7403 .not => {
7404 if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv))
7405 return .{ .eflags = cc.negate() };
7406 try self.spillEflagsIfOccupied();
7407 src_mcv = try self.resolveInst(src_air);
7408 },
7354 else => {},7409 else => {},
7355 },7410 },
7356 else => {},7411 else => {},
...@@ -11873,8 +11928,18 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -11873,8 +11928,18 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
11873 try self.spillEflagsIfOccupied();11928 try self.spillEflagsIfOccupied();
11874 for (items, relocs, 0..) |item, *reloc, i| {11929 for (items, relocs, 0..) |item, *reloc, i| {
11875 const item_mcv = try self.resolveInst(item);11930 const item_mcv = try self.resolveInst(item);
11876 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, item_mcv);11931 const cc: Condition = switch (condition) {
11877 reloc.* = try self.asmJccReloc(if (i < relocs.len - 1) .e else .ne, undefined);11932 .eflags => |cc| switch (item_mcv.immediate) {
11933 0 => cc.negate(),
11934 1 => cc,
11935 else => unreachable,
11936 },
11937 else => cc: {
11938 try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, item_mcv);
11939 break :cc .e;
11940 },
11941 };
11942 reloc.* = try self.asmJccReloc(if (i < relocs.len - 1) cc else cc.negate(), undefined);
11878 }11943 }
1187911944
11880 for (liveness.deaths[case_i]) |operand| try self.processDeath(operand);11945 for (liveness.deaths[case_i]) |operand| try self.processDeath(operand);
...@@ -14380,6 +14445,10 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {...@@ -14380,6 +14445,10 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1438014445
14381 const bin_op = self.air.instructions.items(.data)[inst].bin_op;14446 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1438214447
14448 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
14449 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
14450 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
14451
14383 const dst_ptr = try self.resolveInst(bin_op.lhs);14452 const dst_ptr = try self.resolveInst(bin_op.lhs);
14384 const dst_ptr_ty = self.typeOf(bin_op.lhs);14453 const dst_ptr_ty = self.typeOf(bin_op.lhs);
14385 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {14454 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {
...@@ -14497,6 +14566,10 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -14497,6 +14566,10 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
14497 const mod = self.bin_file.options.module.?;14566 const mod = self.bin_file.options.module.?;
14498 const bin_op = self.air.instructions.items(.data)[inst].bin_op;14567 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1449914568
14569 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
14570 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
14571 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
14572
14500 const dst_ptr = try self.resolveInst(bin_op.lhs);14573 const dst_ptr = try self.resolveInst(bin_op.lhs);
14501 const dst_ptr_ty = self.typeOf(bin_op.lhs);14574 const dst_ptr_ty = self.typeOf(bin_op.lhs);
14502 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {14575 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {