authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-16 19:45:30+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:37:29+02:00
log9e5c8cb008f75c2e570a0e48d5d014e936c103ca
treeaf9bf9c8457a4137b1fc534e7eac8a0a4400b8ec
parent2aee2302515ba444999b82c2e40cbc35dee08baf

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.

7 files changed, 1158 insertions(+), 1397 deletions(-)

src/arch/x86_64/CodeGen.zig+427-633
...@@ -35,14 +35,10 @@ const caller_preserved_regs = abi.caller_preserved_regs;...@@ -35,14 +35,10 @@ const caller_preserved_regs = abi.caller_preserved_regs;
35const allocatable_registers = abi.allocatable_registers;35const allocatable_registers = abi.allocatable_registers;
36const c_abi_int_param_regs = abi.c_abi_int_param_regs;36const c_abi_int_param_regs = abi.c_abi_int_param_regs;
37const c_abi_int_return_regs = abi.c_abi_int_return_regs;37const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers, spillInstruction);38const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
39const RegisterLock = RegisterManager.RegisterLock;39const RegisterLock = RegisterManager.RegisterLock;
40const Register = bits.Register;40const Register = bits.Register;
4141
42const AvxRegisterManager = RegisterManagerFn(Self, AvxRegister, &abi.avx_regs, spillInstructionAvx);
43const AvxRegisterLock = AvxRegisterManager.RegisterLock;
44const AvxRegister = bits.AvxRegister;
45
46const InnerError = error{42const InnerError = error{
47 OutOfMemory,43 OutOfMemory,
48 CodegenFail,44 CodegenFail,
...@@ -92,8 +88,7 @@ branch_stack: *std.ArrayList(Branch),...@@ -92,8 +88,7 @@ branch_stack: *std.ArrayList(Branch),
92// Key is the block instruction88// Key is the block instruction
93blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},89blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
9490
95register_manager: RegisterManager,91register_manager: RegisterManager = .{},
96avx_register_manager: AvxRegisterManager,
97/// Maps offset to what is stored there.92/// Maps offset to what is stored there.
98stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},93stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9994
...@@ -133,8 +128,6 @@ pub const MCValue = union(enum) {...@@ -133,8 +128,6 @@ pub const MCValue = union(enum) {
133 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,128 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,
134 /// and the operation is a signed operation.129 /// and the operation is a signed operation.
135 register_overflow_signed: Register,130 register_overflow_signed: Register,
136 /// The value is in an AVX register.
137 avx_register: AvxRegister,
138 /// The value is in memory at a hard-coded address.131 /// The value is in memory at a hard-coded address.
139 /// If the type is a pointer, it means the pointer address is at this memory location.132 /// If the type is a pointer, it means the pointer address is at this memory location.
140 memory: u64,133 memory: u64,
...@@ -202,7 +195,6 @@ pub const MCValue = union(enum) {...@@ -202,7 +195,6 @@ pub const MCValue = union(enum) {
202 fn isRegister(mcv: MCValue) bool {195 fn isRegister(mcv: MCValue) bool {
203 return switch (mcv) {196 return switch (mcv) {
204 .register => true,197 .register => true,
205 .avx_register => true,
206 else => false,198 else => false,
207 };199 };
208 }200 }
...@@ -304,11 +296,7 @@ pub fn generate(...@@ -304,11 +296,7 @@ pub fn generate(
304 .mir_to_air_map = if (builtin.mode == .Debug)296 .mir_to_air_map = if (builtin.mode == .Debug)
305 std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator)297 std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator)
306 else {},298 else {},
307 .register_manager = undefined,
308 .avx_register_manager = undefined,
309 };299 };
310 function.register_manager = .{ .function = &function };
311 function.avx_register_manager = .{ .function = &function };
312 defer function.stack.deinit(bin_file.allocator);300 defer function.stack.deinit(bin_file.allocator);
313 defer function.blocks.deinit(bin_file.allocator);301 defer function.blocks.deinit(bin_file.allocator);
314 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);302 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
...@@ -400,17 +388,15 @@ fn gen(self: *Self) InnerError!void {...@@ -400,17 +388,15 @@ fn gen(self: *Self) InnerError!void {
400 if (cc != .Naked) {388 if (cc != .Naked) {
401 _ = try self.addInst(.{389 _ = try self.addInst(.{
402 .tag = .push,390 .tag = .push,
403 .ops = (Mir.Ops(Register, Register){391 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }),
404 .reg1 = .rbp,
405 }).encode(),
406 .data = undefined, // unused for push reg,392 .data = undefined, // unused for push reg,
407 });393 });
408 _ = try self.addInst(.{394 _ = try self.addInst(.{
409 .tag = .mov,395 .tag = .mov,
410 .ops = (Mir.Ops(Register, Register){396 .ops = Mir.Inst.Ops.encode(.{
411 .reg1 = .rbp,397 .reg1 = .rbp,
412 .reg2 = .rsp,398 .reg2 = .rsp,
413 }).encode(),399 }),
414 .data = undefined,400 .data = undefined,
415 });401 });
416 // We want to subtract the aligned stack frame size from rsp here, but we don't402 // 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 {...@@ -447,9 +433,7 @@ fn gen(self: *Self) InnerError!void {
447 // push the callee_preserved_regs that were used433 // push the callee_preserved_regs that were used
448 const backpatch_push_callee_preserved_regs_i = try self.addInst(.{434 const backpatch_push_callee_preserved_regs_i = try self.addInst(.{
449 .tag = .push_regs_from_callee_preserved_regs,435 .tag = .push_regs_from_callee_preserved_regs,
450 .ops = (Mir.Ops(Register, Register){436 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }),
451 .reg1 = .rbp,
452 }).encode(),
453 .data = .{ .payload = undefined }, // to be backpatched437 .data = .{ .payload = undefined }, // to be backpatched
454 });438 });
455439
...@@ -489,9 +473,7 @@ fn gen(self: *Self) InnerError!void {...@@ -489,9 +473,7 @@ fn gen(self: *Self) InnerError!void {
489 // pop the callee_preserved_regs473 // pop the callee_preserved_regs
490 _ = try self.addInst(.{474 _ = try self.addInst(.{
491 .tag = .pop_regs_from_callee_preserved_regs,475 .tag = .pop_regs_from_callee_preserved_regs,
492 .ops = (Mir.Ops(Register, Register){476 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }),
493 .reg1 = .rbp,
494 }).encode(),
495 .data = .{ .payload = callee_preserved_regs_payload },477 .data = .{ .payload = callee_preserved_regs_payload },
496 });478 });
497479
...@@ -510,17 +492,13 @@ fn gen(self: *Self) InnerError!void {...@@ -510,17 +492,13 @@ fn gen(self: *Self) InnerError!void {
510492
511 _ = try self.addInst(.{493 _ = try self.addInst(.{
512 .tag = .pop,494 .tag = .pop,
513 .ops = (Mir.Ops(Register, Register){495 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rbp }),
514 .reg1 = .rbp,
515 }).encode(),
516 .data = undefined,496 .data = undefined,
517 });497 });
518498
519 _ = try self.addInst(.{499 _ = try self.addInst(.{
520 .tag = .ret,500 .tag = .ret,
521 .ops = (Mir.Ops(Register, Register){501 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b11 }),
522 .flags = 0b11,
523 }).encode(),
524 .data = undefined,502 .data = undefined,
525 });503 });
526504
...@@ -534,16 +512,12 @@ fn gen(self: *Self) InnerError!void {...@@ -534,16 +512,12 @@ fn gen(self: *Self) InnerError!void {
534 if (aligned_stack_end > 0) {512 if (aligned_stack_end > 0) {
535 self.mir_instructions.set(backpatch_stack_sub, .{513 self.mir_instructions.set(backpatch_stack_sub, .{
536 .tag = .sub,514 .tag = .sub,
537 .ops = (Mir.Ops(Register, Register){515 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
538 .reg1 = .rsp,
539 }).encode(),
540 .data = .{ .imm = aligned_stack_end },516 .data = .{ .imm = aligned_stack_end },
541 });517 });
542 self.mir_instructions.set(backpatch_stack_add, .{518 self.mir_instructions.set(backpatch_stack_add, .{
543 .tag = .add,519 .tag = .add,
544 .ops = (Mir.Ops(Register, Register){520 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
545 .reg1 = .rsp,
546 }).encode(),
547 .data = .{ .imm = aligned_stack_end },521 .data = .{ .imm = aligned_stack_end },
548 });522 });
549 }523 }
...@@ -908,8 +882,8 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -908,8 +882,8 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
908 // TODO check if AVX available882 // TODO check if AVX available
909 const ptr_bytes: u64 = 32;883 const ptr_bytes: u64 = 32;
910 if (abi_size <= ptr_bytes) {884 if (abi_size <= ptr_bytes) {
911 if (self.avx_register_manager.tryAllocReg(inst)) |reg| {885 if (self.register_manager.tryAllocReg(inst)) |reg| {
912 return MCValue{ .avx_register = avxRegisterAlias(reg, abi_size) };886 return MCValue{ .register = registerAlias(reg, abi_size) };
913 }887 }
914 }888 }
915 },889 },
...@@ -947,21 +921,6 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -947,21 +921,6 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
947 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});921 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
948}922}
949923
950pub fn spillInstructionAvx(self: *Self, reg: AvxRegister, inst: Air.Inst.Index) !void {
951 const stack_mcv = try self.allocRegOrMem(inst, false);
952 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
953 const reg_mcv = self.getResolvedInstValue(inst);
954 switch (reg_mcv) {
955 .avx_register => |other| {
956 assert(reg.to256() == other.to256());
957 },
958 else => {},
959 }
960 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
961 try branch.inst_table.put(self.gpa, inst, stack_mcv);
962 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
963}
964
965pub fn spillCompareFlagsIfOccupied(self: *Self) !void {924pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
966 if (self.compare_flags_inst) |inst_to_save| {925 if (self.compare_flags_inst) |inst_to_save| {
967 const mcv = self.getResolvedInstValue(inst_to_save);926 const mcv = self.getResolvedInstValue(inst_to_save);
...@@ -972,7 +931,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -972,7 +931,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
972 .compare_flags_signed,931 .compare_flags_signed,
973 .compare_flags_unsigned,932 .compare_flags_unsigned,
974 => try self.allocRegOrMem(inst_to_save, true),933 => try self.allocRegOrMem(inst_to_save, true),
975 .avx_register => try self.allocRegOrMem(inst_to_save, false),
976 else => unreachable,934 else => unreachable,
977 };935 };
978936
...@@ -990,7 +948,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -990,7 +948,6 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
990 .register_overflow_signed,948 .register_overflow_signed,
991 .register_overflow_unsigned,949 .register_overflow_unsigned,
992 => |reg| self.register_manager.freeReg(reg),950 => |reg| self.register_manager.freeReg(reg),
993 .avx_register => |reg| self.avx_register_manager.freeReg(reg),
994 else => {},951 else => {},
995 }952 }
996 }953 }
...@@ -1236,10 +1193,10 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {...@@ -1236,10 +1193,10 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1236 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);1193 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
1237 _ = try self.addInst(.{1194 _ = try self.addInst(.{
1238 .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below,1195 .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below,
1239 .ops = (Mir.Ops(Register, Register){1196 .ops = Mir.Inst.Ops.encode(.{
1240 .reg1 = dst_mcv.register,1197 .reg1 = dst_mcv.register,
1241 .reg2 = lhs_reg,1198 .reg2 = lhs_reg,
1242 }).encode(),1199 }),
1243 .data = undefined,1200 .data = undefined,
1244 });1201 });
12451202
...@@ -1440,10 +1397,10 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1440,10 +1397,10 @@ fn genSetStackTruncatedOverflowCompare(
1440 };1397 };
1441 _ = try self.addInst(.{1398 _ = try self.addInst(.{
1442 .tag = .cond_set_byte_overflow,1399 .tag = .cond_set_byte_overflow,
1443 .ops = (Mir.Ops(Register, Register){1400 .ops = Mir.Inst.Ops.encode(.{
1444 .reg1 = overflow_reg.to8(),1401 .reg1 = overflow_reg.to8(),
1445 .flags = flags,1402 .flags = flags,
1446 }).encode(),1403 }),
1447 .data = undefined,1404 .data = undefined,
1448 });1405 });
14491406
...@@ -1460,10 +1417,7 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1460,10 +1417,7 @@ fn genSetStackTruncatedOverflowCompare(
1460 const eq_reg = temp_regs[2];1417 const eq_reg = temp_regs[2];
1461 _ = try self.addInst(.{1418 _ = try self.addInst(.{
1462 .tag = .cond_set_byte_eq_ne,1419 .tag = .cond_set_byte_eq_ne,
1463 .ops = (Mir.Ops(Register, Register){1420 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
1464 .reg1 = eq_reg.to8(),
1465 .flags = 0b00,
1466 }).encode(),
1467 .data = undefined,1421 .data = undefined,
1468 });1422 });
14691423
...@@ -1609,19 +1563,17 @@ fn genIntMulDivOpMir(...@@ -1609,19 +1563,17 @@ fn genIntMulDivOpMir(
1609 .signed => {1563 .signed => {
1610 _ = try self.addInst(.{1564 _ = try self.addInst(.{
1611 .tag = .cwd,1565 .tag = .cwd,
1612 .ops = (Mir.Ops(Register, Register){1566 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b11 }),
1613 .flags = 0b11,
1614 }).encode(),
1615 .data = undefined,1567 .data = undefined,
1616 });1568 });
1617 },1569 },
1618 .unsigned => {1570 .unsigned => {
1619 _ = try self.addInst(.{1571 _ = try self.addInst(.{
1620 .tag = .xor,1572 .tag = .xor,
1621 .ops = (Mir.Ops(Register, Register){1573 .ops = Mir.Inst.Ops.encode(.{
1622 .reg1 = .rdx,1574 .reg1 = .rdx,
1623 .reg2 = .rdx,1575 .reg2 = .rdx,
1624 }).encode(),1576 }),
1625 .data = undefined,1577 .data = undefined,
1626 });1578 });
1627 },1579 },
...@@ -1640,16 +1592,14 @@ fn genIntMulDivOpMir(...@@ -1640,16 +1592,14 @@ fn genIntMulDivOpMir(
1640 .register => |reg| {1592 .register => |reg| {
1641 _ = try self.addInst(.{1593 _ = try self.addInst(.{
1642 .tag = tag,1594 .tag = tag,
1643 .ops = (Mir.Ops(Register, Register){1595 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
1644 .reg1 = reg,
1645 }).encode(),
1646 .data = undefined,1596 .data = undefined,
1647 });1597 });
1648 },1598 },
1649 .stack_offset => |off| {1599 .stack_offset => |off| {
1650 _ = try self.addInst(.{1600 _ = try self.addInst(.{
1651 .tag = tag,1601 .tag = tag,
1652 .ops = (Mir.Ops(Register, Register){1602 .ops = Mir.Inst.Ops.encode(.{
1653 .reg2 = .rbp,1603 .reg2 = .rbp,
1654 .flags = switch (abi_size) {1604 .flags = switch (abi_size) {
1655 1 => 0b00,1605 1 => 0b00,
...@@ -1658,7 +1608,7 @@ fn genIntMulDivOpMir(...@@ -1658,7 +1608,7 @@ fn genIntMulDivOpMir(
1658 8 => 0b11,1608 8 => 0b11,
1659 else => unreachable,1609 else => unreachable,
1660 },1610 },
1661 }).encode(),1611 }),
1662 .data = .{ .imm = @bitCast(u32, -off) },1612 .data = .{ .imm = @bitCast(u32, -off) },
1663 });1613 });
1664 },1614 },
...@@ -1691,34 +1641,34 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -1691,34 +1641,34 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
16911641
1692 _ = try self.addInst(.{1642 _ = try self.addInst(.{
1693 .tag = .xor,1643 .tag = .xor,
1694 .ops = (Mir.Ops(Register, Register){1644 .ops = Mir.Inst.Ops.encode(.{
1695 .reg1 = divisor.to64(),1645 .reg1 = divisor.to64(),
1696 .reg2 = dividend.to64(),1646 .reg2 = dividend.to64(),
1697 }).encode(),1647 }),
1698 .data = undefined,1648 .data = undefined,
1699 });1649 });
1700 _ = try self.addInst(.{1650 _ = try self.addInst(.{
1701 .tag = .sar,1651 .tag = .sar,
1702 .ops = (Mir.Ops(Register, Register){1652 .ops = Mir.Inst.Ops.encode(.{
1703 .reg1 = divisor.to64(),1653 .reg1 = divisor.to64(),
1704 .flags = 0b10,1654 .flags = 0b10,
1705 }).encode(),1655 }),
1706 .data = .{ .imm = 63 },1656 .data = .{ .imm = 63 },
1707 });1657 });
1708 _ = try self.addInst(.{1658 _ = try self.addInst(.{
1709 .tag = .@"test",1659 .tag = .@"test",
1710 .ops = (Mir.Ops(Register, Register){1660 .ops = Mir.Inst.Ops.encode(.{
1711 .reg1 = .rdx,1661 .reg1 = .rdx,
1712 .reg2 = .rdx,1662 .reg2 = .rdx,
1713 }).encode(),1663 }),
1714 .data = undefined,1664 .data = undefined,
1715 });1665 });
1716 _ = try self.addInst(.{1666 _ = try self.addInst(.{
1717 .tag = .cond_mov_eq,1667 .tag = .cond_mov_eq,
1718 .ops = (Mir.Ops(Register, Register){1668 .ops = Mir.Inst.Ops.encode(.{
1719 .reg1 = divisor.to64(),1669 .reg1 = divisor.to64(),
1720 .reg2 = .rdx,1670 .reg2 = .rdx,
1721 }).encode(),1671 }),
1722 .data = undefined,1672 .data = undefined,
1723 });1673 });
1724 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });1674 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 {...@@ -2102,11 +2052,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2102 // mov reg, [rbp - 8]2052 // mov reg, [rbp - 8]
2103 _ = try self.addInst(.{2053 _ = try self.addInst(.{
2104 .tag = .mov,2054 .tag = .mov,
2105 .ops = (Mir.Ops(Register, Register){2055 .ops = Mir.Inst.Ops.encode(.{
2106 .reg1 = addr_reg.to64(),2056 .reg1 = addr_reg.to64(),
2107 .reg2 = .rbp,2057 .reg2 = .rbp,
2108 .flags = 0b01,2058 .flags = 0b01,
2109 }).encode(),2059 }),
2110 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },2060 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
2111 });2061 });
2112 },2062 },
...@@ -2187,10 +2137,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2187,10 +2137,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2187 // lea reg, [rbp]2137 // lea reg, [rbp]
2188 _ = try self.addInst(.{2138 _ = try self.addInst(.{
2189 .tag = .lea,2139 .tag = .lea,
2190 .ops = (Mir.Ops(Register, Register){2140 .ops = Mir.Inst.Ops.encode(.{
2191 .reg1 = addr_reg.to64(),2141 .reg1 = addr_reg.to64(),
2192 .reg2 = .rbp,2142 .reg2 = .rbp,
2193 }).encode(),2143 }),
2194 .data = .{ .imm = @bitCast(u32, -off) },2144 .data = .{ .imm = @bitCast(u32, -off) },
2195 });2145 });
2196 },2146 },
...@@ -2198,10 +2148,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2198,10 +2148,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2198 // lea reg, [rbp]2148 // lea reg, [rbp]
2199 _ = try self.addInst(.{2149 _ = try self.addInst(.{
2200 .tag = .lea,2150 .tag = .lea,
2201 .ops = (Mir.Ops(Register, Register){2151 .ops = Mir.Inst.Ops.encode(.{
2202 .reg1 = addr_reg.to64(),2152 .reg1 = addr_reg.to64(),
2203 .reg2 = .rbp,2153 .reg2 = .rbp,
2204 }).encode(),2154 }),
2205 .data = .{ .imm = @bitCast(u32, -off) },2155 .data = .{ .imm = @bitCast(u32, -off) },
2206 });2156 });
2207 },2157 },
...@@ -2266,11 +2216,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2266,11 +2216,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2266 // mov dst_mcv, [dst_mcv]2216 // mov dst_mcv, [dst_mcv]
2267 _ = try self.addInst(.{2217 _ = try self.addInst(.{
2268 .tag = .mov,2218 .tag = .mov,
2269 .ops = (Mir.Ops(Register, Register){2219 .ops = Mir.Inst.Ops.encode(.{
2270 .flags = 0b01,
2271 .reg1 = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)),2220 .reg1 = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)),
2272 .reg2 = dst_mcv.register,2221 .reg2 = dst_mcv.register,
2273 }).encode(),2222 .flags = 0b01,
2223 }),
2274 .data = .{ .imm = 0 },2224 .data = .{ .imm = 0 },
2275 });2225 });
2276 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };2226 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...@@ -2532,11 +2482,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2532 // mov dst_reg, [reg]2482 // mov dst_reg, [reg]
2533 _ = try self.addInst(.{2483 _ = try self.addInst(.{
2534 .tag = .mov,2484 .tag = .mov,
2535 .ops = (Mir.Ops(Register, Register){2485 .ops = Mir.Inst.Ops.encode(.{
2536 .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),2486 .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
2537 .reg2 = reg,2487 .reg2 = reg,
2538 .flags = 0b01,2488 .flags = 0b01,
2539 }).encode(),2489 }),
2540 .data = .{ .imm = 0 },2490 .data = .{ .imm = 0 },
2541 });2491 });
2542 },2492 },
...@@ -2552,9 +2502,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2552,9 +2502,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2552 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),2502 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
2553 }2503 }
2554 },2504 },
2555 .avx_register => {
2556 return self.fail("TODO load for AVX register", .{});
2557 },
2558 .memory,2505 .memory,
2559 .got_load,2506 .got_load,
2560 .direct_load,2507 .direct_load,
...@@ -2606,10 +2553,10 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2606,10 +2553,10 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2606 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);2553 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
2607 _ = try self.addInst(.{2554 _ = try self.addInst(.{
2608 .tag = .lea_pie,2555 .tag = .lea_pie,
2609 .ops = (Mir.Ops(Register, Register){2556 .ops = Mir.Inst.Ops.encode(.{
2610 .reg1 = registerAlias(reg, abi_size),2557 .reg1 = registerAlias(reg, abi_size),
2611 .flags = flags,2558 .flags = flags,
2612 }).encode(),2559 }),
2613 .data = .{2560 .data = .{
2614 .load_reloc = .{2561 .load_reloc = .{
2615 .atom_index = fn_owner_decl.link.macho.local_sym_index,2562 .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...@@ -2670,7 +2617,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2670 });2617 });
2671 _ = try self.addInst(.{2618 _ = try self.addInst(.{
2672 .tag = .mov_mem_imm,2619 .tag = .mov_mem_imm,
2673 .ops = (Mir.Ops(Register, Register){2620 .ops = Mir.Inst.Ops.encode(.{
2674 .reg1 = reg.to64(),2621 .reg1 = reg.to64(),
2675 .flags = switch (abi_size) {2622 .flags = switch (abi_size) {
2676 1 => 0b00,2623 1 => 0b00,
...@@ -2678,7 +2625,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2678,7 +2625,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2678 4 => 0b10,2625 4 => 0b10,
2679 else => unreachable,2626 else => unreachable,
2680 },2627 },
2681 }).encode(),2628 }),
2682 .data = .{ .payload = payload },2629 .data = .{ .payload = payload },
2683 });2630 });
2684 },2631 },
...@@ -2692,11 +2639,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2692,11 +2639,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2692 const tmp_reg = try self.copyToTmpRegister(value_ty, value);2639 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
2693 _ = try self.addInst(.{2640 _ = try self.addInst(.{
2694 .tag = .mov,2641 .tag = .mov,
2695 .ops = (Mir.Ops(Register, Register){2642 .ops = Mir.Inst.Ops.encode(.{
2696 .reg1 = reg.to64(),2643 .reg1 = reg.to64(),
2697 .reg2 = tmp_reg.to64(),2644 .reg2 = tmp_reg.to64(),
2698 .flags = 0b10,2645 .flags = 0b10,
2699 }).encode(),2646 }),
2700 .data = .{ .imm = 0 },2647 .data = .{ .imm = 0 },
2701 });2648 });
2702 },2649 },
...@@ -2708,11 +2655,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2708,11 +2655,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2708 .register => |src_reg| {2655 .register => |src_reg| {
2709 _ = try self.addInst(.{2656 _ = try self.addInst(.{
2710 .tag = .mov,2657 .tag = .mov,
2711 .ops = (Mir.Ops(Register, Register){2658 .ops = Mir.Inst.Ops.encode(.{
2712 .reg1 = reg.to64(),2659 .reg1 = reg.to64(),
2713 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),2660 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
2714 .flags = 0b10,2661 .flags = 0b10,
2715 }).encode(),2662 }),
2716 .data = .{ .imm = 0 },2663 .data = .{ .imm = 0 },
2717 });2664 });
2718 },2665 },
...@@ -2736,9 +2683,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2736,9 +2683,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2736 },2683 },
2737 }2684 }
2738 },2685 },
2739 .avx_register => {
2740 return self.fail("TODO store for AVX register", .{});
2741 },
2742 .got_load,2686 .got_load,
2743 .direct_load,2687 .direct_load,
2744 .memory,2688 .memory,
...@@ -2759,11 +2703,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2759,11 +2703,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2759 // mov reg, [reg]2703 // mov reg, [reg]
2760 _ = try self.addInst(.{2704 _ = try self.addInst(.{
2761 .tag = .mov,2705 .tag = .mov,
2762 .ops = (Mir.Ops(Register, Register){2706 .ops = Mir.Inst.Ops.encode(.{
2763 .reg1 = addr_reg.to64(),2707 .reg1 = addr_reg.to64(),
2764 .reg2 = addr_reg.to64(),2708 .reg2 = addr_reg.to64(),
2765 .flags = 0b01,2709 .flags = 0b01,
2766 }).encode(),2710 }),
2767 .data = .{ .imm = 0 },2711 .data = .{ .imm = 0 },
2768 });2712 });
27692713
...@@ -2798,21 +2742,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2798,21 +2742,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2798 }2742 }
2799 _ = try self.addInst(.{2743 _ = try self.addInst(.{
2800 .tag = .mov_mem_imm,2744 .tag = .mov_mem_imm,
2801 .ops = (Mir.Ops(Register, Register){2745 .ops = Mir.Inst.Ops.encode(.{
2802 .reg1 = addr_reg.to64(),2746 .reg1 = addr_reg.to64(),
2803 .flags = flags,2747 .flags = flags,
2804 }).encode(),2748 }),
2805 .data = .{ .payload = payload },2749 .data = .{ .payload = payload },
2806 });2750 });
2807 },2751 },
2808 .register => |reg| {2752 .register => |reg| {
2809 _ = try self.addInst(.{2753 _ = try self.addInst(.{
2810 .tag = .mov,2754 .tag = .mov,
2811 .ops = (Mir.Ops(Register, Register){2755 .ops = Mir.Inst.Ops.encode(.{
2812 .reg1 = addr_reg.to64(),2756 .reg1 = addr_reg.to64(),
2813 .reg2 = reg,2757 .reg2 = reg,
2814 .flags = 0b10,2758 .flags = 0b10,
2815 }).encode(),2759 }),
2816 .data = .{ .imm = 0 },2760 .data = .{ .imm = 0 },
2817 });2761 });
2818 },2762 },
...@@ -2829,20 +2773,20 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2829,20 +2773,20 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28292773
2830 _ = try self.addInst(.{2774 _ = try self.addInst(.{
2831 .tag = .mov,2775 .tag = .mov,
2832 .ops = (Mir.Ops(Register, Register){2776 .ops = Mir.Inst.Ops.encode(.{
2833 .reg1 = tmp_reg,2777 .reg1 = tmp_reg,
2834 .reg2 = tmp_reg,2778 .reg2 = tmp_reg,
2835 .flags = 0b01,2779 .flags = 0b01,
2836 }).encode(),2780 }),
2837 .data = .{ .imm = 0 },2781 .data = .{ .imm = 0 },
2838 });2782 });
2839 _ = try self.addInst(.{2783 _ = try self.addInst(.{
2840 .tag = .mov,2784 .tag = .mov,
2841 .ops = (Mir.Ops(Register, Register){2785 .ops = Mir.Inst.Ops.encode(.{
2842 .reg1 = addr_reg.to64(),2786 .reg1 = addr_reg.to64(),
2843 .reg2 = tmp_reg,2787 .reg2 = tmp_reg,
2844 .flags = 0b10,2788 .flags = 0b10,
2845 }).encode(),2789 }),
2846 .data = .{ .imm = 0 },2790 .data = .{ .imm = 0 },
2847 });2791 });
2848 return;2792 return;
...@@ -2856,11 +2800,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2856,11 +2800,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2856 const tmp_reg = try self.copyToTmpRegister(value_ty, value);2800 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
2857 _ = try self.addInst(.{2801 _ = try self.addInst(.{
2858 .tag = .mov,2802 .tag = .mov,
2859 .ops = (Mir.Ops(Register, Register){2803 .ops = Mir.Inst.Ops.encode(.{
2860 .reg1 = addr_reg.to64(),2804 .reg1 = addr_reg.to64(),
2861 .reg2 = tmp_reg,2805 .reg2 = tmp_reg,
2862 .flags = 0b10,2806 .flags = 0b10,
2863 }).encode(),2807 }),
2864 .data = .{ .imm = 0 },2808 .data = .{ .imm = 0 },
2865 });2809 });
2866 return;2810 return;
...@@ -3017,10 +2961,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3017,10 +2961,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3017 if (signedness == .signed and field_size < 8) {2961 if (signedness == .signed and field_size < 8) {
3018 _ = try self.addInst(.{2962 _ = try self.addInst(.{
3019 .tag = .mov_sign_extend,2963 .tag = .mov_sign_extend,
3020 .ops = (Mir.Ops(Register, Register){2964 .ops = Mir.Inst.Ops.encode(.{
3021 .reg1 = dst_mcv.register,2965 .reg1 = dst_mcv.register,
3022 .reg2 = registerAlias(dst_mcv.register, field_size),2966 .reg2 = registerAlias(dst_mcv.register, field_size),
3023 }).encode(),2967 }),
3024 .data = undefined,2968 .data = undefined,
3025 });2969 });
3026 }2970 }
...@@ -3048,10 +2992,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3048,10 +2992,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3048 };2992 };
3049 _ = try self.addInst(.{2993 _ = try self.addInst(.{
3050 .tag = .cond_set_byte_overflow,2994 .tag = .cond_set_byte_overflow,
3051 .ops = (Mir.Ops(Register, Register){2995 .ops = Mir.Inst.Ops.encode(.{
3052 .reg1 = dst_reg.to8(),2996 .reg1 = dst_reg.to8(),
3053 .flags = flags,2997 .flags = flags,
3054 }).encode(),2998 }),
3055 .data = undefined,2999 .data = undefined,
3056 });3000 });
3057 break :result MCValue{ .register = dst_reg.to8() };3001 break :result MCValue{ .register = dst_reg.to8() };
...@@ -3092,10 +3036,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi...@@ -3092,10 +3036,7 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
3092 1 => {3036 1 => {
3093 _ = try self.addInst(.{3037 _ = try self.addInst(.{
3094 .tag = tag,3038 .tag = tag,
3095 .ops = (Mir.Ops(Register, Register){3039 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }),
3096 .reg1 = registerAlias(reg, abi_size),
3097 .flags = 0b00,
3098 }).encode(),
3099 .data = undefined,3040 .data = undefined,
3100 });3041 });
3101 return;3042 return;
...@@ -3103,10 +3044,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi...@@ -3103,10 +3044,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
3103 else => {3044 else => {
3104 _ = try self.addInst(.{3045 _ = try self.addInst(.{
3105 .tag = tag,3046 .tag = tag,
3106 .ops = (Mir.Ops(Register, Register){3047 .ops = Mir.Inst.Ops.encode(.{
3107 .reg1 = registerAlias(reg, abi_size),3048 .reg1 = registerAlias(reg, abi_size),
3108 .flags = 0b10,3049 .flags = 0b10,
3109 }).encode(),3050 }),
3110 .data = .{ .imm = @intCast(u8, imm) },3051 .data = .{ .imm = @intCast(u8, imm) },
3111 });3052 });
3112 return;3053 return;
...@@ -3124,10 +3065,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi...@@ -3124,10 +3065,10 @@ fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shi
31243065
3125 _ = try self.addInst(.{3066 _ = try self.addInst(.{
3126 .tag = tag,3067 .tag = tag,
3127 .ops = (Mir.Ops(Register, Register){3068 .ops = Mir.Inst.Ops.encode(.{
3128 .reg1 = registerAlias(reg, abi_size),3069 .reg1 = registerAlias(reg, abi_size),
3129 .flags = 0b01,3070 .flags = 0b01,
3130 }).encode(),3071 }),
3131 .data = undefined,3072 .data = undefined,
3132 });3073 });
3133}3074}
...@@ -3383,32 +3324,6 @@ fn genBinOp(...@@ -3383,32 +3324,6 @@ fn genBinOp(
3383 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});3324 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
3384 }3325 }
33853326
3386 if (lhs_ty.zigTypeTag() == .Float) {
3387 switch (tag) {
3388 .add => {
3389 const dst_reg: AvxRegister = blk: {
3390 const reg = try self.avx_register_manager.allocReg(null);
3391 try self.genSetAvxReg(lhs_ty, reg, lhs);
3392 break :blk reg.to128();
3393 };
3394 const dst_lock = self.avx_register_manager.lockRegAssumeUnused(dst_reg);
3395 defer self.avx_register_manager.unlockReg(dst_lock);
3396
3397 const src_reg: AvxRegister = blk: {
3398 const reg = try self.avx_register_manager.allocReg(null);
3399 try self.genSetAvxReg(lhs_ty, reg, rhs);
3400 break :blk reg.to128();
3401 };
3402 const src_lock = self.avx_register_manager.lockRegAssumeUnused(src_reg);
3403 defer self.avx_register_manager.unlockReg(src_lock);
3404
3405 try self.genBinOpMir(.add_f64, lhs_ty, .{ .avx_register = dst_reg }, .{ .avx_register = src_reg });
3406 return MCValue{ .avx_register = dst_reg };
3407 },
3408 else => unreachable,
3409 }
3410 }
3411
3412 const is_commutative: bool = switch (tag) {3327 const is_commutative: bool = switch (tag) {
3413 .add,3328 .add,
3414 .addwrap,3329 .addwrap,
...@@ -3526,25 +3441,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3526,25 +3441,39 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3526 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);3441 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
3527 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });3442 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
3528 },3443 },
3529 .register => |src_reg| {3444 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
3530 _ = try self.addInst(.{3445 .Float => switch (dst_ty.tag()) {
3531 .tag = mir_tag,3446 .f64 => {
3532 .ops = (Mir.Ops(Register, Register){3447 _ = try self.addInst(.{
3533 .reg1 = registerAlias(dst_reg, abi_size),3448 .tag = switch (mir_tag) {
3534 .reg2 = registerAlias(src_reg, abi_size),3449 .add => .add_f64,
3535 }).encode(),3450 .cmp => .cmp_f64,
3536 .data = undefined,3451 else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}),
3537 });3452 },
3538 },3453 .ops = Mir.Inst.Ops.encode(.{
3539 .avx_register => {3454 .reg1 = dst_reg.to128(),
3540 return self.fail("TODO genBinOp for AVX register", .{});3455 .reg2 = src_reg.to128(),
3456 }),
3457 .data = undefined,
3458 });
3459 },
3460 else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}),
3461 },
3462 else => {
3463 _ = try self.addInst(.{
3464 .tag = mir_tag,
3465 .ops = Mir.Inst.Ops.encode(.{
3466 .reg1 = registerAlias(dst_reg, abi_size),
3467 .reg2 = registerAlias(src_reg, abi_size),
3468 }),
3469 .data = undefined,
3470 });
3471 },
3541 },3472 },
3542 .immediate => |imm| {3473 .immediate => |imm| {
3543 _ = try self.addInst(.{3474 _ = try self.addInst(.{
3544 .tag = mir_tag,3475 .tag = mir_tag,
3545 .ops = (Mir.Ops(Register, Register){3476 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size) }),
3546 .reg1 = registerAlias(dst_reg, abi_size),
3547 }).encode(),
3548 .data = .{ .imm = @truncate(u32, imm) },3477 .data = .{ .imm = @truncate(u32, imm) },
3549 });3478 });
3550 },3479 },
...@@ -3567,39 +3496,16 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3567,39 +3496,16 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3567 }3496 }
3568 _ = try self.addInst(.{3497 _ = try self.addInst(.{
3569 .tag = mir_tag,3498 .tag = mir_tag,
3570 .ops = (Mir.Ops(Register, Register){3499 .ops = Mir.Inst.Ops.encode(.{
3571 .reg1 = registerAlias(dst_reg, abi_size),3500 .reg1 = registerAlias(dst_reg, abi_size),
3572 .reg2 = .rbp,3501 .reg2 = .rbp,
3573 .flags = 0b01,3502 .flags = 0b01,
3574 }).encode(),3503 }),
3575 .data = .{ .imm = @bitCast(u32, -off) },3504 .data = .{ .imm = @bitCast(u32, -off) },
3576 });3505 });
3577 },3506 },
3578 }3507 }
3579 },3508 },
3580 .avx_register => |dst_reg| {
3581 switch (src_mcv) {
3582 .avx_register => |src_reg| {
3583 switch (dst_ty.zigTypeTag()) {
3584 .Float => switch (dst_ty.tag()) {
3585 .f64 => {
3586 _ = try self.addInst(.{
3587 .tag = mir_tag,
3588 .ops = (Mir.Ops(AvxRegister, AvxRegister){
3589 .reg1 = dst_reg.to128(),
3590 .reg2 = src_reg.to128(),
3591 }).encode(),
3592 .data = undefined,
3593 });
3594 },
3595 else => return self.fail("TODO genBinOp for AVX register and type {}", .{dst_ty.fmtDebug()}),
3596 },
3597 else => return self.fail("TODO genBinOp for AVX register and type {}", .{dst_ty.fmtDebug()}),
3598 }
3599 },
3600 else => return self.fail("TODO genBinOp for AVX register", .{}),
3601 }
3602 },
3603 .ptr_stack_offset, .stack_offset => |off| {3509 .ptr_stack_offset, .stack_offset => |off| {
3604 if (off > math.maxInt(i32)) {3510 if (off > math.maxInt(i32)) {
3605 return self.fail("stack offset too large", .{});3511 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...@@ -3617,17 +3523,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3617 .register => |src_reg| {3523 .register => |src_reg| {
3618 _ = try self.addInst(.{3524 _ = try self.addInst(.{
3619 .tag = mir_tag,3525 .tag = mir_tag,
3620 .ops = (Mir.Ops(Register, Register){3526 .ops = Mir.Inst.Ops.encode(.{
3621 .reg1 = .rbp,3527 .reg1 = .rbp,
3622 .reg2 = registerAlias(src_reg, abi_size),3528 .reg2 = registerAlias(src_reg, abi_size),
3623 .flags = 0b10,3529 .flags = 0b10,
3624 }).encode(),3530 }),
3625 .data = .{ .imm = @bitCast(u32, -off) },3531 .data = .{ .imm = @bitCast(u32, -off) },
3626 });3532 });
3627 },3533 },
3628 .avx_register => {
3629 return self.fail("TODO genBinOp for AVX register", .{});
3630 },
3631 .immediate => |imm| {3534 .immediate => |imm| {
3632 const tag: Mir.Inst.Tag = switch (mir_tag) {3535 const tag: Mir.Inst.Tag = switch (mir_tag) {
3633 .add => .add_mem_imm,3536 .add => .add_mem_imm,
...@@ -3651,10 +3554,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3651,10 +3554,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3651 });3554 });
3652 _ = try self.addInst(.{3555 _ = try self.addInst(.{
3653 .tag = tag,3556 .tag = tag,
3654 .ops = (Mir.Ops(Register, Register){3557 .ops = Mir.Inst.Ops.encode(.{
3655 .reg1 = .rbp,3558 .reg1 = .rbp,
3656 .flags = flags,3559 .flags = flags,
3657 }).encode(),3560 }),
3658 .data = .{ .payload = payload },3561 .data = .{ .payload = payload },
3659 });3562 });
3660 },3563 },
...@@ -3697,7 +3600,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3697,7 +3600,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3697 .ptr_stack_offset => unreachable,3600 .ptr_stack_offset => unreachable,
3698 .register_overflow_unsigned => unreachable,3601 .register_overflow_unsigned => unreachable,
3699 .register_overflow_signed => unreachable,3602 .register_overflow_signed => unreachable,
3700 .avx_register => unreachable,
3701 .register => |dst_reg| {3603 .register => |dst_reg| {
3702 switch (src_mcv) {3604 switch (src_mcv) {
3703 .none => unreachable,3605 .none => unreachable,
...@@ -3706,15 +3608,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3706,15 +3608,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3706 .ptr_stack_offset => unreachable,3608 .ptr_stack_offset => unreachable,
3707 .register_overflow_unsigned => unreachable,3609 .register_overflow_unsigned => unreachable,
3708 .register_overflow_signed => unreachable,3610 .register_overflow_signed => unreachable,
3709 .avx_register => unreachable,
3710 .register => |src_reg| {3611 .register => |src_reg| {
3711 // register, register3612 // register, register
3712 _ = try self.addInst(.{3613 _ = try self.addInst(.{
3713 .tag = .imul_complex,3614 .tag = .imul_complex,
3714 .ops = (Mir.Ops(Register, Register){3615 .ops = Mir.Inst.Ops.encode(.{
3715 .reg1 = registerAlias(dst_reg, abi_size),3616 .reg1 = registerAlias(dst_reg, abi_size),
3716 .reg2 = registerAlias(src_reg, abi_size),3617 .reg2 = registerAlias(src_reg, abi_size),
3717 }).encode(),3618 }),
3718 .data = undefined,3619 .data = undefined,
3719 });3620 });
3720 },3621 },
...@@ -3724,11 +3625,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3724,11 +3625,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3724 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {3625 if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
3725 _ = try self.addInst(.{3626 _ = try self.addInst(.{
3726 .tag = .imul_complex,3627 .tag = .imul_complex,
3727 .ops = (Mir.Ops(Register, Register){3628 .ops = Mir.Inst.Ops.encode(.{
3728 .reg1 = dst_reg.to32(),3629 .reg1 = dst_reg.to32(),
3729 .reg2 = dst_reg.to32(),3630 .reg2 = dst_reg.to32(),
3730 .flags = 0b10,3631 .flags = 0b10,
3731 }).encode(),3632 }),
3732 .data = .{ .imm = @truncate(u32, imm) },3633 .data = .{ .imm = @truncate(u32, imm) },
3733 });3634 });
3734 } else {3635 } else {
...@@ -3740,11 +3641,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3740,11 +3641,11 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3740 .stack_offset => |off| {3641 .stack_offset => |off| {
3741 _ = try self.addInst(.{3642 _ = try self.addInst(.{
3742 .tag = .imul_complex,3643 .tag = .imul_complex,
3743 .ops = (Mir.Ops(Register, Register){3644 .ops = Mir.Inst.Ops.encode(.{
3744 .reg1 = registerAlias(dst_reg, abi_size),3645 .reg1 = registerAlias(dst_reg, abi_size),
3745 .reg2 = .rbp,3646 .reg2 = .rbp,
3746 .flags = 0b01,3647 .flags = 0b01,
3747 }).encode(),3648 }),
3748 .data = .{ .imm = @bitCast(u32, -off) },3649 .data = .{ .imm = @bitCast(u32, -off) },
3749 });3650 });
3750 },3651 },
...@@ -3770,7 +3671,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3770,7 +3671,6 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3770 .ptr_stack_offset => unreachable,3671 .ptr_stack_offset => unreachable,
3771 .register_overflow_unsigned => unreachable,3672 .register_overflow_unsigned => unreachable,
3772 .register_overflow_signed => unreachable,3673 .register_overflow_signed => unreachable,
3773 .avx_register => unreachable,
3774 .register => |src_reg| {3674 .register => |src_reg| {
3775 // copy dst to a register3675 // copy dst to a register
3776 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);3676 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...@@ -3778,10 +3678,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3778 // register, register3678 // register, register
3779 _ = try self.addInst(.{3679 _ = try self.addInst(.{
3780 .tag = .imul_complex,3680 .tag = .imul_complex,
3781 .ops = (Mir.Ops(Register, Register){3681 .ops = Mir.Inst.Ops.encode(.{
3782 .reg1 = registerAlias(dst_reg, abi_size),3682 .reg1 = registerAlias(dst_reg, abi_size),
3783 .reg2 = registerAlias(src_reg, abi_size),3683 .reg2 = registerAlias(src_reg, abi_size),
3784 }).encode(),3684 }),
3785 .data = undefined,3685 .data = undefined,
3786 });3686 });
3787 // copy dst_reg back out3687 // copy dst_reg back out
...@@ -3888,9 +3788,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3888,9 +3788,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3888fn airBreakpoint(self: *Self) !void {3788fn airBreakpoint(self: *Self) !void {
3889 _ = try self.addInst(.{3789 _ = try self.addInst(.{
3890 .tag = .interrupt,3790 .tag = .interrupt,
3891 .ops = (Mir.Ops{3791 .ops = Mir.Inst.Ops.encode(.{}),
3892 .flags = 0b00,
3893 }).encode(),
3894 .data = undefined,3792 .data = undefined,
3895 });3793 });
3896 return self.finishAirBookkeeping();3794 return self.finishAirBookkeeping();
...@@ -3973,9 +3871,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3973,9 +3871,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3973 .ptr_stack_offset => {3871 .ptr_stack_offset => {
3974 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});3872 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
3975 },3873 },
3976 .avx_register => {
3977 return self.fail("TODO implement calling with MCValue.avx_register arg", .{});
3978 },
3979 .undef => unreachable,3874 .undef => unreachable,
3980 .immediate => unreachable,3875 .immediate => unreachable,
3981 .unreach => unreachable,3876 .unreach => unreachable,
...@@ -3994,9 +3889,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3994,9 +3889,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3994 // Adjust the stack3889 // Adjust the stack
3995 _ = try self.addInst(.{3890 _ = try self.addInst(.{
3996 .tag = .sub,3891 .tag = .sub,
3997 .ops = (Mir.Ops(Register, Register){3892 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
3998 .reg1 = .rsp,
3999 }).encode(),
4000 .data = .{ .imm = info.stack_byte_count },3893 .data = .{ .imm = info.stack_byte_count },
4001 });3894 });
4002 }3895 }
...@@ -4020,9 +3913,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4020,9 +3913,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4020 unreachable;3913 unreachable;
4021 _ = try self.addInst(.{3914 _ = try self.addInst(.{
4022 .tag = .call,3915 .tag = .call,
4023 .ops = (Mir.Ops(Register, Register){3916 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4024 .flags = 0b01,
4025 }).encode(),
4026 .data = .{ .imm = @truncate(u32, got_addr) },3917 .data = .{ .imm = @truncate(u32, got_addr) },
4027 });3918 });
4028 } else if (func_value.castTag(.extern_fn)) |_| {3919 } else if (func_value.castTag(.extern_fn)) |_| {
...@@ -4036,10 +3927,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4036,10 +3927,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4036 try self.genSetReg(Type.initTag(.usize), .rax, mcv);3927 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4037 _ = try self.addInst(.{3928 _ = try self.addInst(.{
4038 .tag = .call,3929 .tag = .call,
4039 .ops = (Mir.Ops(Register, Register){3930 .ops = Mir.Inst.Ops.encode(.{
4040 .reg1 = .rax,3931 .reg1 = .rax,
4041 .flags = 0b01,3932 .flags = 0b01,
4042 }).encode(),3933 }),
4043 .data = undefined,3934 .data = undefined,
4044 });3935 });
4045 }3936 }
...@@ -4054,10 +3945,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4054,10 +3945,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4054 // callq *%rax3945 // callq *%rax
4055 _ = try self.addInst(.{3946 _ = try self.addInst(.{
4056 .tag = .call,3947 .tag = .call,
4057 .ops = (Mir.Ops(Register, Register){3948 .ops = Mir.Inst.Ops.encode(.{
4058 .reg1 = .rax,3949 .reg1 = .rax,
4059 .flags = 0b01,3950 .flags = 0b01,
4060 }).encode(),3951 }),
4061 .data = undefined,3952 .data = undefined,
4062 });3953 });
4063 } else if (func_value.castTag(.extern_fn)) |func_payload| {3954 } 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....@@ -4089,10 +3980,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4089 try self.genSetReg(Type.initTag(.usize), .rax, mcv);3980 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4090 _ = try self.addInst(.{3981 _ = try self.addInst(.{
4091 .tag = .call,3982 .tag = .call,
4092 .ops = (Mir.Ops(Register, Register){3983 .ops = Mir.Inst.Ops.encode(.{
4093 .reg1 = .rax,3984 .reg1 = .rax,
4094 .flags = 0b01,3985 .flags = 0b01,
4095 }).encode(),3986 }),
4096 .data = undefined,3987 .data = undefined,
4097 });3988 });
4098 }3989 }
...@@ -4107,9 +3998,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4107,9 +3998,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4107 const fn_got_addr = got_addr + got_index * ptr_bytes;3998 const fn_got_addr = got_addr + got_index * ptr_bytes;
4108 _ = try self.addInst(.{3999 _ = try self.addInst(.{
4109 .tag = .call,4000 .tag = .call,
4110 .ops = (Mir.Ops(Register, Register){4001 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4111 .flags = 0b01,
4112 }).encode(),
4113 .data = .{ .imm = @intCast(u32, fn_got_addr) },4002 .data = .{ .imm = @intCast(u32, fn_got_addr) },
4114 });4003 });
4115 } else return self.fail("TODO implement calling extern fn on plan9", .{});4004 } 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....@@ -4119,10 +4008,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4119 try self.genSetReg(Type.initTag(.usize), .rax, mcv);4008 try self.genSetReg(Type.initTag(.usize), .rax, mcv);
4120 _ = try self.addInst(.{4009 _ = try self.addInst(.{
4121 .tag = .call,4010 .tag = .call,
4122 .ops = (Mir.Ops(Register, Register){4011 .ops = Mir.Inst.Ops.encode(.{
4123 .reg1 = .rax,4012 .reg1 = .rax,
4124 .flags = 0b01,4013 .flags = 0b01,
4125 }).encode(),4014 }),
4126 .data = undefined,4015 .data = undefined,
4127 });4016 });
4128 }4017 }
...@@ -4132,9 +4021,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4132,9 +4021,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4132 // Readjust the stack4021 // Readjust the stack
4133 _ = try self.addInst(.{4022 _ = try self.addInst(.{
4134 .tag = .add,4023 .tag = .add,
4135 .ops = (Mir.Ops(Register, Register){4024 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rsp }),
4136 .reg1 = .rsp,
4137 }).encode(),
4138 .data = .{ .imm = info.stack_byte_count },4025 .data = .{ .imm = info.stack_byte_count },
4139 });4026 });
4140 }4027 }
...@@ -4192,9 +4079,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -4192,9 +4079,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
4192 // which is available if the jump is 127 bytes or less forward.4079 // which is available if the jump is 127 bytes or less forward.
4193 const jmp_reloc = try self.addInst(.{4080 const jmp_reloc = try self.addInst(.{
4194 .tag = .jmp,4081 .tag = .jmp,
4195 .ops = (Mir.Ops(Register, Register){4082 .ops = Mir.Inst.Ops.encode(.{}),
4196 .flags = 0b00,
4197 }).encode(),
4198 .data = .{ .inst = undefined },4083 .data = .{ .inst = undefined },
4199 });4084 });
4200 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);4085 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
...@@ -4227,9 +4112,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -4227,9 +4112,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
4227 // which is available if the jump is 127 bytes or less forward.4112 // which is available if the jump is 127 bytes or less forward.
4228 const jmp_reloc = try self.addInst(.{4113 const jmp_reloc = try self.addInst(.{
4229 .tag = .jmp,4114 .tag = .jmp,
4230 .ops = (Mir.Ops(Register, Register){4115 .ops = Mir.Inst.Ops.encode(.{}),
4231 .flags = 0b00,
4232 }).encode(),
4233 .data = .{ .inst = undefined },4116 .data = .{ .inst = undefined },
4234 });4117 });
4235 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);4118 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 {...@@ -4256,37 +4139,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4256 self.compare_flags_inst = inst;4139 self.compare_flags_inst = inst;
42574140
4258 const result: MCValue = result: {4141 const result: MCValue = result: {
4259 if (ty.zigTypeTag() == .Float) {
4260 const lhs = try self.resolveInst(bin_op.lhs);
4261 const rhs = try self.resolveInst(bin_op.rhs);
4262
4263 const dst_reg: AvxRegister = blk: {
4264 const reg = try self.avx_register_manager.allocReg(null);
4265 try self.genSetAvxReg(ty, reg, lhs);
4266 break :blk reg.to128();
4267 };
4268 const dst_lock = self.avx_register_manager.lockRegAssumeUnused(dst_reg);
4269 defer self.avx_register_manager.unlockReg(dst_lock);
4270
4271 const src_reg: AvxRegister = blk: {
4272 const reg = try self.avx_register_manager.allocReg(null);
4273 try self.genSetAvxReg(ty, reg, rhs);
4274 break :blk reg.to128();
4275 };
4276 const src_lock = self.avx_register_manager.lockRegAssumeUnused(src_reg);
4277 defer self.avx_register_manager.unlockReg(src_lock);
4278
4279 _ = try self.addInst(.{
4280 .tag = .cmp_f64,
4281 .ops = (Mir.Ops(AvxRegister, AvxRegister){
4282 .reg1 = dst_reg,
4283 .reg2 = src_reg,
4284 }).encode(),
4285 .data = undefined,
4286 });
4287
4288 break :result MCValue{ .compare_flags_unsigned = op };
4289 }
4290 // There are 2 operands, destination and source.4142 // There are 2 operands, destination and source.
4291 // Either one, but not both, can be a memory operand.4143 // Either one, but not both, can be a memory operand.
4292 // Source operand can be an immediate, 8 bits or 32 bits.4144 // 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 {...@@ -4304,8 +4156,28 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
43044156
4305 const dst_mcv = MCValue{ .register = dst_reg };4157 const dst_mcv = MCValue{ .register = dst_reg };
43064158
4159 const rhs_ty = self.air.typeOf(bin_op.rhs);
4307 // This instruction supports only signed 32-bit immediates at most.4160 // This instruction supports only signed 32-bit immediates at most.
4308 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);4161 const src_mcv: MCValue = blk: {
4162 switch (rhs_ty.zigTypeTag()) {
4163 .Float => {
4164 const rhs = try self.resolveInst(bin_op.rhs);
4165 const rhs_lock: ?RegisterLock = switch (rhs) {
4166 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4167 else => null,
4168 };
4169 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
4170 const src_reg = try self.copyToTmpRegister(rhs_ty, rhs);
4171 break :blk MCValue{ .register = src_reg };
4172 },
4173 else => break :blk try self.limitImmediateType(bin_op.rhs, i32),
4174 }
4175 };
4176 const src_lock: ?RegisterLock = switch (src_mcv) {
4177 .register => |reg| self.register_manager.lockReg(reg),
4178 else => null,
4179 };
4180 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
43094181
4310 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);4182 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
4311 break :result switch (signedness) {4183 break :result switch (signedness) {
...@@ -4504,9 +4376,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -4504,9 +4376,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4504 Mir.Inst.Tag.cond_jmp_greater_less;4376 Mir.Inst.Tag.cond_jmp_greater_less;
4505 return self.addInst(.{4377 return self.addInst(.{
4506 .tag = tag,4378 .tag = tag,
4507 .ops = (Mir.Ops(Register, Register){4379 .ops = Mir.Inst.Ops.encode(.{ .flags = flags }),
4508 .flags = flags,
4509 }).encode(),
4510 .data = .{ .inst = undefined },4380 .data = .{ .inst = undefined },
4511 });4381 });
4512 },4382 },
...@@ -4514,17 +4384,12 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -4514,17 +4384,12 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4514 try self.spillCompareFlagsIfOccupied();4384 try self.spillCompareFlagsIfOccupied();
4515 _ = try self.addInst(.{4385 _ = try self.addInst(.{
4516 .tag = .@"test",4386 .tag = .@"test",
4517 .ops = (Mir.Ops(Register, Register){4387 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
4518 .reg1 = reg,
4519 .flags = 0b00,
4520 }).encode(),
4521 .data = .{ .imm = 1 },4388 .data = .{ .imm = 1 },
4522 });4389 });
4523 return self.addInst(.{4390 return self.addInst(.{
4524 .tag = .cond_jmp_eq_ne,4391 .tag = .cond_jmp_eq_ne,
4525 .ops = (Mir.Ops(Register, Register){4392 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4526 .flags = 0b01,
4527 }).encode(),
4528 .data = .{ .inst = undefined },4393 .data = .{ .inst = undefined },
4529 });4394 });
4530 },4395 },
...@@ -4918,9 +4783,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -4918,9 +4783,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
4918 try self.genBody(body);4783 try self.genBody(body);
4919 _ = try self.addInst(.{4784 _ = try self.addInst(.{
4920 .tag = .jmp,4785 .tag = .jmp,
4921 .ops = (Mir.Ops(Register, Register){4786 .ops = Mir.Inst.Ops.encode(.{}),
4922 .flags = 0b00,
4923 }).encode(),
4924 .data = .{ .inst = jmp_target },4787 .data = .{ .inst = jmp_target },
4925 });4788 });
4926 return self.finishAirBookkeeping();4789 return self.finishAirBookkeeping();
...@@ -4971,19 +4834,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4971,19 +4834,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4971 .immediate => |imm| {4834 .immediate => |imm| {
4972 _ = try self.addInst(.{4835 _ = try self.addInst(.{
4973 .tag = .xor,4836 .tag = .xor,
4974 .ops = (Mir.Ops(Register, Register){4837 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size) }),
4975 .reg1 = registerAlias(cond_reg, abi_size),
4976 }).encode(),
4977 .data = .{ .imm = @intCast(u32, imm) },4838 .data = .{ .imm = @intCast(u32, imm) },
4978 });4839 });
4979 },4840 },
4980 .register => |reg| {4841 .register => |reg| {
4981 _ = try self.addInst(.{4842 _ = try self.addInst(.{
4982 .tag = .xor,4843 .tag = .xor,
4983 .ops = (Mir.Ops(Register, Register){4844 .ops = Mir.Inst.Ops.encode(.{
4984 .reg1 = registerAlias(cond_reg, abi_size),4845 .reg1 = registerAlias(cond_reg, abi_size),
4985 .reg2 = registerAlias(reg, abi_size),4846 .reg2 = registerAlias(reg, abi_size),
4986 }).encode(),4847 }),
4987 .data = undefined,4848 .data = undefined,
4988 });4849 });
4989 },4850 },
...@@ -5002,17 +4863,15 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -5002,17 +4863,15 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
50024863
5003 _ = try self.addInst(.{4864 _ = try self.addInst(.{
5004 .tag = .@"test",4865 .tag = .@"test",
5005 .ops = (Mir.Ops(Register, Register){4866 .ops = Mir.Inst.Ops.encode(.{
5006 .reg1 = registerAlias(cond_reg, abi_size),4867 .reg1 = registerAlias(cond_reg, abi_size),
5007 .reg2 = registerAlias(cond_reg, abi_size),4868 .reg2 = registerAlias(cond_reg, abi_size),
5008 }).encode(),4869 }),
5009 .data = undefined,4870 .data = undefined,
5010 });4871 });
5011 return self.addInst(.{4872 return self.addInst(.{
5012 .tag = .cond_jmp_eq_ne,4873 .tag = .cond_jmp_eq_ne,
5013 .ops = (Mir.Ops(Register, Register){4874 .ops = Mir.Inst.Ops.encode(.{}),
5014 .flags = 0b00,
5015 }).encode(),
5016 .data = .{ .inst = undefined },4875 .data = .{ .inst = undefined },
5017 });4876 });
5018 },4877 },
...@@ -5156,17 +5015,20 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -5156,17 +5015,20 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
5156 if (block_mcv == .none) {5015 if (block_mcv == .none) {
5157 block_data.mcv = switch (operand_mcv) {5016 block_data.mcv = switch (operand_mcv) {
5158 .none, .dead, .unreach => unreachable,5017 .none, .dead, .unreach => unreachable,
5159 .register, .stack_offset, .memory => operand_mcv,5018 .stack_offset, .memory => operand_mcv,
5160 .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: {5019 .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: {
5161 const new_mcv = try self.allocRegOrMem(block, true);5020 const new_mcv = try self.allocRegOrMem(block, true);
5162 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5021 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
5163 break :blk new_mcv;5022 break :blk new_mcv;
5164 },5023 },
5165 .avx_register => blk: {5024 .register => blk: {
5166 // TODO not needed; return operand_mcv ones we can transfer between XMM registers5025 if (self.air.typeOfIndex(block).zigTypeTag() == .Float) {
5167 const new_mcv = try self.allocRegOrMem(block, false);5026 // TODO not needed; return operand_mcv ones we can transfer between XMM registers
5168 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5027 const new_mcv = try self.allocRegOrMem(block, false);
5169 break :blk new_mcv;5028 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
5029 break :blk new_mcv;
5030 }
5031 break :blk operand_mcv;
5170 },5032 },
5171 else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),5033 else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),
5172 };5034 };
...@@ -5184,9 +5046,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {...@@ -5184,9 +5046,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
5184 // Leave the jump offset undefined5046 // Leave the jump offset undefined
5185 const jmp_reloc = try self.addInst(.{5047 const jmp_reloc = try self.addInst(.{
5186 .tag = .jmp,5048 .tag = .jmp,
5187 .ops = (Mir.Ops(Register, Register){5049 .ops = Mir.Inst.Ops.encode(.{}),
5188 .flags = 0b00,
5189 }).encode(),
5190 .data = .{ .inst = undefined },5050 .data = .{ .inst = undefined },
5191 });5051 });
5192 block_data.relocs.appendAssumeCapacity(jmp_reloc);5052 block_data.relocs.appendAssumeCapacity(jmp_reloc);
...@@ -5274,9 +5134,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5274,9 +5134,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5274 };5134 };
5275 _ = try self.addInst(.{5135 _ = try self.addInst(.{
5276 .tag = .push,5136 .tag = .push,
5277 .ops = (Mir.Ops(Register, Register){5137 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b10 }),
5278 .flags = 0b10,
5279 }).encode(),
5280 .data = .{ .imm = n },5138 .data = .{ .imm = n },
5281 });5139 });
5282 } else if (mem.indexOf(u8, arg, "%%")) |l| {5140 } else if (mem.indexOf(u8, arg, "%%")) |l| {
...@@ -5285,9 +5143,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5285,9 +5143,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5285 return self.fail("unrecognized register: '{s}'", .{reg_name});5143 return self.fail("unrecognized register: '{s}'", .{reg_name});
5286 _ = try self.addInst(.{5144 _ = try self.addInst(.{
5287 .tag = .push,5145 .tag = .push,
5288 .ops = (Mir.Ops(Register, Register){5146 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
5289 .reg1 = reg,
5290 }).encode(),
5291 .data = undefined,5147 .data = undefined,
5292 });5148 });
5293 } else return self.fail("TODO more push operands", .{});5149 } else return self.fail("TODO more push operands", .{});
...@@ -5299,9 +5155,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5299,9 +5155,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5299 return self.fail("unrecognized register: '{s}'", .{reg_name});5155 return self.fail("unrecognized register: '{s}'", .{reg_name});
5300 _ = try self.addInst(.{5156 _ = try self.addInst(.{
5301 .tag = .pop,5157 .tag = .pop,
5302 .ops = (Mir.Ops(Register, Register){5158 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
5303 .reg1 = reg,
5304 }).encode(),
5305 .data = undefined,5159 .data = undefined,
5306 });5160 });
5307 } else return self.fail("TODO more pop operands", .{});5161 } else return self.fail("TODO more pop operands", .{});
...@@ -5365,7 +5219,6 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {...@@ -5365,7 +5219,6 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
5365 .none => return,5219 .none => return,
5366 .immediate => unreachable,5220 .immediate => unreachable,
5367 .register => |reg| return self.genSetReg(ty, reg, val),5221 .register => |reg| return self.genSetReg(ty, reg, val),
5368 .avx_register => |reg| return self.genSetAvxReg(ty, reg, val),
5369 .stack_offset => |off| return self.genSetStack(ty, off, val, .{}),5222 .stack_offset => |off| return self.genSetStack(ty, off, val, .{}),
5370 .memory => {5223 .memory => {
5371 return self.fail("TODO implement setRegOrMem for memory", .{});5224 return self.fail("TODO implement setRegOrMem for memory", .{});
...@@ -5396,9 +5249,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5396,9 +5249,6 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5396 .register_overflow_unsigned,5249 .register_overflow_unsigned,
5397 .register_overflow_signed,5250 .register_overflow_signed,
5398 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),5251 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5399 .avx_register => {
5400 return self.fail("TODO genSetStackArg for AVX register", .{});
5401 },
5402 .compare_flags_unsigned,5252 .compare_flags_unsigned,
5403 .compare_flags_signed,5253 .compare_flags_signed,
5404 => {5254 => {
...@@ -5417,7 +5267,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5417,7 +5267,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5417 });5267 });
5418 _ = try self.addInst(.{5268 _ = try self.addInst(.{
5419 .tag = .mov_mem_imm,5269 .tag = .mov_mem_imm,
5420 .ops = (Mir.Ops(Register, Register){5270 .ops = Mir.Inst.Ops.encode(.{
5421 .reg1 = .rsp,5271 .reg1 = .rsp,
5422 .flags = switch (abi_size) {5272 .flags = switch (abi_size) {
5423 1 => 0b00,5273 1 => 0b00,
...@@ -5425,7 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5425,7 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5425 4 => 0b10,5275 4 => 0b10,
5426 else => unreachable,5276 else => unreachable,
5427 },5277 },
5428 }).encode(),5278 }),
5429 .data = .{ .payload = payload },5279 .data = .{ .payload = payload },
5430 });5280 });
5431 },5281 },
...@@ -5453,11 +5303,11 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5453,11 +5303,11 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5453 .register => |reg| {5303 .register => |reg| {
5454 _ = try self.addInst(.{5304 _ = try self.addInst(.{
5455 .tag = .mov,5305 .tag = .mov,
5456 .ops = (Mir.Ops(Register, Register){5306 .ops = Mir.Inst.Ops.encode(.{
5457 .reg1 = .rsp,5307 .reg1 = .rsp,
5458 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),5308 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
5459 .flags = 0b10,5309 .flags = 0b10,
5460 }).encode(),5310 }),
5461 .data = .{ .imm = @bitCast(u32, -stack_offset) },5311 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5462 });5312 });
5463 },5313 },
...@@ -5520,10 +5370,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5520,10 +5370,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5520 };5370 };
5521 _ = try self.addInst(.{5371 _ = try self.addInst(.{
5522 .tag = .cond_set_byte_overflow,5372 .tag = .cond_set_byte_overflow,
5523 .ops = (Mir.Ops(Register, Register){5373 .ops = Mir.Inst.Ops.encode(.{
5524 .reg1 = tmp_reg.to8(),5374 .reg1 = tmp_reg.to8(),
5525 .flags = flags,5375 .flags = flags,
5526 }).encode(),5376 }),
5527 .data = undefined,5377 .data = undefined,
5528 });5378 });
55295379
...@@ -5550,7 +5400,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5550,7 +5400,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5550 });5400 });
5551 _ = try self.addInst(.{5401 _ = try self.addInst(.{
5552 .tag = .mov_mem_imm,5402 .tag = .mov_mem_imm,
5553 .ops = (Mir.Ops(Register, Register){5403 .ops = Mir.Inst.Ops.encode(.{
5554 .reg1 = base_reg,5404 .reg1 = base_reg,
5555 .flags = switch (abi_size) {5405 .flags = switch (abi_size) {
5556 1 => 0b00,5406 1 => 0b00,
...@@ -5558,7 +5408,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5558,7 +5408,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5558 4 => 0b10,5408 4 => 0b10,
5559 else => unreachable,5409 else => unreachable,
5560 },5410 },
5561 }).encode(),5411 }),
5562 .data = .{ .payload = payload },5412 .data = .{ .payload = payload },
5563 });5413 });
5564 },5414 },
...@@ -5572,10 +5422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5572,10 +5422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5572 });5422 });
5573 _ = try self.addInst(.{5423 _ = try self.addInst(.{
5574 .tag = .mov_mem_imm,5424 .tag = .mov_mem_imm,
5575 .ops = (Mir.Ops(Register, Register){5425 .ops = Mir.Inst.Ops.encode(.{
5576 .reg1 = base_reg,5426 .reg1 = base_reg,
5577 .flags = 0b10,5427 .flags = 0b10,
5578 }).encode(),5428 }),
5579 .data = .{ .payload = payload },5429 .data = .{ .payload = payload },
5580 });5430 });
5581 }5431 }
...@@ -5586,10 +5436,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5586,10 +5436,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5586 });5436 });
5587 _ = try self.addInst(.{5437 _ = try self.addInst(.{
5588 .tag = .mov_mem_imm,5438 .tag = .mov_mem_imm,
5589 .ops = (Mir.Ops(Register, Register){5439 .ops = Mir.Inst.Ops.encode(.{
5590 .reg1 = base_reg,5440 .reg1 = base_reg,
5591 .flags = 0b10,5441 .flags = 0b10,
5592 }).encode(),5442 }),
5593 .data = .{ .payload = payload },5443 .data = .{ .payload = payload },
5594 });5444 });
5595 }5445 }
...@@ -5605,65 +5455,64 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5605,65 +5455,64 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5605 }5455 }
56065456
5607 const base_reg = opts.dest_stack_base orelse .rbp;5457 const base_reg = opts.dest_stack_base orelse .rbp;
5608 if (!math.isPowerOfTwo(abi_size)) {
5609 const reg_lock = self.register_manager.lockReg(reg);
5610 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
5611
5612 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
5613
5614 var next_offset = stack_offset;
5615 var remainder = abi_size;
5616 while (remainder > 0) {
5617 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
5618
5619 _ = try self.addInst(.{
5620 .tag = .mov,
5621 .ops = (Mir.Ops(Register, Register){
5622 .reg1 = base_reg,
5623 .reg2 = registerAlias(tmp_reg, nearest_power_of_two),
5624 .flags = 0b10,
5625 }).encode(),
5626 .data = .{ .imm = @bitCast(u32, -next_offset) },
5627 });
56285458
5629 if (nearest_power_of_two > 1) {
5630 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 });
5631 }
5632
5633 remainder -= nearest_power_of_two;
5634 next_offset -= nearest_power_of_two;
5635 }
5636 } else {
5637 _ = try self.addInst(.{
5638 .tag = .mov,
5639 .ops = (Mir.Ops(Register, Register){
5640 .reg1 = base_reg,
5641 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
5642 .flags = 0b10,
5643 }).encode(),
5644 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5645 });
5646 }
5647 },
5648 .avx_register => |reg| {
5649 const base_reg = opts.dest_stack_base orelse .rbp;
5650 switch (ty.zigTypeTag()) {5459 switch (ty.zigTypeTag()) {
5651 .Float => switch (ty.tag()) {5460 .Float => switch (ty.tag()) {
5652 .f32 => return self.fail("TODO genSetStack for AVX register for f32", .{}),5461 .f32 => return self.fail("TODO genSetStack for register for f32", .{}),
5653 .f64 => {5462 .f64 => {
5654 _ = try self.addInst(.{5463 _ = try self.addInst(.{
5655 .tag = .mov_f64,5464 .tag = .mov_f64,
5656 .ops = (Mir.Ops(Register, AvxRegister){5465 .ops = Mir.Inst.Ops.encode(.{
5657 .reg1 = base_reg,5466 .reg1 = base_reg,
5658 .reg2 = reg.to128(),5467 .reg2 = reg.to128(),
5659 .flags = 0b01,5468 .flags = 0b01,
5660 }).encode(),5469 }),
5661 .data = .{ .imm = @bitCast(u32, -stack_offset) },5470 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5662 });5471 });
5663 },5472 },
5664 else => return self.fail("TODO genSetStack for AVX register for type {}", .{ty.fmtDebug()}),5473 else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),
5474 },
5475 else => {
5476 if (!math.isPowerOfTwo(abi_size)) {
5477 const reg_lock = self.register_manager.lockReg(reg);
5478 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
5479
5480 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
5481
5482 var next_offset = stack_offset;
5483 var remainder = abi_size;
5484 while (remainder > 0) {
5485 const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder));
5486
5487 _ = try self.addInst(.{
5488 .tag = .mov,
5489 .ops = Mir.Inst.Ops.encode(.{
5490 .reg1 = base_reg,
5491 .reg2 = registerAlias(tmp_reg, nearest_power_of_two),
5492 .flags = 0b10,
5493 }),
5494 .data = .{ .imm = @bitCast(u32, -next_offset) },
5495 });
5496
5497 if (nearest_power_of_two > 1) {
5498 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 });
5499 }
5500
5501 remainder -= nearest_power_of_two;
5502 next_offset -= nearest_power_of_two;
5503 }
5504 } else {
5505 _ = try self.addInst(.{
5506 .tag = .mov,
5507 .ops = Mir.Inst.Ops.encode(.{
5508 .reg1 = base_reg,
5509 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
5510 .flags = 0b10,
5511 }),
5512 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5513 });
5514 }
5665 },5515 },
5666 else => return self.fail("TODO genSetStack for AVX register for type {}", .{ty.fmtDebug()}),
5667 }5516 }
5668 },5517 },
5669 .memory,5518 .memory,
...@@ -5742,20 +5591,20 @@ fn genInlineMemcpy(...@@ -5742,20 +5591,20 @@ fn genInlineMemcpy(
5742 .ptr_stack_offset, .stack_offset => |off| {5591 .ptr_stack_offset, .stack_offset => |off| {
5743 _ = try self.addInst(.{5592 _ = try self.addInst(.{
5744 .tag = .lea,5593 .tag = .lea,
5745 .ops = (Mir.Ops(Register, Register){5594 .ops = Mir.Inst.Ops.encode(.{
5746 .reg1 = dst_addr_reg.to64(),5595 .reg1 = dst_addr_reg.to64(),
5747 .reg2 = opts.dest_stack_base orelse .rbp,5596 .reg2 = opts.dest_stack_base orelse .rbp,
5748 }).encode(),5597 }),
5749 .data = .{ .imm = @bitCast(u32, -off) },5598 .data = .{ .imm = @bitCast(u32, -off) },
5750 });5599 });
5751 },5600 },
5752 .register => |reg| {5601 .register => |reg| {
5753 _ = try self.addInst(.{5602 _ = try self.addInst(.{
5754 .tag = .mov,5603 .tag = .mov,
5755 .ops = (Mir.Ops(Register, Register){5604 .ops = Mir.Inst.Ops.encode(.{
5756 .reg1 = registerAlias(dst_addr_reg, @divExact(reg.size(), 8)),5605 .reg1 = registerAlias(dst_addr_reg, @divExact(reg.size(), 8)),
5757 .reg2 = reg,5606 .reg2 = reg,
5758 }).encode(),5607 }),
5759 .data = undefined,5608 .data = undefined,
5760 });5609 });
5761 },5610 },
...@@ -5777,20 +5626,20 @@ fn genInlineMemcpy(...@@ -5777,20 +5626,20 @@ fn genInlineMemcpy(
5777 .ptr_stack_offset, .stack_offset => |off| {5626 .ptr_stack_offset, .stack_offset => |off| {
5778 _ = try self.addInst(.{5627 _ = try self.addInst(.{
5779 .tag = .lea,5628 .tag = .lea,
5780 .ops = (Mir.Ops(Register, Register){5629 .ops = Mir.Inst.Ops.encode(.{
5781 .reg1 = src_addr_reg.to64(),5630 .reg1 = src_addr_reg.to64(),
5782 .reg2 = opts.source_stack_base orelse .rbp,5631 .reg2 = opts.source_stack_base orelse .rbp,
5783 }).encode(),5632 }),
5784 .data = .{ .imm = @bitCast(u32, -off) },5633 .data = .{ .imm = @bitCast(u32, -off) },
5785 });5634 });
5786 },5635 },
5787 .register => |reg| {5636 .register => |reg| {
5788 _ = try self.addInst(.{5637 _ = try self.addInst(.{
5789 .tag = .mov,5638 .tag = .mov,
5790 .ops = (Mir.Ops(Register, Register){5639 .ops = Mir.Inst.Ops.encode(.{
5791 .reg1 = registerAlias(src_addr_reg, @divExact(reg.size(), 8)),5640 .reg1 = registerAlias(src_addr_reg, @divExact(reg.size(), 8)),
5792 .reg2 = reg,5641 .reg2 = reg,
5793 }).encode(),5642 }),
5794 .data = undefined,5643 .data = undefined,
5795 });5644 });
5796 },5645 },
...@@ -5810,18 +5659,14 @@ fn genInlineMemcpy(...@@ -5810,18 +5659,14 @@ fn genInlineMemcpy(
5810 // mov rcx, 05659 // mov rcx, 0
5811 _ = try self.addInst(.{5660 _ = try self.addInst(.{
5812 .tag = .mov,5661 .tag = .mov,
5813 .ops = (Mir.Ops(Register, Register){5662 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rcx }),
5814 .reg1 = .rcx,
5815 }).encode(),
5816 .data = .{ .imm = 0 },5663 .data = .{ .imm = 0 },
5817 });5664 });
58185665
5819 // mov rax, 05666 // mov rax, 0
5820 _ = try self.addInst(.{5667 _ = try self.addInst(.{
5821 .tag = .mov,5668 .tag = .mov,
5822 .ops = (Mir.Ops(Register, Register){5669 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }),
5823 .reg1 = .rax,
5824 }).encode(),
5825 .data = .{ .imm = 0 },5670 .data = .{ .imm = 0 },
5826 });5671 });
58275672
...@@ -5829,70 +5674,62 @@ fn genInlineMemcpy(...@@ -5829,70 +5674,62 @@ fn genInlineMemcpy(
5829 // cmp count, 05674 // cmp count, 0
5830 const loop_start = try self.addInst(.{5675 const loop_start = try self.addInst(.{
5831 .tag = .cmp,5676 .tag = .cmp,
5832 .ops = (Mir.Ops(Register, Register){5677 .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
5833 .reg1 = count_reg,
5834 }).encode(),
5835 .data = .{ .imm = 0 },5678 .data = .{ .imm = 0 },
5836 });5679 });
58375680
5838 // je end5681 // je end
5839 const loop_reloc = try self.addInst(.{5682 const loop_reloc = try self.addInst(.{
5840 .tag = .cond_jmp_eq_ne,5683 .tag = .cond_jmp_eq_ne,
5841 .ops = (Mir.Ops(Register, Register){ .flags = 0b01 }).encode(),5684 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
5842 .data = .{ .inst = undefined },5685 .data = .{ .inst = undefined },
5843 });5686 });
58445687
5845 // mov tmp, [addr + rcx]5688 // mov tmp, [addr + rcx]
5846 _ = try self.addInst(.{5689 _ = try self.addInst(.{
5847 .tag = .mov_scale_src,5690 .tag = .mov_scale_src,
5848 .ops = (Mir.Ops(Register, Register){5691 .ops = Mir.Inst.Ops.encode(.{
5849 .reg1 = tmp_reg.to8(),5692 .reg1 = tmp_reg.to8(),
5850 .reg2 = src_addr_reg,5693 .reg2 = src_addr_reg,
5851 }).encode(),5694 }),
5852 .data = .{ .imm = 0 },5695 .data = .{ .imm = 0 },
5853 });5696 });
58545697
5855 // mov [stack_offset + rax], tmp5698 // mov [stack_offset + rax], tmp
5856 _ = try self.addInst(.{5699 _ = try self.addInst(.{
5857 .tag = .mov_scale_dst,5700 .tag = .mov_scale_dst,
5858 .ops = (Mir.Ops(Register, Register){5701 .ops = Mir.Inst.Ops.encode(.{
5859 .reg1 = dst_addr_reg,5702 .reg1 = dst_addr_reg,
5860 .reg2 = tmp_reg.to8(),5703 .reg2 = tmp_reg.to8(),
5861 }).encode(),5704 }),
5862 .data = .{ .imm = 0 },5705 .data = .{ .imm = 0 },
5863 });5706 });
58645707
5865 // add rcx, 15708 // add rcx, 1
5866 _ = try self.addInst(.{5709 _ = try self.addInst(.{
5867 .tag = .add,5710 .tag = .add,
5868 .ops = (Mir.Ops(Register, Register){5711 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rcx }),
5869 .reg1 = .rcx,
5870 }).encode(),
5871 .data = .{ .imm = 1 },5712 .data = .{ .imm = 1 },
5872 });5713 });
58735714
5874 // add rax, 15715 // add rax, 1
5875 _ = try self.addInst(.{5716 _ = try self.addInst(.{
5876 .tag = .add,5717 .tag = .add,
5877 .ops = (Mir.Ops(Register, Register){5718 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }),
5878 .reg1 = .rax,
5879 }).encode(),
5880 .data = .{ .imm = 1 },5719 .data = .{ .imm = 1 },
5881 });5720 });
58825721
5883 // sub count, 15722 // sub count, 1
5884 _ = try self.addInst(.{5723 _ = try self.addInst(.{
5885 .tag = .sub,5724 .tag = .sub,
5886 .ops = (Mir.Ops(Register, Register){5725 .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
5887 .reg1 = count_reg,
5888 }).encode(),
5889 .data = .{ .imm = 1 },5726 .data = .{ .imm = 1 },
5890 });5727 });
58915728
5892 // jmp loop5729 // jmp loop
5893 _ = try self.addInst(.{5730 _ = try self.addInst(.{
5894 .tag = .jmp,5731 .tag = .jmp,
5895 .ops = (Mir.Ops(Register, Register){ .flags = 0b00 }).encode(),5732 .ops = Mir.Inst.Ops.encode(.{}),
5896 .data = .{ .inst = loop_start },5733 .data = .{ .inst = loop_start },
5897 });5734 });
58985735
...@@ -5924,20 +5761,20 @@ fn genInlineMemset(...@@ -5924,20 +5761,20 @@ fn genInlineMemset(
5924 .ptr_stack_offset, .stack_offset => |off| {5761 .ptr_stack_offset, .stack_offset => |off| {
5925 _ = try self.addInst(.{5762 _ = try self.addInst(.{
5926 .tag = .lea,5763 .tag = .lea,
5927 .ops = (Mir.Ops(Register, Register){5764 .ops = Mir.Inst.Ops.encode(.{
5928 .reg1 = addr_reg.to64(),5765 .reg1 = addr_reg.to64(),
5929 .reg2 = opts.dest_stack_base orelse .rbp,5766 .reg2 = opts.dest_stack_base orelse .rbp,
5930 }).encode(),5767 }),
5931 .data = .{ .imm = @bitCast(u32, -off) },5768 .data = .{ .imm = @bitCast(u32, -off) },
5932 });5769 });
5933 },5770 },
5934 .register => |reg| {5771 .register => |reg| {
5935 _ = try self.addInst(.{5772 _ = try self.addInst(.{
5936 .tag = .mov,5773 .tag = .mov,
5937 .ops = (Mir.Ops(Register, Register){5774 .ops = Mir.Inst.Ops.encode(.{
5938 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),5775 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
5939 .reg2 = reg,5776 .reg2 = reg,
5940 }).encode(),5777 }),
5941 .data = undefined,5778 .data = undefined,
5942 });5779 });
5943 },5780 },
...@@ -5955,16 +5792,14 @@ fn genInlineMemset(...@@ -5955,16 +5792,14 @@ fn genInlineMemset(
5955 // cmp rax, -15792 // cmp rax, -1
5956 const loop_start = try self.addInst(.{5793 const loop_start = try self.addInst(.{
5957 .tag = .cmp,5794 .tag = .cmp,
5958 .ops = (Mir.Ops(Register, Register){5795 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }),
5959 .reg1 = .rax,
5960 }).encode(),
5961 .data = .{ .imm = @bitCast(u32, @as(i32, -1)) },5796 .data = .{ .imm = @bitCast(u32, @as(i32, -1)) },
5962 });5797 });
59635798
5964 // je end5799 // je end
5965 const loop_reloc = try self.addInst(.{5800 const loop_reloc = try self.addInst(.{
5966 .tag = .cond_jmp_eq_ne,5801 .tag = .cond_jmp_eq_ne,
5967 .ops = (Mir.Ops(Register, Register){ .flags = 0b01 }).encode(),5802 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
5968 .data = .{ .inst = undefined },5803 .data = .{ .inst = undefined },
5969 });5804 });
59705805
...@@ -5980,9 +5815,7 @@ fn genInlineMemset(...@@ -5980,9 +5815,7 @@ fn genInlineMemset(
5980 });5815 });
5981 _ = try self.addInst(.{5816 _ = try self.addInst(.{
5982 .tag = .mov_mem_index_imm,5817 .tag = .mov_mem_index_imm,
5983 .ops = (Mir.Ops(Register, Register){5818 .ops = Mir.Inst.Ops.encode(.{ .reg1 = addr_reg }),
5984 .reg1 = addr_reg,
5985 }).encode(),
5986 .data = .{ .payload = payload },5819 .data = .{ .payload = payload },
5987 });5820 });
5988 },5821 },
...@@ -5992,16 +5825,14 @@ fn genInlineMemset(...@@ -5992,16 +5825,14 @@ fn genInlineMemset(
5992 // sub rax, 15825 // sub rax, 1
5993 _ = try self.addInst(.{5826 _ = try self.addInst(.{
5994 .tag = .sub,5827 .tag = .sub,
5995 .ops = (Mir.Ops(Register, Register){5828 .ops = Mir.Inst.Ops.encode(.{ .reg1 = .rax }),
5996 .reg1 = .rax,
5997 }).encode(),
5998 .data = .{ .imm = 1 },5829 .data = .{ .imm = 1 },
5999 });5830 });
60005831
6001 // jmp loop5832 // jmp loop
6002 _ = try self.addInst(.{5833 _ = try self.addInst(.{
6003 .tag = .jmp,5834 .tag = .jmp,
6004 .ops = (Mir.Ops(Register, Register){ .flags = 0b00 }).encode(),5835 .ops = Mir.Inst.Ops.encode(.{}),
6005 .data = .{ .inst = loop_start },5836 .data = .{ .inst = loop_start },
6006 });5837 });
60075838
...@@ -6009,88 +5840,6 @@ fn genInlineMemset(...@@ -6009,88 +5840,6 @@ fn genInlineMemset(
6009 try self.performReloc(loop_reloc);5840 try self.performReloc(loop_reloc);
6010}5841}
60115842
6012fn genSetAvxReg(self: *Self, ty: Type, reg: AvxRegister, mcv: MCValue) InnerError!void {
6013 switch (mcv) {
6014 .dead => unreachable,
6015 .register_overflow_unsigned,
6016 .register_overflow_signed,
6017 => unreachable,
6018 .stack_offset => |off| {
6019 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6020 return self.fail("stack offset too large", .{});
6021 }
6022
6023 switch (ty.zigTypeTag()) {
6024 .Float => {
6025 switch (ty.tag()) {
6026 .f32 => return self.fail("TODO genSetAvxReg from stack offset for f32", .{}),
6027 .f64 => {
6028 _ = try self.addInst(.{
6029 .tag = .mov_f64,
6030 .ops = (Mir.Ops(AvxRegister, Register){
6031 .reg1 = reg.to128(),
6032 .reg2 = .rbp,
6033 }).encode(),
6034 .data = .{ .imm = @bitCast(u32, -off) },
6035 });
6036 },
6037 else => return self.fail("TODO genSetAvxReg from stack offset for {}", .{ty.fmtDebug()}),
6038 }
6039 },
6040 else => return self.fail("TODO genSetAvxReg from stack offset for type {}", .{ty.fmtDebug()}),
6041 }
6042 },
6043 .avx_register => |src_reg| {
6044 switch (ty.zigTypeTag()) {
6045 .Float => {
6046 switch (ty.tag()) {
6047 .f32 => return self.fail("TODO genSetAvxReg from register for f32", .{}),
6048 .f64 => {
6049 _ = try self.addInst(.{
6050 .tag = .mov_f64,
6051 .ops = (Mir.Ops(AvxRegister, AvxRegister){
6052 .reg1 = reg.to128(),
6053 .reg2 = src_reg.to128(),
6054 .flags = 0b10,
6055 }).encode(),
6056 .data = undefined,
6057 });
6058 },
6059 else => return self.fail("TODO genSetAvxReg from register for {}", .{ty.fmtDebug()}),
6060 }
6061 },
6062 else => return self.fail("TODO genSetAvxReg from register for type {}", .{ty.fmtDebug()}),
6063 }
6064 },
6065 .memory => {
6066 switch (ty.zigTypeTag()) {
6067 .Float => {
6068 switch (ty.tag()) {
6069 .f32 => return self.fail("TODO genSetAvxReg from memory for f32", .{}),
6070 .f64 => {
6071 const base_reg = try self.register_manager.allocReg(null);
6072 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
6073 _ = try self.addInst(.{
6074 .tag = .mov_f64,
6075 .ops = (Mir.Ops(AvxRegister, Register){
6076 .reg1 = reg.to128(),
6077 .reg2 = base_reg.to64(),
6078 }).encode(),
6079 .data = .{ .imm = 0 },
6080 });
6081 },
6082 else => return self.fail("TODO genSetAvxReg from memory for {}", .{ty.fmtDebug()}),
6083 }
6084 },
6085 else => return self.fail("TODO genSetAvxReg from memory for type {}", .{ty.fmtDebug()}),
6086 }
6087 },
6088 else => |other| {
6089 return self.fail("TODO genSetAvxReg from {}", .{other});
6090 },
6091 }
6092}
6093
6094fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {5843fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
6095 const abi_size = @intCast(u32, ty.abiSize(self.target.*));5844 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
6096 switch (mcv) {5845 switch (mcv) {
...@@ -6098,17 +5847,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6098,17 +5847,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6098 .register_overflow_unsigned,5847 .register_overflow_unsigned,
6099 .register_overflow_signed,5848 .register_overflow_signed,
6100 => unreachable,5849 => unreachable,
6101 .avx_register => unreachable,
6102 .ptr_stack_offset => |off| {5850 .ptr_stack_offset => |off| {
6103 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {5851 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6104 return self.fail("stack offset too large", .{});5852 return self.fail("stack offset too large", .{});
6105 }5853 }
6106 _ = try self.addInst(.{5854 _ = try self.addInst(.{
6107 .tag = .lea,5855 .tag = .lea,
6108 .ops = (Mir.Ops(Register, Register){5856 .ops = Mir.Inst.Ops.encode(.{
6109 .reg1 = registerAlias(reg, abi_size),5857 .reg1 = registerAlias(reg, abi_size),
6110 .reg2 = .rbp,5858 .reg2 = .rbp,
6111 }).encode(),5859 }),
6112 .data = .{ .imm = @bitCast(u32, -off) },5860 .data = .{ .imm = @bitCast(u32, -off) },
6113 });5861 });
6114 },5862 },
...@@ -6145,10 +5893,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6145,10 +5893,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6145 };5893 };
6146 _ = try self.addInst(.{5894 _ = try self.addInst(.{
6147 .tag = tag,5895 .tag = tag,
6148 .ops = (Mir.Ops(Register, Register){5896 .ops = Mir.Inst.Ops.encode(.{
6149 .reg1 = reg.to8(),5897 .reg1 = reg.to8(),
6150 .flags = flags,5898 .flags = flags,
6151 }).encode(),5899 }),
6152 .data = undefined,5900 .data = undefined,
6153 });5901 });
6154 },5902 },
...@@ -6158,10 +5906,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6158,10 +5906,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6158 if (x == 0) {5906 if (x == 0) {
6159 _ = try self.addInst(.{5907 _ = try self.addInst(.{
6160 .tag = .xor,5908 .tag = .xor,
6161 .ops = (Mir.Ops(Register, Register){5909 .ops = Mir.Inst.Ops.encode(.{
6162 .reg1 = reg.to32(),5910 .reg1 = reg.to32(),
6163 .reg2 = reg.to32(),5911 .reg2 = reg.to32(),
6164 }).encode(),5912 }),
6165 .data = undefined,5913 .data = undefined,
6166 });5914 });
6167 return;5915 return;
...@@ -6170,9 +5918,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6170,9 +5918,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6170 // Next best case: if we set the lower four bytes, the upper four will be zeroed.5918 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
6171 _ = try self.addInst(.{5919 _ = try self.addInst(.{
6172 .tag = .mov,5920 .tag = .mov,
6173 .ops = (Mir.Ops(Register, Register){5921 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }),
6174 .reg1 = registerAlias(reg, abi_size),
6175 }).encode(),
6176 .data = .{ .imm = @truncate(u32, x) },5922 .data = .{ .imm = @truncate(u32, x) },
6177 });5923 });
6178 return;5924 return;
...@@ -6187,9 +5933,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6187,9 +5933,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6187 const payload = try self.addExtra(Mir.Imm64.encode(x));5933 const payload = try self.addExtra(Mir.Imm64.encode(x));
6188 _ = try self.addInst(.{5934 _ = try self.addInst(.{
6189 .tag = .movabs,5935 .tag = .movabs,
6190 .ops = (Mir.Ops(Register, Register){5936 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64() }),
6191 .reg1 = reg.to64(),
6192 }).encode(),
6193 .data = .{ .payload = payload },5937 .data = .{ .payload = payload },
6194 });5938 });
6195 },5939 },
...@@ -6198,40 +5942,60 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6198,40 +5942,60 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6198 if (src_reg.id() == reg.id())5942 if (src_reg.id() == reg.id())
6199 return;5943 return;
62005944
6201 if (ty.zigTypeTag() == .Int) blk: {5945 switch (ty.zigTypeTag()) {
6202 switch (ty.intInfo(self.target.*).signedness) {5946 .Int => switch (ty.intInfo(self.target.*).signedness) {
6203 .signed => {5947 .signed => {
6204 if (abi_size > 4) break :blk;5948 if (abi_size <= 4) {
6205 _ = try self.addInst(.{5949 _ = try self.addInst(.{
6206 .tag = .mov_sign_extend,5950 .tag = .mov_sign_extend,
6207 .ops = (Mir.Ops(Register, Register){5951 .ops = Mir.Inst.Ops.encode(.{
6208 .reg1 = reg.to64(),5952 .reg1 = reg.to64(),
6209 .reg2 = registerAlias(src_reg, abi_size),5953 .reg2 = registerAlias(src_reg, abi_size),
6210 }).encode(),5954 }),
6211 .data = undefined,5955 .data = undefined,
6212 });5956 });
5957 return;
5958 }
6213 },5959 },
6214 .unsigned => {5960 .unsigned => {
6215 if (abi_size > 2) break :blk;5961 if (abi_size <= 2) {
5962 _ = try self.addInst(.{
5963 .tag = .mov_zero_extend,
5964 .ops = Mir.Inst.Ops.encode(.{
5965 .reg1 = reg.to64(),
5966 .reg2 = registerAlias(src_reg, abi_size),
5967 }),
5968 .data = undefined,
5969 });
5970 return;
5971 }
5972 },
5973 },
5974 .Float => switch (ty.tag()) {
5975 .f32 => return self.fail("TODO genSetReg from register for f32", .{}),
5976 .f64 => {
6216 _ = try self.addInst(.{5977 _ = try self.addInst(.{
6217 .tag = .mov_zero_extend,5978 .tag = .mov_f64,
6218 .ops = (Mir.Ops(Register, Register){5979 .ops = Mir.Inst.Ops.encode(.{
6219 .reg1 = reg.to64(),5980 .reg1 = reg.to128(),
6220 .reg2 = registerAlias(src_reg, abi_size),5981 .reg2 = src_reg.to128(),
6221 }).encode(),5982 .flags = 0b10,
5983 }),
6222 .data = undefined,5984 .data = undefined,
6223 });5985 });
5986 return;
6224 },5987 },
6225 }5988 else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),
6226 return;5989 },
5990 else => {},
6227 }5991 }
62285992
6229 _ = try self.addInst(.{5993 _ = try self.addInst(.{
6230 .tag = .mov,5994 .tag = .mov,
6231 .ops = (Mir.Ops(Register, Register){5995 .ops = Mir.Inst.Ops.encode(.{
6232 .reg1 = registerAlias(reg, abi_size),5996 .reg1 = registerAlias(reg, abi_size),
6233 .reg2 = registerAlias(src_reg, abi_size),5997 .reg2 = registerAlias(src_reg, abi_size),
6234 }).encode(),5998 }),
6235 .data = undefined,5999 .data = undefined,
6236 });6000 });
6237 },6001 },
...@@ -6241,107 +6005,148 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6241,107 +6005,148 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6241 try self.loadMemPtrIntoRegister(reg, Type.usize, mcv);6005 try self.loadMemPtrIntoRegister(reg, Type.usize, mcv);
6242 _ = try self.addInst(.{6006 _ = try self.addInst(.{
6243 .tag = .mov,6007 .tag = .mov,
6244 .ops = (Mir.Ops(Register, Register){6008 .ops = Mir.Inst.Ops.encode(.{
6245 .reg1 = registerAlias(reg, abi_size),6009 .reg1 = registerAlias(reg, abi_size),
6246 .reg2 = reg.to64(),6010 .reg2 = reg.to64(),
6247 .flags = 0b01,6011 .flags = 0b01,
6248 }).encode(),6012 }),
6249 .data = .{ .imm = 0 },6013 .data = .{ .imm = 0 },
6250 });6014 });
6251 },6015 },
6252 .memory => |x| {6016 .memory => |x| switch (ty.zigTypeTag()) {
6253 if (x <= math.maxInt(i32)) {6017 .Float => {
6254 // mov reg, [ds:imm32]6018 switch (ty.tag()) {
6255 _ = try self.addInst(.{6019 .f32 => return self.fail("TODO genSetReg from memory for f32", .{}),
6256 .tag = .mov,6020 .f64 => {
6257 .ops = (Mir.Ops(Register, Register){6021 const base_reg = try self.register_manager.allocReg(null);
6258 .reg1 = registerAlias(reg, abi_size),6022 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
6259 .flags = 0b01,6023 _ = try self.addInst(.{
6260 }).encode(),6024 .tag = .mov_f64,
6261 .data = .{ .imm = @truncate(u32, x) },6025 .ops = Mir.Inst.Ops.encode(.{
6262 });6026 .reg1 = reg.to128(),
6263 } else {6027 .reg2 = base_reg.to64(),
6264 // If this is RAX, we can use a direct load.6028 }),
6265 // Otherwise, we need to load the address, then indirectly load the value.6029 .data = .{ .imm = 0 },
6266 if (reg.id() == 0) {6030 });
6267 // movabs rax, ds:moffs646031 },
6268 const payload = try self.addExtra(Mir.Imm64.encode(x));6032 else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}),
6269 _ = try self.addInst(.{6033 }
6270 .tag = .movabs,6034 },
6271 .ops = (Mir.Ops(Register, Register){6035 else => {
6272 .reg1 = .rax,6036 if (x <= math.maxInt(i32)) {
6273 .flags = 0b01, // imm64 will become moffs646037 // mov reg, [ds:imm32]
6274 }).encode(),
6275 .data = .{ .payload = payload },
6276 });
6277 } else {
6278 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
6279 try self.genSetReg(ty, reg, MCValue{ .immediate = x });
6280
6281 // mov reg, [reg + 0x0]
6282 _ = try self.addInst(.{6038 _ = try self.addInst(.{
6283 .tag = .mov,6039 .tag = .mov,
6284 .ops = (Mir.Ops(Register, Register){6040 .ops = Mir.Inst.Ops.encode(.{
6285 .reg1 = registerAlias(reg, abi_size),6041 .reg1 = registerAlias(reg, abi_size),
6286 .reg2 = reg.to64(),
6287 .flags = 0b01,6042 .flags = 0b01,
6288 }).encode(),6043 }),
6289 .data = .{ .imm = 0 },6044 .data = .{ .imm = @truncate(u32, x) },
6290 });6045 });
6046 } else {
6047 // If this is RAX, we can use a direct load.
6048 // Otherwise, we need to load the address, then indirectly load the value.
6049 if (reg.id() == 0) {
6050 // movabs rax, ds:moffs64
6051 const payload = try self.addExtra(Mir.Imm64.encode(x));
6052 _ = try self.addInst(.{
6053 .tag = .movabs,
6054 .ops = Mir.Inst.Ops.encode(.{
6055 .reg1 = .rax,
6056 .flags = 0b01, // imm64 will become moffs64
6057 }),
6058 .data = .{ .payload = payload },
6059 });
6060 } else {
6061 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
6062 try self.genSetReg(ty, reg, MCValue{ .immediate = x });
6063
6064 // mov reg, [reg + 0x0]
6065 _ = try self.addInst(.{
6066 .tag = .mov,
6067 .ops = Mir.Inst.Ops.encode(.{
6068 .reg1 = registerAlias(reg, abi_size),
6069 .reg2 = reg.to64(),
6070 .flags = 0b01,
6071 }),
6072 .data = .{ .imm = 0 },
6073 });
6074 }
6291 }6075 }
6292 }6076 },
6293 },6077 },
6294 .stack_offset => |off| {6078 .stack_offset => |off| {
6295 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {6079 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6296 return self.fail("stack offset too large", .{});6080 return self.fail("stack offset too large", .{});
6297 }6081 }
62986082
6299 if (ty.zigTypeTag() == .Int) blk: {6083 switch (ty.zigTypeTag()) {
6300 switch (ty.intInfo(self.target.*).signedness) {6084 .Int => switch (ty.intInfo(self.target.*).signedness) {
6301 .signed => {6085 .signed => {
6302 const flags: u2 = switch (abi_size) {6086 if (abi_size <= 4) {
6303 1 => 0b01,6087 const flags: u2 = switch (abi_size) {
6304 2 => 0b10,6088 1 => 0b01,
6305 4 => 0b11,6089 2 => 0b10,
6306 else => break :blk,6090 4 => 0b11,
6307 };6091 else => unreachable,
6308 _ = try self.addInst(.{6092 };
6309 .tag = .mov_sign_extend,6093 _ = try self.addInst(.{
6310 .ops = (Mir.Ops(Register, Register){6094 .tag = .mov_sign_extend,
6311 .reg1 = reg.to64(),6095 .ops = Mir.Inst.Ops.encode(.{
6312 .reg2 = .rbp,6096 .reg1 = reg.to64(),
6313 .flags = flags,6097 .reg2 = .rbp,
6314 }).encode(),6098 .flags = flags,
6315 .data = .{ .imm = @bitCast(u32, -off) },6099 }),
6316 });6100 .data = .{ .imm = @bitCast(u32, -off) },
6101 });
6102 return;
6103 }
6317 },6104 },
6318 .unsigned => {6105 .unsigned => {
6319 const flags: u2 = switch (abi_size) {6106 if (abi_size <= 2) {
6320 1 => 0b01,6107 const flags: u2 = switch (abi_size) {
6321 2 => 0b10,6108 1 => 0b01,
6322 else => break :blk,6109 2 => 0b10,
6323 };6110 else => unreachable,
6111 };
6112 _ = try self.addInst(.{
6113 .tag = .mov_zero_extend,
6114 .ops = Mir.Inst.Ops.encode(.{
6115 .reg1 = reg.to64(),
6116 .reg2 = .rbp,
6117 .flags = flags,
6118 }),
6119 .data = .{ .imm = @bitCast(u32, -off) },
6120 });
6121 return;
6122 }
6123 },
6124 },
6125 .Float => switch (ty.tag()) {
6126 .f32 => return self.fail("TODO genSetReg from stack offset for f32", .{}),
6127 .f64 => {
6324 _ = try self.addInst(.{6128 _ = try self.addInst(.{
6325 .tag = .mov_zero_extend,6129 .tag = .mov_f64,
6326 .ops = (Mir.Ops(Register, Register){6130 .ops = Mir.Inst.Ops.encode(.{
6327 .reg1 = reg.to64(),6131 .reg1 = reg.to128(),
6328 .reg2 = .rbp,6132 .reg2 = .rbp,
6329 .flags = flags,6133 }),
6330 }).encode(),
6331 .data = .{ .imm = @bitCast(u32, -off) },6134 .data = .{ .imm = @bitCast(u32, -off) },
6332 });6135 });
6136 return;
6333 },6137 },
6334 }6138 else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}),
6335 return;6139 },
6140 else => {},
6336 }6141 }
63376142
6338 _ = try self.addInst(.{6143 _ = try self.addInst(.{
6339 .tag = .mov,6144 .tag = .mov,
6340 .ops = (Mir.Ops(Register, Register){6145 .ops = Mir.Inst.Ops.encode(.{
6341 .reg1 = registerAlias(reg, abi_size),6146 .reg1 = registerAlias(reg, abi_size),
6342 .reg2 = .rbp,6147 .reg2 = .rbp,
6343 .flags = 0b01,6148 .flags = 0b01,
6344 }).encode(),6149 }),
6345 .data = .{ .imm = @bitCast(u32, -off) },6150 .data = .{ .imm = @bitCast(u32, -off) },
6346 });6151 });
6347 },6152 },
...@@ -6408,14 +6213,14 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -6408,14 +6213,14 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
6408 };6213 };
6409 _ = try self.addInst(.{6214 _ = try self.addInst(.{
6410 .tag = .fld,6215 .tag = .fld,
6411 .ops = (Mir.Ops(Register, Register){6216 .ops = Mir.Inst.Ops.encode(.{
6217 .reg1 = .rbp,
6412 .flags = switch (src_ty.abiSize(self.target.*)) {6218 .flags = switch (src_ty.abiSize(self.target.*)) {
6413 4 => 0b01,6219 4 => 0b01,
6414 8 => 0b10,6220 8 => 0b10,
6415 else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),6221 else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),
6416 },6222 },
6417 .reg1 = .rbp,6223 }),
6418 }).encode(),
6419 .data = .{ .imm = @bitCast(u32, -stack_offset) },6224 .data = .{ .imm = @bitCast(u32, -stack_offset) },
6420 });6225 });
64216226
...@@ -6423,15 +6228,15 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -6423,15 +6228,15 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
6423 const stack_dst = try self.allocRegOrMem(inst, false);6228 const stack_dst = try self.allocRegOrMem(inst, false);
6424 _ = try self.addInst(.{6229 _ = try self.addInst(.{
6425 .tag = .fisttp,6230 .tag = .fisttp,
6426 .ops = (Mir.Ops(Register, Register){6231 .ops = Mir.Inst.Ops.encode(.{
6232 .reg1 = .rbp,
6427 .flags = switch (dst_ty.abiSize(self.target.*)) {6233 .flags = switch (dst_ty.abiSize(self.target.*)) {
6428 1...2 => 0b00,6234 1...2 => 0b00,
6429 3...4 => 0b01,6235 3...4 => 0b01,
6430 5...8 => 0b10,6236 5...8 => 0b10,
6431 else => |size| return self.fail("TODO convert float with abiSize={}", .{size}),6237 else => |size| return self.fail("TODO convert float with abiSize={}", .{size}),
6432 },6238 },
6433 .reg1 = .rbp,6239 }),
6434 }).encode(),
6435 .data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) },6240 .data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) },
6436 });6241 });
64376242
...@@ -6527,11 +6332,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -6527,11 +6332,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6527 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);6332 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
6528 _ = try self.addInst(.{6333 _ = try self.addInst(.{
6529 .tag = .mov,6334 .tag = .mov,
6530 .ops = (Mir.Ops(Register, Register){6335 .ops = Mir.Inst.Ops.encode(.{
6531 .reg1 = reg,6336 .reg1 = reg,
6532 .reg2 = reg,6337 .reg2 = reg,
6533 .flags = 0b01,6338 .flags = 0b01,
6534 }).encode(),6339 }),
6535 .data = .{ .imm = 0 },6340 .data = .{ .imm = 0 },
6536 });6341 });
6537 break :blk MCValue{ .register = reg };6342 break :blk MCValue{ .register = reg };
...@@ -7095,22 +6900,11 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -7095,22 +6900,11 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
7095 return reg.to32();6900 return reg.to32();
7096 } else if (size_bytes <= 8) {6901 } else if (size_bytes <= 8) {
7097 return reg.to64();6902 return reg.to64();
7098 } else {
7099 unreachable;
7100 }
7101}
7102
7103/// Returns AVX register wide enough to hold at least `size_bytes`.
7104fn avxRegisterAlias(reg: AvxRegister, size_bytes: u32) AvxRegister {
7105 if (size_bytes == 0) {
7106 unreachable; // should be comptime known
7107 } else if (size_bytes <= 16) {6903 } else if (size_bytes <= 16) {
7108 return reg.to128();6904 return reg.to128();
7109 } else if (size_bytes <= 32) {6905 } else if (size_bytes <= 32) {
7110 return reg.to256();6906 return reg.to256();
7111 } else {6907 } else unreachable;
7112 unreachable;
7113 }
7114}6908}
71156909
7116/// Truncates the value in the register in place.6910/// Truncates the value in the register in place.
src/arch/x86_64/Emit.zig+383-389
...@@ -25,9 +25,8 @@ const MCValue = @import("CodeGen.zig").MCValue;...@@ -25,9 +25,8 @@ const MCValue = @import("CodeGen.zig").MCValue;
25const Mir = @import("Mir.zig");25const Mir = @import("Mir.zig");
26const Module = @import("../../Module.zig");26const Module = @import("../../Module.zig");
27const Instruction = bits.Instruction;27const Instruction = bits.Instruction;
28const GpRegister = bits.Register;
29const AvxRegister = bits.AvxRegister;
30const Type = @import("../../type.zig").Type;28const Type = @import("../../type.zig").Type;
29const Register = bits.Register;
3130
32mir: Mir,31mir: Mir,
33bin_file: *link.File,32bin_file: *link.File,
...@@ -238,7 +237,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void {...@@ -238,7 +237,7 @@ fn fixupRelocs(emit: *Emit) InnerError!void {
238fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {237fn mirInterrupt(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
239 const tag = emit.mir.instructions.items(.tag)[inst];238 const tag = emit.mir.instructions.items(.tag)[inst];
240 assert(tag == .interrupt);239 assert(tag == .interrupt);
241 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);240 const ops = emit.mir.instructions.items(.ops)[inst].decode();
242 switch (ops.flags) {241 switch (ops.flags) {
243 0b00 => return lowerToZoEnc(.int3, emit.code),242 0b00 => return lowerToZoEnc(.int3, emit.code),
244 else => return emit.fail("TODO handle variant 0b{b} of interrupt instruction", .{ops.flags}),243 else => return emit.fail("TODO handle variant 0b{b} of interrupt instruction", .{ops.flags}),
...@@ -254,11 +253,11 @@ fn mirSyscall(emit: *Emit) InnerError!void {...@@ -254,11 +253,11 @@ fn mirSyscall(emit: *Emit) InnerError!void {
254}253}
255254
256fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {255fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
257 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);256 const ops = emit.mir.instructions.items(.ops)[inst].decode();
258 switch (ops.flags) {257 switch (ops.flags) {
259 0b00 => {258 0b00 => {
260 // PUSH/POP reg259 // PUSH/POP reg
261 return lowerToOEnc(tag, Register.reg(ops.reg1), emit.code);260 return lowerToOEnc(tag, ops.reg1, emit.code);
262 },261 },
263 0b01 => {262 0b01 => {
264 // PUSH/POP r/m64263 // PUSH/POP r/m64
...@@ -283,7 +282,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -283,7 +282,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
283}282}
284283
285fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {284fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
286 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);285 const ops = emit.mir.instructions.items(.ops)[inst].decode();
287 const payload = emit.mir.instructions.items(.data)[inst].payload;286 const payload = emit.mir.instructions.items(.data)[inst].payload;
288 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;287 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;
289 const regs = data.regs;288 const regs = data.regs;
...@@ -294,9 +293,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -294,9 +293,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
294 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{293 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
295 .disp = @bitCast(u32, -@intCast(i32, disp)),294 .disp = @bitCast(u32, -@intCast(i32, disp)),
296 .base = ops.reg1,295 .base = ops.reg1,
297 }), Register.reg(reg.to64()), emit.code);296 }), reg.to64(), emit.code);
298 } else {297 } else {
299 try lowerToRmEnc(.mov, Register.reg(reg.to64()), RegisterOrMemory.mem(.qword_ptr, .{298 try lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{
300 .disp = @bitCast(u32, -@intCast(i32, disp)),299 .disp = @bitCast(u32, -@intCast(i32, disp)),
301 .base = ops.reg1,300 .base = ops.reg1,
302 }), emit.code);301 }), emit.code);
...@@ -306,7 +305,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -306,7 +305,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
306}305}
307306
308fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {307fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
309 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);308 const ops = emit.mir.instructions.items(.ops)[inst].decode();
310 switch (ops.flags) {309 switch (ops.flags) {
311 0b00 => {310 0b00 => {
312 const target = emit.mir.instructions.items(.data)[inst].inst;311 const target = emit.mir.instructions.items(.data)[inst].inst;
...@@ -335,7 +334,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -335,7 +334,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
335 0b10 => {334 0b10 => {
336 // JMP/CALL r/m64335 // JMP/CALL r/m64
337 const imm = emit.mir.instructions.items(.data)[inst].imm;336 const imm = emit.mir.instructions.items(.data)[inst].imm;
338 return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{337 return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
339 .disp = imm,338 .disp = imm,
340 .base = ops.reg1,339 .base = ops.reg1,
341 }), emit.code);340 }), emit.code);
...@@ -345,7 +344,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -345,7 +344,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
345}344}
346345
347fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {346fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
348 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);347 const ops = emit.mir.instructions.items(.ops)[inst].decode();
349 const target = emit.mir.instructions.items(.data)[inst].inst;348 const target = emit.mir.instructions.items(.data)[inst].inst;
350 const tag = switch (mir_tag) {349 const tag = switch (mir_tag) {
351 .cond_jmp_greater_less => switch (ops.flags) {350 .cond_jmp_greater_less => switch (ops.flags) {
...@@ -377,7 +376,7 @@ fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerErr...@@ -377,7 +376,7 @@ fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerErr
377}376}
378377
379fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {378fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
380 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);379 const ops = emit.mir.instructions.items(.ops)[inst].decode();
381 const tag = switch (mir_tag) {380 const tag = switch (mir_tag) {
382 .cond_set_byte_greater_less => switch (ops.flags) {381 .cond_set_byte_greater_less => switch (ops.flags) {
383 0b00 => Tag.setge,382 0b00 => Tag.setge,
...@@ -407,9 +406,9 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne...@@ -407,9 +406,9 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne
407}406}
408407
409fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {408fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
410 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);409 const ops = emit.mir.instructions.items(.ops)[inst].decode();
411 if (ops.flags == 0b00) {410 if (ops.flags == 0b00) {
412 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);411 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
413 }412 }
414 const imm = emit.mir.instructions.items(.data)[inst].imm;413 const imm = emit.mir.instructions.items(.data)[inst].imm;
415 const ptr_size: Memory.PtrSize = switch (ops.flags) {414 const ptr_size: Memory.PtrSize = switch (ops.flags) {
...@@ -418,7 +417,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -418,7 +417,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
418 0b10 => .dword_ptr,417 0b10 => .dword_ptr,
419 0b11 => .qword_ptr,418 0b11 => .qword_ptr,
420 };419 };
421 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(ptr_size, .{420 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ptr_size, .{
422 .disp = imm,421 .disp = imm,
423 .base = ops.reg2,422 .base = ops.reg2,
424 }), emit.code);423 }), emit.code);
...@@ -427,7 +426,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -427,7 +426,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
427fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {426fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
428 const tag = emit.mir.instructions.items(.tag)[inst];427 const tag = emit.mir.instructions.items(.tag)[inst];
429 assert(tag == .@"test");428 assert(tag == .@"test");
430 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);429 const ops = emit.mir.instructions.items(.ops)[inst].decode();
431 switch (ops.flags) {430 switch (ops.flags) {
432 0b00 => {431 0b00 => {
433 if (ops.reg2 == .none) {432 if (ops.reg2 == .none) {
...@@ -442,12 +441,7 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -442,12 +441,7 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
442 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code);441 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code);
443 }442 }
444 // TEST r/m64, r64443 // TEST r/m64, r64
445 return lowerToMrEnc(444 return lowerToMrEnc(.@"test", RegisterOrMemory.reg(ops.reg1), ops.reg2, emit.code);
446 .@"test",
447 RegisterOrMemory.reg(ops.reg1),
448 Register.reg(ops.reg2),
449 emit.code,
450 );
451 },445 },
452 else => return emit.fail("TODO more TEST alternatives", .{}),446 else => return emit.fail("TODO more TEST alternatives", .{}),
453 }447 }
...@@ -456,7 +450,7 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -456,7 +450,7 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
456fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {450fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
457 const tag = emit.mir.instructions.items(.tag)[inst];451 const tag = emit.mir.instructions.items(.tag)[inst];
458 assert(tag == .ret);452 assert(tag == .ret);
459 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);453 const ops = emit.mir.instructions.items(.ops)[inst].decode();
460 switch (ops.flags) {454 switch (ops.flags) {
461 0b00 => {455 0b00 => {
462 // RETF imm16456 // RETF imm16
...@@ -480,7 +474,7 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -480,7 +474,7 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
480}474}
481475
482fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {476fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
483 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);477 const ops = emit.mir.instructions.items(.ops)[inst].decode();
484 switch (ops.flags) {478 switch (ops.flags) {
485 0b00 => {479 0b00 => {
486 if (ops.reg2 == .none) {480 if (ops.reg2 == .none) {
...@@ -491,14 +485,14 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -491,14 +485,14 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
491 }485 }
492 // mov reg1, reg2486 // mov reg1, reg2
493 // RM487 // RM
494 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);488 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
495 },489 },
496 0b01 => {490 0b01 => {
497 // mov reg1, [reg2 + imm32]491 // mov reg1, [reg2 + imm32]
498 // RM492 // RM
499 const imm = emit.mir.instructions.items(.data)[inst].imm;493 const imm = emit.mir.instructions.items(.data)[inst].imm;
500 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;494 const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
501 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{495 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
502 .disp = imm,496 .disp = imm,
503 .base = src_reg,497 .base = src_reg,
504 }), emit.code);498 }), emit.code);
...@@ -510,10 +504,10 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -510,10 +504,10 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
510 // mov [reg1 + imm32], reg2504 // mov [reg1 + imm32], reg2
511 // MR505 // MR
512 const imm = emit.mir.instructions.items(.data)[inst].imm;506 const imm = emit.mir.instructions.items(.data)[inst].imm;
513 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{507 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg2.size()), .{
514 .disp = imm,508 .disp = imm,
515 .base = ops.reg1,509 .base = ops.reg1,
516 }), Register.reg(ops.reg2), emit.code);510 }), ops.reg2, emit.code);
517 },511 },
518 0b11 => {512 0b11 => {
519 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});513 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
...@@ -522,7 +516,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -522,7 +516,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
522}516}
523517
524fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {518fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
525 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);519 const ops = emit.mir.instructions.items(.ops)[inst].decode();
526 assert(ops.reg2 == .none);520 assert(ops.reg2 == .none);
527 const payload = emit.mir.instructions.items(.data)[inst].payload;521 const payload = emit.mir.instructions.items(.data)[inst].payload;
528 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;522 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
...@@ -539,19 +533,14 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -539,19 +533,14 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
539}533}
540534
541inline fn setRexWRegister(reg: Register) bool {535inline fn setRexWRegister(reg: Register) bool {
542 switch (reg) {536 if (reg.size() == 64) return true;
543 .avx_register => return false,537 return switch (reg) {
544 .register => |r| {538 .ah, .ch, .dh, .bh => true,
545 if (r.size() == 64) return true;539 else => false,
546 return switch (r) {540 };
547 .ah, .bh, .ch, .dh => true,
548 else => false,
549 };
550 },
551 }
552}541}
553542
554inline fn immOpSize(u_imm: u32) u8 {543inline fn immOpSize(u_imm: u32) u6 {
555 const imm = @bitCast(i32, u_imm);544 const imm = @bitCast(i32, u_imm);
556 if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {545 if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
557 return 8;546 return 8;
...@@ -563,7 +552,7 @@ inline fn immOpSize(u_imm: u32) u8 {...@@ -563,7 +552,7 @@ inline fn immOpSize(u_imm: u32) u8 {
563}552}
564553
565fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {554fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
566 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);555 const ops = emit.mir.instructions.items(.ops)[inst].decode();
567 const scale = ops.flags;556 const scale = ops.flags;
568 const imm = emit.mir.instructions.items(.data)[inst].imm;557 const imm = emit.mir.instructions.items(.data)[inst].imm;
569 // OP reg1, [reg2 + scale*rcx + imm32]558 // OP reg1, [reg2 + scale*rcx + imm32]
...@@ -571,7 +560,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -571,7 +560,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
571 .scale = scale,560 .scale = scale,
572 .index = .rcx,561 .index = .rcx,
573 };562 };
574 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{563 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
575 .disp = imm,564 .disp = imm,
576 .base = ops.reg2,565 .base = ops.reg2,
577 .scale_index = scale_index,566 .scale_index = scale_index,
...@@ -579,7 +568,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -579,7 +568,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
579}568}
580569
581fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {570fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
582 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);571 const ops = emit.mir.instructions.items(.ops)[inst].decode();
583 const scale = ops.flags;572 const scale = ops.flags;
584 const imm = emit.mir.instructions.items(.data)[inst].imm;573 const imm = emit.mir.instructions.items(.data)[inst].imm;
585 const scale_index = ScaleIndex{574 const scale_index = ScaleIndex{
...@@ -595,15 +584,15 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -595,15 +584,15 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
595 }), imm, emit.code);584 }), imm, emit.code);
596 }585 }
597 // OP [reg1 + scale*rax + imm32], reg2586 // OP [reg1 + scale*rax + imm32], reg2
598 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{587 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg2.size()), .{
599 .disp = imm,588 .disp = imm,
600 .base = ops.reg1,589 .base = ops.reg1,
601 .scale_index = scale_index,590 .scale_index = scale_index,
602 }), Register.reg(ops.reg2), emit.code);591 }), ops.reg2, emit.code);
603}592}
604593
605fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {594fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
606 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);595 const ops = emit.mir.instructions.items(.ops)[inst].decode();
607 const scale = ops.flags;596 const scale = ops.flags;
608 const payload = emit.mir.instructions.items(.data)[inst].payload;597 const payload = emit.mir.instructions.items(.data)[inst].payload;
609 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;598 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
...@@ -620,7 +609,7 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -620,7 +609,7 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
620}609}
621610
622fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {611fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
623 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);612 const ops = emit.mir.instructions.items(.ops)[inst].decode();
624 assert(ops.reg2 == .none);613 assert(ops.reg2 == .none);
625 const payload = emit.mir.instructions.items(.data)[inst].payload;614 const payload = emit.mir.instructions.items(.data)[inst].payload;
626 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;615 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
...@@ -645,27 +634,27 @@ fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!v...@@ -645,27 +634,27 @@ fn mirArithMemIndexImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!v
645fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {634fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
646 const mir_tag = emit.mir.instructions.items(.tag)[inst];635 const mir_tag = emit.mir.instructions.items(.tag)[inst];
647 assert(mir_tag == .mov_sign_extend);636 assert(mir_tag == .mov_sign_extend);
648 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);637 const ops = emit.mir.instructions.items(.ops)[inst].decode();
649 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;638 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;
650 switch (ops.flags) {639 switch (ops.flags) {
651 0b00 => {640 0b00 => {
652 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;641 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;
653 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);642 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
654 },643 },
655 0b01 => {644 0b01 => {
656 return lowerToRmEnc(.movsx, Register.reg(ops.reg1), RegisterOrMemory.mem(.byte_ptr, .{645 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{
657 .disp = imm,646 .disp = imm,
658 .base = ops.reg2,647 .base = ops.reg2,
659 }), emit.code);648 }), emit.code);
660 },649 },
661 0b10 => {650 0b10 => {
662 return lowerToRmEnc(.movsx, Register.reg(ops.reg1), RegisterOrMemory.mem(.word_ptr, .{651 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{
663 .disp = imm,652 .disp = imm,
664 .base = ops.reg2,653 .base = ops.reg2,
665 }), emit.code);654 }), emit.code);
666 },655 },
667 0b11 => {656 0b11 => {
668 return lowerToRmEnc(.movsxd, Register.reg(ops.reg1), RegisterOrMemory.mem(.dword_ptr, .{657 return lowerToRmEnc(.movsxd, ops.reg1, RegisterOrMemory.mem(.dword_ptr, .{
669 .disp = imm,658 .disp = imm,
670 .base = ops.reg2,659 .base = ops.reg2,
671 }), emit.code);660 }), emit.code);
...@@ -676,20 +665,20 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -676,20 +665,20 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
676fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {665fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
677 const mir_tag = emit.mir.instructions.items(.tag)[inst];666 const mir_tag = emit.mir.instructions.items(.tag)[inst];
678 assert(mir_tag == .mov_zero_extend);667 assert(mir_tag == .mov_zero_extend);
679 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);668 const ops = emit.mir.instructions.items(.ops)[inst].decode();
680 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;669 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;
681 switch (ops.flags) {670 switch (ops.flags) {
682 0b00 => {671 0b00 => {
683 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);672 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
684 },673 },
685 0b01 => {674 0b01 => {
686 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.mem(.byte_ptr, .{675 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{
687 .disp = imm,676 .disp = imm,
688 .base = ops.reg2,677 .base = ops.reg2,
689 }), emit.code);678 }), emit.code);
690 },679 },
691 0b10 => {680 0b10 => {
692 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.mem(.word_ptr, .{681 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{
693 .disp = imm,682 .disp = imm,
694 .base = ops.reg2,683 .base = ops.reg2,
695 }), emit.code);684 }), emit.code);
...@@ -703,31 +692,46 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -703,31 +692,46 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
703fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {692fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
704 const tag = emit.mir.instructions.items(.tag)[inst];693 const tag = emit.mir.instructions.items(.tag)[inst];
705 assert(tag == .movabs);694 assert(tag == .movabs);
706 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);695 const ops = emit.mir.instructions.items(.ops)[inst].decode();
707 const imm: u64 = if (ops.reg1.size() == 64) blk: {696 switch (ops.flags) {
708 const payload = emit.mir.instructions.items(.data)[inst].payload;697 0b00 => {
709 const imm = emit.mir.extraData(Mir.Imm64, payload).data;698 const imm: u64 = if (ops.reg1.size() == 64) blk: {
710 break :blk imm.decode();699 const payload = emit.mir.instructions.items(.data)[inst].payload;
711 } else emit.mir.instructions.items(.data)[inst].imm;700 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
712 if (ops.flags == 0b00) {701 break :blk imm.decode();
713 // movabs reg, imm64702 } else emit.mir.instructions.items(.data)[inst].imm;
714 // OI703 // movabs reg, imm64
715 return lowerToOiEnc(.mov, Register.reg(ops.reg1), imm, emit.code);704 // OI
716 }705 return lowerToOiEnc(.mov, ops.reg1, imm, emit.code);
717 if (ops.reg1 == .none) {706 },
718 // movabs moffs64, rax707 0b01 => {
719 // TD708 if (ops.reg1 == .none) {
720 return lowerToTdEnc(.mov, imm, Register.reg(ops.reg2), emit.code);709 const imm: u64 = if (ops.reg2.size() == 64) blk: {
710 const payload = emit.mir.instructions.items(.data)[inst].payload;
711 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
712 break :blk imm.decode();
713 } else emit.mir.instructions.items(.data)[inst].imm;
714 // movabs moffs64, rax
715 // TD
716 return lowerToTdEnc(.mov, imm, ops.reg2, emit.code);
717 }
718 const imm: u64 = if (ops.reg1.size() == 64) blk: {
719 const payload = emit.mir.instructions.items(.data)[inst].payload;
720 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
721 break :blk imm.decode();
722 } else emit.mir.instructions.items(.data)[inst].imm;
723 // movabs rax, moffs64
724 // FD
725 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
726 },
727 else => return emit.fail("TODO unused variant: movabs 0b{b}", .{ops.flags}),
721 }728 }
722 // movabs rax, moffs64
723 // FD
724 return lowerToFdEnc(.mov, Register.reg(ops.reg1), imm, emit.code);
725}729}
726730
727fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {731fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
728 const tag = emit.mir.instructions.items(.tag)[inst];732 const tag = emit.mir.instructions.items(.tag)[inst];
729 assert(tag == .fisttp);733 assert(tag == .fisttp);
730 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);734 const ops = emit.mir.instructions.items(.ops)[inst].decode();
731735
732 // the selecting between operand sizes for this particular `fisttp` instruction736 // the selecting between operand sizes for this particular `fisttp` instruction
733 // is done via opcode instead of the usual prefixes.737 // is done via opcode instead of the usual prefixes.
...@@ -749,7 +753,7 @@ fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -749,7 +753,7 @@ fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
749fn mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {753fn mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
750 const tag = emit.mir.instructions.items(.tag)[inst];754 const tag = emit.mir.instructions.items(.tag)[inst];
751 assert(tag == .fld);755 assert(tag == .fld);
752 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);756 const ops = emit.mir.instructions.items(.ops)[inst].decode();
753757
754 // the selecting between operand sizes for this particular `fisttp` instruction758 // the selecting between operand sizes for this particular `fisttp` instruction
755 // is done via opcode instead of the usual prefixes.759 // is done via opcode instead of the usual prefixes.
...@@ -768,7 +772,7 @@ fn mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -768,7 +772,7 @@ fn mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
768}772}
769773
770fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {774fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
771 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);775 const ops = emit.mir.instructions.items(.ops)[inst].decode();
772 switch (ops.flags) {776 switch (ops.flags) {
773 0b00 => {777 0b00 => {
774 // sal reg1, 1778 // sal reg1, 1
...@@ -793,12 +797,11 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -793,12 +797,11 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
793}797}
794798
795fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {799fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
796 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);800 const ops = emit.mir.instructions.items(.ops)[inst].decode();
797 if (ops.reg1 != .none) {801 if (ops.reg1 != .none) {
798 assert(ops.reg2 == .none);802 assert(ops.reg2 == .none);
799 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);803 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
800 }804 }
801 assert(ops.reg1 == .none);
802 assert(ops.reg2 != .none);805 assert(ops.reg2 != .none);
803 const imm = emit.mir.instructions.items(.data)[inst].imm;806 const imm = emit.mir.instructions.items(.data)[inst].imm;
804 const ptr_size: Memory.PtrSize = switch (ops.flags) {807 const ptr_size: Memory.PtrSize = switch (ops.flags) {
...@@ -816,27 +819,27 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -816,27 +819,27 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
816fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {819fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
817 const tag = emit.mir.instructions.items(.tag)[inst];820 const tag = emit.mir.instructions.items(.tag)[inst];
818 assert(tag == .imul_complex);821 assert(tag == .imul_complex);
819 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);822 const ops = emit.mir.instructions.items(.ops)[inst].decode();
820 switch (ops.flags) {823 switch (ops.flags) {
821 0b00 => {824 0b00 => {
822 return lowerToRmEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);825 return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
823 },826 },
824 0b01 => {827 0b01 => {
825 const imm = emit.mir.instructions.items(.data)[inst].imm;828 const imm = emit.mir.instructions.items(.data)[inst].imm;
826 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;829 const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
827 return lowerToRmEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.mem(.qword_ptr, .{830 return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{
828 .disp = imm,831 .disp = imm,
829 .base = src_reg,832 .base = src_reg,
830 }), emit.code);833 }), emit.code);
831 },834 },
832 0b10 => {835 0b10 => {
833 const imm = emit.mir.instructions.items(.data)[inst].imm;836 const imm = emit.mir.instructions.items(.data)[inst].imm;
834 return lowerToRmiEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), imm, emit.code);837 return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, emit.code);
835 },838 },
836 0b11 => {839 0b11 => {
837 const payload = emit.mir.instructions.items(.data)[inst].payload;840 const payload = emit.mir.instructions.items(.data)[inst].payload;
838 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;841 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
839 return lowerToRmiEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.mem(.qword_ptr, .{842 return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{
840 .disp = imm_pair.dest_off,843 .disp = imm_pair.dest_off,
841 .base = ops.reg2,844 .base = ops.reg2,
842 }), imm_pair.operand, emit.code);845 }), imm_pair.operand, emit.code);
...@@ -845,7 +848,7 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -845,7 +848,7 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
845}848}
846849
847fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {850fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
848 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);851 const ops = emit.mir.instructions.items(.ops)[inst].decode();
849 const tag: Tag = switch (ops.flags) {852 const tag: Tag = switch (ops.flags) {
850 0b00 => .cbw,853 0b00 => .cbw,
851 0b01 => .cwd,854 0b01 => .cwd,
...@@ -858,17 +861,17 @@ fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -858,17 +861,17 @@ fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
858fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {861fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
859 const tag = emit.mir.instructions.items(.tag)[inst];862 const tag = emit.mir.instructions.items(.tag)[inst];
860 assert(tag == .lea);863 assert(tag == .lea);
861 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);864 const ops = emit.mir.instructions.items(.ops)[inst].decode();
862 switch (ops.flags) {865 switch (ops.flags) {
863 0b00 => {866 0b00 => {
864 // lea reg1, [reg2 + imm32]867 // lea reg1, [reg2 + imm32]
865 // RM868 // RM
866 const imm = emit.mir.instructions.items(.data)[inst].imm;869 const imm = emit.mir.instructions.items(.data)[inst].imm;
867 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;870 const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
868 return lowerToRmEnc(871 return lowerToRmEnc(
869 .lea,872 .lea,
870 Register.reg(ops.reg1),873 ops.reg1,
871 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{874 RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
872 .disp = imm,875 .disp = imm,
873 .base = src_reg,876 .base = src_reg,
874 }),877 }),
...@@ -881,8 +884,8 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -881,8 +884,8 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
881 const start_offset = emit.code.items.len;884 const start_offset = emit.code.items.len;
882 try lowerToRmEnc(885 try lowerToRmEnc(
883 .lea,886 .lea,
884 Register.reg(ops.reg1),887 ops.reg1,
885 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),888 RegisterOrMemory.rip(Memory.PtrSize.new(ops.reg1.size()), 0),
886 emit.code,889 emit.code,
887 );890 );
888 const end_offset = emit.code.items.len;891 const end_offset = emit.code.items.len;
...@@ -895,15 +898,15 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -895,15 +898,15 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
895 0b10 => {898 0b10 => {
896 // lea reg, [rbp + rcx + imm32]899 // lea reg, [rbp + rcx + imm32]
897 const imm = emit.mir.instructions.items(.data)[inst].imm;900 const imm = emit.mir.instructions.items(.data)[inst].imm;
898 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;901 const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
899 const scale_index = ScaleIndex{902 const scale_index = ScaleIndex{
900 .scale = 0,903 .scale = 0,
901 .index = .rcx,904 .index = .rcx,
902 };905 };
903 return lowerToRmEnc(906 return lowerToRmEnc(
904 .lea,907 .lea,
905 Register.reg(ops.reg1),908 ops.reg1,
906 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{909 RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
907 .disp = imm,910 .disp = imm,
908 .base = src_reg,911 .base = src_reg,
909 .scale_index = scale_index,912 .scale_index = scale_index,
...@@ -918,15 +921,15 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -918,15 +921,15 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
918fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {921fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
919 const tag = emit.mir.instructions.items(.tag)[inst];922 const tag = emit.mir.instructions.items(.tag)[inst];
920 assert(tag == .lea_pie);923 assert(tag == .lea_pie);
921 const ops = Mir.Ops(GpRegister, GpRegister).decode(emit.mir.instructions.items(.ops)[inst]);924 const ops = emit.mir.instructions.items(.ops)[inst].decode();
922 const load_reloc = emit.mir.instructions.items(.data)[inst].load_reloc;925 const load_reloc = emit.mir.instructions.items(.data)[inst].load_reloc;
923926
924 // lea reg1, [rip + reloc]927 // lea reg1, [rip + reloc]
925 // RM928 // RM
926 try lowerToRmEnc(929 try lowerToRmEnc(
927 .lea,930 .lea,
928 Register.reg(ops.reg1),931 ops.reg1,
929 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),932 RegisterOrMemory.rip(Memory.PtrSize.new(ops.reg1.size()), 0),
930 emit.code,933 emit.code,
931 );934 );
932935
...@@ -962,78 +965,70 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -962,78 +965,70 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
962fn mirMovF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {965fn mirMovF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
963 const tag = emit.mir.instructions.items(.tag)[inst];966 const tag = emit.mir.instructions.items(.tag)[inst];
964 assert(tag == .mov_f64);967 assert(tag == .mov_f64);
965 const ops = emit.mir.instructions.items(.ops)[inst];968 const ops = emit.mir.instructions.items(.ops)[inst].decode();
966 const flags = @truncate(u2, ops);
967969
968 switch (flags) {970 switch (ops.flags) {
969 0b00 => {971 0b00 => {
970 const decoded = Mir.Ops(AvxRegister, GpRegister).decode(ops);
971 const imm = emit.mir.instructions.items(.data)[inst].imm;972 const imm = emit.mir.instructions.items(.data)[inst].imm;
972 return lowerToRmEnc(.vmovsd, Register.avxReg(decoded.reg1), RegisterOrMemory.mem(.qword_ptr, .{973 return lowerToVmEnc(.vmovsd, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{
973 .disp = imm,974 .disp = imm,
974 .base = decoded.reg2,975 .base = ops.reg2,
975 }), emit.code);976 }), emit.code);
976 },977 },
977 0b01 => {978 0b01 => {
978 const decoded = Mir.Ops(GpRegister, AvxRegister).decode(ops);
979 const imm = emit.mir.instructions.items(.data)[inst].imm;979 const imm = emit.mir.instructions.items(.data)[inst].imm;
980 return lowerToMrEnc(.vmovsd, RegisterOrMemory.mem(.qword_ptr, .{980 return lowerToMvEnc(.vmovsd, RegisterOrMemory.mem(.qword_ptr, .{
981 .disp = imm,981 .disp = imm,
982 .base = decoded.reg1,982 .base = ops.reg1,
983 }), Register.avxReg(decoded.reg2), emit.code);983 }), ops.reg2, emit.code);
984 },984 },
985 0b10 => {985 0b10 => {
986 const decoded = Mir.Ops(AvxRegister, AvxRegister).decode(ops);
987 return lowerToRvmEnc(986 return lowerToRvmEnc(
988 .vmovsd,987 .vmovsd,
989 Register.avxReg(decoded.reg1),988 ops.reg1,
990 Register.avxReg(decoded.reg1),989 ops.reg1,
991 RegisterOrMemory.avxReg(decoded.reg2),990 RegisterOrMemory.reg(ops.reg2),
992 emit.code,991 emit.code,
993 );992 );
994 },993 },
995 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{flags}),994 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
996 }995 }
997}996}
998997
999fn mirAddF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {998fn mirAddF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1000 const tag = emit.mir.instructions.items(.tag)[inst];999 const tag = emit.mir.instructions.items(.tag)[inst];
1001 assert(tag == .add_f64);1000 assert(tag == .add_f64);
1002 const ops = emit.mir.instructions.items(.ops)[inst];1001 const ops = emit.mir.instructions.items(.ops)[inst].decode();
1003 const flags = @truncate(u2, ops);
10041002
1005 switch (flags) {1003 switch (ops.flags) {
1006 0b00 => {1004 0b00 => {
1007 const decoded = Mir.Ops(AvxRegister, AvxRegister).decode(ops);
1008 return lowerToRvmEnc(1005 return lowerToRvmEnc(
1009 .vaddsd,1006 .vaddsd,
1010 Register.avxReg(decoded.reg1),1007 ops.reg1,
1011 Register.avxReg(decoded.reg1),1008 ops.reg1,
1012 RegisterOrMemory.avxReg(decoded.reg2),1009 RegisterOrMemory.reg(ops.reg2),
1013 emit.code,1010 emit.code,
1014 );1011 );
1015 },1012 },
1016 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{flags}),1013 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
1017 }1014 }
1018}1015}
10191016
1020fn mirCmpF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {1017fn mirCmpF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1021 const tag = emit.mir.instructions.items(.tag)[inst];1018 const tag = emit.mir.instructions.items(.tag)[inst];
1022 assert(tag == .cmp_f64);1019 assert(tag == .cmp_f64);
1023 const ops = emit.mir.instructions.items(.ops)[inst];1020 const ops = emit.mir.instructions.items(.ops)[inst].decode();
1024 const flags = @truncate(u2, ops);
10251021
1026 switch (flags) {1022 switch (ops.flags) {
1027 0b00 => {1023 0b00 => {
1028 const decoded = Mir.Ops(AvxRegister, AvxRegister).decode(ops);1024 return lowerToVmEnc(
1029 return lowerToRmEnc(
1030 .vucomisd,1025 .vucomisd,
1031 Register.avxReg(decoded.reg1),1026 ops.reg1,
1032 RegisterOrMemory.avxReg(decoded.reg2),1027 RegisterOrMemory.reg(ops.reg2),
1033 emit.code,1028 emit.code,
1034 );1029 );
1035 },1030 },
1036 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{flags}),1031 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
1037 }1032 }
1038}1033}
10391034
...@@ -1277,6 +1272,18 @@ const Tag = enum {...@@ -1277,6 +1272,18 @@ const Tag = enum {
1277 vcmpsd,1272 vcmpsd,
1278 vucomisd,1273 vucomisd,
12791274
1275 fn isAvx(tag: Tag) bool {
1276 return switch (tag) {
1277 .vmovsd,
1278 .vaddsd,
1279 .vcmpsd,
1280 .vucomisd,
1281 => true,
1282
1283 else => false,
1284 };
1285 }
1286
1280 fn isSetCC(tag: Tag) bool {1287 fn isSetCC(tag: Tag) bool {
1281 return switch (tag) {1288 return switch (tag) {
1282 .seto,1289 .seto,
...@@ -1361,6 +1368,12 @@ const Encoding = enum {...@@ -1361,6 +1368,12 @@ const Encoding = enum {
1361 /// OP r64, r/m64, imm321368 /// OP r64, r/m64, imm32
1362 rmi,1369 rmi,
13631370
1371 /// OP xmm1, xmm2/m64
1372 vm,
1373
1374 /// OP m64, xmm1
1375 mv,
1376
1364 /// OP xmm1, xmm2, xmm3/m641377 /// OP xmm1, xmm2, xmm3/m64
1365 rvm,1378 rvm,
13661379
...@@ -1389,7 +1402,7 @@ const OpCode = union(enum) {...@@ -1389,7 +1402,7 @@ const OpCode = union(enum) {
13891402
1390 fn encodeWithReg(opc: OpCode, encoder: Encoder, reg: Register) void {1403 fn encodeWithReg(opc: OpCode, encoder: Encoder, reg: Register) void {
1391 assert(opc == .one_byte);1404 assert(opc == .one_byte);
1392 encoder.opcode_withReg(opc.one_byte, reg.lowId());1405 encoder.opcode_withReg(opc.one_byte, reg.lowEnc());
1393 }1406 }
1394};1407};
13951408
...@@ -1536,6 +1549,15 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1536,6 +1549,15 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1536 .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69),1549 .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69),
1537 else => null,1550 else => null,
1538 },1551 },
1552 .mv => return switch (tag) {
1553 .vmovsd => OpCode.oneByte(0x11),
1554 else => null,
1555 },
1556 .vm => return switch (tag) {
1557 .vmovsd => OpCode.oneByte(0x10),
1558 .vucomisd => OpCode.oneByte(0x2e),
1559 else => null,
1560 },
1539 .rvm => return switch (tag) {1561 .rvm => return switch (tag) {
1540 .vaddsd => OpCode.oneByte(0x58),1562 .vaddsd => OpCode.oneByte(0x58),
1541 .vmovsd => OpCode.oneByte(0x10),1563 .vmovsd => OpCode.oneByte(0x10),
...@@ -1647,11 +1669,11 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {...@@ -1647,11 +1669,11 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {
1647 } = .none,1669 } = .none,
1648 } = blk: {1670 } = blk: {
1649 switch (enc) {1671 switch (enc) {
1650 .mr => switch (tag) {1672 .mv => switch (tag) {
1651 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },1673 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },
1652 else => return null,1674 else => return null,
1653 },1675 },
1654 .rm => switch (tag) {1676 .vm => switch (tag) {
1655 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },1677 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },
1656 .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true },1678 .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true },
1657 else => return null,1679 else => return null,
...@@ -1697,61 +1719,50 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {...@@ -1697,61 +1719,50 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {
1697 } };1719 } };
1698}1720}
16991721
1700const ScaleIndex = struct {1722const ScaleIndex = packed struct {
1701 scale: u2,1723 scale: u2,
1702 index: GpRegister,1724 index: Register,
1703};1725};
17041726
1705const Memory = struct {1727const Memory = struct {
1706 base: ?GpRegister,1728 base: ?Register,
1707 rip: bool = false,1729 rip: bool = false,
1708 disp: u32,1730 disp: u32,
1709 ptr_size: PtrSize,1731 ptr_size: PtrSize,
1710 scale_index: ?ScaleIndex = null,1732 scale_index: ?ScaleIndex = null,
17111733
1712 const PtrSize = enum {1734 const PtrSize = enum(u2) {
1713 byte_ptr,1735 byte_ptr = 0b00,
1714 word_ptr,1736 word_ptr = 0b01,
1715 dword_ptr,1737 dword_ptr = 0b10,
1716 qword_ptr,1738 qword_ptr = 0b11,
17171739
1718 fn fromBits(in_bits: u64) PtrSize {1740 fn new(bit_size: u64) PtrSize {
1719 return switch (in_bits) {1741 return @intToEnum(PtrSize, math.log2_int(u4, @intCast(u4, @divExact(bit_size, 8))));
1720 8 => .byte_ptr,
1721 16 => .word_ptr,
1722 32 => .dword_ptr,
1723 64 => .qword_ptr,
1724 else => unreachable,
1725 };
1726 }1742 }
17271743
1728 /// Returns size in bits.1744 /// Returns size in bits.
1729 fn size(ptr_size: PtrSize) u64 {1745 fn size(ptr_size: PtrSize) u64 {
1730 return switch (ptr_size) {1746 return 8 * (math.powi(u8, 2, @enumToInt(ptr_size)) catch unreachable);
1731 .byte_ptr => 8,
1732 .word_ptr => 16,
1733 .dword_ptr => 32,
1734 .qword_ptr => 64,
1735 };
1736 }1747 }
1737 };1748 };
17381749
1739 fn encode(mem_op: Memory, encoder: Encoder, operand: u3) void {1750 fn encode(mem_op: Memory, encoder: Encoder, operand: u3) void {
1740 if (mem_op.base) |base| {1751 if (mem_op.base) |base| {
1741 const dst = base.lowId();1752 const dst = base.lowEnc();
1742 const src = operand;1753 const src = operand;
1743 if (dst == 4 or mem_op.scale_index != null) {1754 if (dst == 4 or mem_op.scale_index != null) {
1744 if (mem_op.disp == 0 and dst != 5) {1755 if (mem_op.disp == 0 and dst != 5) {
1745 encoder.modRm_SIBDisp0(src);1756 encoder.modRm_SIBDisp0(src);
1746 if (mem_op.scale_index) |si| {1757 if (mem_op.scale_index) |si| {
1747 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);1758 encoder.sib_scaleIndexBase(si.scale, si.index.lowEnc(), dst);
1748 } else {1759 } else {
1749 encoder.sib_base(dst);1760 encoder.sib_base(dst);
1750 }1761 }
1751 } else if (immOpSize(mem_op.disp) == 8) {1762 } else if (immOpSize(mem_op.disp) == 8) {
1752 encoder.modRm_SIBDisp8(src);1763 encoder.modRm_SIBDisp8(src);
1753 if (mem_op.scale_index) |si| {1764 if (mem_op.scale_index) |si| {
1754 encoder.sib_scaleIndexBaseDisp8(si.scale, si.index.lowId(), dst);1765 encoder.sib_scaleIndexBaseDisp8(si.scale, si.index.lowEnc(), dst);
1755 } else {1766 } else {
1756 encoder.sib_baseDisp8(dst);1767 encoder.sib_baseDisp8(dst);
1757 }1768 }
...@@ -1759,7 +1770,7 @@ const Memory = struct {...@@ -1759,7 +1770,7 @@ const Memory = struct {
1759 } else {1770 } else {
1760 encoder.modRm_SIBDisp32(src);1771 encoder.modRm_SIBDisp32(src);
1761 if (mem_op.scale_index) |si| {1772 if (mem_op.scale_index) |si| {
1762 encoder.sib_scaleIndexBaseDisp32(si.scale, si.index.lowId(), dst);1773 encoder.sib_scaleIndexBaseDisp32(si.scale, si.index.lowEnc(), dst);
1763 } else {1774 } else {
1764 encoder.sib_baseDisp32(dst);1775 encoder.sib_baseDisp32(dst);
1765 }1776 }
...@@ -1782,7 +1793,7 @@ const Memory = struct {...@@ -1782,7 +1793,7 @@ const Memory = struct {
1782 } else {1793 } else {
1783 encoder.modRm_SIBDisp0(operand);1794 encoder.modRm_SIBDisp0(operand);
1784 if (mem_op.scale_index) |si| {1795 if (mem_op.scale_index) |si| {
1785 encoder.sib_scaleIndexDisp32(si.scale, si.index.lowId());1796 encoder.sib_scaleIndexDisp32(si.scale, si.index.lowEnc());
1786 } else {1797 } else {
1787 encoder.sib_disp32();1798 encoder.sib_disp32();
1788 }1799 }
...@@ -1791,6 +1802,7 @@ const Memory = struct {...@@ -1791,6 +1802,7 @@ const Memory = struct {
1791 }1802 }
1792 }1803 }
17931804
1805 /// Returns size in bits.
1794 fn size(memory: Memory) u64 {1806 fn size(memory: Memory) u64 {
1795 return memory.ptr_size.size();1807 return memory.ptr_size.size();
1796 }1808 }
...@@ -1805,55 +1817,17 @@ fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {...@@ -1805,55 +1817,17 @@ fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {
1805 }1817 }
1806}1818}
18071819
1808const Register = union(enum) {
1809 register: GpRegister,
1810 avx_register: AvxRegister,
1811
1812 fn reg(register: GpRegister) Register {
1813 return .{ .register = register };
1814 }
1815
1816 fn avxReg(register: AvxRegister) Register {
1817 return .{ .avx_register = register };
1818 }
1819
1820 fn lowId(register: Register) u3 {
1821 return switch (register) {
1822 .register => |r| r.lowId(),
1823 .avx_register => |r| r.lowId(),
1824 };
1825 }
1826
1827 fn size(register: Register) u64 {
1828 return switch (register) {
1829 .register => |r| r.size(),
1830 .avx_register => |r| r.size(),
1831 };
1832 }
1833
1834 fn isExtended(register: Register) bool {
1835 return switch (register) {
1836 .register => |r| r.isExtended(),
1837 .avx_register => |r| r.isExtended(),
1838 };
1839 }
1840};
1841
1842const RegisterOrMemory = union(enum) {1820const RegisterOrMemory = union(enum) {
1843 register: Register,1821 register: Register,
1844 memory: Memory,1822 memory: Memory,
18451823
1846 fn reg(register: GpRegister) RegisterOrMemory {1824 fn reg(register: Register) RegisterOrMemory {
1847 return .{ .register = Register.reg(register) };1825 return .{ .register = register };
1848 }
1849
1850 fn avxReg(register: AvxRegister) RegisterOrMemory {
1851 return .{ .register = Register.avxReg(register) };
1852 }1826 }
18531827
1854 fn mem(ptr_size: Memory.PtrSize, args: struct {1828 fn mem(ptr_size: Memory.PtrSize, args: struct {
1855 disp: u32,1829 disp: u32,
1856 base: ?GpRegister = null,1830 base: ?Register = null,
1857 scale_index: ?ScaleIndex = null,1831 scale_index: ?ScaleIndex = null,
1858 }) RegisterOrMemory {1832 }) RegisterOrMemory {
1859 return .{1833 return .{
...@@ -1877,6 +1851,7 @@ const RegisterOrMemory = union(enum) {...@@ -1877,6 +1851,7 @@ const RegisterOrMemory = union(enum) {
1877 };1851 };
1878 }1852 }
18791853
1854 /// Returns size in bits.
1880 fn size(reg_or_mem: RegisterOrMemory) u64 {1855 fn size(reg_or_mem: RegisterOrMemory) u64 {
1881 return switch (reg_or_mem) {1856 return switch (reg_or_mem) {
1882 .register => |reg| reg.size(),1857 .register => |reg| reg.size(),
...@@ -1886,6 +1861,7 @@ const RegisterOrMemory = union(enum) {...@@ -1886,6 +1861,7 @@ const RegisterOrMemory = union(enum) {
1886};1861};
18871862
1888fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {1863fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
1864 assert(!tag.isAvx());
1889 const opc = getOpCode(tag, .zo, false).?;1865 const opc = getOpCode(tag, .zo, false).?;
1890 const encoder = try Encoder.init(code, 2);1866 const encoder = try Encoder.init(code, 2);
1891 switch (tag) {1867 switch (tag) {
...@@ -1900,6 +1876,7 @@ fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {...@@ -1900,6 +1876,7 @@ fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
1900}1876}
19011877
1902fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {1878fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1879 assert(!tag.isAvx());
1903 if (tag == .ret_far or tag == .ret_near) {1880 if (tag == .ret_far or tag == .ret_near) {
1904 const encoder = try Encoder.init(code, 3);1881 const encoder = try Encoder.init(code, 3);
1905 const opc = getOpCode(tag, .i, false).?;1882 const opc = getOpCode(tag, .i, false).?;
...@@ -1917,6 +1894,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1917,6 +1894,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1917}1894}
19181895
1919fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {1896fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
1897 assert(!tag.isAvx());
1920 const opc = getOpCode(tag, .o, false).?;1898 const opc = getOpCode(tag, .o, false).?;
1921 const encoder = try Encoder.init(code, 3);1899 const encoder = try Encoder.init(code, 3);
1922 if (reg.size() == 16) {1900 if (reg.size() == 16) {
...@@ -1930,6 +1908,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi...@@ -1930,6 +1908,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi
1930}1908}
19311909
1932fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {1910fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1911 assert(!tag.isAvx());
1933 const opc = getOpCode(tag, .d, false).?;1912 const opc = getOpCode(tag, .d, false).?;
1934 const encoder = try Encoder.init(code, 6);1913 const encoder = try Encoder.init(code, 6);
1935 opc.encode(encoder);1914 opc.encode(encoder);
...@@ -1937,6 +1916,7 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1937,6 +1916,7 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1937}1916}
19381917
1939fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {1918fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {
1919 assert(!tag.isAvx());
1940 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;1920 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
1941 const modrm_ext = getModRmExt(tag).?;1921 const modrm_ext = getModRmExt(tag).?;
1942 switch (reg_or_mem) {1922 switch (reg_or_mem) {
...@@ -1951,7 +1931,7 @@ fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *st...@@ -1951,7 +1931,7 @@ fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *st
1951 .b = reg.isExtended(),1931 .b = reg.isExtended(),
1952 });1932 });
1953 opc.encode(encoder);1933 opc.encode(encoder);
1954 encoder.modRm_direct(modrm_ext, reg.lowId());1934 encoder.modRm_direct(modrm_ext, reg.lowEnc());
1955 },1935 },
1956 .memory => |mem_op| {1936 .memory => |mem_op| {
1957 const encoder = try Encoder.init(code, 8);1937 const encoder = try Encoder.init(code, 8);
...@@ -1992,6 +1972,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I...@@ -1992,6 +1972,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I
1992}1972}
19931973
1994fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void {1974fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void {
1975 assert(!tag.isAvx());
1995 const opc = if (td)1976 const opc = if (td)
1996 getOpCode(tag, .td, reg.size() == 8).?1977 getOpCode(tag, .td, reg.size() == 8).?
1997 else1978 else
...@@ -2014,6 +1995,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),...@@ -2014,6 +1995,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
2014}1995}
20151996
2016fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void {1997fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void {
1998 assert(!tag.isAvx());
2017 const opc = getOpCode(tag, .oi, reg.size() == 8).?;1999 const opc = getOpCode(tag, .oi, reg.size() == 8).?;
2018 const encoder = try Encoder.init(code, 10);2000 const encoder = try Encoder.init(code, 10);
2019 if (reg.size() == 16) {2001 if (reg.size() == 16) {
...@@ -2040,6 +2022,7 @@ fn lowerToMiXEnc(...@@ -2040,6 +2022,7 @@ fn lowerToMiXEnc(
2040 enc: Encoding,2022 enc: Encoding,
2041 code: *std.ArrayList(u8),2023 code: *std.ArrayList(u8),
2042) InnerError!void {2024) InnerError!void {
2025 assert(!tag.isAvx());
2043 const modrm_ext = getModRmExt(tag).?;2026 const modrm_ext = getModRmExt(tag).?;
2044 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;2027 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
2045 switch (reg_or_mem) {2028 switch (reg_or_mem) {
...@@ -2056,7 +2039,7 @@ fn lowerToMiXEnc(...@@ -2056,7 +2039,7 @@ fn lowerToMiXEnc(
2056 .b = dst_reg.isExtended(),2039 .b = dst_reg.isExtended(),
2057 });2040 });
2058 opc.encode(encoder);2041 opc.encode(encoder);
2059 encoder.modRm_direct(modrm_ext, dst_reg.lowId());2042 encoder.modRm_direct(modrm_ext, dst_reg.lowEnc());
2060 encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_reg.size());2043 encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_reg.size());
2061 },2044 },
2062 .memory => |dst_mem| {2045 .memory => |dst_mem| {
...@@ -2095,84 +2078,43 @@ fn lowerToRmEnc(...@@ -2095,84 +2078,43 @@ fn lowerToRmEnc(
2095 reg_or_mem: RegisterOrMemory,2078 reg_or_mem: RegisterOrMemory,
2096 code: *std.ArrayList(u8),2079 code: *std.ArrayList(u8),
2097) InnerError!void {2080) InnerError!void {
2081 assert(!tag.isAvx());
2098 const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8).?;2082 const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8).?;
2099 switch (reg_or_mem) {2083 switch (reg_or_mem) {
2100 .register => |src_reg| {2084 .register => |src_reg| {
2101 const encoder: Encoder = blk: {2085 const encoder = try Encoder.init(code, 5);
2102 switch (reg) {2086 if (reg.size() == 16) {
2103 .register => {2087 encoder.prefix16BitMode();
2104 const encoder = try Encoder.init(code, 4);2088 }
2105 if (reg.size() == 16) {2089 encoder.rex(.{
2106 encoder.prefix16BitMode();2090 .w = setRexWRegister(reg) or setRexWRegister(src_reg),
2107 }2091 .r = reg.isExtended(),
2108 encoder.rex(.{2092 .b = src_reg.isExtended(),
2109 .w = setRexWRegister(reg) or setRexWRegister(src_reg),2093 });
2110 .r = reg.isExtended(),
2111 .b = src_reg.isExtended(),
2112 });
2113 break :blk encoder;
2114 },
2115 .avx_register => {
2116 const encoder = try Encoder.init(code, 5);
2117 var vex_prefix = getVexPrefix(tag, .rm).?;
2118 const vex = &vex_prefix.prefix;
2119 vex.rex(.{
2120 .r = reg.isExtended(),
2121 .b = src_reg.isExtended(),
2122 });
2123 encoder.vex(vex_prefix.prefix);
2124 break :blk encoder;
2125 },
2126 }
2127 };
2128 opc.encode(encoder);2094 opc.encode(encoder);
2129 encoder.modRm_direct(reg.lowId(), src_reg.lowId());2095 encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc());
2130 },2096 },
2131 .memory => |src_mem| {2097 .memory => |src_mem| {
2132 const encoder: Encoder = blk: {2098 const encoder = try Encoder.init(code, 9);
2133 switch (reg) {2099 if (reg.size() == 16) {
2134 .register => {2100 encoder.prefix16BitMode();
2135 const encoder = try Encoder.init(code, 9);2101 }
2136 if (reg.size() == 16) {2102 if (src_mem.base) |base| {
2137 encoder.prefix16BitMode();2103 // TODO handle 32-bit base register - requires prefix 0x67
2138 }2104 // Intel Manual, Vol 1, chapter 3.6 and 3.6.1
2139 if (src_mem.base) |base| {2105 encoder.rex(.{
2140 // TODO handle 32-bit base register - requires prefix 0x672106 .w = setRexWRegister(reg),
2141 // Intel Manual, Vol 1, chapter 3.6 and 3.6.12107 .r = reg.isExtended(),
2142 encoder.rex(.{2108 .b = base.isExtended(),
2143 .w = setRexWRegister(reg),2109 });
2144 .r = reg.isExtended(),2110 } else {
2145 .b = base.isExtended(),2111 encoder.rex(.{
2146 });2112 .w = setRexWRegister(reg),
2147 } else {2113 .r = reg.isExtended(),
2148 encoder.rex(.{2114 });
2149 .w = setRexWRegister(reg),2115 }
2150 .r = reg.isExtended(),
2151 });
2152 }
2153 break :blk encoder;
2154 },
2155 .avx_register => {
2156 const encoder = try Encoder.init(code, 10);
2157 var vex_prefix = getVexPrefix(tag, .rm).?;
2158 const vex = &vex_prefix.prefix;
2159 if (src_mem.base) |base| {
2160 vex.rex(.{
2161 .r = reg.isExtended(),
2162 .b = base.isExtended(),
2163 });
2164 } else {
2165 vex.rex(.{
2166 .r = reg.isExtended(),
2167 });
2168 }
2169 encoder.vex(vex_prefix.prefix);
2170 break :blk encoder;
2171 },
2172 }
2173 };
2174 opc.encode(encoder);2116 opc.encode(encoder);
2175 src_mem.encode(encoder, reg.lowId());2117 src_mem.encode(encoder, reg.lowEnc());
2176 },2118 },
2177 }2119 }
2178}2120}
...@@ -2183,6 +2125,7 @@ fn lowerToMrEnc(...@@ -2183,6 +2125,7 @@ fn lowerToMrEnc(
2183 reg: Register,2125 reg: Register,
2184 code: *std.ArrayList(u8),2126 code: *std.ArrayList(u8),
2185) InnerError!void {2127) InnerError!void {
2128 assert(!tag.isAvx());
2186 const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8).?;2129 const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8).?;
2187 switch (reg_or_mem) {2130 switch (reg_or_mem) {
2188 .register => |dst_reg| {2131 .register => |dst_reg| {
...@@ -2196,53 +2139,27 @@ fn lowerToMrEnc(...@@ -2196,53 +2139,27 @@ fn lowerToMrEnc(
2196 .b = dst_reg.isExtended(),2139 .b = dst_reg.isExtended(),
2197 });2140 });
2198 opc.encode(encoder);2141 opc.encode(encoder);
2199 encoder.modRm_direct(reg.lowId(), dst_reg.lowId());2142 encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc());
2200 },2143 },
2201 .memory => |dst_mem| {2144 .memory => |dst_mem| {
2202 const encoder: Encoder = blk: {2145 const encoder = try Encoder.init(code, 9);
2203 switch (reg) {2146 if (reg.size() == 16) {
2204 .register => {2147 encoder.prefix16BitMode();
2205 const encoder = try Encoder.init(code, 9);2148 }
2206 if (reg.size() == 16) {2149 if (dst_mem.base) |base| {
2207 encoder.prefix16BitMode();2150 encoder.rex(.{
2208 }2151 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
2209 if (dst_mem.base) |base| {2152 .r = reg.isExtended(),
2210 encoder.rex(.{2153 .b = base.isExtended(),
2211 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),2154 });
2212 .r = reg.isExtended(),2155 } else {
2213 .b = base.isExtended(),2156 encoder.rex(.{
2214 });2157 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
2215 } else {2158 .r = reg.isExtended(),
2216 encoder.rex(.{2159 });
2217 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),2160 }
2218 .r = reg.isExtended(),
2219 });
2220 }
2221 break :blk encoder;
2222 },
2223 .avx_register => {
2224 const encoder = try Encoder.init(code, 10);
2225 var vex_prefix = getVexPrefix(tag, .mr).?;
2226 const vex = &vex_prefix.prefix;
2227 if (dst_mem.base) |base| {
2228 vex.rex(.{
2229 .w = dst_mem.ptr_size == .qword_ptr,
2230 .r = reg.isExtended(),
2231 .b = base.isExtended(),
2232 });
2233 } else {
2234 vex.rex(.{
2235 .w = dst_mem.ptr_size == .qword_ptr,
2236 .r = reg.isExtended(),
2237 });
2238 }
2239 encoder.vex(vex_prefix.prefix);
2240 break :blk encoder;
2241 },
2242 }
2243 };
2244 opc.encode(encoder);2161 opc.encode(encoder);
2245 dst_mem.encode(encoder, reg.lowId());2162 dst_mem.encode(encoder, reg.lowEnc());
2246 },2163 },
2247 }2164 }
2248}2165}
...@@ -2254,6 +2171,7 @@ fn lowerToRmiEnc(...@@ -2254,6 +2171,7 @@ fn lowerToRmiEnc(
2254 imm: u32,2171 imm: u32,
2255 code: *std.ArrayList(u8),2172 code: *std.ArrayList(u8),
2256) InnerError!void {2173) InnerError!void {
2174 assert(!tag.isAvx());
2257 const opc = getOpCode(tag, .rmi, false).?;2175 const opc = getOpCode(tag, .rmi, false).?;
2258 const encoder = try Encoder.init(code, 13);2176 const encoder = try Encoder.init(code, 13);
2259 if (reg.size() == 16) {2177 if (reg.size() == 16) {
...@@ -2267,7 +2185,7 @@ fn lowerToRmiEnc(...@@ -2267,7 +2185,7 @@ fn lowerToRmiEnc(
2267 .b = src_reg.isExtended(),2185 .b = src_reg.isExtended(),
2268 });2186 });
2269 opc.encode(encoder);2187 opc.encode(encoder);
2270 encoder.modRm_direct(reg.lowId(), src_reg.lowId());2188 encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc());
2271 },2189 },
2272 .memory => |src_mem| {2190 .memory => |src_mem| {
2273 if (src_mem.base) |base| {2191 if (src_mem.base) |base| {
...@@ -2285,12 +2203,94 @@ fn lowerToRmiEnc(...@@ -2285,12 +2203,94 @@ fn lowerToRmiEnc(
2285 });2203 });
2286 }2204 }
2287 opc.encode(encoder);2205 opc.encode(encoder);
2288 src_mem.encode(encoder, reg.lowId());2206 src_mem.encode(encoder, reg.lowEnc());
2289 },2207 },
2290 }2208 }
2291 encodeImm(encoder, imm, reg.size());2209 encodeImm(encoder, imm, reg.size());
2292}2210}
22932211
2212/// Also referred to as XM encoding in Intel manual.
2213fn lowerToVmEnc(
2214 tag: Tag,
2215 reg: Register,
2216 reg_or_mem: RegisterOrMemory,
2217 code: *std.ArrayList(u8),
2218) InnerError!void {
2219 const opc = getOpCode(tag, .vm, false).?;
2220 var vex_prefix = getVexPrefix(tag, .vm).?;
2221 const vex = &vex_prefix.prefix;
2222 switch (reg_or_mem) {
2223 .register => |src_reg| {
2224 const encoder = try Encoder.init(code, 5);
2225 vex.rex(.{
2226 .r = reg.isExtended(),
2227 .b = src_reg.isExtended(),
2228 });
2229 encoder.vex(vex_prefix.prefix);
2230 opc.encode(encoder);
2231 encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc());
2232 },
2233 .memory => |src_mem| {
2234 assert(src_mem.ptr_size == .qword_ptr);
2235 const encoder = try Encoder.init(code, 10);
2236 if (src_mem.base) |base| {
2237 vex.rex(.{
2238 .r = reg.isExtended(),
2239 .b = base.isExtended(),
2240 });
2241 } else {
2242 vex.rex(.{
2243 .r = reg.isExtended(),
2244 });
2245 }
2246 encoder.vex(vex_prefix.prefix);
2247 opc.encode(encoder);
2248 src_mem.encode(encoder, reg.lowEnc());
2249 },
2250 }
2251}
2252
2253/// Usually referred to as MR encoding with V/V in Intel manual.
2254fn lowerToMvEnc(
2255 tag: Tag,
2256 reg_or_mem: RegisterOrMemory,
2257 reg: Register,
2258 code: *std.ArrayList(u8),
2259) InnerError!void {
2260 const opc = getOpCode(tag, .mv, false).?;
2261 var vex_prefix = getVexPrefix(tag, .mv).?;
2262 const vex = &vex_prefix.prefix;
2263 switch (reg_or_mem) {
2264 .register => |dst_reg| {
2265 const encoder = try Encoder.init(code, 4);
2266 vex.rex(.{
2267 .r = reg.isExtended(),
2268 .b = dst_reg.isExtended(),
2269 });
2270 encoder.vex(vex_prefix.prefix);
2271 opc.encode(encoder);
2272 encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc());
2273 },
2274 .memory => |dst_mem| {
2275 assert(dst_mem.ptr_size == .qword_ptr);
2276 const encoder = try Encoder.init(code, 10);
2277 if (dst_mem.base) |base| {
2278 vex.rex(.{
2279 .r = reg.isExtended(),
2280 .b = base.isExtended(),
2281 });
2282 } else {
2283 vex.rex(.{
2284 .r = reg.isExtended(),
2285 });
2286 }
2287 encoder.vex(vex_prefix.prefix);
2288 opc.encode(encoder);
2289 dst_mem.encode(encoder, reg.lowEnc());
2290 },
2291 }
2292}
2293
2294fn lowerToRvmEnc(2294fn lowerToRvmEnc(
2295 tag: Tag,2295 tag: Tag,
2296 reg1: Register,2296 reg1: Register,
...@@ -2305,7 +2305,7 @@ fn lowerToRvmEnc(...@@ -2305,7 +2305,7 @@ fn lowerToRvmEnc(
2305 .register => |reg3| {2305 .register => |reg3| {
2306 if (vex_prefix.reg) |vvvv| {2306 if (vex_prefix.reg) |vvvv| {
2307 switch (vvvv) {2307 switch (vvvv) {
2308 .nds => vex.reg(reg2.avx_register.id()),2308 .nds => vex.reg(reg2.enc()),
2309 else => unreachable, // TODO2309 else => unreachable, // TODO
2310 }2310 }
2311 }2311 }
...@@ -2316,7 +2316,7 @@ fn lowerToRvmEnc(...@@ -2316,7 +2316,7 @@ fn lowerToRvmEnc(
2316 });2316 });
2317 encoder.vex(vex_prefix.prefix);2317 encoder.vex(vex_prefix.prefix);
2318 opc.encode(encoder);2318 opc.encode(encoder);
2319 encoder.modRm_direct(reg1.lowId(), reg3.lowId());2319 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());
2320 },2320 },
2321 .memory => |dst_mem| {2321 .memory => |dst_mem| {
2322 _ = dst_mem;2322 _ = dst_mem;
...@@ -2341,7 +2341,7 @@ fn lowerToRvmiEnc(...@@ -2341,7 +2341,7 @@ fn lowerToRvmiEnc(
2341 .register => |reg3| {2341 .register => |reg3| {
2342 if (vex_prefix.reg) |vvvv| {2342 if (vex_prefix.reg) |vvvv| {
2343 switch (vvvv) {2343 switch (vvvv) {
2344 .nds => vex.reg(reg2.avx_register.id()),2344 .nds => vex.reg(reg2.enc()),
2345 else => unreachable, // TODO2345 else => unreachable, // TODO
2346 }2346 }
2347 }2347 }
...@@ -2352,7 +2352,7 @@ fn lowerToRvmiEnc(...@@ -2352,7 +2352,7 @@ fn lowerToRvmiEnc(
2352 });2352 });
2353 encoder.vex(vex_prefix.prefix);2353 encoder.vex(vex_prefix.prefix);
2354 opc.encode(encoder);2354 opc.encode(encoder);
2355 encoder.modRm_direct(reg1.lowId(), reg3.lowId());2355 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());
2356 break :blk encoder;2356 break :blk encoder;
2357 },2357 },
2358 .memory => |dst_mem| {2358 .memory => |dst_mem| {
...@@ -2490,23 +2490,23 @@ test "lower MI encoding" {...@@ -2490,23 +2490,23 @@ test "lower MI encoding" {
2490test "lower RM encoding" {2490test "lower RM encoding" {
2491 var emit = TestEmit.init();2491 var emit = TestEmit.init();
2492 defer emit.deinit();2492 defer emit.deinit();
2493 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.reg(.rbx), emit.code());2493 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), emit.code());
2494 try expectEqualHexStrings("\x48\x8b\xc3", emit.lowered(), "mov rax, rbx");2494 try expectEqualHexStrings("\x48\x8b\xc3", emit.lowered(), "mov rax, rbx");
2495 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), emit.code());2495 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), emit.code());
2496 try expectEqualHexStrings("\x49\x8b\x03", emit.lowered(), "mov rax, qword ptr [r11 + 0]");2496 try expectEqualHexStrings("\x49\x8b\x03", emit.lowered(), "mov rax, qword ptr [r11 + 0]");
2497 try lowerToRmEnc(.add, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), emit.code());2497 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), emit.code());
2498 try expectEqualHexStrings(2498 try expectEqualHexStrings(
2499 "\x4C\x03\x1C\x25\x00\x00\x00\x10",2499 "\x4C\x03\x1C\x25\x00\x00\x00\x10",
2500 emit.lowered(),2500 emit.lowered(),
2501 "add r11, qword ptr [ds:0x10000000]",2501 "add r11, qword ptr [ds:0x10000000]",
2502 );2502 );
2503 try lowerToRmEnc(.add, Register.reg(.r12b), RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), emit.code());2503 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), emit.code());
2504 try expectEqualHexStrings(2504 try expectEqualHexStrings(
2505 "\x44\x02\x24\x25\x00\x00\x00\x10",2505 "\x44\x02\x24\x25\x00\x00\x00\x10",
2506 emit.lowered(),2506 emit.lowered(),
2507 "add r11b, byte ptr [ds:0x10000000]",2507 "add r11b, byte ptr [ds:0x10000000]",
2508 );2508 );
2509 try lowerToRmEnc(.sub, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{2509 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
2510 .disp = 0x10000000,2510 .disp = 0x10000000,
2511 .base = .r13,2511 .base = .r13,
2512 }), emit.code());2512 }), emit.code());
...@@ -2515,7 +2515,7 @@ test "lower RM encoding" {...@@ -2515,7 +2515,7 @@ test "lower RM encoding" {
2515 emit.lowered(),2515 emit.lowered(),
2516 "sub r11, qword ptr [r13 + 0x10000000]",2516 "sub r11, qword ptr [r13 + 0x10000000]",
2517 );2517 );
2518 try lowerToRmEnc(.sub, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{2518 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
2519 .disp = 0x10000000,2519 .disp = 0x10000000,
2520 .base = .r12,2520 .base = .r12,
2521 }), emit.code());2521 }), emit.code());
...@@ -2524,14 +2524,14 @@ test "lower RM encoding" {...@@ -2524,14 +2524,14 @@ test "lower RM encoding" {
2524 emit.lowered(),2524 emit.lowered(),
2525 "sub r11, qword ptr [r12 + 0x10000000]",2525 "sub r11, qword ptr [r12 + 0x10000000]",
2526 );2526 );
2527 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{2527 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2528 .disp = @bitCast(u32, @as(i32, -4)),2528 .disp = @bitCast(u32, @as(i32, -4)),
2529 .base = .rbp,2529 .base = .rbp,
2530 }), emit.code());2530 }), emit.code());
2531 try expectEqualHexStrings("\x48\x8B\x45\xFC", emit.lowered(), "mov rax, qword ptr [rbp - 4]");2531 try expectEqualHexStrings("\x48\x8B\x45\xFC", emit.lowered(), "mov rax, qword ptr [rbp - 4]");
2532 try lowerToRmEnc(.lea, Register.reg(.rax), RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());2532 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
2533 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", emit.lowered(), "lea rax, [rip + 0x10]");2533 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", emit.lowered(), "lea rax, [rip + 0x10]");
2534 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{2534 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2535 .disp = @bitCast(u32, @as(i32, -8)),2535 .disp = @bitCast(u32, @as(i32, -8)),
2536 .base = .rbp,2536 .base = .rbp,
2537 .scale_index = .{2537 .scale_index = .{
...@@ -2540,7 +2540,7 @@ test "lower RM encoding" {...@@ -2540,7 +2540,7 @@ test "lower RM encoding" {
2540 },2540 },
2541 }), emit.code());2541 }), emit.code());
2542 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");2542 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
2543 try lowerToRmEnc(.mov, Register.reg(.eax), RegisterOrMemory.mem(.dword_ptr, .{2543 try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
2544 .disp = @bitCast(u32, @as(i32, -4)),2544 .disp = @bitCast(u32, @as(i32, -4)),
2545 .base = .rbp,2545 .base = .rbp,
2546 .scale_index = .{2546 .scale_index = .{
...@@ -2549,7 +2549,7 @@ test "lower RM encoding" {...@@ -2549,7 +2549,7 @@ test "lower RM encoding" {
2549 },2549 },
2550 }), emit.code());2550 }), emit.code());
2551 try expectEqualHexStrings("\x8B\x44\x95\xFC", emit.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");2551 try expectEqualHexStrings("\x8B\x44\x95\xFC", emit.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
2552 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{2552 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2553 .disp = @bitCast(u32, @as(i32, -8)),2553 .disp = @bitCast(u32, @as(i32, -8)),
2554 .base = .rbp,2554 .base = .rbp,
2555 .scale_index = .{2555 .scale_index = .{
...@@ -2558,7 +2558,7 @@ test "lower RM encoding" {...@@ -2558,7 +2558,7 @@ test "lower RM encoding" {
2558 },2558 },
2559 }), emit.code());2559 }), emit.code());
2560 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");2560 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
2561 try lowerToRmEnc(.mov, Register.reg(.r8b), RegisterOrMemory.mem(.byte_ptr, .{2561 try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{
2562 .disp = @bitCast(u32, @as(i32, -24)),2562 .disp = @bitCast(u32, @as(i32, -24)),
2563 .base = .rsi,2563 .base = .rsi,
2564 .scale_index = .{2564 .scale_index = .{
...@@ -2567,7 +2567,7 @@ test "lower RM encoding" {...@@ -2567,7 +2567,7 @@ test "lower RM encoding" {
2567 },2567 },
2568 }), emit.code());2568 }), emit.code());
2569 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", emit.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");2569 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", emit.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
2570 try lowerToRmEnc(.lea, Register.reg(.rsi), RegisterOrMemory.mem(.qword_ptr, .{2570 try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{
2571 .disp = 0,2571 .disp = 0,
2572 .base = .rbp,2572 .base = .rbp,
2573 .scale_index = .{2573 .scale_index = .{
...@@ -2576,33 +2576,25 @@ test "lower RM encoding" {...@@ -2576,33 +2576,25 @@ test "lower RM encoding" {
2576 },2576 },
2577 }), emit.code());2577 }), emit.code());
2578 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", emit.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");2578 try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", emit.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");
2579
2580 // AVX extension tests
2581 try lowerToRmEnc(.vmovsd, Register.avxReg(.xmm1), RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
2582 try expectEqualHexStrings(
2583 "\xC5\xFB\x10\x0D\x10\x00\x00\x00",
2584 emit.lowered(),
2585 "vmovsd xmm1, qword ptr [rip + 0x10]",
2586 );
2587}2579}
25882580
2589test "lower MR encoding" {2581test "lower MR encoding" {
2590 var emit = TestEmit.init();2582 var emit = TestEmit.init();
2591 defer emit.deinit();2583 defer emit.deinit();
2592 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), Register.reg(.rbx), emit.code());2584 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, emit.code());
2593 try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx");2585 try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx");
2594 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{2586 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
2595 .disp = @bitCast(u32, @as(i32, -4)),2587 .disp = @bitCast(u32, @as(i32, -4)),
2596 .base = .rbp,2588 .base = .rbp,
2597 }), Register.reg(.r11), emit.code());2589 }), .r11, emit.code());
2598 try expectEqualHexStrings("\x4c\x89\x5d\xfc", emit.lowered(), "mov qword ptr [rbp - 4], r11");2590 try expectEqualHexStrings("\x4c\x89\x5d\xfc", emit.lowered(), "mov qword ptr [rbp - 4], r11");
2599 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), Register.reg(.r12b), emit.code());2591 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, emit.code());
2600 try expectEqualHexStrings(2592 try expectEqualHexStrings(
2601 "\x44\x00\x24\x25\x00\x00\x00\x10",2593 "\x44\x00\x24\x25\x00\x00\x00\x10",
2602 emit.lowered(),2594 emit.lowered(),
2603 "add byte ptr [ds:0x10000000], r12b",2595 "add byte ptr [ds:0x10000000], r12b",
2604 );2596 );
2605 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), Register.reg(.r12d), emit.code());2597 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, emit.code());
2606 try expectEqualHexStrings(2598 try expectEqualHexStrings(
2607 "\x44\x01\x24\x25\x00\x00\x00\x10",2599 "\x44\x01\x24\x25\x00\x00\x00\x10",
2608 emit.lowered(),2600 emit.lowered(),
...@@ -2611,61 +2603,53 @@ test "lower MR encoding" {...@@ -2611,61 +2603,53 @@ test "lower MR encoding" {
2611 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{2603 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{
2612 .disp = 0x10000000,2604 .disp = 0x10000000,
2613 .base = .r11,2605 .base = .r11,
2614 }), Register.reg(.r12), emit.code());2606 }), .r12, emit.code());
2615 try expectEqualHexStrings(2607 try expectEqualHexStrings(
2616 "\x4D\x29\xA3\x00\x00\x00\x10",2608 "\x4D\x29\xA3\x00\x00\x00\x10",
2617 emit.lowered(),2609 emit.lowered(),
2618 "sub qword ptr [r11 + 0x10000000], r12",2610 "sub qword ptr [r11 + 0x10000000], r12",
2619 );2611 );
2620 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), Register.reg(.r12), emit.code());2612 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, emit.code());
2621 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12");2613 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12");
2622
2623 // AVX extension tests
2624 try lowerToMrEnc(.vmovsd, RegisterOrMemory.rip(.qword_ptr, 0x10), Register.avxReg(.xmm1), emit.code());
2625 try expectEqualHexStrings(
2626 "\xC5\xFB\x11\x0D\x10\x00\x00\x00",
2627 emit.lowered(),
2628 "vmovsd qword ptr [rip + 0x10], xmm1",
2629 );
2630}2614}
26312615
2632test "lower OI encoding" {2616test "lower OI encoding" {
2633 var emit = TestEmit.init();2617 var emit = TestEmit.init();
2634 defer emit.deinit();2618 defer emit.deinit();
2635 try lowerToOiEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code());2619 try lowerToOiEnc(.mov, .rax, 0x1000000000000000, emit.code());
2636 try expectEqualHexStrings(2620 try expectEqualHexStrings(
2637 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",2621 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
2638 emit.lowered(),2622 emit.lowered(),
2639 "movabs rax, 0x1000000000000000",2623 "movabs rax, 0x1000000000000000",
2640 );2624 );
2641 try lowerToOiEnc(.mov, Register.reg(.r11), 0x1000000000000000, emit.code());2625 try lowerToOiEnc(.mov, .r11, 0x1000000000000000, emit.code());
2642 try expectEqualHexStrings(2626 try expectEqualHexStrings(
2643 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",2627 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
2644 emit.lowered(),2628 emit.lowered(),
2645 "movabs r11, 0x1000000000000000",2629 "movabs r11, 0x1000000000000000",
2646 );2630 );
2647 try lowerToOiEnc(.mov, Register.reg(.r11d), 0x10000000, emit.code());2631 try lowerToOiEnc(.mov, .r11d, 0x10000000, emit.code());
2648 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", emit.lowered(), "mov r11d, 0x10000000");2632 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", emit.lowered(), "mov r11d, 0x10000000");
2649 try lowerToOiEnc(.mov, Register.reg(.r11w), 0x1000, emit.code());2633 try lowerToOiEnc(.mov, .r11w, 0x1000, emit.code());
2650 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", emit.lowered(), "mov r11w, 0x1000");2634 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", emit.lowered(), "mov r11w, 0x1000");
2651 try lowerToOiEnc(.mov, Register.reg(.r11b), 0x10, emit.code());2635 try lowerToOiEnc(.mov, .r11b, 0x10, emit.code());
2652 try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10");2636 try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10");
2653}2637}
26542638
2655test "lower FD/TD encoding" {2639test "lower FD/TD encoding" {
2656 var emit = TestEmit.init();2640 var emit = TestEmit.init();
2657 defer emit.deinit();2641 defer emit.deinit();
2658 try lowerToFdEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code());2642 try lowerToFdEnc(.mov, .rax, 0x1000000000000000, emit.code());
2659 try expectEqualHexStrings(2643 try expectEqualHexStrings(
2660 "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",2644 "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",
2661 emit.lowered(),2645 emit.lowered(),
2662 "mov rax, ds:0x1000000000000000",2646 "mov rax, ds:0x1000000000000000",
2663 );2647 );
2664 try lowerToFdEnc(.mov, Register.reg(.eax), 0x10000000, emit.code());2648 try lowerToFdEnc(.mov, .eax, 0x10000000, emit.code());
2665 try expectEqualHexStrings("\xa1\x00\x00\x00\x10", emit.lowered(), "mov eax, ds:0x10000000");2649 try expectEqualHexStrings("\xa1\x00\x00\x00\x10", emit.lowered(), "mov eax, ds:0x10000000");
2666 try lowerToFdEnc(.mov, Register.reg(.ax), 0x1000, emit.code());2650 try lowerToFdEnc(.mov, .ax, 0x1000, emit.code());
2667 try expectEqualHexStrings("\x66\xa1\x00\x10", emit.lowered(), "mov ax, ds:0x1000");2651 try expectEqualHexStrings("\x66\xa1\x00\x10", emit.lowered(), "mov ax, ds:0x1000");
2668 try lowerToFdEnc(.mov, Register.reg(.al), 0x10, emit.code());2652 try lowerToFdEnc(.mov, .al, 0x10, emit.code());
2669 try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10");2653 try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10");
2670}2654}
26712655
...@@ -2741,16 +2725,16 @@ test "lower M1 and MC encodings" {...@@ -2741,16 +2725,16 @@ test "lower M1 and MC encodings" {
2741test "lower O encoding" {2725test "lower O encoding" {
2742 var emit = TestEmit.init();2726 var emit = TestEmit.init();
2743 defer emit.deinit();2727 defer emit.deinit();
2744 try lowerToOEnc(.pop, Register.reg(.r12), emit.code());2728 try lowerToOEnc(.pop, .r12, emit.code());
2745 try expectEqualHexStrings("\x41\x5c", emit.lowered(), "pop r12");2729 try expectEqualHexStrings("\x41\x5c", emit.lowered(), "pop r12");
2746 try lowerToOEnc(.push, Register.reg(.r12w), emit.code());2730 try lowerToOEnc(.push, .r12w, emit.code());
2747 try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w");2731 try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w");
2748}2732}
27492733
2750test "lower RMI encoding" {2734test "lower RMI encoding" {
2751 var emit = TestEmit.init();2735 var emit = TestEmit.init();
2752 defer emit.deinit();2736 defer emit.deinit();
2753 try lowerToRmiEnc(.imul, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{2737 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2754 .disp = @bitCast(u32, @as(i32, -8)),2738 .disp = @bitCast(u32, @as(i32, -8)),
2755 .base = .rbp,2739 .base = .rbp,
2756 }), 0x10, emit.code());2740 }), 0x10, emit.code());
...@@ -2759,39 +2743,49 @@ test "lower RMI encoding" {...@@ -2759,39 +2743,49 @@ test "lower RMI encoding" {
2759 emit.lowered(),2743 emit.lowered(),
2760 "imul rax, qword ptr [rbp - 8], 0x10",2744 "imul rax, qword ptr [rbp - 8], 0x10",
2761 );2745 );
2762 try lowerToRmiEnc(.imul, Register.reg(.eax), RegisterOrMemory.mem(.dword_ptr, .{2746 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
2763 .disp = @bitCast(u32, @as(i32, -4)),2747 .disp = @bitCast(u32, @as(i32, -4)),
2764 .base = .rbp,2748 .base = .rbp,
2765 }), 0x10, emit.code());2749 }), 0x10, emit.code());
2766 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", emit.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");2750 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", emit.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
2767 try lowerToRmiEnc(.imul, Register.reg(.ax), RegisterOrMemory.mem(.word_ptr, .{2751 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
2768 .disp = @bitCast(u32, @as(i32, -2)),2752 .disp = @bitCast(u32, @as(i32, -2)),
2769 .base = .rbp,2753 .base = .rbp,
2770 }), 0x10, emit.code());2754 }), 0x10, emit.code());
2771 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", emit.lowered(), "imul ax, word ptr [rbp - 2], 0x10");2755 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", emit.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
2772 try lowerToRmiEnc(.imul, Register.reg(.r12), RegisterOrMemory.reg(.r12), 0x10, emit.code());2756 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, emit.code());
2773 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", emit.lowered(), "imul r12, r12, 0x10");2757 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", emit.lowered(), "imul r12, r12, 0x10");
2774 try lowerToRmiEnc(.imul, Register.reg(.r12w), RegisterOrMemory.reg(.r12w), 0x10, emit.code());2758 try lowerToRmiEnc(.imul, .r12w, RegisterOrMemory.reg(.r12w), 0x10, emit.code());
2775 try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10");2759 try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10");
2776}2760}
27772761
2778test "lower to RVM encoding" {2762test "lower MV encoding" {
2779 var emit = TestEmit.init();2763 var emit = TestEmit.init();
2780 defer emit.deinit();2764 defer emit.deinit();
2781 try lowerToRvmEnc(2765 try lowerToMvEnc(.vmovsd, RegisterOrMemory.rip(.qword_ptr, 0x10), .xmm1, emit.code());
2782 .vaddsd,2766 try expectEqualHexStrings(
2783 Register.avxReg(.xmm0),2767 "\xC5\xFB\x11\x0D\x10\x00\x00\x00",
2784 Register.avxReg(.xmm1),2768 emit.lowered(),
2785 RegisterOrMemory.avxReg(.xmm2),2769 "vmovsd qword ptr [rip + 0x10], xmm1",
2786 emit.code(),
2787 );2770 );
2788 try expectEqualHexStrings("\xC5\xF3\x58\xC2", emit.lowered(), "vaddsd xmm0, xmm1, xmm2");2771}
2789 try lowerToRvmEnc(2772
2790 .vaddsd,2773test "lower VM encoding" {
2791 Register.avxReg(.xmm0),2774 var emit = TestEmit.init();
2792 Register.avxReg(.xmm0),2775 defer emit.deinit();
2793 RegisterOrMemory.avxReg(.xmm1),2776 try lowerToVmEnc(.vmovsd, .xmm1, RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
2794 emit.code(),2777 try expectEqualHexStrings(
2778 "\xC5\xFB\x10\x0D\x10\x00\x00\x00",
2779 emit.lowered(),
2780 "vmovsd xmm1, qword ptr [rip + 0x10]",
2795 );2781 );
2782}
2783
2784test "lower to RVM encoding" {
2785 var emit = TestEmit.init();
2786 defer emit.deinit();
2787 try lowerToRvmEnc(.vaddsd, .xmm0, .xmm1, RegisterOrMemory.reg(.xmm2), emit.code());
2788 try expectEqualHexStrings("\xC5\xF3\x58\xC2", emit.lowered(), "vaddsd xmm0, xmm1, xmm2");
2789 try lowerToRvmEnc(.vaddsd, .xmm0, .xmm0, RegisterOrMemory.reg(.xmm1), emit.code());
2796 try expectEqualHexStrings("\xC5\xFB\x58\xC1", emit.lowered(), "vaddsd xmm0, xmm0, xmm1");2790 try expectEqualHexStrings("\xC5\xFB\x58\xC1", emit.lowered(), "vaddsd xmm0, xmm0, xmm1");
2797}2791}
src/arch/x86_64/Mir.zig+32-34
...@@ -14,8 +14,7 @@ const assert = std.debug.assert;...@@ -14,8 +14,7 @@ const assert = std.debug.assert;
14const bits = @import("bits.zig");14const bits = @import("bits.zig");
15const Air = @import("../../Air.zig");15const Air = @import("../../Air.zig");
16const CodeGen = @import("CodeGen.zig");16const CodeGen = @import("CodeGen.zig");
17const GpRegister = bits.Register;17const Register = bits.Register;
18const AvxRegister = bits.AvxRegister;
1918
20instructions: std.MultiArrayList(Inst).Slice,19instructions: std.MultiArrayList(Inst).Slice,
21/// The meaning of this data is determined by `Inst.Tag` value.20/// The meaning of this data is determined by `Inst.Tag` value.
...@@ -23,11 +22,7 @@ extra: []const u32,...@@ -23,11 +22,7 @@ extra: []const u32,
2322
24pub const Inst = struct {23pub const Inst = struct {
25 tag: Tag,24 tag: Tag,
26 /// This is 3 fields, and the meaning of each depends on `tag`.25 ops: Ops,
27 /// reg1: Register
28 /// reg2: Register
29 /// flags: u2
30 ops: u16,
31 /// The meaning of this depends on `tag` and `ops`.26 /// The meaning of this depends on `tag` and `ops`.
32 data: Data,27 data: Data,
3328
...@@ -397,6 +392,36 @@ pub const Inst = struct {...@@ -397,6 +392,36 @@ pub const Inst = struct {
397 /// The position of an MIR instruction within the `Mir` instructions array.392 /// The position of an MIR instruction within the `Mir` instructions array.
398 pub const Index = u32;393 pub const Index = u32;
399394
395 pub const Ops = packed struct {
396 reg1: u7,
397 reg2: u7,
398 flags: u2,
399
400 pub fn encode(vals: struct {
401 reg1: Register = .none,
402 reg2: Register = .none,
403 flags: u2 = 0b00,
404 }) Ops {
405 return .{
406 .reg1 = @enumToInt(vals.reg1),
407 .reg2 = @enumToInt(vals.reg2),
408 .flags = vals.flags,
409 };
410 }
411
412 pub fn decode(ops: Ops) struct {
413 reg1: Register,
414 reg2: Register,
415 flags: u2,
416 } {
417 return .{
418 .reg1 = @intToEnum(Register, ops.reg1),
419 .reg2 = @intToEnum(Register, ops.reg2),
420 .flags = ops.flags,
421 };
422 }
423 };
424
400 /// All instructions have a 4-byte payload, which is contained within425 /// All instructions have a 4-byte payload, which is contained within
401 /// this union. `Tag` determines which union field is active, as well as426 /// this union. `Tag` determines which union field is active, as well as
402 /// how to interpret the data within.427 /// how to interpret the data within.
...@@ -466,33 +491,6 @@ pub const DbgLineColumn = struct {...@@ -466,33 +491,6 @@ pub const DbgLineColumn = struct {
466 column: u32,491 column: u32,
467};492};
468493
469pub fn Ops(comptime Reg1: type, comptime Reg2: type) type {
470 return struct {
471 reg1: Reg1 = .none,
472 reg2: Reg2 = .none,
473 flags: u2 = 0b00,
474
475 pub fn encode(self: @This()) u16 {
476 var ops: u16 = 0;
477 ops |= @intCast(u16, @enumToInt(self.reg1)) << 9;
478 ops |= @intCast(u16, @enumToInt(self.reg2)) << 2;
479 ops |= self.flags;
480 return ops;
481 }
482
483 pub fn decode(ops: u16) @This() {
484 const reg1 = @intToEnum(Reg1, @truncate(u7, ops >> 9));
485 const reg2 = @intToEnum(Reg2, @truncate(u7, ops >> 2));
486 const flags = @truncate(u2, ops);
487 return .{
488 .reg1 = reg1,
489 .reg2 = reg2,
490 .flags = flags,
491 };
492 }
493 };
494}
495
496pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {494pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
497 mir.instructions.deinit(gpa);495 mir.instructions.deinit(gpa);
498 gpa.free(mir.extra);496 gpa.free(mir.extra);
src/arch/x86_64/abi.zig+11-6
...@@ -3,7 +3,6 @@ const Type = @import("../../type.zig").Type;...@@ -3,7 +3,6 @@ const Type = @import("../../type.zig").Type;
3const Target = std.Target;3const Target = std.Target;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Register = @import("bits.zig").Register;5const Register = @import("bits.zig").Register;
6const AvxRegister = @import("bits.zig").AvxRegister;
76
8pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };7pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
98
...@@ -379,11 +378,17 @@ pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };...@@ -379,11 +378,17 @@ pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };
379/// the caller relinquishes control to a subroutine via call instruction (or similar).378/// the caller relinquishes control to a subroutine via call instruction (or similar).
380/// In other words, these registers are free to use by the callee.379/// In other words, these registers are free to use by the callee.
381pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };380pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
382pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs;381pub const avx_regs = [_]Register{
383pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
384pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
385
386pub const avx_regs = [_]AvxRegister{
387 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,382 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
388 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,383 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,
389};384};
385pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ avx_regs;
386
387// Masks for register manager
388const FreeRegInt = std.meta.Int(.unsigned, allocatable_registers.len);
389// TODO
390pub const gp_mask: FreeRegInt = 0x3fff;
391pub const avx_mask: FreeRegInt = 0x3fff_c000;
392
393pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
394pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
src/arch/x86_64/bits.zig+38-62
...@@ -43,17 +43,36 @@ pub const Register = enum(u7) {...@@ -43,17 +43,36 @@ pub const Register = enum(u7) {
43 al, cl, dl, bl, ah, ch, dh, bh,43 al, cl, dl, bl, ah, ch, dh, bh,
44 r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b,44 r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b,
4545
46 // Pseudo, used only for MIR to signify that the46 // 64-79, 256-bit registers.
47 // operand is not a register but an immediate, etc.47 // id is int value - 64.
48 ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7,
49 ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15,
50
51 // 80-95, 128-bit registers.
52 // id is int value - 80.
53 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
54 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
55
56 // Pseudo-value for MIR instructions.
48 none,57 none,
4958
59 pub fn id(self: Register) u5 {
60 return switch (@enumToInt(self)) {
61 0...63 => @as(u5, @truncate(u4, @enumToInt(self))),
62 64...79 => @truncate(u5, @enumToInt(self)),
63 else => unreachable,
64 };
65 }
66
50 /// Returns the bit-width of the register.67 /// Returns the bit-width of the register.
51 pub fn size(self: Register) u7 {68 pub fn size(self: Register) u9 {
52 return switch (@enumToInt(self)) {69 return switch (@enumToInt(self)) {
53 0...15 => 64,70 0...15 => 64,
54 16...31 => 32,71 16...31 => 32,
55 32...47 => 16,72 32...47 => 16,
56 48...64 => 8,73 48...63 => 8,
74 64...79 => 256,
75 80...95 => 128,
57 else => unreachable,76 else => unreachable,
58 };77 };
59 }78 }
...@@ -72,15 +91,23 @@ pub const Register = enum(u7) {...@@ -72,15 +91,23 @@ pub const Register = enum(u7) {
72 /// an instruction (@see isExtended), and requires special handling. The91 /// an instruction (@see isExtended), and requires special handling. The
73 /// lower three bits are often embedded directly in instructions (such as92 /// lower three bits are often embedded directly in instructions (such as
74 /// the B8 variant of moves), or used in R/M bytes.93 /// the B8 variant of moves), or used in R/M bytes.
75 pub fn id(self: Register) u4 {94 pub fn enc(self: Register) u4 {
76 return @truncate(u4, @enumToInt(self));95 return @truncate(u4, @enumToInt(self));
77 }96 }
7897
79 /// Like id, but only returns the lower 3 bits.98 /// Like enc, but only returns the lower 3 bits.
80 pub fn lowId(self: Register) u3 {99 pub fn lowEnc(self: Register) u3 {
81 return @truncate(u3, @enumToInt(self));100 return @truncate(u3, @enumToInt(self));
82 }101 }
83102
103 pub fn to256(self: Register) Register {
104 return @intToEnum(Register, @as(u8, self.id()) + 64);
105 }
106
107 pub fn to128(self: Register) Register {
108 return @intToEnum(Register, @as(u8, self.id()) + 80);
109 }
110
84 /// Convert from any register to its 64 bit alias.111 /// Convert from any register to its 64 bit alias.
85 pub fn to64(self: Register) Register {112 pub fn to64(self: Register) Register {
86 return @intToEnum(Register, self.id());113 return @intToEnum(Register, self.id());
...@@ -126,57 +153,6 @@ pub const Register = enum(u7) {...@@ -126,57 +153,6 @@ pub const Register = enum(u7) {
126 }153 }
127};154};
128155
129/// AVX registers.
130/// TODO missing dwarfLocOp implementation.
131/// TODO add support for AVX-512
132pub const AvxRegister = enum(u6) {
133 // 256-bit registers
134 ymm0, ymm1, ymm2, ymm3, ymm4, ymm5, ymm6, ymm7,
135 ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15,
136
137 // 128-bit registers
138 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
139 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
140
141 // Pseudo, used only for MIR to signify that the
142 // operand is not a register but an immediate, etc.
143 none,
144
145 /// Returns the bit-width of the register.
146 pub fn size(self: AvxRegister) u9 {
147 return switch (@enumToInt(self)) {
148 0...15 => 256,
149 16...31 => 128,
150 else => unreachable,
151 };
152 }
153
154 /// Returns whether the register is *extended*.
155 pub fn isExtended(self: AvxRegister) bool {
156 return @enumToInt(self) & 0x08 != 0;
157 }
158
159 /// This returns the 4-bit register ID.
160 pub fn id(self: AvxRegister) u4 {
161 return @truncate(u4, @enumToInt(self));
162 }
163
164 /// Like id, but only returns the lower 3 bits.
165 pub fn lowId(self: AvxRegister) u3 {
166 return @truncate(u3, @enumToInt(self));
167 }
168
169 /// Convert from any register to its 256 bit alias.
170 pub fn to256(self: AvxRegister) AvxRegister {
171 return @intToEnum(AvxRegister, self.id());
172 }
173
174 /// Convert from any register to its 128 bit alias.
175 pub fn to128(self: AvxRegister) AvxRegister {
176 return @intToEnum(AvxRegister, @as(u8, self.id()) + 16);
177 }
178};
179
180// zig fmt: on156// zig fmt: on
181157
182/// Encoding helper functions for x86_64 instructions158/// Encoding helper functions for x86_64 instructions
...@@ -792,7 +768,7 @@ test "Encoder helpers - Vex prefix" {...@@ -792,7 +768,7 @@ test "Encoder helpers - Vex prefix" {
792 {768 {
793 stream.reset();769 stream.reset();
794 var vex_prefix = Encoder.Vex{};770 var vex_prefix = Encoder.Vex{};
795 vex_prefix.reg(AvxRegister.xmm15.id());771 vex_prefix.reg(Register.xmm15.id());
796 const nwritten = vex_prefix.write(writer);772 const nwritten = vex_prefix.write(writer);
797 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x80 }, buf[0..nwritten]);773 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x80 }, buf[0..nwritten]);
798 }774 }
...@@ -832,7 +808,7 @@ test "Encoder helpers - Vex prefix" {...@@ -832,7 +808,7 @@ test "Encoder helpers - Vex prefix" {
832 vex.simd_prefix_66();808 vex.simd_prefix_66();
833 encoder.vex(vex); // use 64 bit operation809 encoder.vex(vex); // use 64 bit operation
834 encoder.opcode_1byte(0x28);810 encoder.opcode_1byte(0x28);
835 encoder.modRm_direct(0, AvxRegister.xmm1.lowId());811 encoder.modRm_direct(0, Register.xmm1.lowId());
836 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0xF9, 0x28, 0xC1 }, code.items);812 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0xF9, 0x28, 0xC1 }, code.items);
837 }813 }
838814
...@@ -846,10 +822,10 @@ test "Encoder helpers - Vex prefix" {...@@ -846,10 +822,10 @@ test "Encoder helpers - Vex prefix" {
846 vex.simd_prefix_66();822 vex.simd_prefix_66();
847 vex.lead_opc_0f();823 vex.lead_opc_0f();
848 vex.rex(.{ .r = true });824 vex.rex(.{ .r = true });
849 vex.reg(AvxRegister.xmm1.id());825 vex.reg(Register.xmm1.id());
850 encoder.vex(vex);826 encoder.vex(vex);
851 encoder.opcode_1byte(0x16);827 encoder.opcode_1byte(0x16);
852 encoder.modRm_RIPDisp32(AvxRegister.xmm13.lowId());828 encoder.modRm_RIPDisp32(Register.xmm13.lowId());
853 encoder.disp32(0);829 encoder.disp32(0);
854 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0x71, 0x16, 0x2D, 0x00, 0x00, 0x00, 0x00 }, code.items);830 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0x71, 0x16, 0x2D, 0x00, 0x00, 0x00, 0x00 }, code.items);
855 }831 }
src/codegen.zig+12-12
...@@ -78,13 +78,13 @@ pub fn generateFunction(...@@ -78,13 +78,13 @@ pub fn generateFunction(
78 debug_output: DebugInfoOutput,78 debug_output: DebugInfoOutput,
79) GenerateSymbolError!FnResult {79) GenerateSymbolError!FnResult {
80 switch (bin_file.options.target.cpu.arch) {80 switch (bin_file.options.target.cpu.arch) {
81 // .arm,81 .arm,
82 // .armeb,82 .armeb,
83 // => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),83 => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
84 // .aarch64,84 .aarch64,
85 // .aarch64_be,85 .aarch64_be,
86 // .aarch64_32,86 .aarch64_32,
87 // => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),87 => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
88 //.arc => return Function(.arc).generate(bin_file, src_loc, func, air, liveness, code, debug_output),88 //.arc => return Function(.arc).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
89 //.avr => return Function(.avr).generate(bin_file, src_loc, func, air, liveness, code, debug_output),89 //.avr => return Function(.avr).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
90 //.bpfel => return Function(.bpfel).generate(bin_file, src_loc, func, air, liveness, code, debug_output),90 //.bpfel => return Function(.bpfel).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
...@@ -101,9 +101,9 @@ pub fn generateFunction(...@@ -101,9 +101,9 @@ pub fn generateFunction(
101 //.r600 => return Function(.r600).generate(bin_file, src_loc, func, air, liveness, code, debug_output),101 //.r600 => return Function(.r600).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
102 //.amdgcn => return Function(.amdgcn).generate(bin_file, src_loc, func, air, liveness, code, debug_output),102 //.amdgcn => return Function(.amdgcn).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
103 //.riscv32 => return Function(.riscv32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),103 //.riscv32 => return Function(.riscv32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
104 // .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),104 .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
105 //.sparc => return Function(.sparc).generate(bin_file, src_loc, func, air, liveness, code, debug_output),105 //.sparc => return Function(.sparc).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
106 // .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),106 .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
107 //.sparcel => return Function(.sparcel).generate(bin_file, src_loc, func, air, liveness, code, debug_output),107 //.sparcel => return Function(.sparcel).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
108 //.s390x => return Function(.s390x).generate(bin_file, src_loc, func, air, liveness, code, debug_output),108 //.s390x => return Function(.s390x).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
109 //.tce => return Function(.tce).generate(bin_file, src_loc, func, air, liveness, code, debug_output),109 //.tce => return Function(.tce).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
...@@ -129,9 +129,9 @@ pub fn generateFunction(...@@ -129,9 +129,9 @@ pub fn generateFunction(
129 //.renderscript32 => return Function(.renderscript32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),129 //.renderscript32 => return Function(.renderscript32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
130 //.renderscript64 => return Function(.renderscript64).generate(bin_file, src_loc, func, air, liveness, code, debug_output),130 //.renderscript64 => return Function(.renderscript64).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
131 //.ve => return Function(.ve).generate(bin_file, src_loc, func, air, liveness, code, debug_output),131 //.ve => return Function(.ve).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
132 // .wasm32,132 .wasm32,
133 // .wasm64,133 .wasm64,
134 // => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),134 => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
135 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),135 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
136 }136 }
137}137}
src/register_manager.zig+255-261
...@@ -23,15 +23,10 @@ pub const AllocateRegistersError = error{...@@ -23,15 +23,10 @@ pub const AllocateRegistersError = error{
23 CodegenFail,23 CodegenFail,
24};24};
2525
26pub fn SpillFn(comptime Function: type, comptime Register: type) type {
27 return fn (*Function, Register, Air.Inst.Index) anyerror!void;
28}
29
30pub fn RegisterManager(26pub fn RegisterManager(
31 comptime Function: type,27 comptime Function: type,
32 comptime Register: type,28 comptime Register: type,
33 comptime tracked_registers: []const Register,29 comptime tracked_registers: []const Register,
34 comptime spill_fn: SpillFn(Function, Register),
35) type {30) type {
36 // architectures which do not have a concept of registers should31 // architectures which do not have a concept of registers should
37 // refrain from using RegisterManager32 // refrain from using RegisterManager
...@@ -52,7 +47,6 @@ pub fn RegisterManager(...@@ -52,7 +47,6 @@ pub fn RegisterManager(
52 allocated_registers: FreeRegInt = 0,47 allocated_registers: FreeRegInt = 0,
53 /// Tracks registers which are locked from being allocated48 /// Tracks registers which are locked from being allocated
54 locked_registers: FreeRegInt = 0,49 locked_registers: FreeRegInt = 0,
55 function: *Function,
5650
57 const Self = @This();51 const Self = @This();
5852
...@@ -61,8 +55,8 @@ pub fn RegisterManager(...@@ -61,8 +55,8 @@ pub fn RegisterManager(
61 const FreeRegInt = std.meta.Int(.unsigned, tracked_registers.len);55 const FreeRegInt = std.meta.Int(.unsigned, tracked_registers.len);
62 const ShiftInt = math.Log2Int(FreeRegInt);56 const ShiftInt = math.Log2Int(FreeRegInt);
6357
64 fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) AllocateRegistersError!void {58 fn getFunction(self: *Self) *Function {
65 return try spill_fn(self.function, reg, inst);59 return @fieldParentPtr(Function, "register_manager", self);
66 }60 }
6761
68 fn getRegisterMask(reg: Register) ?FreeRegInt {62 fn getRegisterMask(reg: Register) ?FreeRegInt {
...@@ -257,14 +251,14 @@ pub fn RegisterManager(...@@ -257,14 +251,14 @@ pub fn RegisterManager(
257 self.markRegUsed(reg);251 self.markRegUsed(reg);
258 } else {252 } else {
259 const spilled_inst = self.registers[index];253 const spilled_inst = self.registers[index];
260 try self.spillInstruction(reg, spilled_inst);254 try self.getFunction().spillInstruction(reg, spilled_inst);
261 }255 }
262 self.registers[index] = inst;256 self.registers[index] = inst;
263 } else {257 } else {
264 // Don't track the register258 // Don't track the register
265 if (!self.isRegFree(reg)) {259 if (!self.isRegFree(reg)) {
266 const spilled_inst = self.registers[index];260 const spilled_inst = self.registers[index];
267 try self.spillInstruction(reg, spilled_inst);261 try self.getFunction().spillInstruction(reg, spilled_inst);
268 self.freeReg(reg);262 self.freeReg(reg);
269 }263 }
270 }264 }
...@@ -299,7 +293,7 @@ pub fn RegisterManager(...@@ -299,7 +293,7 @@ pub fn RegisterManager(
299 // stack allocation.293 // stack allocation.
300 const spilled_inst = self.registers[index];294 const spilled_inst = self.registers[index];
301 self.registers[index] = tracked_inst;295 self.registers[index] = tracked_inst;
302 try self.spillInstruction(reg, spilled_inst);296 try self.getFunction().spillInstruction(reg, spilled_inst);
303 } else {297 } else {
304 self.getRegAssumeFree(reg, tracked_inst);298 self.getRegAssumeFree(reg, tracked_inst);
305 }299 }
...@@ -308,7 +302,7 @@ pub fn RegisterManager(...@@ -308,7 +302,7 @@ pub fn RegisterManager(
308 // Move the instruction that was previously there to a302 // Move the instruction that was previously there to a
309 // stack allocation.303 // stack allocation.
310 const spilled_inst = self.registers[index];304 const spilled_inst = self.registers[index];
311 try self.spillInstruction(reg, spilled_inst);305 try self.getFunction().spillInstruction(reg, spilled_inst);
312 self.freeReg(reg);306 self.freeReg(reg);
313 }307 }
314 }308 }
...@@ -338,253 +332,253 @@ pub fn RegisterManager(...@@ -338,253 +332,253 @@ pub fn RegisterManager(
338 };332 };
339}333}
340334
341//const MockRegister1 = enum(u2) {335const MockRegister1 = enum(u2) {
342// r0,336 r0,
343// r1,337 r1,
344// r2,338 r2,
345// r3,339 r3,
346340
347// pub fn id(reg: MockRegister1) u2 {341 pub fn id(reg: MockRegister1) u2 {
348// return @enumToInt(reg);342 return @enumToInt(reg);
349// }343 }
344
345 const allocatable_registers = [_]MockRegister1{ .r2, .r3 };
346};
347
348const MockRegister2 = enum(u2) {
349 r0,
350 r1,
351 r2,
352 r3,
353
354 pub fn id(reg: MockRegister2) u2 {
355 return @enumToInt(reg);
356 }
357
358 const allocatable_registers = [_]MockRegister2{ .r0, .r1, .r2, .r3 };
359};
360
361fn MockFunction(comptime Register: type) type {
362 return struct {
363 allocator: Allocator,
364 register_manager: RegisterManager(Self, Register, &Register.allocatable_registers) = .{},
365 spilled: std.ArrayListUnmanaged(Register) = .{},
366
367 const Self = @This();
368
369 pub fn deinit(self: *Self) void {
370 self.spilled.deinit(self.allocator);
371 }
372
373 pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
374 _ = inst;
375 try self.spilled.append(self.allocator, reg);
376 }
377
378 pub fn genAdd(self: *Self, res: Register, lhs: Register, rhs: Register) !void {
379 _ = self;
380 _ = res;
381 _ = lhs;
382 _ = rhs;
383 }
384 };
385}
386
387const MockFunction1 = MockFunction(MockRegister1);
388const MockFunction2 = MockFunction(MockRegister2);
389
390test "default state" {
391 const allocator = std.testing.allocator;
392
393 var function = MockFunction1{
394 .allocator = allocator,
395 };
396 defer function.deinit();
397
398 try expect(!function.register_manager.isRegAllocated(.r2));
399 try expect(!function.register_manager.isRegAllocated(.r3));
400 try expect(function.register_manager.isRegFree(.r2));
401 try expect(function.register_manager.isRegFree(.r3));
402}
403
404test "tryAllocReg: no spilling" {
405 const allocator = std.testing.allocator;
406
407 var function = MockFunction1{
408 .allocator = allocator,
409 };
410 defer function.deinit();
411
412 const mock_instruction: Air.Inst.Index = 1;
413
414 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction));
415 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction));
416 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction));
417
418 try expect(function.register_manager.isRegAllocated(.r2));
419 try expect(function.register_manager.isRegAllocated(.r3));
420 try expect(!function.register_manager.isRegFree(.r2));
421 try expect(!function.register_manager.isRegFree(.r3));
422
423 function.register_manager.freeReg(.r2);
424 function.register_manager.freeReg(.r3);
425
426 try expect(function.register_manager.isRegAllocated(.r2));
427 try expect(function.register_manager.isRegAllocated(.r3));
428 try expect(function.register_manager.isRegFree(.r2));
429 try expect(function.register_manager.isRegFree(.r3));
430}
431
432test "allocReg: spilling" {
433 const allocator = std.testing.allocator;
350434
351// const allocatable_registers = [_]MockRegister1{ .r2, .r3 };435 var function = MockFunction1{
352//};436 .allocator = allocator,
353437 };
354//const MockRegister2 = enum(u2) {438 defer function.deinit();
355// r0,439
356// r1,440 const mock_instruction: Air.Inst.Index = 1;
357// r2,441
358// r3,442 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
359443 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
360// pub fn id(reg: MockRegister2) u2 {444
361// return @enumToInt(reg);445 // Spill a register
362// }446 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
363447 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
364// const allocatable_registers = [_]MockRegister2{ .r0, .r1, .r2, .r3 };448
365//};449 // No spilling necessary
366450 function.register_manager.freeReg(.r3);
367//fn MockFunction(comptime Register: type) type {451 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
368// return struct {452 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
369// allocator: Allocator,453
370// register_manager: RegisterManager(Self, Register, &Register.allocatable_registers) = .{},454 // Locked registers
371// spilled: std.ArrayListUnmanaged(Register) = .{},455 function.register_manager.freeReg(.r3);
372456 {
373// const Self = @This();457 const lock = function.register_manager.lockReg(.r2);
374458 defer if (lock) |reg| function.register_manager.unlockReg(reg);
375// pub fn deinit(self: *Self) void {459
376// self.spilled.deinit(self.allocator);460 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
377// }461 }
378462 try expect(!function.register_manager.lockedRegsExist());
379// pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {463}
380// _ = inst;464
381// try self.spilled.append(self.allocator, reg);465test "tryAllocRegs" {
382// }466 const allocator = std.testing.allocator;
383467
384// pub fn genAdd(self: *Self, res: Register, lhs: Register, rhs: Register) !void {468 var function = MockFunction2{
385// _ = self;469 .allocator = allocator,
386// _ = res;470 };
387// _ = lhs;471 defer function.deinit();
388// _ = rhs;472
389// }473 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
390// };474
391//}475 try expect(function.register_manager.isRegAllocated(.r0));
392476 try expect(function.register_manager.isRegAllocated(.r1));
393//const MockFunction1 = MockFunction(MockRegister1);477 try expect(function.register_manager.isRegAllocated(.r2));
394//const MockFunction2 = MockFunction(MockRegister2);478 try expect(!function.register_manager.isRegAllocated(.r3));
395479
396//test "default state" {480 // Locked registers
397// const allocator = std.testing.allocator;481 function.register_manager.freeReg(.r0);
398482 function.register_manager.freeReg(.r2);
399// var function = MockFunction1{483 function.register_manager.freeReg(.r3);
400// .allocator = allocator,484 {
401// };485 const lock = function.register_manager.lockReg(.r1);
402// defer function.deinit();486 defer if (lock) |reg| function.register_manager.unlockReg(reg);
403487
404// try expect(!function.register_manager.isRegAllocated(.r2));488 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
405// try expect(!function.register_manager.isRegAllocated(.r3));489 }
406// try expect(function.register_manager.isRegFree(.r2));490 try expect(!function.register_manager.lockedRegsExist());
407// try expect(function.register_manager.isRegFree(.r3));491
408//}492 try expect(function.register_manager.isRegAllocated(.r0));
409493 try expect(function.register_manager.isRegAllocated(.r1));
410//test "tryAllocReg: no spilling" {494 try expect(function.register_manager.isRegAllocated(.r2));
411// const allocator = std.testing.allocator;495 try expect(function.register_manager.isRegAllocated(.r3));
412496}
413// var function = MockFunction1{497
414// .allocator = allocator,498test "allocRegs: normal usage" {
415// };499 // TODO: convert this into a decltest once that is supported
416// defer function.deinit();500
417501 const allocator = std.testing.allocator;
418// const mock_instruction: Air.Inst.Index = 1;502
419503 var function = MockFunction2{
420// try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction));504 .allocator = allocator,
421// try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction));505 };
422// try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction));506 defer function.deinit();
423507
424// try expect(function.register_manager.isRegAllocated(.r2));508 {
425// try expect(function.register_manager.isRegAllocated(.r3));509 const result_reg: MockRegister2 = .r1;
426// try expect(!function.register_manager.isRegFree(.r2));510
427// try expect(!function.register_manager.isRegFree(.r3));511 // The result register is known and fixed at this point, we
428512 // don't want to accidentally allocate lhs or rhs to the
429// function.register_manager.freeReg(.r2);513 // result register, this is why we lock it.
430// function.register_manager.freeReg(.r3);514 //
431515 // Using defer unlock right after lock is a good idea in
432// try expect(function.register_manager.isRegAllocated(.r2));516 // most cases as you probably are using the locked registers
433// try expect(function.register_manager.isRegAllocated(.r3));517 // in the remainder of this scope and don't need to use it
434// try expect(function.register_manager.isRegFree(.r2));518 // after the end of this scope. However, in some situations,
435// try expect(function.register_manager.isRegFree(.r3));519 // it may make sense to manually unlock registers before the
436//}520 // end of the scope when you are certain that they don't
437521 // contain any valuable data anymore and can be reused. For an
438//test "allocReg: spilling" {522 // example of that, see `selectively reducing register
439// const allocator = std.testing.allocator;523 // pressure`.
440524 const lock = function.register_manager.lockReg(result_reg);
441// var function = MockFunction1{525 defer if (lock) |reg| function.register_manager.unlockReg(reg);
442// .allocator = allocator,526
443// };527 const regs = try function.register_manager.allocRegs(2, .{ null, null });
444// defer function.deinit();528 try function.genAdd(result_reg, regs[0], regs[1]);
445529 }
446// const mock_instruction: Air.Inst.Index = 1;530}
447531
448// try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));532test "allocRegs: selectively reducing register pressure" {
449// try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));533 // TODO: convert this into a decltest once that is supported
450534
451// // Spill a register535 const allocator = std.testing.allocator;
452// try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));536
453// try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);537 var function = MockFunction2{
454538 .allocator = allocator,
455// // No spilling necessary539 };
456// function.register_manager.freeReg(.r3);540 defer function.deinit();
457// try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));541
458// try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);542 {
459543 const result_reg: MockRegister2 = .r1;
460// // Locked registers544
461// function.register_manager.freeReg(.r3);545 const lock = function.register_manager.lockReg(result_reg);
462// {546
463// const lock = function.register_manager.lockReg(.r2);547 // Here, we don't defer unlock because we manually unlock
464// defer if (lock) |reg| function.register_manager.unlockReg(reg);548 // after genAdd
465549 const regs = try function.register_manager.allocRegs(2, .{ null, null });
466// try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));550
467// }551 try function.genAdd(result_reg, regs[0], regs[1]);
468// try expect(!function.register_manager.lockedRegsExist());552 function.register_manager.unlockReg(lock.?);
469//}553
470554 const extra_summand_reg = try function.register_manager.allocReg(null);
471//test "tryAllocRegs" {555 try function.genAdd(result_reg, result_reg, extra_summand_reg);
472// const allocator = std.testing.allocator;556 }
473557}
474// var function = MockFunction2{558
475// .allocator = allocator,559test "getReg" {
476// };560 const allocator = std.testing.allocator;
477// defer function.deinit();561
478562 var function = MockFunction1{
479// try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);563 .allocator = allocator,
480564 };
481// try expect(function.register_manager.isRegAllocated(.r0));565 defer function.deinit();
482// try expect(function.register_manager.isRegAllocated(.r1));566
483// try expect(function.register_manager.isRegAllocated(.r2));567 const mock_instruction: Air.Inst.Index = 1;
484// try expect(!function.register_manager.isRegAllocated(.r3));568
485569 try function.register_manager.getReg(.r3, mock_instruction);
486// // Locked registers570
487// function.register_manager.freeReg(.r0);571 try expect(!function.register_manager.isRegAllocated(.r2));
488// function.register_manager.freeReg(.r2);572 try expect(function.register_manager.isRegAllocated(.r3));
489// function.register_manager.freeReg(.r3);573 try expect(function.register_manager.isRegFree(.r2));
490// {574 try expect(!function.register_manager.isRegFree(.r3));
491// const lock = function.register_manager.lockReg(.r1);575
492// defer if (lock) |reg| function.register_manager.unlockReg(reg);576 // Spill r3
493577 try function.register_manager.getReg(.r3, mock_instruction);
494// try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);578
495// }579 try expect(!function.register_manager.isRegAllocated(.r2));
496// try expect(!function.register_manager.lockedRegsExist());580 try expect(function.register_manager.isRegAllocated(.r3));
497581 try expect(function.register_manager.isRegFree(.r2));
498// try expect(function.register_manager.isRegAllocated(.r0));582 try expect(!function.register_manager.isRegFree(.r3));
499// try expect(function.register_manager.isRegAllocated(.r1));583 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r3}, function.spilled.items);
500// try expect(function.register_manager.isRegAllocated(.r2));584}
501// try expect(function.register_manager.isRegAllocated(.r3));
502//}
503
504//test "allocRegs: normal usage" {
505// // TODO: convert this into a decltest once that is supported
506
507// const allocator = std.testing.allocator;
508
509// var function = MockFunction2{
510// .allocator = allocator,
511// };
512// defer function.deinit();
513
514// {
515// const result_reg: MockRegister2 = .r1;
516
517// // The result register is known and fixed at this point, we
518// // don't want to accidentally allocate lhs or rhs to the
519// // result register, this is why we lock it.
520// //
521// // Using defer unlock right after lock is a good idea in
522// // most cases as you probably are using the locked registers
523// // in the remainder of this scope and don't need to use it
524// // after the end of this scope. However, in some situations,
525// // it may make sense to manually unlock registers before the
526// // end of the scope when you are certain that they don't
527// // contain any valuable data anymore and can be reused. For an
528// // example of that, see `selectively reducing register
529// // pressure`.
530// const lock = function.register_manager.lockReg(result_reg);
531// defer if (lock) |reg| function.register_manager.unlockReg(reg);
532
533// const regs = try function.register_manager.allocRegs(2, .{ null, null });
534// try function.genAdd(result_reg, regs[0], regs[1]);
535// }
536//}
537
538//test "allocRegs: selectively reducing register pressure" {
539// // TODO: convert this into a decltest once that is supported
540
541// const allocator = std.testing.allocator;
542
543// var function = MockFunction2{
544// .allocator = allocator,
545// };
546// defer function.deinit();
547
548// {
549// const result_reg: MockRegister2 = .r1;
550
551// const lock = function.register_manager.lockReg(result_reg);
552
553// // Here, we don't defer unlock because we manually unlock
554// // after genAdd
555// const regs = try function.register_manager.allocRegs(2, .{ null, null });
556
557// try function.genAdd(result_reg, regs[0], regs[1]);
558// function.register_manager.unlockReg(lock.?);
559
560// const extra_summand_reg = try function.register_manager.allocReg(null);
561// try function.genAdd(result_reg, result_reg, extra_summand_reg);
562// }
563//}
564
565//test "getReg" {
566// const allocator = std.testing.allocator;
567
568// var function = MockFunction1{
569// .allocator = allocator,
570// };
571// defer function.deinit();
572
573// const mock_instruction: Air.Inst.Index = 1;
574
575// try function.register_manager.getReg(.r3, mock_instruction);
576
577// try expect(!function.register_manager.isRegAllocated(.r2));
578// try expect(function.register_manager.isRegAllocated(.r3));
579// try expect(function.register_manager.isRegFree(.r2));
580// try expect(!function.register_manager.isRegFree(.r3));
581
582// // Spill r3
583// try function.register_manager.getReg(.r3, mock_instruction);
584
585// try expect(!function.register_manager.isRegAllocated(.r2));
586// try expect(function.register_manager.isRegAllocated(.r3));
587// try expect(function.register_manager.isRegFree(.r2));
588// try expect(!function.register_manager.isRegFree(.r3));
589// try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r3}, function.spilled.items);
590//}