authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-08 10:02:06+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-08 10:02:06+01:00
log2302ded9511a6ee5bc3d672e6405df6a955b3622
tree206c999bcc8a2b6959c1372575849145dacf7ead
parentfc59a0406157dbd0704cf9f05cd04b6a8c87d7df
parent785bccd4cea63b3f2266e7f8928000e2d5110b3b
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10832 from ziglang/x64-more-structs

stage2,x64: pass more tests with structs

5 files changed, 273 insertions(+), 60 deletions(-)

src/arch/x86_64/CodeGen.zig+98-15
...@@ -2036,16 +2036,60 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2036,16 +2036,60 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2036 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2036 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2037 const mcv = try self.resolveInst(operand);2037 const mcv = try self.resolveInst(operand);
2038 const struct_ty = self.air.typeOf(operand);2038 const struct_ty = self.air.typeOf(operand);
2039 const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));2039 const struct_size = struct_ty.abiSize(self.target.*);
2040 const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));2040 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
2041 const struct_field_ty = struct_ty.structFieldType(index);2041 const struct_field_ty = struct_ty.structFieldType(index);
2042 const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));2042 const struct_field_size = struct_field_ty.abiSize(self.target.*);
20432043
2044 switch (mcv) {2044 switch (mcv) {
2045 .stack_offset => |off| {2045 .stack_offset => |off| {
2046 const stack_offset = off + struct_size - struct_field_offset - struct_field_size;2046 const offset_to_field = struct_size - struct_field_offset - struct_field_size;
2047 const stack_offset = off + @intCast(i32, offset_to_field);
2047 break :result MCValue{ .stack_offset = stack_offset };2048 break :result MCValue{ .stack_offset = stack_offset };
2048 },2049 },
2050 .register => |reg| {
2051 self.register_manager.freezeRegs(&.{reg});
2052 defer self.register_manager.unfreezeRegs(&.{reg});
2053
2054 const dst_mcv = blk: {
2055 if (self.reuseOperand(inst, operand, 0, mcv)) {
2056 break :blk mcv;
2057 } else {
2058 const dst_mcv = try self.copyToNewRegister(inst, Type.usize, .{ .register = reg.to64() });
2059 break :blk dst_mcv;
2060 }
2061 };
2062
2063 // Shift by struct_field_offset.
2064 const shift_amount = @intCast(u8, struct_field_offset * 8);
2065 if (shift_amount > 0) {
2066 if (shift_amount == 1) {
2067 _ = try self.addInst(.{
2068 .tag = .shr,
2069 .ops = (Mir.Ops{
2070 .reg1 = dst_mcv.register,
2071 }).encode(),
2072 .data = undefined,
2073 });
2074 } else {
2075 _ = try self.addInst(.{
2076 .tag = .shr,
2077 .ops = (Mir.Ops{
2078 .reg1 = dst_mcv.register,
2079 .flags = 0b10,
2080 }).encode(),
2081 .data = .{ .imm = shift_amount },
2082 });
2083 }
2084 }
2085
2086 // Mask with reg.size() - struct_field_size
2087 const mask_shift = @intCast(u6, (64 - struct_field_ty.bitSize(self.target.*)));
2088 const mask = (~@as(u64, 0)) >> mask_shift;
2089 try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .immediate = mask });
2090
2091 break :result dst_mcv;
2092 },
2049 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),2093 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
2050 }2094 }
2051 };2095 };
...@@ -3498,6 +3542,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3498,6 +3542,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3498}3542}
34993543
3500fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {3544fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {
3545 const abi_size = ty.abiSize(self.target.*);
3501 switch (mcv) {3546 switch (mcv) {
3502 .dead => unreachable,3547 .dead => unreachable,
3503 .ptr_embedded_in_code => unreachable,3548 .ptr_embedded_in_code => unreachable,
...@@ -3521,7 +3566,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3521,7 +3566,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3521 return self.genSetStack(ty, stack_offset, .{ .register = reg });3566 return self.genSetStack(ty, stack_offset, .{ .register = reg });
3522 },3567 },
3523 .immediate => |x_big| {3568 .immediate => |x_big| {
3524 const abi_size = ty.abiSize(self.target.*);
3525 const adj_off = stack_offset + @intCast(i32, abi_size);3569 const adj_off = stack_offset + @intCast(i32, abi_size);
3526 if (adj_off > 128) {3570 if (adj_off > 128) {
3527 return self.fail("TODO implement set stack variable with large stack offset", .{});3571 return self.fail("TODO implement set stack variable with large stack offset", .{});
...@@ -3594,7 +3638,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3594,7 +3638,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3594 if (stack_offset > math.maxInt(i32)) {3638 if (stack_offset > math.maxInt(i32)) {
3595 return self.fail("stack offset too large", .{});3639 return self.fail("stack offset too large", .{});
3596 }3640 }
3597 const abi_size = ty.abiSize(self.target.*);
3598 const adj_off = stack_offset + @intCast(i32, abi_size);3641 const adj_off = stack_offset + @intCast(i32, abi_size);
3599 _ = try self.addInst(.{3642 _ = try self.addInst(.{
3600 .tag = .mov,3643 .tag = .mov,
...@@ -3611,11 +3654,46 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3611,11 +3654,46 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3611 .got_load,3654 .got_load,
3612 .direct_load,3655 .direct_load,
3613 => {3656 => {
3614 if (ty.abiSize(self.target.*) <= 8) {3657 if (abi_size <= 8) {
3615 const reg = try self.copyToTmpRegister(ty, mcv);3658 const reg = try self.copyToTmpRegister(ty, mcv);
3616 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3659 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3617 }3660 }
3618 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});3661
3662 try self.register_manager.getReg(.rax, null);
3663 try self.register_manager.getReg(.rcx, null);
3664
3665 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3666 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
3667
3668 const addr_reg: Register = blk: {
3669 switch (mcv) {
3670 .memory => |addr| {
3671 const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
3672 break :blk reg;
3673 },
3674 else => {
3675 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
3676 },
3677 }
3678 };
3679
3680 self.register_manager.freezeRegs(&.{addr_reg});
3681 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3682
3683 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3684 const count_reg = regs[0];
3685 const tmp_reg = regs[1];
3686
3687 // TODO allow for abi_size to be u64
3688 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3689
3690 return self.genInlineMemcpy(
3691 -(stack_offset + @intCast(i32, abi_size)),
3692 .rbp,
3693 addr_reg.to64(),
3694 count_reg.to64(),
3695 tmp_reg.to8(),
3696 );
3619 },3697 },
3620 .ptr_stack_offset => {3698 .ptr_stack_offset => {
3621 const reg = try self.copyToTmpRegister(ty, mcv);3699 const reg = try self.copyToTmpRegister(ty, mcv);
...@@ -3627,7 +3705,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3627,7 +3705,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3627 return;3705 return;
3628 }3706 }
36293707
3630 const abi_size = ty.abiSize(self.target.*);
3631 if (abi_size <= 8) {3708 if (abi_size <= 8) {
3632 const reg = try self.copyToTmpRegister(ty, mcv);3709 const reg = try self.copyToTmpRegister(ty, mcv);
3633 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3710 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
...@@ -4670,11 +4747,17 @@ fn parseRegName(name: []const u8) ?Register {...@@ -4670,11 +4747,17 @@ fn parseRegName(name: []const u8) ?Register {
46704747
4671fn registerAlias(reg: Register, size_bytes: u32) Register {4748fn registerAlias(reg: Register, size_bytes: u32) Register {
4672 // For x86_64 we have to pick a smaller register alias depending on abi size.4749 // For x86_64 we have to pick a smaller register alias depending on abi size.
4673 switch (size_bytes) {4750 if (size_bytes == 0) {
4674 1 => return reg.to8(),4751 unreachable; // should be comptime known
4675 2 => return reg.to16(),4752 } else if (size_bytes <= 1) {
4676 4 => return reg.to32(),4753 return reg.to8();
4677 8 => return reg.to64(),4754 } else if (size_bytes <= 2) {
4678 else => unreachable,4755 return reg.to16();
4756 } else if (size_bytes <= 4) {
4757 return reg.to32();
4758 } else if (size_bytes <= 8) {
4759 return reg.to64();
4760 } else {
4761 unreachable; // TODO handle floating-point registers
4679 }4762 }
4680}4763}
src/arch/x86_64/Emit.zig+140-16
...@@ -133,6 +133,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -133,6 +133,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
133 .lea => try emit.mirLea(inst),133 .lea => try emit.mirLea(inst),
134 .lea_pie => try emit.mirLeaPie(inst),134 .lea_pie => try emit.mirLeaPie(inst),
135135
136 .shl => try emit.mirShift(.shl, inst),
137 .sal => try emit.mirShift(.sal, inst),
138 .shr => try emit.mirShift(.shr, inst),
139 .sar => try emit.mirShift(.sar, inst),
140
136 .imul_complex => try emit.mirIMulComplex(inst),141 .imul_complex => try emit.mirIMulComplex(inst),
137142
138 .push => try emit.mirPushPop(.push, inst),143 .push => try emit.mirPushPop(.push, inst),
...@@ -653,6 +658,31 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -653,6 +658,31 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
653 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);658 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
654}659}
655660
661fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
662 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
663 switch (ops.flags) {
664 0b00 => {
665 // sal reg1, 1
666 // M1
667 return lowerToM1Enc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
668 },
669 0b01 => {
670 // sal reg1, .cl
671 // MC
672 return lowerToMcEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
673 },
674 0b10 => {
675 // sal reg1, imm8
676 // MI
677 const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);
678 return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);
679 },
680 0b11 => {
681 return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});
682 },
683 }
684}
685
656fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {686fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
657 const tag = emit.mir.instructions.items(.tag)[inst];687 const tag = emit.mir.instructions.items(.tag)[inst];
658 assert(tag == .imul_complex);688 assert(tag == .imul_complex);
...@@ -743,13 +773,13 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -743,13 +773,13 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
743 emit.code,773 emit.code,
744 );774 );
745 const end_offset = emit.code.items.len;775 const end_offset = emit.code.items.len;
746 const reloc_type = switch (ops.flags) {
747 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
748 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
749 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
750 };
751 const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index;776 const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index;
752 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {777 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
778 const reloc_type = switch (ops.flags) {
779 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
780 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
781 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
782 };
753 const decl = macho_file.active_decl.?;783 const decl = macho_file.active_decl.?;
754 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{784 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
755 .offset = @intCast(u32, end_offset - 4),785 .offset = @intCast(u32, end_offset - 4),
...@@ -1064,6 +1094,10 @@ const Tag = enum {...@@ -1064,6 +1094,10 @@ const Tag = enum {
1064 setng,1094 setng,
1065 setnle,1095 setnle,
1066 setg,1096 setg,
1097 shl,
1098 sal,
1099 shr,
1100 sar,
10671101
1068 fn isSetCC(tag: Tag) bool {1102 fn isSetCC(tag: Tag) bool {
1069 return switch (tag) {1103 return switch (tag) {
...@@ -1119,9 +1153,18 @@ const Encoding = enum {...@@ -1119,9 +1153,18 @@ const Encoding = enum {
1119 /// OP imm321153 /// OP imm32
1120 i,1154 i,
11211155
1156 /// OP r/m64, 1
1157 m1,
1158
1159 /// OP r/m64, .cl
1160 mc,
1161
1122 /// OP r/m64, imm321162 /// OP r/m64, imm32
1123 mi,1163 mi,
11241164
1165 /// OP r/m64, imm8
1166 mi8,
1167
1125 /// OP r/m64, r641168 /// OP r/m64, r64
1126 mr,1169 mr,
11271170
...@@ -1230,12 +1273,25 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1230,12 +1273,25 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1230 .ret_far => OpCode.oneByte(0xca),1273 .ret_far => OpCode.oneByte(0xca),
1231 else => null,1274 else => null,
1232 },1275 },
1276 .m1 => return switch (tag) {
1277 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1),
1278 else => null,
1279 },
1280 .mc => return switch (tag) {
1281 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3),
1282 else => null,
1283 },
1233 .mi => return switch (tag) {1284 .mi => return switch (tag) {
1234 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81),1285 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81),
1235 .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7),1286 .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7),
1236 .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),1287 .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
1237 else => null,1288 else => null,
1238 },1289 },
1290 .mi8 => return switch (tag) {
1291 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83),
1292 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1),
1293 else => null,
1294 },
1239 .mr => return switch (tag) {1295 .mr => return switch (tag) {
1240 .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11),1296 .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11),
1241 .add => OpCode.oneByte(if (is_one_byte) 0x00 else 0x01),1297 .add => OpCode.oneByte(if (is_one_byte) 0x00 else 0x01),
...@@ -1331,6 +1387,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1331,6 +1387,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
1331 .setnle,1387 .setnle,
1332 .setg,1388 .setg,
1333 => 0x0,1389 => 0x0,
1390 .shl,
1391 .sal,
1392 => 0x4,
1393 .shr => 0x5,
1394 .sar => 0x7,
1334 else => null,1395 else => null,
1335 };1396 };
1336}1397}
...@@ -1528,8 +1589,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1528,8 +1589,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1528 encoder.imm32(@bitCast(i32, imm));1589 encoder.imm32(@bitCast(i32, imm));
1529}1590}
15301591
1531fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {1592fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {
1532 const opc = getOpCode(tag, .m, false).?;1593 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
1533 const modrm_ext = getModRmExt(tag).?;1594 const modrm_ext = getModRmExt(tag).?;
1534 switch (reg_or_mem) {1595 switch (reg_or_mem) {
1535 .register => |reg| {1596 .register => |reg| {
...@@ -1537,11 +1598,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))...@@ -1537,11 +1598,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
1537 if (reg.size() == 16) {1598 if (reg.size() == 16) {
1538 encoder.prefix16BitMode();1599 encoder.prefix16BitMode();
1539 }1600 }
1601 const wide = if (tag == .jmp_near) false else setRexWRegister(reg);
1540 encoder.rex(.{1602 encoder.rex(.{
1541 .w = switch (reg) {1603 .w = wide,
1542 .ah, .bh, .ch, .dh => true,
1543 else => false,
1544 },
1545 .b = reg.isExtended(),1604 .b = reg.isExtended(),
1546 });1605 });
1547 opc.encode(encoder);1606 opc.encode(encoder);
...@@ -1553,8 +1612,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))...@@ -1553,8 +1612,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
1553 encoder.prefix16BitMode();1612 encoder.prefix16BitMode();
1554 }1613 }
1555 if (mem_op.base) |base| {1614 if (mem_op.base) |base| {
1615 const wide = if (tag == .jmp_near) false else mem_op.ptr_size == .qword_ptr;
1556 encoder.rex(.{1616 encoder.rex(.{
1557 .w = false,1617 .w = wide,
1558 .b = base.isExtended(),1618 .b = base.isExtended(),
1559 });1619 });
1560 }1620 }
...@@ -1564,6 +1624,18 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))...@@ -1564,6 +1624,18 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
1564 }1624 }
1565}1625}
15661626
1627fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
1628 return lowerToMxEnc(tag, reg_or_mem, .m, code);
1629}
1630
1631fn lowerToM1Enc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
1632 return lowerToMxEnc(tag, reg_or_mem, .m1, code);
1633}
1634
1635fn lowerToMcEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
1636 return lowerToMxEnc(tag, reg_or_mem, .mc, code);
1637}
1638
1567fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) InnerError!void {1639fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
1568 return lowerToTdFdEnc(tag, reg, moffs, code, true);1640 return lowerToTdFdEnc(tag, reg, moffs, code, true);
1569}1641}
...@@ -1614,9 +1686,15 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) Inn...@@ -1614,9 +1686,15 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) Inn
1614 }1686 }
1615}1687}
16161688
1617fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) InnerError!void {1689fn lowerToMiXEnc(
1690 tag: Tag,
1691 reg_or_mem: RegisterOrMemory,
1692 imm: u32,
1693 enc: Encoding,
1694 code: *std.ArrayList(u8),
1695) InnerError!void {
1618 const modrm_ext = getModRmExt(tag).?;1696 const modrm_ext = getModRmExt(tag).?;
1619 const opc = getOpCode(tag, .mi, reg_or_mem.size() == 8).?;1697 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
1620 switch (reg_or_mem) {1698 switch (reg_or_mem) {
1621 .register => |dst_reg| {1699 .register => |dst_reg| {
1622 const encoder = try Encoder.init(code, 7);1700 const encoder = try Encoder.init(code, 7);
...@@ -1632,7 +1710,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr...@@ -1632,7 +1710,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr
1632 });1710 });
1633 opc.encode(encoder);1711 opc.encode(encoder);
1634 encoder.modRm_direct(modrm_ext, dst_reg.lowId());1712 encoder.modRm_direct(modrm_ext, dst_reg.lowId());
1635 encodeImm(encoder, imm, dst_reg.size());1713 encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_reg.size());
1636 },1714 },
1637 .memory => |dst_mem| {1715 .memory => |dst_mem| {
1638 const encoder = try Encoder.init(code, 12);1716 const encoder = try Encoder.init(code, 12);
...@@ -1651,11 +1729,19 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr...@@ -1651,11 +1729,19 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr
1651 }1729 }
1652 opc.encode(encoder);1730 opc.encode(encoder);
1653 dst_mem.encode(encoder, modrm_ext);1731 dst_mem.encode(encoder, modrm_ext);
1654 encodeImm(encoder, imm, dst_mem.ptr_size.size());1732 encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_mem.ptr_size.size());
1655 },1733 },
1656 }1734 }
1657}1735}
16581736
1737fn lowerToMiImm8Enc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u8, code: *std.ArrayList(u8)) InnerError!void {
1738 return lowerToMiXEnc(tag, reg_or_mem, imm, .mi8, code);
1739}
1740
1741fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1742 return lowerToMiXEnc(tag, reg_or_mem, imm, .mi, code);
1743}
1744
1659fn lowerToRmEnc(1745fn lowerToRmEnc(
1660 tag: Tag,1746 tag: Tag,
1661 reg: Register,1747 reg: Register,
...@@ -1902,6 +1988,9 @@ test "lower MI encoding" {...@@ -1902,6 +1988,9 @@ test "lower MI encoding" {
1902 emit.lowered(),1988 emit.lowered(),
1903 "mov qword ptr [rcx*2 + 0x10000000], 0x10",1989 "mov qword ptr [rcx*2 + 0x10000000], 0x10",
1904 );1990 );
1991
1992 try lowerToMiImm8Enc(.add, RegisterOrMemory.reg(.rax), 0x10, emit.code());
1993 try expectEqualHexStrings("\x48\x83\xC0\x10", emit.lowered(), "add rax, 0x10");
1905}1994}
19061995
1907test "lower RM encoding" {1996test "lower RM encoding" {
...@@ -2100,6 +2189,41 @@ test "lower M encoding" {...@@ -2100,6 +2189,41 @@ test "lower M encoding" {
2100 try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");2189 try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");
2101}2190}
21022191
2192test "lower M1 and MC encodings" {
2193 var emit = TestEmit.init();
2194 defer emit.deinit();
2195 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12), emit.code());
2196 try expectEqualHexStrings("\x49\xD1\xE4", emit.lowered(), "sal r12, 1");
2197 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12d), emit.code());
2198 try expectEqualHexStrings("\x41\xD1\xE4", emit.lowered(), "sal r12d, 1");
2199 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12w), emit.code());
2200 try expectEqualHexStrings("\x66\x41\xD1\xE4", emit.lowered(), "sal r12w, 1");
2201 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12b), emit.code());
2202 try expectEqualHexStrings("\x41\xD0\xE4", emit.lowered(), "sal r12b, 1");
2203 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.rax), emit.code());
2204 try expectEqualHexStrings("\x48\xD1\xE0", emit.lowered(), "sal rax, 1");
2205 try lowerToM1Enc(.sal, RegisterOrMemory.reg(.eax), emit.code());
2206 try expectEqualHexStrings("\xD1\xE0", emit.lowered(), "sal eax, 1");
2207 try lowerToM1Enc(.sal, RegisterOrMemory.mem(.qword_ptr, .{
2208 .disp = @bitCast(u32, @as(i32, -0x10)),
2209 .base = .rbp,
2210 }), emit.code());
2211 try expectEqualHexStrings("\x48\xD1\x65\xF0", emit.lowered(), "sal qword ptr [rbp - 0x10], 1");
2212 try lowerToM1Enc(.sal, RegisterOrMemory.mem(.dword_ptr, .{
2213 .disp = @bitCast(u32, @as(i32, -0x10)),
2214 .base = .rbp,
2215 }), emit.code());
2216 try expectEqualHexStrings("\xD1\x65\xF0", emit.lowered(), "sal dword ptr [rbp - 0x10], 1");
2217
2218 try lowerToMcEnc(.shr, RegisterOrMemory.reg(.r12), emit.code());
2219 try expectEqualHexStrings("\x49\xD3\xEC", emit.lowered(), "shr r12, cl");
2220 try lowerToMcEnc(.shr, RegisterOrMemory.reg(.rax), emit.code());
2221 try expectEqualHexStrings("\x48\xD3\xE8", emit.lowered(), "shr rax, cl");
2222
2223 try lowerToMcEnc(.sar, RegisterOrMemory.reg(.rsi), emit.code());
2224 try expectEqualHexStrings("\x48\xD3\xFE", emit.lowered(), "sar rsi, cl");
2225}
2226
2103test "lower O encoding" {2227test "lower O encoding" {
2104 var emit = TestEmit.init();2228 var emit = TestEmit.init();
2105 defer emit.deinit();2229 defer emit.deinit();
src/arch/x86_64/Mir.zig+31-24
...@@ -142,30 +142,6 @@ pub const Inst = struct {...@@ -142,30 +142,6 @@ pub const Inst = struct {
142 rcr_scale_dst,142 rcr_scale_dst,
143 rcr_scale_imm,143 rcr_scale_imm,
144 rcr_mem_index_imm,144 rcr_mem_index_imm,
145 shl,
146 shl_mem_imm,
147 shl_scale_src,
148 shl_scale_dst,
149 shl_scale_imm,
150 shl_mem_index_imm,
151 sal,
152 sal_mem_imm,
153 sal_scale_src,
154 sal_scale_dst,
155 sal_scale_imm,
156 sal_mem_index_imm,
157 shr,
158 shr_mem_imm,
159 shr_scale_src,
160 shr_scale_dst,
161 shr_scale_imm,
162 shr_mem_index_imm,
163 sar,
164 sar_mem_imm,
165 sar_scale_src,
166 sar_scale_dst,
167 sar_scale_imm,
168 sar_mem_index_imm,
169 sbb,145 sbb,
170 sbb_mem_imm,146 sbb_mem_imm,
171 sbb_scale_src,147 sbb_scale_src,
...@@ -212,6 +188,37 @@ pub const Inst = struct {...@@ -212,6 +188,37 @@ pub const Inst = struct {
212 /// * `Data` contains `linker_sym_index` 188 /// * `Data` contains `linker_sym_index`
213 lea_pie,189 lea_pie,
214190
191 /// ops flags: form:
192 /// 0b00 reg1, 1
193 /// 0b01 reg1, .cl
194 /// 0b10 reg1, imm8
195 /// Notes:
196 /// * If flags == 0b10, uses `imm`.
197 shl,
198 shl_mem_imm,
199 shl_scale_src,
200 shl_scale_dst,
201 shl_scale_imm,
202 shl_mem_index_imm,
203 sal,
204 sal_mem_imm,
205 sal_scale_src,
206 sal_scale_dst,
207 sal_scale_imm,
208 sal_mem_index_imm,
209 shr,
210 shr_mem_imm,
211 shr_scale_src,
212 shr_scale_dst,
213 shr_scale_imm,
214 shr_mem_index_imm,
215 sar,
216 sar_mem_imm,
217 sar_scale_src,
218 sar_scale_dst,
219 sar_scale_imm,
220 sar_mem_index_imm,
221
215 /// ops flags: form:222 /// ops flags: form:
216 /// 0bX0 reg1223 /// 0bX0 reg1
217 /// 0bX1 [reg1 + imm32]224 /// 0bX1 [reg1 + imm32]
src/codegen.zig-1
...@@ -372,7 +372,6 @@ pub fn generateSymbol(...@@ -372,7 +372,6 @@ pub fn generateSymbol(
372 return Result{ .appended = {} };372 return Result{ .appended = {} };
373 },373 },
374 .Struct => {374 .Struct => {
375 // TODO debug info
376 const struct_obj = typed_value.ty.castTag(.@"struct").?.data;375 const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
377 if (struct_obj.layout == .Packed) {376 if (struct_obj.layout == .Packed) {
378 return Result{377 return Result{
test/behavior/struct.zig+4-4
...@@ -9,7 +9,7 @@ const maxInt = std.math.maxInt;...@@ -9,7 +9,7 @@ const maxInt = std.math.maxInt;
9top_level_field: i32,9top_level_field: i32,
1010
11test "top level fields" {11test "top level fields" {
12 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1313
14 var instance = @This(){14 var instance = @This(){
15 .top_level_field = 1234,15 .top_level_field = 1234,
...@@ -176,7 +176,7 @@ const MemberFnTestFoo = struct {...@@ -176,7 +176,7 @@ const MemberFnTestFoo = struct {
176};176};
177177
178test "call member function directly" {178test "call member function directly" {
179 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
180180
181 const instance = MemberFnTestFoo{ .x = 1234 };181 const instance = MemberFnTestFoo{ .x = 1234 };
182 const result = MemberFnTestFoo.member(instance);182 const result = MemberFnTestFoo.member(instance);
...@@ -184,7 +184,7 @@ test "call member function directly" {...@@ -184,7 +184,7 @@ test "call member function directly" {
184}184}
185185
186test "store member function in variable" {186test "store member function in variable" {
187 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
188188
189 const instance = MemberFnTestFoo{ .x = 1234 };189 const instance = MemberFnTestFoo{ .x = 1234 };
190 const memberFn = MemberFnTestFoo.member;190 const memberFn = MemberFnTestFoo.member;
...@@ -206,7 +206,7 @@ const MemberFnRand = struct {...@@ -206,7 +206,7 @@ const MemberFnRand = struct {
206};206};
207207
208test "return struct byval from function" {208test "return struct byval from function" {
209 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210210
211 const bar = makeBar2(1234, 5678);211 const bar = makeBar2(1234, 5678);
212 try expect(bar.y == 5678);212 try expect(bar.y == 5678);