authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-20 06:22:38-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-21 08:49:54+01:00
logf316cb29cc094c37be191f1eb72ee70eb0dc99ee
tree4da361453ffd24fb0a9d3d9d8a8e1221bb5f3375
parent3f4569bf187bfe296323aee6fbb59ab374041243

x86_64: implement atomic and fence ops


12 files changed, 436 insertions(+), 155 deletions(-)

src/arch/x86_64/CodeGen.zig+245-92
......@@ -410,6 +410,25 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
410410 });
411411}
412412
413fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
414 _ = try self.addInst(.{
415 .tag = .setcc,
416 .ops = switch (m) {
417 .sib => .m_sib_cc,
418 .rip => .m_rip_cc,
419 else => unreachable,
420 },
421 .data = .{ .x_cc = .{
422 .payload = switch (m) {
423 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
424 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
425 else => unreachable,
426 },
427 .cc = cc,
428 } },
429 });
430}
431
413432fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
414433 _ = try self.addInst(.{
415434 .tag = .cmovcc,
......@@ -890,7 +909,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
890909 .breakpoint => try self.airBreakpoint(),
891910 .ret_addr => try self.airRetAddr(inst),
892911 .frame_addr => try self.airFrameAddress(inst),
893 .fence => try self.airFence(),
912 .fence => try self.airFence(inst),
894913 .cond_br => try self.airCondBr(inst),
895914 .dbg_stmt => try self.airDbgStmt(inst),
896915 .fptrunc => try self.airFptrunc(inst),
......@@ -1880,13 +1899,17 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
18801899 if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
18811900 switch (opt_mcv) {
18821901 .register => |reg| try self.truncateRegister(pl_ty, reg),
1902 .register_overflow => |ro| try self.truncateRegister(pl_ty, ro.reg),
18831903 else => {},
18841904 }
18851905 break :result opt_mcv;
18861906 }
18871907
18881908 const pl_mcv = try self.allocRegOrMem(inst, true);
1889 try self.setRegOrMem(pl_ty, pl_mcv, opt_mcv);
1909 try self.setRegOrMem(pl_ty, pl_mcv, switch (opt_mcv) {
1910 else => opt_mcv,
1911 .register_overflow => |ro| .{ .register = ro.reg },
1912 });
18901913 break :result pl_mcv;
18911914 };
18921915 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -1969,8 +1992,14 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
19691992 },
19701993 .register => |reg| {
19711994 // TODO reuse operand
1972 const lock = self.register_manager.lockRegAssumeUnused(reg);
1973 defer self.register_manager.unlockReg(lock);
1995 self.register_manager.getRegAssumeFree(.rcx, null);
1996 const rcx_lock =
1997 if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
1998 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
1999
2000 const eu_lock = self.register_manager.lockReg(reg);
2001 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
2002
19742003 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
19752004 if (err_off > 0) {
19762005 const shift = @intCast(u6, err_off * 8);
......@@ -2018,8 +2047,14 @@ fn genUnwrapErrorUnionPayloadMir(
20182047 },
20192048 .register => |reg| {
20202049 // TODO reuse operand
2021 const lock = self.register_manager.lockRegAssumeUnused(reg);
2022 defer self.register_manager.unlockReg(lock);
2050 self.register_manager.getRegAssumeFree(.rcx, null);
2051 const rcx_lock =
2052 if (payload_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
2053 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
2054
2055 const eu_lock = self.register_manager.lockReg(reg);
2056 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
2057
20232058 const result_reg: Register = if (maybe_inst) |inst|
20242059 (try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)).register
20252060 else
......@@ -3129,7 +3164,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
31293164 .none => unreachable,
31303165 .dead => unreachable,
31313166 .unreach => unreachable,
3132 .eflags => unreachable,
3167 .eflags => |cc| {
3168 try self.asmSetccMemory(Memory.sib(
3169 Memory.PtrSize.fromSize(abi_size),
3170 .{ .base = reg.to64(), .disp = 0 },
3171 ), cc);
3172 },
31333173 .undef => {
31343174 if (!self.wantSafety()) return; // The already existing value will do just fine.
31353175 switch (abi_size) {
......@@ -3598,8 +3638,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
35983638 },
35993639 else => {},
36003640 }
3601 assert(self.register_manager.isRegFree(.rcx));
3602 try self.register_manager.getReg(.rcx, null);
3641 self.register_manager.getRegAssumeFree(.rcx, null);
36033642 try self.genSetReg(Type.u8, .rcx, shift);
36043643 }
36053644
......@@ -3639,8 +3678,7 @@ fn genShiftBinOp(
36393678 };
36403679 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
36413680
3642 assert(self.register_manager.isRegFree(.rcx));
3643 try self.register_manager.getReg(.rcx, null);
3681 self.register_manager.getRegAssumeFree(.rcx, null);
36443682 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
36453683 defer self.register_manager.unlockReg(rcx_lock);
36463684
......@@ -4230,7 +4268,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
42304268 .base = .rbp,
42314269 .disp = -off,
42324270 }),
4233 Immediate.u(@intCast(u32, imm)),
4271 if (math.cast(i32, @bitCast(i64, imm))) |small|
4272 Immediate.s(small)
4273 else
4274 Immediate.u(@intCast(u32, imm)),
42344275 );
42354276 },
42364277 64 => {
......@@ -4506,9 +4547,14 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
45064547 return self.finishAir(inst, result, .{ .none, .none, .none });
45074548}
45084549
4509fn airFence(self: *Self) !void {
4510 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
4511 //return self.finishAirBookkeeping();
4550fn airFence(self: *Self, inst: Air.Inst.Index) !void {
4551 const order = self.air.instructions.items(.data)[inst].fence;
4552 switch (order) {
4553 .Unordered, .Monotonic => unreachable,
4554 .Acquire, .Release, .AcqRel => {},
4555 .SeqCst => try self.asmOpOnly(.mfence),
4556 }
4557 return self.finishAirBookkeeping();
45124558}
45134559
45144560fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
......@@ -5075,6 +5121,11 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
50755121}
50765122
50775123fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
5124 switch (opt_mcv) {
5125 .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() },
5126 else => {},
5127 }
5128
50785129 try self.spillEflagsIfOccupied();
50795130 self.eflags_inst = inst;
50805131
......@@ -5196,8 +5247,13 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
51965247 try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 });
51975248 },
51985249 .register => |reg| {
5199 const maybe_lock = self.register_manager.lockReg(reg);
5200 defer if (maybe_lock) |lock| self.register_manager.unlockReg(lock);
5250 self.register_manager.getRegAssumeFree(.rcx, null);
5251 const rcx_lock = if (err_off > 0) self.register_manager.lockRegAssumeUnused(.rcx) else null;
5252 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
5253
5254 const eu_lock = self.register_manager.lockReg(reg);
5255 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
5256
52015257 const tmp_reg = try self.copyToTmpRegister(ty, operand);
52025258 if (err_off > 0) {
52035259 const shift = @intCast(u6, err_off * 8);
......@@ -5389,69 +5445,6 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
53895445 return self.finishAir(inst, result, .{ .none, .none, .none });
53905446}
53915447
5392fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u32 {
5393 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
5394 switch (condition) {
5395 .none => unreachable,
5396 .undef => unreachable,
5397 .dead, .unreach => unreachable,
5398 .eflags => unreachable,
5399 .register => |cond_reg| {
5400 try self.spillEflagsIfOccupied();
5401
5402 const cond_reg_lock = self.register_manager.lockReg(cond_reg);
5403 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);
5404
5405 switch (case) {
5406 .none => unreachable,
5407 .undef => unreachable,
5408 .dead, .unreach => unreachable,
5409 .immediate => |imm| try self.asmRegisterImmediate(
5410 .xor,
5411 registerAlias(cond_reg, abi_size),
5412 Immediate.u(imm),
5413 ),
5414 .register => |reg| try self.asmRegisterRegister(
5415 .xor,
5416 registerAlias(cond_reg, abi_size),
5417 registerAlias(reg, abi_size),
5418 ),
5419 .stack_offset => {
5420 if (abi_size <= 8) {
5421 const reg = try self.copyToTmpRegister(ty, case);
5422 return self.genCondSwitchMir(ty, condition, .{ .register = reg });
5423 }
5424
5425 return self.fail("TODO implement switch mir when case is stack offset with abi larger than 8 bytes", .{});
5426 },
5427 else => {
5428 return self.fail("TODO implement switch mir when case is {}", .{case});
5429 },
5430 }
5431
5432 const aliased_reg = registerAlias(cond_reg, abi_size);
5433 try self.asmRegisterRegister(.@"test", aliased_reg, aliased_reg);
5434 return self.asmJccReloc(undefined, .ne);
5435 },
5436 .stack_offset => {
5437 try self.spillEflagsIfOccupied();
5438
5439 if (abi_size <= 8) {
5440 const reg = try self.copyToTmpRegister(ty, condition);
5441 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
5442 defer self.register_manager.unlockReg(reg_lock);
5443 return self.genCondSwitchMir(ty, .{ .register = reg }, case);
5444 }
5445
5446 return self.fail("TODO implement switch mir when condition is stack offset with abi larger than 8 bytes", .{});
5447 },
5448 else => {
5449 return self.fail("TODO implemenent switch mir when condition is {}", .{condition});
5450 },
5451 }
5452 return 0; // TODO
5453}
5454
54555448fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
54565449 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
54575450 const condition = try self.resolveInst(pl_op.operand);
......@@ -5496,8 +5489,10 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
54965489 defer self.gpa.free(relocs);
54975490
54985491 for (items, relocs) |item, *reloc| {
5492 try self.spillEflagsIfOccupied();
54995493 const item_mcv = try self.resolveInst(item);
5500 reloc.* = try self.genCondSwitchMir(condition_ty, condition, item_mcv);
5494 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
5495 reloc.* = try self.asmJccReloc(undefined, .ne);
55015496 }
55025497
55035498 // Capture the state of register and stack allocation state so that we can revert to it.
......@@ -6624,26 +6619,184 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
66246619
66256620fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
66266621 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6627 const extra = self.air.extraData(Air.Block, ty_pl.payload);
6628 _ = extra;
6629 return self.fail("TODO implement x86 airCmpxchg", .{});
6630 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6622 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
6623
6624 const ptr_ty = self.air.typeOf(extra.ptr);
6625 const ptr_mcv = try self.resolveInst(extra.ptr);
6626 const val_ty = self.air.typeOf(extra.expected_value);
6627
6628 const exp_mcv = try self.resolveInst(extra.expected_value);
6629 try self.genSetReg(val_ty, .rax, exp_mcv);
6630 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
6631 defer self.register_manager.unlockReg(rax_lock);
6632
6633 const new_mcv = try self.resolveInst(extra.new_value);
6634 const new_reg = try self.copyToTmpRegister(val_ty, new_mcv);
6635 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
6636 defer self.register_manager.unlockReg(new_lock);
6637
6638 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
6639 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6640 const ptr_mem: Memory = switch (ptr_mcv) {
6641 .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
6642 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
6643 else => Memory.sib(ptr_size, .{
6644 .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
6645 .disp = 0,
6646 }),
6647 };
6648 const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
6649 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
6650
6651 try self.spillEflagsIfOccupied();
6652 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
6653 .r1 = new_reg,
6654 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
6655 } } });
6656
6657 const result: MCValue = result: {
6658 if (self.liveness.isUnused(inst)) break :result .dead;
6659
6660 self.eflags_inst = inst;
6661 break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
6662 };
6663 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6664}
6665
6666fn atomicOp(
6667 self: *Self,
6668 dst_reg: Register,
6669 ptr_mcv: MCValue,
6670 val_mcv: MCValue,
6671 ptr_ty: Type,
6672 val_ty: Type,
6673 unused: bool,
6674 op: ?std.builtin.AtomicRmwOp,
6675 order: std.builtin.AtomicOrder,
6676) InnerError!void {
6677 const dst_lock = self.register_manager.lockReg(dst_reg);
6678 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6679
6680 const ptr_lock = switch (ptr_mcv) {
6681 .register => |reg| self.register_manager.lockReg(reg),
6682 else => null,
6683 };
6684 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
6685
6686 const val_lock = switch (val_mcv) {
6687 .register => |reg| self.register_manager.lockReg(reg),
6688 else => null,
6689 };
6690 defer if (val_lock) |lock| self.register_manager.unlockReg(lock);
6691
6692 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
6693 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6694 const ptr_mem: Memory = switch (ptr_mcv) {
6695 .register => |reg| Memory.sib(ptr_size, .{ .base = reg, .disp = 0 }),
6696 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
6697 else => Memory.sib(ptr_size, .{
6698 .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv),
6699 .disp = 0,
6700 }),
6701 };
6702 const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
6703 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
6704
6705 try self.genSetReg(val_ty, dst_reg, val_mcv);
6706
6707 const need_loop = val_ty.isRuntimeFloat() or if (op) |rmw| switch (rmw) {
6708 .Xchg, .Add, .Sub => false,
6709 .And, .Or, .Xor => !unused,
6710 .Nand, .Max, .Min => true,
6711 } else false;
6712 if (!need_loop) {
6713 const tag: Mir.Inst.Tag = if (op) |rmw| switch (rmw) {
6714 .Xchg => if (unused) .mov else .xchg,
6715 .Add => if (unused) .add else .xadd,
6716 .Sub => if (unused) .sub else .xadd,
6717 .And => .@"and",
6718 .Or => .@"or",
6719 .Xor => .xor,
6720 else => unreachable,
6721 } else switch (order) {
6722 .Unordered, .Monotonic, .Release, .AcqRel => .mov,
6723 .Acquire => unreachable,
6724 .SeqCst => .xchg,
6725 };
6726 if (op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
6727 try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
6728 }
6729 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
6730 .mov, .xchg => .mr_sib,
6731 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
6732 else => unreachable,
6733 }, .data = .{ .rx = .{
6734 .r1 = registerAlias(dst_reg, val_abi_size),
6735 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
6736 } } });
6737 return;
6738 }
6739
6740 return self.fail("TODO implement x86 atomic loop", .{});
66316741}
66326742
66336743fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
6634 _ = inst;
6635 return self.fail("TODO implement x86 airAtomicRmw", .{});
6744 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6745 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
6746
6747 const dst_reg = try self.register_manager.allocReg(inst, gp);
6748
6749 const ptr_ty = self.air.typeOf(pl_op.operand);
6750 const ptr_mcv = try self.resolveInst(pl_op.operand);
6751
6752 const val_ty = self.air.typeOf(extra.operand);
6753 const val_mcv = try self.resolveInst(extra.operand);
6754
6755 const unused = self.liveness.isUnused(inst);
6756 try self.atomicOp(dst_reg, ptr_mcv, val_mcv, ptr_ty, val_ty, unused, extra.op(), extra.ordering());
6757 const result: MCValue = if (unused) .dead else .{ .register = dst_reg };
6758 return self.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none });
66366759}
66376760
66386761fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
6639 _ = inst;
6640 return self.fail("TODO implement airAtomicLoad for {}", .{self.target.cpu.arch});
6762 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
6763
6764 const result: MCValue = result: {
6765 if (self.liveness.isUnused(inst)) break :result .dead;
6766
6767 const ptr_ty = self.air.typeOf(atomic_load.ptr);
6768 const ptr_mcv = try self.resolveInst(atomic_load.ptr);
6769 const ptr_lock = switch (ptr_mcv) {
6770 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
6771 else => null,
6772 };
6773 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
6774
6775 const dst_mcv =
6776 if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv))
6777 ptr_mcv
6778 else
6779 try self.allocRegOrMem(inst, true);
6780
6781 try self.load(dst_mcv, ptr_mcv, ptr_ty);
6782 break :result dst_mcv;
6783 };
6784 return self.finishAir(inst, result, .{ atomic_load.ptr, .none, .none });
66416785}
66426786
66436787fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
6644 _ = inst;
6645 _ = order;
6646 return self.fail("TODO implement airAtomicStore for {}", .{self.target.cpu.arch});
6788 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6789
6790 const dst_reg = try self.register_manager.allocReg(null, gp);
6791
6792 const ptr_ty = self.air.typeOf(bin_op.lhs);
6793 const ptr_mcv = try self.resolveInst(bin_op.lhs);
6794
6795 const val_ty = self.air.typeOf(bin_op.rhs);
6796 const val_mcv = try self.resolveInst(bin_op.rhs);
6797
6798 try self.atomicOp(dst_reg, ptr_mcv, val_mcv, ptr_ty, val_ty, true, null, order);
6799 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
66476800}
66486801
66496802fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
src/arch/x86_64/Emit.zig+91-14
......@@ -87,6 +87,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
8787 .cdq,
8888 .cqo,
8989 .cmp,
90 .cmpxchg,
9091 .div,
9192 .fisttp,
9293 .fld,
......@@ -95,7 +96,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
9596 .int3,
9697 .jmp,
9798 .lea,
99 .lfence,
98100 .lzcnt,
101 .mfence,
99102 .mov,
100103 .movzx,
101104 .mul,
......@@ -110,6 +113,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
110113 .sal,
111114 .sar,
112115 .sbb,
116 .sfence,
113117 .shl,
114118 .shr,
115119 .sub,
......@@ -117,6 +121,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
117121 .@"test",
118122 .tzcnt,
119123 .ud2,
124 .xadd,
125 .xchg,
120126 .xor,
121127
122128 .addss,
......@@ -148,6 +154,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
148154 .stos,
149155 => try emit.mirString(tag, inst),
150156
157 .cmpxchgb => try emit.mirCmpxchgBytes(inst),
158
151159 .jmp_reloc => try emit.mirJmpReloc(inst),
152160
153161 .call_extern => try emit.mirCallExtern(inst),
......@@ -214,6 +222,20 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
214222 const ops = emit.mir.instructions.items(.ops)[inst];
215223 const data = emit.mir.instructions.items(.data)[inst];
216224
225 const prefix: Instruction.Prefix = switch (ops) {
226 .lock_m_sib,
227 .lock_m_rip,
228 .lock_mi_u_sib,
229 .lock_mi_u_rip,
230 .lock_mi_s_sib,
231 .lock_mi_s_rip,
232 .lock_mr_sib,
233 .lock_mr_rip,
234 .lock_moffs_rax,
235 => .lock,
236 else => .none,
237 };
238
217239 var op1: Instruction.Operand = .none;
218240 var op2: Instruction.Operand = .none;
219241 var op3: Instruction.Operand = .none;
......@@ -252,35 +274,35 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
252274 op2 = .{ .reg = data.rri.r2 };
253275 op3 = .{ .imm = imm };
254276 },
255 .m_sib => {
277 .m_sib, .lock_m_sib => {
256278 const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
257279 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
258280 },
259 .m_rip => {
281 .m_rip, .lock_m_rip => {
260282 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
261283 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
262284 },
263 .mi_s_sib, .mi_u_sib => {
285 .mi_s_sib, .mi_u_sib, .lock_mi_s_sib, .lock_mi_u_sib => {
264286 const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;
265287 const imm = switch (ops) {
266 .mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
267 .mi_u_sib => Immediate.u(data.xi.imm),
288 .mi_s_sib, .lock_mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
289 .mi_u_sib, .lock_mi_u_sib => Immediate.u(data.xi.imm),
268290 else => unreachable,
269291 };
270292 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
271293 op2 = .{ .imm = imm };
272294 },
273 .mi_u_rip, .mi_s_rip => {
295 .mi_u_rip, .mi_s_rip, .lock_mi_u_rip, .lock_mi_s_rip => {
274296 const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;
275297 const imm = switch (ops) {
276 .mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
277 .mi_u_rip => Immediate.u(data.xi.imm),
298 .mi_s_rip, .lock_mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
299 .mi_u_rip, .lock_mi_u_rip => Immediate.u(data.xi.imm),
278300 else => unreachable,
279301 };
280302 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
281303 op2 = .{ .imm = imm };
282304 },
283 .rm_sib, .mr_sib => {
305 .rm_sib, .mr_sib, .lock_mr_sib => {
284306 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
285307 const op_r = .{ .reg = data.rx.r1 };
286308 const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
......@@ -289,23 +311,23 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
289311 op1 = op_r;
290312 op2 = op_m;
291313 },
292 .mr_sib => {
314 .mr_sib, .lock_mr_sib => {
293315 op1 = op_m;
294316 op2 = op_r;
295317 },
296318 else => unreachable,
297319 }
298320 },
299 .rm_rip, .mr_rip => {
321 .rm_rip, .mr_rip, .lock_mr_rip => {
300322 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
301323 const op_r = .{ .reg = data.rx.r1 };
302324 const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
303325 switch (ops) {
304 .rm_sib => {
326 .rm_rip => {
305327 op1 = op_r;
306328 op2 = op_m;
307329 },
308 .mr_sib => {
330 .mr_rip, .lock_mr_rip => {
309331 op1 = op_m;
310332 op2 = op_r;
311333 },
......@@ -319,6 +341,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
319341 }
320342
321343 return emit.encode(mnemonic, .{
344 .prefix = prefix,
322345 .op1 = op1,
323346 .op2 = op2,
324347 .op3 = op3,
......@@ -348,6 +371,39 @@ fn mirString(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!vo
348371 }
349372}
350373
374fn mirCmpxchgBytes(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
375 const ops = emit.mir.instructions.items(.ops)[inst];
376 const data = emit.mir.instructions.items(.data)[inst];
377
378 var op1: Instruction.Operand = .none;
379 switch (ops) {
380 .m_sib, .lock_m_sib => {
381 const sib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
382 op1 = .{ .mem = Mir.MemorySib.decode(sib) };
383 },
384 .m_rip, .lock_m_rip => {
385 const rip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
386 op1 = .{ .mem = Mir.MemoryRip.decode(rip) };
387 },
388 else => unreachable,
389 }
390
391 const mnemonic: Instruction.Mnemonic = switch (op1.mem.bitSize()) {
392 64 => .cmpxchg8b,
393 128 => .cmpxchg16b,
394 else => unreachable,
395 };
396
397 return emit.encode(mnemonic, .{
398 .prefix = switch (ops) {
399 .m_sib, .m_rip => .none,
400 .lock_m_sib, .lock_m_rip => .lock,
401 else => unreachable,
402 },
403 .op1 = op1,
404 });
405}
406
351407fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
352408 const ops = emit.mir.instructions.items(.ops)[inst];
353409 const payload = emit.mir.instructions.items(.data)[inst].payload;
......@@ -361,8 +417,13 @@ fn mirMovMoffs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
361417 .op2 = .{ .mem = Memory.moffs(seg, offset) },
362418 });
363419 },
364 .moffs_rax => {
420 .moffs_rax, .lock_moffs_rax => {
365421 try emit.encode(.mov, .{
422 .prefix = switch (ops) {
423 .moffs_rax => .none,
424 .lock_moffs_rax => .lock,
425 else => unreachable,
426 },
366427 .op1 = .{ .mem = Memory.moffs(seg, offset) },
367428 .op2 = .{ .reg = .rax },
368429 });
......@@ -455,6 +516,22 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
455516 .op1 = .{ .reg = data.r1 },
456517 });
457518 },
519 .m_sib_cc => {
520 const data = emit.mir.instructions.items(.data)[inst].x_cc;
521 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
522 const mnemonic = mnemonicFromConditionCode("set", data.cc);
523 return emit.encode(mnemonic, .{
524 .op1 = .{ .mem = Mir.MemorySib.decode(extra) },
525 });
526 },
527 .m_rip_cc => {
528 const data = emit.mir.instructions.items(.data)[inst].x_cc;
529 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
530 const mnemonic = mnemonicFromConditionCode("set", data.cc);
531 return emit.encode(mnemonic, .{
532 .op1 = .{ .mem = Mir.MemoryRip.decode(extra) },
533 });
534 },
458535 else => unreachable, // TODO
459536 }
460537}
src/arch/x86_64/Encoding.zig+9-6
......@@ -314,6 +314,7 @@ pub const Mnemonic = enum {
314314 cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
315315 cmp,
316316 cmps, cmpsb, cmpsd, cmpsq, cmpsw,
317 cmpxchg, cmpxchg8b, cmpxchg16b,
317318 cqo, cwd, cwde,
318319 div,
319320 fisttp, fld,
......@@ -321,10 +322,10 @@ pub const Mnemonic = enum {
321322 ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
322323 jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
323324 jmp,
324 lea,
325 lea, lfence,
325326 lods, lodsb, lodsd, lodsq, lodsw,
326327 lzcnt,
327 mov,
328 mfence, mov,
328329 movs, movsb, movsd, movsq, movsw,
329330 movsx, movsxd, movzx, mul,
330331 neg, nop, not,
......@@ -337,10 +338,11 @@ pub const Mnemonic = enum {
337338 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
338339 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
339340 setnz, seto, setp, setpe, setpo, sets, setz,
341 sfence,
340342 stos, stosb, stosd, stosq, stosw,
341343 @"test", tzcnt,
342344 ud2,
343 xor,
345 xadd, xchg, xor,
344346 // SSE
345347 addss,
346348 cmpss,
......@@ -387,7 +389,7 @@ pub const Op = enum {
387389 cl,
388390 r8, r16, r32, r64,
389391 rm8, rm16, rm32, rm64,
390 m8, m16, m32, m64, m80,
392 m8, m16, m32, m64, m80, m128,
391393 rel8, rel16, rel32,
392394 m,
393395 moffs,
......@@ -436,6 +438,7 @@ pub const Op = enum {
436438 32 => .m32,
437439 64 => .m64,
438440 80 => .m80,
441 128 => .m128,
439442 else => unreachable,
440443 };
441444 },
......@@ -473,7 +476,7 @@ pub const Op = enum {
473476 .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32,
474477 .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64,
475478 .m80 => 80,
476 .xmm => 128,
479 .m128, .xmm => 128,
477480 };
478481 }
479482
......@@ -520,7 +523,7 @@ pub const Op = enum {
520523 // zig fmt: off
521524 return switch (op) {
522525 .rm8, .rm16, .rm32, .rm64,
523 .m8, .m16, .m32, .m64, .m80,
526 .m8, .m16, .m32, .m64, .m80, .m128,
524527 .m,
525528 .xmm_m32, .xmm_m64,
526529 => true,
src/arch/x86_64/Mir.zig+35-7
......@@ -66,6 +66,10 @@ pub const Inst = struct {
6666 cqo,
6767 /// Logical compare
6868 cmp,
69 /// Compare and exchange
70 cmpxchg,
71 /// Compare and exchange bytes
72 cmpxchgb,
6973 /// Unsigned division
7074 div,
7175 /// Store integer with truncation
......@@ -82,8 +86,12 @@ pub const Inst = struct {
8286 jmp,
8387 /// Load effective address
8488 lea,
89 /// Load fence
90 lfence,
8591 /// Count the number of leading zero bits
8692 lzcnt,
93 /// Memory fence
94 mfence,
8795 /// Move
8896 mov,
8997 /// Move with sign extension
......@@ -114,6 +122,8 @@ pub const Inst = struct {
114122 sar,
115123 /// Integer subtraction with borrow
116124 sbb,
125 /// Store fence
126 sfence,
117127 /// Logical shift left
118128 shl,
119129 /// Logical shift right
......@@ -128,6 +138,10 @@ pub const Inst = struct {
128138 tzcnt,
129139 /// Undefined instruction
130140 ud2,
141 /// Exchange and add
142 xadd,
143 /// Exchange register/memory with register
144 xchg,
131145 /// Logical exclusive-or
132146 xor,
133147
......@@ -242,10 +256,10 @@ pub const Inst = struct {
242256 /// Uses `rri` payload.
243257 rri_u,
244258 /// Register with condition code (CC).
245 /// Uses `r_c` payload.
259 /// Uses `r_cc` payload.
246260 r_cc,
247261 /// Register, register with condition code (CC).
248 /// Uses `rr_c` payload.
262 /// Uses `rr_cc` payload.
249263 rr_cc,
250264 /// Register, immediate (sign-extended) operands.
251265 /// Uses `ri` payload.
......@@ -283,6 +297,12 @@ pub const Inst = struct {
283297 /// Single memory (RIP) operand.
284298 /// Uses `payload` with extra data of type `MemoryRip`.
285299 m_rip,
300 /// Single memory (SIB) operand with condition code (CC).
301 /// Uses `x_cc` with extra data of type `MemorySib`.
302 m_sib_cc,
303 /// Single memory (RIP) operand with condition code (CC).
304 /// Uses `x_cc` with extra data of type `MemoryRip`.
305 m_rip_cc,
286306 /// Memory (SIB), immediate (unsigned) operands.
287307 /// Uses `xi` payload with extra data of type `MemorySib`.
288308 mi_u_sib,
......@@ -301,6 +321,12 @@ pub const Inst = struct {
301321 /// Memory (RIP), register operands.
302322 /// Uses `rx` payload with extra data of type `MemoryRip`.
303323 mr_rip,
324 /// Rax, Memory moffs.
325 /// Uses `payload` with extra data of type `MemoryMoffs`.
326 rax_moffs,
327 /// Memory moffs, rax.
328 /// Uses `payload` with extra data of type `MemoryMoffs`.
329 moffs_rax,
304330 /// Single memory (SIB) operand with lock prefix.
305331 /// Uses `payload` with extra data of type `MemorySib`.
306332 lock_m_sib,
......@@ -325,12 +351,9 @@ pub const Inst = struct {
325351 /// Memory (RIP), register operands with lock prefix.
326352 /// Uses `rx` payload with extra data of type `MemoryRip`.
327353 lock_mr_rip,
328 /// Rax, Memory moffs.
354 /// Memory moffs, rax with lock prefix.
329355 /// Uses `payload` with extra data of type `MemoryMoffs`.
330 rax_moffs,
331 /// Memory moffs, rax.
332 /// Uses `payload` with extra data of type `MemoryMoffs`.
333 moffs_rax,
356 lock_moffs_rax,
334357 /// References another Mir instruction directly.
335358 /// Uses `inst` payload.
336359 inst,
......@@ -381,6 +404,11 @@ pub const Inst = struct {
381404 r2: Register,
382405 imm: u32,
383406 },
407 /// Condition code (CC), followed by custom payload found in extra.
408 x_cc: struct {
409 payload: u32,
410 cc: bits.Condition,
411 },
384412 /// Register with condition code (CC).
385413 r_cc: struct {
386414 r1: Register,
src/arch/x86_64/encoder.zig+2-1
......@@ -117,7 +117,8 @@ pub const Instruction = struct {
117117
118118 pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
119119 const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
120 log.debug("no encoding found for: {s} {s} {s} {s} {s}", .{
120 log.debug("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
121 @tagName(args.prefix),
121122 @tagName(mnemonic),
122123 @tagName(Encoding.Op.fromOperand(args.op1)),
123124 @tagName(Encoding.Op.fromOperand(args.op2)),
src/arch/x86_64/encodings.zig+38
......@@ -252,6 +252,15 @@ pub const table = &[_]Entry{
252252 .{ .cmpsd, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .none },
253253 .{ .cmpsq, .np, .none, .none, .none, .none, &.{ 0xa7 }, 0, .long },
254254
255 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
256 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
257 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
258 .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
259 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
260
261 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
262 .{ .cmpxchg16b, .m, .m128, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .long },
263
255264 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .none },
256265 .{ .div, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 6, .rex },
257266 .{ .div, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 6, .none },
......@@ -328,6 +337,8 @@ pub const table = &[_]Entry{
328337 .{ .lea, .rm, .r32, .m, .none, .none, &.{ 0x8d }, 0, .none },
329338 .{ .lea, .rm, .r64, .m, .none, .none, &.{ 0x8d }, 0, .long },
330339
340 .{ .lfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xe8 }, 0, .none },
341
331342 .{ .lods, .np, .m8, .none, .none, .none, &.{ 0xac }, 0, .none },
332343 .{ .lods, .np, .m16, .none, .none, .none, &.{ 0xad }, 0, .none },
333344 .{ .lods, .np, .m32, .none, .none, .none, &.{ 0xad }, 0, .none },
......@@ -341,6 +352,8 @@ pub const table = &[_]Entry{
341352 .{ .lzcnt, .rm, .r32, .rm32, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .none },
342353 .{ .lzcnt, .rm, .r64, .rm64, .none, .none, &.{ 0xf3, 0x0f, 0xbd }, 0, .long },
343354
355 .{ .mfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf0 }, 0, .none },
356
344357 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .none },
345358 .{ .mov, .mr, .rm8, .r8, .none, .none, &.{ 0x88 }, 0, .rex },
346359 .{ .mov, .mr, .rm16, .r16, .none, .none, &.{ 0x89 }, 0, .none },
......@@ -588,6 +601,8 @@ pub const table = &[_]Entry{
588601 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .none },
589602 .{ .setz, .m, .rm8, .none, .none, .none, &.{ 0x0f, 0x94 }, 0, .rex },
590603
604 .{ .sfence, .np, .none, .none, .none, .none, &.{ 0x0f, 0xae, 0xf8 }, 0, .none },
605
591606 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .none },
592607 .{ .shl, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 4, .rex },
593608 .{ .shl, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 4, .none },
......@@ -675,6 +690,29 @@ pub const table = &[_]Entry{
675690
676691 .{ .ud2, .np, .none, .none, .none, .none, &.{ 0x0f, 0x0b }, 0, .none },
677692
693 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .none },
694 .{ .xadd, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xc0 }, 0, .rex },
695 .{ .xadd, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
696 .{ .xadd, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xc1 }, 0, .none },
697 .{ .xadd, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xc1 }, 0, .long },
698
699 .{ .xchg, .o, .ax, .r16, .none, .none, &.{ 0x90 }, 0, .none },
700 .{ .xchg, .o, .r16, .ax, .none, .none, &.{ 0x90 }, 0, .none },
701 .{ .xchg, .o, .eax, .r32, .none, .none, &.{ 0x90 }, 0, .none },
702 .{ .xchg, .o, .rax, .r64, .none, .none, &.{ 0x90 }, 0, .long },
703 .{ .xchg, .o, .r32, .eax, .none, .none, &.{ 0x90 }, 0, .none },
704 .{ .xchg, .o, .r64, .rax, .none, .none, &.{ 0x90 }, 0, .long },
705 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .none },
706 .{ .xchg, .mr, .rm8, .r8, .none, .none, &.{ 0x86 }, 0, .rex },
707 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .none },
708 .{ .xchg, .rm, .r8, .rm8, .none, .none, &.{ 0x86 }, 0, .rex },
709 .{ .xchg, .mr, .rm16, .r16, .none, .none, &.{ 0x87 }, 0, .none },
710 .{ .xchg, .rm, .r16, .rm16, .none, .none, &.{ 0x87 }, 0, .none },
711 .{ .xchg, .mr, .rm32, .r32, .none, .none, &.{ 0x87 }, 0, .none },
712 .{ .xchg, .mr, .rm64, .r64, .none, .none, &.{ 0x87 }, 0, .long },
713 .{ .xchg, .rm, .r32, .rm32, .none, .none, &.{ 0x87 }, 0, .none },
714 .{ .xchg, .rm, .r64, .rm64, .none, .none, &.{ 0x87 }, 0, .long },
715
678716 .{ .xor, .zi, .al, .imm8, .none, .none, &.{ 0x34 }, 0, .none },
679717 .{ .xor, .zi, .ax, .imm16, .none, .none, &.{ 0x35 }, 0, .none },
680718 .{ .xor, .zi, .eax, .imm32, .none, .none, &.{ 0x35 }, 0, .none },
src/register_manager.zig+16-24
......@@ -305,40 +305,32 @@ pub fn RegisterManager(
305305 pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
306306 const index = indexOfRegIntoTracked(reg) orelse return;
307307 log.debug("getReg {} for inst {?}", .{ reg, inst });
308 self.markRegAllocated(reg);
309308
310 if (inst) |tracked_inst|
311 if (!self.isRegFree(reg)) {
312 // Move the instruction that was previously there to a
313 // stack allocation.
314 const spilled_inst = self.registers[index];
315 self.registers[index] = tracked_inst;
316 try self.getFunction().spillInstruction(reg, spilled_inst);
317 } else {
318 self.getRegAssumeFree(reg, tracked_inst);
319 }
320 else {
321 if (!self.isRegFree(reg)) {
322 // Move the instruction that was previously there to a
323 // stack allocation.
324 const spilled_inst = self.registers[index];
325 try self.getFunction().spillInstruction(reg, spilled_inst);
326 self.freeReg(reg);
327 }
328 }
309 if (!self.isRegFree(reg)) {
310 self.markRegAllocated(reg);
311
312 // Move the instruction that was previously there to a
313 // stack allocation.
314 const spilled_inst = self.registers[index];
315 if (inst) |tracked_inst| self.registers[index] = tracked_inst;
316 try self.getFunction().spillInstruction(reg, spilled_inst);
317 if (inst == null) self.freeReg(reg);
318 } else self.getRegAssumeFree(reg, inst);
329319 }
330320
331321 /// Allocates the specified register with the specified
332322 /// instruction. Asserts that the register is free and no
333323 /// spilling is necessary.
334 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
324 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: ?Air.Inst.Index) void {
335325 const index = indexOfRegIntoTracked(reg) orelse return;
336 log.debug("getRegAssumeFree {} for inst {}", .{ reg, inst });
326 log.debug("getRegAssumeFree {} for inst {?}", .{ reg, inst });
337327 self.markRegAllocated(reg);
338328
339329 assert(self.isRegFree(reg));
340 self.registers[index] = inst;
341 self.markRegUsed(reg);
330 if (inst) |tracked_inst| {
331 self.registers[index] = tracked_inst;
332 self.markRegUsed(reg);
333 }
342334 }
343335
344336 /// Marks the specified register as free
test/behavior/atomics.zig-7
......@@ -33,7 +33,6 @@ fn testCmpxchg() !void {
3333
3434test "fence" {
3535 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3938
......@@ -44,7 +43,6 @@ test "fence" {
4443
4544test "atomicrmw and atomicload" {
4645 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4947 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5048 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -73,7 +71,6 @@ fn testAtomicLoad(ptr: *u8) !void {
7371
7472test "cmpxchg with ptr" {
7573 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7774 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7875 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7976 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -162,7 +159,6 @@ test "cmpxchg on a global variable" {
162159
163160test "atomic load and rmw with enum" {
164161 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
165 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
166162 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
167163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
168164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -180,7 +176,6 @@ test "atomic load and rmw with enum" {
180176
181177test "atomic store" {
182178 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
184179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
185180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -194,7 +189,6 @@ test "atomic store" {
194189
195190test "atomic store comptime" {
196191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
197 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
198192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
199193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
200194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -424,7 +418,6 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
424418
425419test "return @atomicStore, using it as a void value" {
426420 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
427 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
428421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
429422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
430423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/13068.zig-1
......@@ -8,7 +8,6 @@ test {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312
1413 list.items.len = 0;
test/behavior/cast.zig-1
......@@ -655,7 +655,6 @@ test "@floatCast cast down" {
655655}
656656
657657test "peer type resolution: unreachable, error set, unreachable" {
658 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
659658 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
660659 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
661660
test/behavior/merge_error_sets.zig-1
......@@ -12,7 +12,6 @@ fn foo() C!void {
1212}
1313
1414test "merge error sets" {
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1716
1817 if (foo()) {
test/behavior/switch.zig-1
......@@ -228,7 +228,6 @@ const SwitchProngWithVarEnum = union(enum) {
228228};
229229
230230test "switch prong with variable" {
231 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
232231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
233232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
234233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO