diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-16 19:45:30 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-05-19 19:37:29 +0200 |
| commit | 9e5c8cb008f75c2e570a0e48d5d014e936c103ca (patch) | |
| tree | af9bf9c8457a4137b1fc534e7eac8a0a4400b8ec /src/arch/x86_64/CodeGen.zig | |
| parent | 2aee2302515ba444999b82c2e40cbc35dee08baf (diff) | |
| download | zig-9e5c8cb008f75c2e570a0e48d5d014e936c103ca.tar.gz zig-9e5c8cb008f75c2e570a0e48d5d014e936c103ca.zip | |
x64: merge general purpose with simd register into one bitset
This way, we do not have to tweak the `RegisterManager` to handle
multiple register types - we have one linear space instead. Additionally
we can use the bitset itself to separate the registers into overlapping
(the ones that are aliases of differing bitwidths) and nonoverlapping
classes (for example, AVX registers do not overlap general purpose
registers, thus they can be allocated simultaneously).
Another huge benefit of this simple approach is the fact that we can
still refer to *all* registers regardless of their class via enum
literals which makes the code so much more readable.
Finally, `RegisterLock` is universal across different register classes.
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 1060 |
1 files changed, 427 insertions, 633 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index e81f2d5435..aa6d04d5d9 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -35,14 +35,10 @@ const caller_preserved_regs = abi.caller_preserved_regs; const allocatable_registers = abi.allocatable_registers; const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; -const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers, spillInstruction); +const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); const RegisterLock = RegisterManager.RegisterLock; const Register = bits.Register; -const AvxRegisterManager = RegisterManagerFn(Self, AvxRegister, &abi.avx_regs, spillInstructionAvx); -const AvxRegisterLock = AvxRegisterManager.RegisterLock; -const AvxRegister = bits.AvxRegister; - const InnerError = error{ OutOfMemory, CodegenFail, @@ -92,8 +88,7 @@ branch_stack: *std.ArrayList(Branch), // Key is the block instruction blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, -register_manager: RegisterManager, -avx_register_manager: AvxRegisterManager, +register_manager: RegisterManager = .{}, /// Maps offset to what is stored there. stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, @@ -133,8 +128,6 @@ pub const MCValue = union(enum) { /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register, /// and the operation is a signed operation. register_overflow_signed: Register, - /// The value is in an AVX register. - avx_register: AvxRegister, /// The value is in memory at a hard-coded address. /// If the type is a pointer, it means the pointer address is at this memory location. memory: u64, @@ -202,7 +195,6 @@ pub const MCValue = union(enum) { fn isRegister(mcv: MCValue) bool { return switch (mcv) { .register => true, - .avx_register => true, else => false, }; } @@ -304,11 +296,7 @@ pub fn generate( .mir_to_air_map = if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) else {}, - .register_manager = undefined, - .avx_register_manager = undefined, }; - function.register_manager = .{ .function = &function }; - function.avx_register_manager = .{ .function = &function }; defer function.stack.deinit(bin_file.allocator); defer function.blocks.deinit(bin_file.allocator); defer function.exitlude_jump_relocs.deinit(bin_file.allocator); @@ -400,17 +388,15 @@ fn gen(self: *Self) InnerError!void { if (cc != .Naked) { _ = try self.addInst(.{ .tag = .push, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rbp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), .data = undefined, // unused for push reg, }); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp, .reg2 = .rsp, - }).encode(), + }), .data = undefined, }); // We want to subtract the aligned stack frame size from rsp here, but we don't @@ -447,9 +433,7 @@ fn gen(self: *Self) InnerError!void { // push the callee_preserved_regs that were used const backpatch_push_callee_preserved_regs_i = try self.addInst(.{ .tag = .push_regs_from_callee_preserved_regs, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rbp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), .data = .{ .payload = undefined }, // to be backpatched }); @@ -489,9 +473,7 @@ fn gen(self: *Self) InnerError!void { // pop the callee_preserved_regs _ = try self.addInst(.{ .tag = .pop_regs_from_callee_preserved_regs, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rbp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), .data = .{ .payload = callee_preserved_regs_payload }, }); @@ -510,17 +492,13 @@ fn gen(self: *Self) InnerError!void { _ = try self.addInst(.{ .tag = .pop, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rbp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }), .data = undefined, }); _ = try self.addInst(.{ .tag = .ret, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b11, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b11 }), .data = undefined, }); @@ -534,16 +512,12 @@ fn gen(self: *Self) InnerError!void { if (aligned_stack_end > 0) { self.mir_instructions.set(backpatch_stack_sub, .{ .tag = .sub, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rsp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }), .data = .{ .imm = aligned_stack_end }, }); self.mir_instructions.set(backpatch_stack_add, .{ .tag = .add, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rsp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }), .data = .{ .imm = aligned_stack_end }, }); } @@ -908,8 +882,8 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { // TODO check if AVX available const ptr_bytes: u64 = 32; if (abi_size <= ptr_bytes) { - if (self.avx_register_manager.tryAllocReg(inst)) |reg| { - return MCValue{ .avx_register = avxRegisterAlias(reg, abi_size) }; + if (self.register_manager.tryAllocReg(inst)) |reg| { + return MCValue{ .register = registerAlias(reg, abi_size) }; } } }, @@ -947,21 +921,6 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); } -pub fn spillInstructionAvx(self: *Self, reg: AvxRegister, inst: Air.Inst.Index) !void { - const stack_mcv = try self.allocRegOrMem(inst, false); - log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); - const reg_mcv = self.getResolvedInstValue(inst); - switch (reg_mcv) { - .avx_register => |other| { - assert(reg.to256() == other.to256()); - }, - else => {}, - } - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - try branch.inst_table.put(self.gpa, inst, stack_mcv); - try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); -} - pub fn spillCompareFlagsIfOccupied(self: *Self) !void { if (self.compare_flags_inst) |inst_to_save| { const mcv = self.getResolvedInstValue(inst_to_save); @@ -972,7 +931,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { .compare_flags_signed, .compare_flags_unsigned, => try self.allocRegOrMem(inst_to_save, true), - .avx_register => try self.allocRegOrMem(inst_to_save, false), else => unreachable, }; @@ -990,7 +948,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { .register_overflow_signed, .register_overflow_unsigned, => |reg| self.register_manager.freeReg(reg), - .avx_register => |reg| self.avx_register_manager.freeReg(reg), else => {}, } } @@ -1236,10 +1193,10 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); _ = try self.addInst(.{ .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_mcv.register, .reg2 = lhs_reg, - }).encode(), + }), .data = undefined, }); @@ -1440,10 +1397,10 @@ fn genSetStackTruncatedOverflowCompare( }; _ = try self.addInst(.{ .tag = .cond_set_byte_overflow, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = overflow_reg.to8(), .flags = flags, - }).encode(), + }), .data = undefined, }); @@ -1460,10 +1417,7 @@ fn genSetStackTruncatedOverflowCompare( const eq_reg = temp_regs[2]; _ = try self.addInst(.{ .tag = .cond_set_byte_eq_ne, - .ops = (Mir.Ops(Register, Register){ - .reg1 = eq_reg.to8(), - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }), .data = undefined, }); @@ -1609,19 +1563,17 @@ fn genIntMulDivOpMir( .signed => { _ = try self.addInst(.{ .tag = .cwd, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b11, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b11 }), .data = undefined, }); }, .unsigned => { _ = try self.addInst(.{ .tag = .xor, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rdx, .reg2 = .rdx, - }).encode(), + }), .data = undefined, }); }, @@ -1640,16 +1592,14 @@ fn genIntMulDivOpMir( .register => |reg| { _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), .data = undefined, }); }, .stack_offset => |off| { _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg2 = .rbp, .flags = switch (abi_size) { 1 => 0b00, @@ -1658,7 +1608,7 @@ fn genIntMulDivOpMir( 8 => 0b11, else => unreachable, }, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -1691,34 +1641,34 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa _ = try self.addInst(.{ .tag = .xor, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = divisor.to64(), .reg2 = dividend.to64(), - }).encode(), + }), .data = undefined, }); _ = try self.addInst(.{ .tag = .sar, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = divisor.to64(), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 63 }, }); _ = try self.addInst(.{ .tag = .@"test", - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rdx, .reg2 = .rdx, - }).encode(), + }), .data = undefined, }); _ = try self.addInst(.{ .tag = .cond_mov_eq, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = divisor.to64(), .reg2 = .rdx, - }).encode(), + }), .data = undefined, }); try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); @@ -2102,11 +2052,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { // mov reg, [rbp - 8] _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = .rbp, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, }); }, @@ -2187,10 +2137,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { // lea reg, [rbp] _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -2198,10 +2148,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { // lea reg, [rbp] _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -2266,11 +2216,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { // mov dst_mcv, [dst_mcv] _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b01, + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)), .reg2 = dst_mcv.register, - }).encode(), + .flags = 0b01, + }), .data = .{ .imm = 0 }, }); break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; @@ -2532,11 +2482,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo // mov dst_reg, [reg] _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)), .reg2 = reg, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = 0 }, }); }, @@ -2552,9 +2502,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), } }, - .avx_register => { - return self.fail("TODO load for AVX register", .{}); - }, .memory, .got_load, .direct_load, @@ -2606,10 +2553,10 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); _ = try self.addInst(.{ .tag = .lea_pie, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .flags = flags, - }).encode(), + }), .data = .{ .load_reloc = .{ .atom_index = fn_owner_decl.link.macho.local_sym_index, @@ -2670,7 +2617,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type }); _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64(), .flags = switch (abi_size) { 1 => 0b00, @@ -2678,7 +2625,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type 4 => 0b10, else => unreachable, }, - }).encode(), + }), .data = .{ .payload = payload }, }); }, @@ -2692,11 +2639,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const tmp_reg = try self.copyToTmpRegister(value_ty, value); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64(), .reg2 = tmp_reg.to64(), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 0 }, }); }, @@ -2708,11 +2655,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type .register => |src_reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64(), .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 0 }, }); }, @@ -2736,9 +2683,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type }, } }, - .avx_register => { - return self.fail("TODO store for AVX register", .{}); - }, .got_load, .direct_load, .memory, @@ -2759,11 +2703,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type // mov reg, [reg] _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = addr_reg.to64(), .flags = 0b01, - }).encode(), + }), .data = .{ .imm = 0 }, }); @@ -2798,21 +2742,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type } _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .flags = flags, - }).encode(), + }), .data = .{ .payload = payload }, }); }, .register => |reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = reg, .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 0 }, }); }, @@ -2829,20 +2773,20 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = tmp_reg, .reg2 = tmp_reg, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = 0 }, }); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = tmp_reg, .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 0 }, }); return; @@ -2856,11 +2800,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const tmp_reg = try self.copyToTmpRegister(value_ty, value); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = tmp_reg, .flags = 0b10, - }).encode(), + }), .data = .{ .imm = 0 }, }); return; @@ -3017,10 +2961,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { if (signedness == .signed and field_size < 8) { _ = try self.addInst(.{ .tag = .mov_sign_extend, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_mcv.register, .reg2 = registerAlias(dst_mcv.register, field_size), - }).encode(), + }), .data = undefined, }); } @@ -3048,10 +2992,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { }; _ = try self.addInst(.{ .tag = .cond_set_byte_overflow, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_reg.to8(), .flags = flags, - }).encode(), + }), .data = undefined, }); break :result MCValue{ .register = dst_reg.to8() }; @@ -3092,10 +3036,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi 1 => { _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(reg, abi_size), - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }), .data = undefined, }); return; @@ -3103,10 +3044,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi else => { _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = @intCast(u8, imm) }, }); return; @@ -3124,10 +3065,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .flags = 0b01, - }).encode(), + }), .data = undefined, }); } @@ -3383,32 +3324,6 @@ fn genBinOp( return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); } - if (lhs_ty.zigTypeTag() == .Float) { - switch (tag) { - .add => { - const dst_reg: AvxRegister = blk: { - const reg = try self.avx_register_manager.allocReg(null); - try self.genSetAvxReg(lhs_ty, reg, lhs); - break :blk reg.to128(); - }; - const dst_lock = self.avx_register_manager.lockRegAssumeUnused(dst_reg); - defer self.avx_register_manager.unlockReg(dst_lock); - - const src_reg: AvxRegister = blk: { - const reg = try self.avx_register_manager.allocReg(null); - try self.genSetAvxReg(lhs_ty, reg, rhs); - break :blk reg.to128(); - }; - const src_lock = self.avx_register_manager.lockRegAssumeUnused(src_reg); - defer self.avx_register_manager.unlockReg(src_lock); - - try self.genBinOpMir(.add_f64, lhs_ty, .{ .avx_register = dst_reg }, .{ .avx_register = src_reg }); - return MCValue{ .avx_register = dst_reg }; - }, - else => unreachable, - } - } - const is_commutative: bool = switch (tag) { .add, .addwrap, @@ -3526,25 +3441,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu const reg = try self.copyToTmpRegister(dst_ty, src_mcv); return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); }, - .register => |src_reg| { - _ = try self.addInst(.{ - .tag = mir_tag, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(dst_reg, abi_size), - .reg2 = registerAlias(src_reg, abi_size), - }).encode(), - .data = undefined, - }); - }, - .avx_register => { - return self.fail("TODO genBinOp for AVX register", .{}); + .register => |src_reg| switch (dst_ty.zigTypeTag()) { + .Float => switch (dst_ty.tag()) { + .f64 => { + _ = try self.addInst(.{ + .tag = switch (mir_tag) { + .add => .add_f64, + .cmp => .cmp_f64, + else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}), + }, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = dst_reg.to128(), + .reg2 = src_reg.to128(), + }), + .data = undefined, + }); + }, + else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}), + }, + else => { + _ = try self.addInst(.{ + .tag = mir_tag, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = registerAlias(dst_reg, abi_size), + .reg2 = registerAlias(src_reg, abi_size), + }), + .data = undefined, + }); + }, }, .immediate => |imm| { _ = try self.addInst(.{ .tag = mir_tag, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(dst_reg, abi_size), - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size) }), .data = .{ .imm = @truncate(u32, imm) }, }); }, @@ -3567,39 +3496,16 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu } _ = try self.addInst(.{ .tag = mir_tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size), .reg2 = .rbp, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, } }, - .avx_register => |dst_reg| { - switch (src_mcv) { - .avx_register => |src_reg| { - switch (dst_ty.zigTypeTag()) { - .Float => switch (dst_ty.tag()) { - .f64 => { - _ = try self.addInst(.{ - .tag = mir_tag, - .ops = (Mir.Ops(AvxRegister, AvxRegister){ - .reg1 = dst_reg.to128(), - .reg2 = src_reg.to128(), - }).encode(), - .data = undefined, - }); - }, - else => return self.fail("TODO genBinOp for AVX register and type {}", .{dst_ty.fmtDebug()}), - }, - else => return self.fail("TODO genBinOp for AVX register and type {}", .{dst_ty.fmtDebug()}), - } - }, - else => return self.fail("TODO genBinOp for AVX register", .{}), - } - }, .ptr_stack_offset, .stack_offset => |off| { if (off > math.maxInt(i32)) { return self.fail("stack offset too large", .{}); @@ -3617,17 +3523,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu .register => |src_reg| { _ = try self.addInst(.{ .tag = mir_tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp, .reg2 = registerAlias(src_reg, abi_size), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, - .avx_register => { - return self.fail("TODO genBinOp for AVX register", .{}); - }, .immediate => |imm| { const tag: Mir.Inst.Tag = switch (mir_tag) { .add => .add_mem_imm, @@ -3651,10 +3554,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu }); _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp, .flags = flags, - }).encode(), + }), .data = .{ .payload = payload }, }); }, @@ -3697,7 +3600,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .ptr_stack_offset => unreachable, .register_overflow_unsigned => unreachable, .register_overflow_signed => unreachable, - .avx_register => unreachable, .register => |dst_reg| { switch (src_mcv) { .none => unreachable, @@ -3706,15 +3608,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .ptr_stack_offset => unreachable, .register_overflow_unsigned => unreachable, .register_overflow_signed => unreachable, - .avx_register => unreachable, .register => |src_reg| { // register, register _ = try self.addInst(.{ .tag = .imul_complex, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size), .reg2 = registerAlias(src_reg, abi_size), - }).encode(), + }), .data = undefined, }); }, @@ -3724,11 +3625,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) { _ = try self.addInst(.{ .tag = .imul_complex, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_reg.to32(), .reg2 = dst_reg.to32(), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = @truncate(u32, imm) }, }); } else { @@ -3740,11 +3641,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .stack_offset => |off| { _ = try self.addInst(.{ .tag = .imul_complex, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size), .reg2 = .rbp, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -3770,7 +3671,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .ptr_stack_offset => unreachable, .register_overflow_unsigned => unreachable, .register_overflow_signed => unreachable, - .avx_register => unreachable, .register => |src_reg| { // copy dst to a register const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); @@ -3778,10 +3678,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M // register, register _ = try self.addInst(.{ .tag = .imul_complex, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size), .reg2 = registerAlias(src_reg, abi_size), - }).encode(), + }), .data = undefined, }); // copy dst_reg back out @@ -3888,9 +3788,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { fn airBreakpoint(self: *Self) !void { _ = try self.addInst(.{ .tag = .interrupt, - .ops = (Mir.Ops{ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = undefined, }); return self.finishAirBookkeeping(); @@ -3973,9 +3871,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. .ptr_stack_offset => { return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); }, - .avx_register => { - return self.fail("TODO implement calling with MCValue.avx_register arg", .{}); - }, .undef => unreachable, .immediate => unreachable, .unreach => unreachable, @@ -3994,9 +3889,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. // Adjust the stack _ = try self.addInst(.{ .tag = .sub, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rsp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }), .data = .{ .imm = info.stack_byte_count }, }); } @@ -4020,9 +3913,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. unreachable; _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b01, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .imm = @truncate(u32, got_addr) }, }); } else if (func_value.castTag(.extern_fn)) |_| { @@ -4036,10 +3927,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. try self.genSetReg(Type.initTag(.usize), .rax, mcv); _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax, .flags = 0b01, - }).encode(), + }), .data = undefined, }); } @@ -4054,10 +3945,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. // callq *%rax _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax, .flags = 0b01, - }).encode(), + }), .data = undefined, }); } else if (func_value.castTag(.extern_fn)) |func_payload| { @@ -4089,10 +3980,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. try self.genSetReg(Type.initTag(.usize), .rax, mcv); _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax, .flags = 0b01, - }).encode(), + }), .data = undefined, }); } @@ -4107,9 +3998,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. const fn_got_addr = got_addr + got_index * ptr_bytes; _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b01, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .imm = @intCast(u32, fn_got_addr) }, }); } else return self.fail("TODO implement calling extern fn on plan9", .{}); @@ -4119,10 +4008,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. try self.genSetReg(Type.initTag(.usize), .rax, mcv); _ = try self.addInst(.{ .tag = .call, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax, .flags = 0b01, - }).encode(), + }), .data = undefined, }); } @@ -4132,9 +4021,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. // Readjust the stack _ = try self.addInst(.{ .tag = .add, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rsp, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }), .data = .{ .imm = info.stack_byte_count }, }); } @@ -4192,9 +4079,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { // which is available if the jump is 127 bytes or less forward. const jmp_reloc = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = undefined }, }); try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); @@ -4227,9 +4112,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { // which is available if the jump is 127 bytes or less forward. const jmp_reloc = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = undefined }, }); try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); @@ -4256,37 +4139,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { self.compare_flags_inst = inst; const result: MCValue = result: { - if (ty.zigTypeTag() == .Float) { - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - - const dst_reg: AvxRegister = blk: { - const reg = try self.avx_register_manager.allocReg(null); - try self.genSetAvxReg(ty, reg, lhs); - break :blk reg.to128(); - }; - const dst_lock = self.avx_register_manager.lockRegAssumeUnused(dst_reg); - defer self.avx_register_manager.unlockReg(dst_lock); - - const src_reg: AvxRegister = blk: { - const reg = try self.avx_register_manager.allocReg(null); - try self.genSetAvxReg(ty, reg, rhs); - break :blk reg.to128(); - }; - const src_lock = self.avx_register_manager.lockRegAssumeUnused(src_reg); - defer self.avx_register_manager.unlockReg(src_lock); - - _ = try self.addInst(.{ - .tag = .cmp_f64, - .ops = (Mir.Ops(AvxRegister, AvxRegister){ - .reg1 = dst_reg, - .reg2 = src_reg, - }).encode(), - .data = undefined, - }); - - break :result MCValue{ .compare_flags_unsigned = op }; - } // There are 2 operands, destination and source. // Either one, but not both, can be a memory operand. // Source operand can be an immediate, 8 bits or 32 bits. @@ -4304,8 +4156,28 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const dst_mcv = MCValue{ .register = dst_reg }; + const rhs_ty = self.air.typeOf(bin_op.rhs); // This instruction supports only signed 32-bit immediates at most. - const src_mcv = try self.limitImmediateType(bin_op.rhs, i32); + const src_mcv: MCValue = blk: { + switch (rhs_ty.zigTypeTag()) { + .Float => { + const rhs = try self.resolveInst(bin_op.rhs); + const rhs_lock: ?RegisterLock = switch (rhs) { + .register => |reg| self.register_manager.lockRegAssumeUnused(reg), + else => null, + }; + defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); + const src_reg = try self.copyToTmpRegister(rhs_ty, rhs); + break :blk MCValue{ .register = src_reg }; + }, + else => break :blk try self.limitImmediateType(bin_op.rhs, i32), + } + }; + const src_lock: ?RegisterLock = switch (src_mcv) { + .register => |reg| self.register_manager.lockReg(reg), + else => null, + }; + defer if (src_lock) |lock| self.register_manager.unlockReg(lock); try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv); break :result switch (signedness) { @@ -4504,9 +4376,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { Mir.Inst.Tag.cond_jmp_greater_less; return self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ - .flags = flags, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = flags }), .data = .{ .inst = undefined }, }); }, @@ -4514,17 +4384,12 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { try self.spillCompareFlagsIfOccupied(); _ = try self.addInst(.{ .tag = .@"test", - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg, - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), .data = .{ .imm = 1 }, }); return self.addInst(.{ .tag = .cond_jmp_eq_ne, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b01, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .inst = undefined }, }); }, @@ -4918,9 +4783,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { try self.genBody(body); _ = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = jmp_target }, }); return self.finishAirBookkeeping(); @@ -4971,19 +4834,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u .immediate => |imm| { _ = try self.addInst(.{ .tag = .xor, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(cond_reg, abi_size), - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size) }), .data = .{ .imm = @intCast(u32, imm) }, }); }, .register => |reg| { _ = try self.addInst(.{ .tag = .xor, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size), .reg2 = registerAlias(reg, abi_size), - }).encode(), + }), .data = undefined, }); }, @@ -5002,17 +4863,15 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u _ = try self.addInst(.{ .tag = .@"test", - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size), .reg2 = registerAlias(cond_reg, abi_size), - }).encode(), + }), .data = undefined, }); return self.addInst(.{ .tag = .cond_jmp_eq_ne, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = undefined }, }); }, @@ -5156,17 +5015,20 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { if (block_mcv == .none) { block_data.mcv = switch (operand_mcv) { .none, .dead, .unreach => unreachable, - .register, .stack_offset, .memory => operand_mcv, + .stack_offset, .memory => operand_mcv, .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: { const new_mcv = try self.allocRegOrMem(block, true); try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); break :blk new_mcv; }, - .avx_register => blk: { - // TODO not needed; return operand_mcv ones we can transfer between XMM registers - const new_mcv = try self.allocRegOrMem(block, false); - try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); - break :blk new_mcv; + .register => blk: { + if (self.air.typeOfIndex(block).zigTypeTag() == .Float) { + // TODO not needed; return operand_mcv ones we can transfer between XMM registers + const new_mcv = try self.allocRegOrMem(block, false); + try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); + break :blk new_mcv; + } + break :blk operand_mcv; }, else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), }; @@ -5184,9 +5046,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void { // Leave the jump offset undefined const jmp_reloc = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b00, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = undefined }, }); block_data.relocs.appendAssumeCapacity(jmp_reloc); @@ -5274,9 +5134,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { }; _ = try self.addInst(.{ .tag = .push, - .ops = (Mir.Ops(Register, Register){ - .flags = 0b10, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b10 }), .data = .{ .imm = n }, }); } else if (mem.indexOf(u8, arg, "%%")) |l| { @@ -5285,9 +5143,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { return self.fail("unrecognized register: '{s}'", .{reg_name}); _ = try self.addInst(.{ .tag = .push, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), .data = undefined, }); } else return self.fail("TODO more push operands", .{}); @@ -5299,9 +5155,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { return self.fail("unrecognized register: '{s}'", .{reg_name}); _ = try self.addInst(.{ .tag = .pop, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), .data = undefined, }); } else return self.fail("TODO more pop operands", .{}); @@ -5365,7 +5219,6 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { .none => return, .immediate => unreachable, .register => |reg| return self.genSetReg(ty, reg, val), - .avx_register => |reg| return self.genSetAvxReg(ty, reg, val), .stack_offset => |off| return self.genSetStack(ty, off, val, .{}), .memory => { return self.fail("TODO implement setRegOrMem for memory", .{}); @@ -5396,9 +5249,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE .register_overflow_unsigned, .register_overflow_signed, => return self.fail("TODO genSetStackArg for register with overflow bit", .{}), - .avx_register => { - return self.fail("TODO genSetStackArg for AVX register", .{}); - }, .compare_flags_unsigned, .compare_flags_signed, => { @@ -5417,7 +5267,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE }); _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp, .flags = switch (abi_size) { 1 => 0b00, @@ -5425,7 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE 4 => 0b10, else => unreachable, }, - }).encode(), + }), .data = .{ .payload = payload }, }); }, @@ -5453,11 +5303,11 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE .register => |reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp, .reg2 = registerAlias(reg, @intCast(u32, abi_size)), .flags = 0b10, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -stack_offset) }, }); }, @@ -5520,10 +5370,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl }; _ = try self.addInst(.{ .tag = .cond_set_byte_overflow, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = tmp_reg.to8(), .flags = flags, - }).encode(), + }), .data = undefined, }); @@ -5550,7 +5400,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl }); _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = base_reg, .flags = switch (abi_size) { 1 => 0b00, @@ -5558,7 +5408,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl 4 => 0b10, else => unreachable, }, - }).encode(), + }), .data = .{ .payload = payload }, }); }, @@ -5572,10 +5422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl }); _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = base_reg, .flags = 0b10, - }).encode(), + }), .data = .{ .payload = payload }, }); } @@ -5586,10 +5436,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl }); _ = try self.addInst(.{ .tag = .mov_mem_imm, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = base_reg, .flags = 0b10, - }).encode(), + }), .data = .{ .payload = payload }, }); } @@ -5605,65 +5455,64 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl } const base_reg = opts.dest_stack_base orelse .rbp; - if (!math.isPowerOfTwo(abi_size)) { - const reg_lock = self.register_manager.lockReg(reg); - defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); - - const tmp_reg = try self.copyToTmpRegister(ty, mcv); - - var next_offset = stack_offset; - var remainder = abi_size; - while (remainder > 0) { - const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); - - _ = try self.addInst(.{ - .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = base_reg, - .reg2 = registerAlias(tmp_reg, nearest_power_of_two), - .flags = 0b10, - }).encode(), - .data = .{ .imm = @bitCast(u32, -next_offset) }, - }); - if (nearest_power_of_two > 1) { - try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }); - } - - remainder -= nearest_power_of_two; - next_offset -= nearest_power_of_two; - } - } else { - _ = try self.addInst(.{ - .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = base_reg, - .reg2 = registerAlias(reg, @intCast(u32, abi_size)), - .flags = 0b10, - }).encode(), - .data = .{ .imm = @bitCast(u32, -stack_offset) }, - }); - } - }, - .avx_register => |reg| { - const base_reg = opts.dest_stack_base orelse .rbp; switch (ty.zigTypeTag()) { .Float => switch (ty.tag()) { - .f32 => return self.fail("TODO genSetStack for AVX register for f32", .{}), + .f32 => return self.fail("TODO genSetStack for register for f32", .{}), .f64 => { _ = try self.addInst(.{ .tag = .mov_f64, - .ops = (Mir.Ops(Register, AvxRegister){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = base_reg, .reg2 = reg.to128(), .flags = 0b01, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -stack_offset) }, }); }, - else => return self.fail("TODO genSetStack for AVX register for type {}", .{ty.fmtDebug()}), + else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}), + }, + else => { + if (!math.isPowerOfTwo(abi_size)) { + const reg_lock = self.register_manager.lockReg(reg); + defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); + + const tmp_reg = try self.copyToTmpRegister(ty, mcv); + + var next_offset = stack_offset; + var remainder = abi_size; + while (remainder > 0) { + const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); + + _ = try self.addInst(.{ + .tag = .mov, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = base_reg, + .reg2 = registerAlias(tmp_reg, nearest_power_of_two), + .flags = 0b10, + }), + .data = .{ .imm = @bitCast(u32, -next_offset) }, + }); + + if (nearest_power_of_two > 1) { + try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }); + } + + remainder -= nearest_power_of_two; + next_offset -= nearest_power_of_two; + } + } else { + _ = try self.addInst(.{ + .tag = .mov, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = base_reg, + .reg2 = registerAlias(reg, @intCast(u32, abi_size)), + .flags = 0b10, + }), + .data = .{ .imm = @bitCast(u32, -stack_offset) }, + }); + } }, - else => return self.fail("TODO genSetStack for AVX register for type {}", .{ty.fmtDebug()}), } }, .memory, @@ -5742,20 +5591,20 @@ fn genInlineMemcpy( .ptr_stack_offset, .stack_offset => |off| { _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_addr_reg.to64(), .reg2 = opts.dest_stack_base orelse .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, .register => |reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_addr_reg, @divExact(reg.size(), 8)), .reg2 = reg, - }).encode(), + }), .data = undefined, }); }, @@ -5777,20 +5626,20 @@ fn genInlineMemcpy( .ptr_stack_offset, .stack_offset => |off| { _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = src_addr_reg.to64(), .reg2 = opts.source_stack_base orelse .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, .register => |reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(src_addr_reg, @divExact(reg.size(), 8)), .reg2 = reg, - }).encode(), + }), .data = undefined, }); }, @@ -5810,18 +5659,14 @@ fn genInlineMemcpy( // mov rcx, 0 _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rcx, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rcx }), .data = .{ .imm = 0 }, }); // mov rax, 0 _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rax, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }), .data = .{ .imm = 0 }, }); @@ -5829,70 +5674,62 @@ fn genInlineMemcpy( // cmp count, 0 const loop_start = try self.addInst(.{ .tag = .cmp, - .ops = (Mir.Ops(Register, Register){ - .reg1 = count_reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }), .data = .{ .imm = 0 }, }); // je end const loop_reloc = try self.addInst(.{ .tag = .cond_jmp_eq_ne, - .ops = (Mir.Ops(Register, Register){ .flags = 0b01 }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .inst = undefined }, }); // mov tmp, [addr + rcx] _ = try self.addInst(.{ .tag = .mov_scale_src, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = tmp_reg.to8(), .reg2 = src_addr_reg, - }).encode(), + }), .data = .{ .imm = 0 }, }); // mov [stack_offset + rax], tmp _ = try self.addInst(.{ .tag = .mov_scale_dst, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = dst_addr_reg, .reg2 = tmp_reg.to8(), - }).encode(), + }), .data = .{ .imm = 0 }, }); // add rcx, 1 _ = try self.addInst(.{ .tag = .add, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rcx, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rcx }), .data = .{ .imm = 1 }, }); // add rax, 1 _ = try self.addInst(.{ .tag = .add, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rax, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }), .data = .{ .imm = 1 }, }); // sub count, 1 _ = try self.addInst(.{ .tag = .sub, - .ops = (Mir.Ops(Register, Register){ - .reg1 = count_reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }), .data = .{ .imm = 1 }, }); // jmp loop _ = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ .flags = 0b00 }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = loop_start }, }); @@ -5924,20 +5761,20 @@ fn genInlineMemset( .ptr_stack_offset, .stack_offset => |off| { _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg.to64(), .reg2 = opts.dest_stack_base orelse .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, .register => |reg| { _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)), .reg2 = reg, - }).encode(), + }), .data = undefined, }); }, @@ -5955,16 +5792,14 @@ fn genInlineMemset( // cmp rax, -1 const loop_start = try self.addInst(.{ .tag = .cmp, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rax, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }), .data = .{ .imm = @bitCast(u32, @as(i32, -1)) }, }); // je end const loop_reloc = try self.addInst(.{ .tag = .cond_jmp_eq_ne, - .ops = (Mir.Ops(Register, Register){ .flags = 0b01 }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), .data = .{ .inst = undefined }, }); @@ -5980,9 +5815,7 @@ fn genInlineMemset( }); _ = try self.addInst(.{ .tag = .mov_mem_index_imm, - .ops = (Mir.Ops(Register, Register){ - .reg1 = addr_reg, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg }), .data = .{ .payload = payload }, }); }, @@ -5992,16 +5825,14 @@ fn genInlineMemset( // sub rax, 1 _ = try self.addInst(.{ .tag = .sub, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rax, - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }), .data = .{ .imm = 1 }, }); // jmp loop _ = try self.addInst(.{ .tag = .jmp, - .ops = (Mir.Ops(Register, Register){ .flags = 0b00 }).encode(), + .ops = Mir.Inst.Ops.encode(.{}), .data = .{ .inst = loop_start }, }); @@ -6009,88 +5840,6 @@ fn genInlineMemset( try self.performReloc(loop_reloc); } -fn genSetAvxReg(self: *Self, ty: Type, reg: AvxRegister, mcv: MCValue) InnerError!void { - switch (mcv) { - .dead => unreachable, - .register_overflow_unsigned, - .register_overflow_signed, - => unreachable, - .stack_offset => |off| { - if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { - return self.fail("stack offset too large", .{}); - } - - switch (ty.zigTypeTag()) { - .Float => { - switch (ty.tag()) { - .f32 => return self.fail("TODO genSetAvxReg from stack offset for f32", .{}), - .f64 => { - _ = try self.addInst(.{ - .tag = .mov_f64, - .ops = (Mir.Ops(AvxRegister, Register){ - .reg1 = reg.to128(), - .reg2 = .rbp, - }).encode(), - .data = .{ .imm = @bitCast(u32, -off) }, - }); - }, - else => return self.fail("TODO genSetAvxReg from stack offset for {}", .{ty.fmtDebug()}), - } - }, - else => return self.fail("TODO genSetAvxReg from stack offset for type {}", .{ty.fmtDebug()}), - } - }, - .avx_register => |src_reg| { - switch (ty.zigTypeTag()) { - .Float => { - switch (ty.tag()) { - .f32 => return self.fail("TODO genSetAvxReg from register for f32", .{}), - .f64 => { - _ = try self.addInst(.{ - .tag = .mov_f64, - .ops = (Mir.Ops(AvxRegister, AvxRegister){ - .reg1 = reg.to128(), - .reg2 = src_reg.to128(), - .flags = 0b10, - }).encode(), - .data = undefined, - }); - }, - else => return self.fail("TODO genSetAvxReg from register for {}", .{ty.fmtDebug()}), - } - }, - else => return self.fail("TODO genSetAvxReg from register for type {}", .{ty.fmtDebug()}), - } - }, - .memory => { - switch (ty.zigTypeTag()) { - .Float => { - switch (ty.tag()) { - .f32 => return self.fail("TODO genSetAvxReg from memory for f32", .{}), - .f64 => { - const base_reg = try self.register_manager.allocReg(null); - try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); - _ = try self.addInst(.{ - .tag = .mov_f64, - .ops = (Mir.Ops(AvxRegister, Register){ - .reg1 = reg.to128(), - .reg2 = base_reg.to64(), - }).encode(), - .data = .{ .imm = 0 }, - }); - }, - else => return self.fail("TODO genSetAvxReg from memory for {}", .{ty.fmtDebug()}), - } - }, - else => return self.fail("TODO genSetAvxReg from memory for type {}", .{ty.fmtDebug()}), - } - }, - else => |other| { - return self.fail("TODO genSetAvxReg from {}", .{other}); - }, - } -} - fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { const abi_size = @intCast(u32, ty.abiSize(self.target.*)); switch (mcv) { @@ -6098,17 +5847,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void .register_overflow_unsigned, .register_overflow_signed, => unreachable, - .avx_register => unreachable, .ptr_stack_offset => |off| { if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { return self.fail("stack offset too large", .{}); } _ = try self.addInst(.{ .tag = .lea, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .reg2 = .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -6145,10 +5893,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void }; _ = try self.addInst(.{ .tag = tag, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to8(), .flags = flags, - }).encode(), + }), .data = undefined, }); }, @@ -6158,10 +5906,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void if (x == 0) { _ = try self.addInst(.{ .tag = .xor, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to32(), .reg2 = reg.to32(), - }).encode(), + }), .data = undefined, }); return; @@ -6170,9 +5918,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void // Next best case: if we set the lower four bytes, the upper four will be zeroed. _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(reg, abi_size), - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }), .data = .{ .imm = @truncate(u32, x) }, }); return; @@ -6187,9 +5933,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void const payload = try self.addExtra(Mir.Imm64.encode(x)); _ = try self.addInst(.{ .tag = .movabs, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg.to64(), - }).encode(), + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64() }), .data = .{ .payload = payload }, }); }, @@ -6198,40 +5942,60 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void if (src_reg.id() == reg.id()) return; - if (ty.zigTypeTag() == .Int) blk: { - switch (ty.intInfo(self.target.*).signedness) { + switch (ty.zigTypeTag()) { + .Int => switch (ty.intInfo(self.target.*).signedness) { .signed => { - if (abi_size > 4) break :blk; - _ = try self.addInst(.{ - .tag = .mov_sign_extend, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg.to64(), - .reg2 = registerAlias(src_reg, abi_size), - }).encode(), - .data = undefined, - }); + if (abi_size <= 4) { + _ = try self.addInst(.{ + .tag = .mov_sign_extend, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = registerAlias(src_reg, abi_size), + }), + .data = undefined, + }); + return; + } }, .unsigned => { - if (abi_size > 2) break :blk; + if (abi_size <= 2) { + _ = try self.addInst(.{ + .tag = .mov_zero_extend, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = registerAlias(src_reg, abi_size), + }), + .data = undefined, + }); + return; + } + }, + }, + .Float => switch (ty.tag()) { + .f32 => return self.fail("TODO genSetReg from register for f32", .{}), + .f64 => { _ = try self.addInst(.{ - .tag = .mov_zero_extend, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg.to64(), - .reg2 = registerAlias(src_reg, abi_size), - }).encode(), + .tag = .mov_f64, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to128(), + .reg2 = src_reg.to128(), + .flags = 0b10, + }), .data = undefined, }); + return; }, - } - return; + else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}), + }, + else => {}, } _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .reg2 = registerAlias(src_reg, abi_size), - }).encode(), + }), .data = undefined, }); }, @@ -6241,107 +6005,148 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .reg2 = reg.to64(), .flags = 0b01, - }).encode(), + }), .data = .{ .imm = 0 }, }); }, - .memory => |x| { - if (x <= math.maxInt(i32)) { - // mov reg, [ds:imm32] - _ = try self.addInst(.{ - .tag = .mov, - .ops = (Mir.Ops(Register, Register){ - .reg1 = registerAlias(reg, abi_size), - .flags = 0b01, - }).encode(), - .data = .{ .imm = @truncate(u32, x) }, - }); - } else { - // If this is RAX, we can use a direct load. - // Otherwise, we need to load the address, then indirectly load the value. - if (reg.id() == 0) { - // movabs rax, ds:moffs64 - const payload = try self.addExtra(Mir.Imm64.encode(x)); - _ = try self.addInst(.{ - .tag = .movabs, - .ops = (Mir.Ops(Register, Register){ - .reg1 = .rax, - .flags = 0b01, // imm64 will become moffs64 - }).encode(), - .data = .{ .payload = payload }, - }); - } else { - // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue. - try self.genSetReg(ty, reg, MCValue{ .immediate = x }); - - // mov reg, [reg + 0x0] + .memory => |x| switch (ty.zigTypeTag()) { + .Float => { + switch (ty.tag()) { + .f32 => return self.fail("TODO genSetReg from memory for f32", .{}), + .f64 => { + const base_reg = try self.register_manager.allocReg(null); + try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); + _ = try self.addInst(.{ + .tag = .mov_f64, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to128(), + .reg2 = base_reg.to64(), + }), + .data = .{ .imm = 0 }, + }); + }, + else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), + } + }, + else => { + if (x <= math.maxInt(i32)) { + // mov reg, [ds:imm32] _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), - .reg2 = reg.to64(), .flags = 0b01, - }).encode(), - .data = .{ .imm = 0 }, + }), + .data = .{ .imm = @truncate(u32, x) }, }); + } else { + // If this is RAX, we can use a direct load. + // Otherwise, we need to load the address, then indirectly load the value. + if (reg.id() == 0) { + // movabs rax, ds:moffs64 + const payload = try self.addExtra(Mir.Imm64.encode(x)); + _ = try self.addInst(.{ + .tag = .movabs, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rax, + .flags = 0b01, // imm64 will become moffs64 + }), + .data = .{ .payload = payload }, + }); + } else { + // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue. + try self.genSetReg(ty, reg, MCValue{ .immediate = x }); + + // mov reg, [reg + 0x0] + _ = try self.addInst(.{ + .tag = .mov, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = registerAlias(reg, abi_size), + .reg2 = reg.to64(), + .flags = 0b01, + }), + .data = .{ .imm = 0 }, + }); + } } - } + }, }, .stack_offset => |off| { if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { return self.fail("stack offset too large", .{}); } - if (ty.zigTypeTag() == .Int) blk: { - switch (ty.intInfo(self.target.*).signedness) { + switch (ty.zigTypeTag()) { + .Int => switch (ty.intInfo(self.target.*).signedness) { .signed => { - const flags: u2 = switch (abi_size) { - 1 => 0b01, - 2 => 0b10, - 4 => 0b11, - else => break :blk, - }; - _ = try self.addInst(.{ - .tag = .mov_sign_extend, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg.to64(), - .reg2 = .rbp, - .flags = flags, - }).encode(), - .data = .{ .imm = @bitCast(u32, -off) }, - }); + if (abi_size <= 4) { + const flags: u2 = switch (abi_size) { + 1 => 0b01, + 2 => 0b10, + 4 => 0b11, + else => unreachable, + }; + _ = try self.addInst(.{ + .tag = .mov_sign_extend, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = .rbp, + .flags = flags, + }), + .data = .{ .imm = @bitCast(u32, -off) }, + }); + return; + } }, .unsigned => { - const flags: u2 = switch (abi_size) { - 1 => 0b01, - 2 => 0b10, - else => break :blk, - }; + if (abi_size <= 2) { + const flags: u2 = switch (abi_size) { + 1 => 0b01, + 2 => 0b10, + else => unreachable, + }; + _ = try self.addInst(.{ + .tag = .mov_zero_extend, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = .rbp, + .flags = flags, + }), + .data = .{ .imm = @bitCast(u32, -off) }, + }); + return; + } + }, + }, + .Float => switch (ty.tag()) { + .f32 => return self.fail("TODO genSetReg from stack offset for f32", .{}), + .f64 => { _ = try self.addInst(.{ - .tag = .mov_zero_extend, - .ops = (Mir.Ops(Register, Register){ - .reg1 = reg.to64(), + .tag = .mov_f64, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to128(), .reg2 = .rbp, - .flags = flags, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); + return; }, - } - return; + else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}), + }, + else => {}, } _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size), .reg2 = .rbp, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -off) }, }); }, @@ -6408,14 +6213,14 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { }; _ = try self.addInst(.{ .tag = .fld, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rbp, .flags = switch (src_ty.abiSize(self.target.*)) { 4 => 0b01, 8 => 0b10, else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}), }, - .reg1 = .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -stack_offset) }, }); @@ -6423,15 +6228,15 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { const stack_dst = try self.allocRegOrMem(inst, false); _ = try self.addInst(.{ .tag = .fisttp, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = .rbp, .flags = switch (dst_ty.abiSize(self.target.*)) { 1...2 => 0b00, 3...4 => 0b01, 5...8 => 0b10, else => |size| return self.fail("TODO convert float with abiSize={}", .{size}), }, - .reg1 = .rbp, - }).encode(), + }), .data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) }, }); @@ -6527,11 +6332,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr); _ = try self.addInst(.{ .tag = .mov, - .ops = (Mir.Ops(Register, Register){ + .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg, .reg2 = reg, .flags = 0b01, - }).encode(), + }), .data = .{ .imm = 0 }, }); break :blk MCValue{ .register = reg }; @@ -7095,22 +6900,11 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { return reg.to32(); } else if (size_bytes <= 8) { return reg.to64(); - } else { - unreachable; - } -} - -/// Returns AVX register wide enough to hold at least `size_bytes`. -fn avxRegisterAlias(reg: AvxRegister, size_bytes: u32) AvxRegister { - if (size_bytes == 0) { - unreachable; // should be comptime known } else if (size_bytes <= 16) { return reg.to128(); } else if (size_bytes <= 32) { return reg.to256(); - } else { - unreachable; - } + } else unreachable; } /// Truncates the value in the register in place. |
