mirror of
https://github.com/ziglang/zig.git
synced 2025-12-15 18:53:07 +00:00
Merge pull request #10832 from ziglang/x64-more-structs
stage2,x64: pass more tests with structs
This commit is contained in:
commit
2302ded951
@ -2036,16 +2036,60 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
|
||||
const mcv = try self.resolveInst(operand);
|
||||
const struct_ty = self.air.typeOf(operand);
|
||||
const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));
|
||||
const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));
|
||||
const struct_size = struct_ty.abiSize(self.target.*);
|
||||
const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
|
||||
const struct_field_ty = struct_ty.structFieldType(index);
|
||||
const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));
|
||||
const struct_field_size = struct_field_ty.abiSize(self.target.*);
|
||||
|
||||
switch (mcv) {
|
||||
.stack_offset => |off| {
|
||||
const stack_offset = off + struct_size - struct_field_offset - struct_field_size;
|
||||
const offset_to_field = struct_size - struct_field_offset - struct_field_size;
|
||||
const stack_offset = off + @intCast(i32, offset_to_field);
|
||||
break :result MCValue{ .stack_offset = stack_offset };
|
||||
},
|
||||
.register => |reg| {
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{reg});
|
||||
|
||||
const dst_mcv = blk: {
|
||||
if (self.reuseOperand(inst, operand, 0, mcv)) {
|
||||
break :blk mcv;
|
||||
} else {
|
||||
const dst_mcv = try self.copyToNewRegister(inst, Type.usize, .{ .register = reg.to64() });
|
||||
break :blk dst_mcv;
|
||||
}
|
||||
};
|
||||
|
||||
// Shift by struct_field_offset.
|
||||
const shift_amount = @intCast(u8, struct_field_offset * 8);
|
||||
if (shift_amount > 0) {
|
||||
if (shift_amount == 1) {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .shr,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = dst_mcv.register,
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
} else {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .shr,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = dst_mcv.register,
|
||||
.flags = 0b10,
|
||||
}).encode(),
|
||||
.data = .{ .imm = shift_amount },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Mask with reg.size() - struct_field_size
|
||||
const mask_shift = @intCast(u6, (64 - struct_field_ty.bitSize(self.target.*)));
|
||||
const mask = (~@as(u64, 0)) >> mask_shift;
|
||||
try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .immediate = mask });
|
||||
|
||||
break :result dst_mcv;
|
||||
},
|
||||
else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
|
||||
}
|
||||
};
|
||||
@ -3498,6 +3542,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
||||
}
|
||||
|
||||
fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
switch (mcv) {
|
||||
.dead => unreachable,
|
||||
.ptr_embedded_in_code => unreachable,
|
||||
@ -3521,7 +3566,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
|
||||
return self.genSetStack(ty, stack_offset, .{ .register = reg });
|
||||
},
|
||||
.immediate => |x_big| {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
const adj_off = stack_offset + @intCast(i32, abi_size);
|
||||
if (adj_off > 128) {
|
||||
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
|
||||
if (stack_offset > math.maxInt(i32)) {
|
||||
return self.fail("stack offset too large", .{});
|
||||
}
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
const adj_off = stack_offset + @intCast(i32, abi_size);
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
@ -3611,11 +3654,46 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
|
||||
.got_load,
|
||||
.direct_load,
|
||||
=> {
|
||||
if (ty.abiSize(self.target.*) <= 8) {
|
||||
if (abi_size <= 8) {
|
||||
const reg = try self.copyToTmpRegister(ty, mcv);
|
||||
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
|
||||
}
|
||||
return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
|
||||
|
||||
try self.register_manager.getReg(.rax, null);
|
||||
try self.register_manager.getReg(.rcx, null);
|
||||
|
||||
self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
|
||||
defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
|
||||
|
||||
const addr_reg: Register = blk: {
|
||||
switch (mcv) {
|
||||
.memory => |addr| {
|
||||
const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
|
||||
break :blk reg;
|
||||
},
|
||||
else => {
|
||||
return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
self.register_manager.freezeRegs(&.{addr_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{addr_reg});
|
||||
|
||||
const regs = try self.register_manager.allocRegs(2, .{ null, null });
|
||||
const count_reg = regs[0];
|
||||
const tmp_reg = regs[1];
|
||||
|
||||
// TODO allow for abi_size to be u64
|
||||
try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
|
||||
|
||||
return self.genInlineMemcpy(
|
||||
-(stack_offset + @intCast(i32, abi_size)),
|
||||
.rbp,
|
||||
addr_reg.to64(),
|
||||
count_reg.to64(),
|
||||
tmp_reg.to8(),
|
||||
);
|
||||
},
|
||||
.ptr_stack_offset => {
|
||||
const reg = try self.copyToTmpRegister(ty, mcv);
|
||||
@ -3627,7 +3705,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
|
||||
return;
|
||||
}
|
||||
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
if (abi_size <= 8) {
|
||||
const reg = try self.copyToTmpRegister(ty, mcv);
|
||||
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
|
||||
@ -4670,11 +4747,17 @@ fn parseRegName(name: []const u8) ?Register {
|
||||
|
||||
fn registerAlias(reg: Register, size_bytes: u32) Register {
|
||||
// For x86_64 we have to pick a smaller register alias depending on abi size.
|
||||
switch (size_bytes) {
|
||||
1 => return reg.to8(),
|
||||
2 => return reg.to16(),
|
||||
4 => return reg.to32(),
|
||||
8 => return reg.to64(),
|
||||
else => unreachable,
|
||||
if (size_bytes == 0) {
|
||||
unreachable; // should be comptime known
|
||||
} else if (size_bytes <= 1) {
|
||||
return reg.to8();
|
||||
} else if (size_bytes <= 2) {
|
||||
return reg.to16();
|
||||
} else if (size_bytes <= 4) {
|
||||
return reg.to32();
|
||||
} else if (size_bytes <= 8) {
|
||||
return reg.to64();
|
||||
} else {
|
||||
unreachable; // TODO handle floating-point registers
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +133,11 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
|
||||
.lea => try emit.mirLea(inst),
|
||||
.lea_pie => try emit.mirLeaPie(inst),
|
||||
|
||||
.shl => try emit.mirShift(.shl, inst),
|
||||
.sal => try emit.mirShift(.sal, inst),
|
||||
.shr => try emit.mirShift(.shr, inst),
|
||||
.sar => try emit.mirShift(.sar, inst),
|
||||
|
||||
.imul_complex => try emit.mirIMulComplex(inst),
|
||||
|
||||
.push => try emit.mirPushPop(.push, inst),
|
||||
@ -653,6 +658,31 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
|
||||
}
|
||||
|
||||
fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
|
||||
const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
|
||||
switch (ops.flags) {
|
||||
0b00 => {
|
||||
// sal reg1, 1
|
||||
// M1
|
||||
return lowerToM1Enc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
|
||||
},
|
||||
0b01 => {
|
||||
// sal reg1, .cl
|
||||
// MC
|
||||
return lowerToMcEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
|
||||
},
|
||||
0b10 => {
|
||||
// sal reg1, imm8
|
||||
// MI
|
||||
const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);
|
||||
return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);
|
||||
},
|
||||
0b11 => {
|
||||
return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
assert(tag == .imul_complex);
|
||||
@ -743,13 +773,13 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
emit.code,
|
||||
);
|
||||
const end_offset = emit.code.items.len;
|
||||
const reloc_type = switch (ops.flags) {
|
||||
0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
|
||||
0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
|
||||
else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
|
||||
};
|
||||
const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index;
|
||||
if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const reloc_type = switch (ops.flags) {
|
||||
0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
|
||||
0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
|
||||
else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
|
||||
};
|
||||
const decl = macho_file.active_decl.?;
|
||||
try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
|
||||
.offset = @intCast(u32, end_offset - 4),
|
||||
@ -1064,6 +1094,10 @@ const Tag = enum {
|
||||
setng,
|
||||
setnle,
|
||||
setg,
|
||||
shl,
|
||||
sal,
|
||||
shr,
|
||||
sar,
|
||||
|
||||
fn isSetCC(tag: Tag) bool {
|
||||
return switch (tag) {
|
||||
@ -1119,9 +1153,18 @@ const Encoding = enum {
|
||||
/// OP imm32
|
||||
i,
|
||||
|
||||
/// OP r/m64, 1
|
||||
m1,
|
||||
|
||||
/// OP r/m64, .cl
|
||||
mc,
|
||||
|
||||
/// OP r/m64, imm32
|
||||
mi,
|
||||
|
||||
/// OP r/m64, imm8
|
||||
mi8,
|
||||
|
||||
/// OP r/m64, r64
|
||||
mr,
|
||||
|
||||
@ -1230,12 +1273,25 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
|
||||
.ret_far => OpCode.oneByte(0xca),
|
||||
else => null,
|
||||
},
|
||||
.m1 => return switch (tag) {
|
||||
.shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1),
|
||||
else => null,
|
||||
},
|
||||
.mc => return switch (tag) {
|
||||
.shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3),
|
||||
else => null,
|
||||
},
|
||||
.mi => return switch (tag) {
|
||||
.adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81),
|
||||
.mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7),
|
||||
.@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
|
||||
else => null,
|
||||
},
|
||||
.mi8 => return switch (tag) {
|
||||
.adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83),
|
||||
.shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1),
|
||||
else => null,
|
||||
},
|
||||
.mr => return switch (tag) {
|
||||
.adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11),
|
||||
.add => OpCode.oneByte(if (is_one_byte) 0x00 else 0x01),
|
||||
@ -1331,6 +1387,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
|
||||
.setnle,
|
||||
.setg,
|
||||
=> 0x0,
|
||||
.shl,
|
||||
.sal,
|
||||
=> 0x4,
|
||||
.shr => 0x5,
|
||||
.sar => 0x7,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
@ -1528,8 +1589,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
|
||||
encoder.imm32(@bitCast(i32, imm));
|
||||
}
|
||||
|
||||
fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
|
||||
const opc = getOpCode(tag, .m, false).?;
|
||||
fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {
|
||||
const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
|
||||
const modrm_ext = getModRmExt(tag).?;
|
||||
switch (reg_or_mem) {
|
||||
.register => |reg| {
|
||||
@ -1537,11 +1598,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
|
||||
if (reg.size() == 16) {
|
||||
encoder.prefix16BitMode();
|
||||
}
|
||||
const wide = if (tag == .jmp_near) false else setRexWRegister(reg);
|
||||
encoder.rex(.{
|
||||
.w = switch (reg) {
|
||||
.ah, .bh, .ch, .dh => true,
|
||||
else => false,
|
||||
},
|
||||
.w = wide,
|
||||
.b = reg.isExtended(),
|
||||
});
|
||||
opc.encode(encoder);
|
||||
@ -1553,8 +1612,9 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
|
||||
encoder.prefix16BitMode();
|
||||
}
|
||||
if (mem_op.base) |base| {
|
||||
const wide = if (tag == .jmp_near) false else mem_op.ptr_size == .qword_ptr;
|
||||
encoder.rex(.{
|
||||
.w = false,
|
||||
.w = wide,
|
||||
.b = base.isExtended(),
|
||||
});
|
||||
}
|
||||
@ -1564,6 +1624,18 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToMxEnc(tag, reg_or_mem, .m, code);
|
||||
}
|
||||
|
||||
fn lowerToM1Enc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToMxEnc(tag, reg_or_mem, .m1, code);
|
||||
}
|
||||
|
||||
fn lowerToMcEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToMxEnc(tag, reg_or_mem, .mc, code);
|
||||
}
|
||||
|
||||
fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToTdFdEnc(tag, reg, moffs, code, true);
|
||||
}
|
||||
@ -1614,9 +1686,15 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) Inn
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
|
||||
fn lowerToMiXEnc(
|
||||
tag: Tag,
|
||||
reg_or_mem: RegisterOrMemory,
|
||||
imm: u32,
|
||||
enc: Encoding,
|
||||
code: *std.ArrayList(u8),
|
||||
) InnerError!void {
|
||||
const modrm_ext = getModRmExt(tag).?;
|
||||
const opc = getOpCode(tag, .mi, reg_or_mem.size() == 8).?;
|
||||
const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;
|
||||
switch (reg_or_mem) {
|
||||
.register => |dst_reg| {
|
||||
const encoder = try Encoder.init(code, 7);
|
||||
@ -1632,7 +1710,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr
|
||||
});
|
||||
opc.encode(encoder);
|
||||
encoder.modRm_direct(modrm_ext, dst_reg.lowId());
|
||||
encodeImm(encoder, imm, dst_reg.size());
|
||||
encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_reg.size());
|
||||
},
|
||||
.memory => |dst_mem| {
|
||||
const encoder = try Encoder.init(code, 12);
|
||||
@ -1651,11 +1729,19 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.Arr
|
||||
}
|
||||
opc.encode(encoder);
|
||||
dst_mem.encode(encoder, modrm_ext);
|
||||
encodeImm(encoder, imm, dst_mem.ptr_size.size());
|
||||
encodeImm(encoder, imm, if (enc == .mi8) 8 else dst_mem.ptr_size.size());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerToMiImm8Enc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u8, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToMiXEnc(tag, reg_or_mem, imm, .mi8, code);
|
||||
}
|
||||
|
||||
fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
|
||||
return lowerToMiXEnc(tag, reg_or_mem, imm, .mi, code);
|
||||
}
|
||||
|
||||
fn lowerToRmEnc(
|
||||
tag: Tag,
|
||||
reg: Register,
|
||||
@ -1902,6 +1988,9 @@ test "lower MI encoding" {
|
||||
emit.lowered(),
|
||||
"mov qword ptr [rcx*2 + 0x10000000], 0x10",
|
||||
);
|
||||
|
||||
try lowerToMiImm8Enc(.add, RegisterOrMemory.reg(.rax), 0x10, emit.code());
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", emit.lowered(), "add rax, 0x10");
|
||||
}
|
||||
|
||||
test "lower RM encoding" {
|
||||
@ -2100,6 +2189,41 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");
|
||||
}
|
||||
|
||||
test "lower M1 and MC encodings" {
|
||||
var emit = TestEmit.init();
|
||||
defer emit.deinit();
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12), emit.code());
|
||||
try expectEqualHexStrings("\x49\xD1\xE4", emit.lowered(), "sal r12, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12d), emit.code());
|
||||
try expectEqualHexStrings("\x41\xD1\xE4", emit.lowered(), "sal r12d, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12w), emit.code());
|
||||
try expectEqualHexStrings("\x66\x41\xD1\xE4", emit.lowered(), "sal r12w, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.r12b), emit.code());
|
||||
try expectEqualHexStrings("\x41\xD0\xE4", emit.lowered(), "sal r12b, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.rax), emit.code());
|
||||
try expectEqualHexStrings("\x48\xD1\xE0", emit.lowered(), "sal rax, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.reg(.eax), emit.code());
|
||||
try expectEqualHexStrings("\xD1\xE0", emit.lowered(), "sal eax, 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.mem(.qword_ptr, .{
|
||||
.disp = @bitCast(u32, @as(i32, -0x10)),
|
||||
.base = .rbp,
|
||||
}), emit.code());
|
||||
try expectEqualHexStrings("\x48\xD1\x65\xF0", emit.lowered(), "sal qword ptr [rbp - 0x10], 1");
|
||||
try lowerToM1Enc(.sal, RegisterOrMemory.mem(.dword_ptr, .{
|
||||
.disp = @bitCast(u32, @as(i32, -0x10)),
|
||||
.base = .rbp,
|
||||
}), emit.code());
|
||||
try expectEqualHexStrings("\xD1\x65\xF0", emit.lowered(), "sal dword ptr [rbp - 0x10], 1");
|
||||
|
||||
try lowerToMcEnc(.shr, RegisterOrMemory.reg(.r12), emit.code());
|
||||
try expectEqualHexStrings("\x49\xD3\xEC", emit.lowered(), "shr r12, cl");
|
||||
try lowerToMcEnc(.shr, RegisterOrMemory.reg(.rax), emit.code());
|
||||
try expectEqualHexStrings("\x48\xD3\xE8", emit.lowered(), "shr rax, cl");
|
||||
|
||||
try lowerToMcEnc(.sar, RegisterOrMemory.reg(.rsi), emit.code());
|
||||
try expectEqualHexStrings("\x48\xD3\xFE", emit.lowered(), "sar rsi, cl");
|
||||
}
|
||||
|
||||
test "lower O encoding" {
|
||||
var emit = TestEmit.init();
|
||||
defer emit.deinit();
|
||||
|
||||
@ -142,30 +142,6 @@ pub const Inst = struct {
|
||||
rcr_scale_dst,
|
||||
rcr_scale_imm,
|
||||
rcr_mem_index_imm,
|
||||
shl,
|
||||
shl_mem_imm,
|
||||
shl_scale_src,
|
||||
shl_scale_dst,
|
||||
shl_scale_imm,
|
||||
shl_mem_index_imm,
|
||||
sal,
|
||||
sal_mem_imm,
|
||||
sal_scale_src,
|
||||
sal_scale_dst,
|
||||
sal_scale_imm,
|
||||
sal_mem_index_imm,
|
||||
shr,
|
||||
shr_mem_imm,
|
||||
shr_scale_src,
|
||||
shr_scale_dst,
|
||||
shr_scale_imm,
|
||||
shr_mem_index_imm,
|
||||
sar,
|
||||
sar_mem_imm,
|
||||
sar_scale_src,
|
||||
sar_scale_dst,
|
||||
sar_scale_imm,
|
||||
sar_mem_index_imm,
|
||||
sbb,
|
||||
sbb_mem_imm,
|
||||
sbb_scale_src,
|
||||
@ -212,6 +188,37 @@ pub const Inst = struct {
|
||||
/// * `Data` contains `linker_sym_index`
|
||||
lea_pie,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0b00 reg1, 1
|
||||
/// 0b01 reg1, .cl
|
||||
/// 0b10 reg1, imm8
|
||||
/// Notes:
|
||||
/// * If flags == 0b10, uses `imm`.
|
||||
shl,
|
||||
shl_mem_imm,
|
||||
shl_scale_src,
|
||||
shl_scale_dst,
|
||||
shl_scale_imm,
|
||||
shl_mem_index_imm,
|
||||
sal,
|
||||
sal_mem_imm,
|
||||
sal_scale_src,
|
||||
sal_scale_dst,
|
||||
sal_scale_imm,
|
||||
sal_mem_index_imm,
|
||||
shr,
|
||||
shr_mem_imm,
|
||||
shr_scale_src,
|
||||
shr_scale_dst,
|
||||
shr_scale_imm,
|
||||
shr_mem_index_imm,
|
||||
sar,
|
||||
sar_mem_imm,
|
||||
sar_scale_src,
|
||||
sar_scale_dst,
|
||||
sar_scale_imm,
|
||||
sar_mem_index_imm,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0bX0 reg1
|
||||
/// 0bX1 [reg1 + imm32]
|
||||
|
||||
@ -372,7 +372,6 @@ pub fn generateSymbol(
|
||||
return Result{ .appended = {} };
|
||||
},
|
||||
.Struct => {
|
||||
// TODO debug info
|
||||
const struct_obj = typed_value.ty.castTag(.@"struct").?.data;
|
||||
if (struct_obj.layout == .Packed) {
|
||||
return Result{
|
||||
|
||||
@ -9,7 +9,7 @@ const maxInt = std.math.maxInt;
|
||||
top_level_field: i32,
|
||||
|
||||
test "top level fields" {
|
||||
if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
var instance = @This(){
|
||||
.top_level_field = 1234,
|
||||
@ -176,7 +176,7 @@ const MemberFnTestFoo = struct {
|
||||
};
|
||||
|
||||
test "call member function directly" {
|
||||
if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
const instance = MemberFnTestFoo{ .x = 1234 };
|
||||
const result = MemberFnTestFoo.member(instance);
|
||||
@ -184,7 +184,7 @@ test "call member function directly" {
|
||||
}
|
||||
|
||||
test "store member function in variable" {
|
||||
if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
const instance = MemberFnTestFoo{ .x = 1234 };
|
||||
const memberFn = MemberFnTestFoo.member;
|
||||
@ -206,7 +206,7 @@ const MemberFnRand = struct {
|
||||
};
|
||||
|
||||
test "return struct byval from function" {
|
||||
if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
const bar = makeBar2(1234, 5678);
|
||||
try expect(bar.y == 5678);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user