mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 08:45:52 +00:00
stage2: refactor handling of immediates in x86_64 backend
Fixes issues with incorrect operand sizes in a handful of cases and allows for usage of differently sized integers in Zig sources.
This commit is contained in:
parent
a5c7742ba6
commit
4d4bbd7624
@ -497,14 +497,14 @@ fn gen(self: *Self) InnerError!void {
|
|||||||
.ops = (Mir.Ops{
|
.ops = (Mir.Ops{
|
||||||
.reg1 = .rsp,
|
.reg1 = .rsp,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment },
|
.data = .{ .imm = @bitCast(u32, @intCast(i32, aligned_stack_end) + stack_adjustment) },
|
||||||
});
|
});
|
||||||
self.mir_instructions.set(backpatch_stack_add, .{
|
self.mir_instructions.set(backpatch_stack_add, .{
|
||||||
.tag = .add,
|
.tag = .add,
|
||||||
.ops = (Mir.Ops{
|
.ops = (Mir.Ops{
|
||||||
.reg1 = .rsp,
|
.reg1 = .rsp,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment },
|
.data = .{ .imm = @bitCast(u32, @intCast(i32, aligned_stack_end) + stack_adjustment) },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1347,7 +1347,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
.reg2 = .rbp,
|
.reg2 = .rbp,
|
||||||
.flags = 0b01,
|
.flags = 0b01,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, off + 16) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },
|
||||||
});
|
});
|
||||||
// add addr, offset
|
// add addr, offset
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
@ -1555,7 +1555,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||||||
try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
|
try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
|
||||||
|
|
||||||
return self.genInlineMemcpy(
|
return self.genInlineMemcpy(
|
||||||
-@intCast(i32, off + abi_size),
|
@bitCast(u32, -@intCast(i32, off + abi_size)),
|
||||||
registerAlias(addr_reg, @divExact(reg.size(), 8)),
|
registerAlias(addr_reg, @divExact(reg.size(), 8)),
|
||||||
count_reg.to64(),
|
count_reg.to64(),
|
||||||
tmp_reg.to8(),
|
tmp_reg.to8(),
|
||||||
@ -1637,7 +1637,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
|||||||
// introduce new MIR tag specifically for mov [reg + 0], imm
|
// introduce new MIR tag specifically for mov [reg + 0], imm
|
||||||
const payload = try self.addExtra(Mir.ImmPair{
|
const payload = try self.addExtra(Mir.ImmPair{
|
||||||
.dest_off = 0,
|
.dest_off = 0,
|
||||||
.operand = @bitCast(i32, @intCast(u32, imm)),
|
.operand = @truncate(u32, imm),
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .mov_mem_imm,
|
.tag = .mov_mem_imm,
|
||||||
@ -1872,7 +1872,7 @@ fn genBinMathOpMir(
|
|||||||
.ops = (Mir.Ops{
|
.ops = (Mir.Ops{
|
||||||
.reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
|
.reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, imm) },
|
.data = .{ .imm = @truncate(u32, imm) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.embedded_in_code, .memory => {
|
.embedded_in_code, .memory => {
|
||||||
@ -1891,7 +1891,7 @@ fn genBinMathOpMir(
|
|||||||
.reg2 = .rbp,
|
.reg2 = .rbp,
|
||||||
.flags = 0b01,
|
.flags = 0b01,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, adj_off) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.compare_flags_unsigned => {
|
.compare_flags_unsigned => {
|
||||||
@ -1926,7 +1926,7 @@ fn genBinMathOpMir(
|
|||||||
.reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
|
.reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
|
||||||
.flags = 0b10,
|
.flags = 0b10,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, adj_off) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.immediate => |imm| {
|
.immediate => |imm| {
|
||||||
@ -1947,8 +1947,8 @@ fn genBinMathOpMir(
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
const payload = try self.addExtra(Mir.ImmPair{
|
const payload = try self.addExtra(Mir.ImmPair{
|
||||||
.dest_off = -@intCast(i32, adj_off),
|
.dest_off = @bitCast(u32, -@intCast(i32, adj_off)),
|
||||||
.operand = @bitCast(i32, @intCast(u32, imm)),
|
.operand = @truncate(u32, imm),
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = tag,
|
.tag = tag,
|
||||||
@ -2015,7 +2015,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
|
|||||||
.reg2 = dst_reg.to32(),
|
.reg2 = dst_reg.to32(),
|
||||||
.flags = 0b10,
|
.flags = 0b10,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, imm) },
|
.data = .{ .imm = @truncate(u32, imm) },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// TODO verify we don't spill and assign to the same register as dst_mcv
|
// TODO verify we don't spill and assign to the same register as dst_mcv
|
||||||
@ -2088,7 +2088,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
const mcv = self.args[arg_index];
|
const mcv = self.args[arg_index];
|
||||||
const payload = try self.addExtra(Mir.ArgDbgInfo{
|
const payload = try self.addExtra(Mir.ArgDbgInfo{
|
||||||
.air_inst = inst,
|
.air_inst = inst,
|
||||||
.arg_index = @intCast(u32, arg_index), // TODO can arg_index: u32?
|
.arg_index = @truncate(u32, arg_index), // TODO can arg_index: u32?
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .arg_dbg_info,
|
.tag = .arg_dbg_info,
|
||||||
@ -2196,7 +2196,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
.ops = (Mir.Ops{
|
.ops = (Mir.Ops{
|
||||||
.flags = 0b01,
|
.flags = 0b01,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @bitCast(i32, got_addr) },
|
.data = .{ .imm = @truncate(u32, got_addr) },
|
||||||
});
|
});
|
||||||
} else if (func_value.castTag(.extern_fn)) |_| {
|
} else if (func_value.castTag(.extern_fn)) |_| {
|
||||||
return self.fail("TODO implement calling extern functions", .{});
|
return self.fail("TODO implement calling extern functions", .{});
|
||||||
@ -3121,8 +3121,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
// offset from rbp, which is at the top of the stack frame.
|
// offset from rbp, which is at the top of the stack frame.
|
||||||
// mov [rbp+offset], immediate
|
// mov [rbp+offset], immediate
|
||||||
const payload = try self.addExtra(Mir.ImmPair{
|
const payload = try self.addExtra(Mir.ImmPair{
|
||||||
.dest_off = -@intCast(i32, adj_off),
|
.dest_off = @bitCast(u32, -@intCast(i32, adj_off)),
|
||||||
.operand = @bitCast(i32, @intCast(u32, x_big)),
|
.operand = @truncate(u32, x_big),
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .mov_mem_imm,
|
.tag = .mov_mem_imm,
|
||||||
@ -3147,8 +3147,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
// insted just use two 32 bit writes to avoid register allocation
|
// insted just use two 32 bit writes to avoid register allocation
|
||||||
{
|
{
|
||||||
const payload = try self.addExtra(Mir.ImmPair{
|
const payload = try self.addExtra(Mir.ImmPair{
|
||||||
.dest_off = negative_offset + 4,
|
.dest_off = @bitCast(u32, negative_offset + 4),
|
||||||
.operand = @bitCast(i32, @truncate(u32, x_big >> 32)),
|
.operand = @truncate(u32, x_big >> 32),
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .mov_mem_imm,
|
.tag = .mov_mem_imm,
|
||||||
@ -3161,8 +3161,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
const payload = try self.addExtra(Mir.ImmPair{
|
const payload = try self.addExtra(Mir.ImmPair{
|
||||||
.dest_off = negative_offset,
|
.dest_off = @bitCast(u32, negative_offset),
|
||||||
.operand = @bitCast(i32, @truncate(u32, x_big)),
|
.operand = @truncate(u32, x_big),
|
||||||
});
|
});
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .mov_mem_imm,
|
.tag = .mov_mem_imm,
|
||||||
@ -3192,7 +3192,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
.reg2 = registerAlias(reg, @intCast(u32, abi_size)),
|
.reg2 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||||
.flags = 0b10,
|
.flags = 0b10,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, adj_off) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.memory, .embedded_in_code => {
|
.memory, .embedded_in_code => {
|
||||||
@ -3228,14 +3228,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
.reg1 = addr_reg.to64(),
|
.reg1 = addr_reg.to64(),
|
||||||
.reg2 = .rbp,
|
.reg2 = .rbp,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, off + abi_size) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, off + abi_size)) },
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO allow for abi_size to be u64
|
// TODO allow for abi_size to be u64
|
||||||
try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
|
try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
|
||||||
|
|
||||||
return self.genInlineMemcpy(
|
return self.genInlineMemcpy(
|
||||||
-@intCast(i32, stack_offset + abi_size),
|
@bitCast(u32, -@intCast(i32, stack_offset + abi_size)),
|
||||||
addr_reg.to64(),
|
addr_reg.to64(),
|
||||||
count_reg.to64(),
|
count_reg.to64(),
|
||||||
tmp_reg.to8(),
|
tmp_reg.to8(),
|
||||||
@ -3246,7 +3246,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||||||
|
|
||||||
fn genInlineMemcpy(
|
fn genInlineMemcpy(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
stack_offset: i32,
|
stack_offset: u32,
|
||||||
addr_reg: Register,
|
addr_reg: Register,
|
||||||
count_reg: Register,
|
count_reg: Register,
|
||||||
tmp_reg: Register,
|
tmp_reg: Register,
|
||||||
@ -3361,7 +3361,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||||||
.reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)),
|
.reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)),
|
||||||
.reg2 = .rbp,
|
.reg2 = .rbp,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, off) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.ptr_embedded_in_code => unreachable,
|
.ptr_embedded_in_code => unreachable,
|
||||||
@ -3426,7 +3426,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||||||
.ops = (Mir.Ops{
|
.ops = (Mir.Ops{
|
||||||
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
|
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, x) },
|
.data = .{ .imm = @truncate(u32, x) },
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3482,7 +3482,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||||||
.reg1 = reg,
|
.reg1 = reg,
|
||||||
.flags = 0b10,
|
.flags = 0b10,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .got_entry = @intCast(u32, x) },
|
.data = .{ .got_entry = @truncate(u32, x) },
|
||||||
});
|
});
|
||||||
// MOV reg, [reg]
|
// MOV reg, [reg]
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
@ -3502,7 +3502,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||||||
.reg1 = reg,
|
.reg1 = reg,
|
||||||
.flags = 0b01,
|
.flags = 0b01,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = @intCast(i32, x) },
|
.data = .{ .imm = @truncate(u32, x) },
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// If this is RAX, we can use a direct load.
|
// If this is RAX, we can use a direct load.
|
||||||
@ -3561,7 +3561,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||||||
.reg2 = .rbp,
|
.reg2 = .rbp,
|
||||||
.flags = 0b01,
|
.flags = 0b01,
|
||||||
}).encode(),
|
}).encode(),
|
||||||
.data = .{ .imm = -@intCast(i32, off) },
|
.data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -483,17 +483,26 @@ inline fn setRexWRegister(reg: Register) bool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn immOpSize(imm: i64) u8 {
|
inline fn immOpSize(u_imm: u32) u8 {
|
||||||
blk: {
|
const imm = @bitCast(i32, u_imm);
|
||||||
_ = math.cast(i8, imm) catch break :blk;
|
if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
blk: {
|
if (math.minInt(i16) <= imm and imm <= math.maxInt(i16)) {
|
||||||
_ = math.cast(i16, imm) catch break :blk;
|
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
blk: {
|
return 32;
|
||||||
_ = math.cast(i32, imm) catch break :blk;
|
}
|
||||||
|
|
||||||
|
inline fn imm64OpSize(u_imm: u64) u8 {
|
||||||
|
const imm = @bitCast(i64, u_imm);
|
||||||
|
if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
if (math.minInt(i16) <= imm and imm <= math.maxInt(i16)) {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
return 64;
|
return 64;
|
||||||
@ -560,10 +569,10 @@ fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
|
|||||||
const tag = isel.mir.instructions.items(.tag)[inst];
|
const tag = isel.mir.instructions.items(.tag)[inst];
|
||||||
assert(tag == .movabs);
|
assert(tag == .movabs);
|
||||||
const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
|
const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
|
||||||
const imm: i64 = if (ops.reg1.size() == 64) blk: {
|
const imm: u64 = if (ops.reg1.size() == 64) blk: {
|
||||||
const payload = isel.mir.instructions.items(.data)[inst].payload;
|
const payload = isel.mir.instructions.items(.data)[inst].payload;
|
||||||
const imm = isel.mir.extraData(Mir.Imm64, payload).data;
|
const imm = isel.mir.extraData(Mir.Imm64, payload).data;
|
||||||
break :blk @bitCast(i64, imm.decode());
|
break :blk imm.decode();
|
||||||
} else isel.mir.instructions.items(.data)[inst].imm;
|
} else isel.mir.instructions.items(.data)[inst].imm;
|
||||||
if (ops.flags == 0b00) {
|
if (ops.flags == 0b00) {
|
||||||
// movabs reg, imm64
|
// movabs reg, imm64
|
||||||
@ -1233,7 +1242,7 @@ const ScaleIndex = struct {
|
|||||||
const Memory = struct {
|
const Memory = struct {
|
||||||
base: ?Register,
|
base: ?Register,
|
||||||
rip: bool = false,
|
rip: bool = false,
|
||||||
disp: i32,
|
disp: u32,
|
||||||
ptr_size: PtrSize,
|
ptr_size: PtrSize,
|
||||||
scale_index: ?ScaleIndex = null,
|
scale_index: ?ScaleIndex = null,
|
||||||
|
|
||||||
@ -1283,7 +1292,7 @@ const Memory = struct {
|
|||||||
} else {
|
} else {
|
||||||
encoder.sib_baseDisp8(dst);
|
encoder.sib_baseDisp8(dst);
|
||||||
}
|
}
|
||||||
encoder.disp8(@intCast(i8, mem_op.disp));
|
encoder.disp8(@bitCast(i8, @truncate(u8, mem_op.disp)));
|
||||||
} else {
|
} else {
|
||||||
encoder.modRm_SIBDisp32(src);
|
encoder.modRm_SIBDisp32(src);
|
||||||
if (mem_op.scale_index) |si| {
|
if (mem_op.scale_index) |si| {
|
||||||
@ -1291,17 +1300,17 @@ const Memory = struct {
|
|||||||
} else {
|
} else {
|
||||||
encoder.sib_baseDisp32(dst);
|
encoder.sib_baseDisp32(dst);
|
||||||
}
|
}
|
||||||
encoder.disp32(mem_op.disp);
|
encoder.disp32(@bitCast(i32, mem_op.disp));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mem_op.disp == 0) {
|
if (mem_op.disp == 0) {
|
||||||
encoder.modRm_indirectDisp0(src, dst);
|
encoder.modRm_indirectDisp0(src, dst);
|
||||||
} else if (immOpSize(mem_op.disp) == 8) {
|
} else if (immOpSize(mem_op.disp) == 8) {
|
||||||
encoder.modRm_indirectDisp8(src, dst);
|
encoder.modRm_indirectDisp8(src, dst);
|
||||||
encoder.disp8(@intCast(i8, mem_op.disp));
|
encoder.disp8(@bitCast(i8, @truncate(u8, mem_op.disp)));
|
||||||
} else {
|
} else {
|
||||||
encoder.modRm_indirectDisp32(src, dst);
|
encoder.modRm_indirectDisp32(src, dst);
|
||||||
encoder.disp32(mem_op.disp);
|
encoder.disp32(@bitCast(i32, mem_op.disp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1315,16 +1324,16 @@ const Memory = struct {
|
|||||||
encoder.sib_disp32();
|
encoder.sib_disp32();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
encoder.disp32(mem_op.disp);
|
encoder.disp32(@bitCast(i32, mem_op.disp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn encodeImm(encoder: Encoder, imm: i32, size: u64) void {
|
fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
8 => encoder.imm8(@intCast(i8, imm)),
|
8 => encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
|
||||||
16 => encoder.imm16(@intCast(i16, imm)),
|
16 => encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
|
||||||
32, 64 => encoder.imm32(imm),
|
32, 64 => encoder.imm32(@bitCast(i32, imm)),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1338,7 +1347,7 @@ const RegisterOrMemory = union(enum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mem(ptr_size: Memory.PtrSize, args: struct {
|
fn mem(ptr_size: Memory.PtrSize, args: struct {
|
||||||
disp: i32,
|
disp: u32,
|
||||||
base: ?Register = null,
|
base: ?Register = null,
|
||||||
scale_index: ?ScaleIndex = null,
|
scale_index: ?ScaleIndex = null,
|
||||||
}) RegisterOrMemory {
|
}) RegisterOrMemory {
|
||||||
@ -1352,7 +1361,7 @@ const RegisterOrMemory = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory {
|
fn rip(ptr_size: Memory.PtrSize, disp: u32) RegisterOrMemory {
|
||||||
return .{
|
return .{
|
||||||
.memory = .{
|
.memory = .{
|
||||||
.base = null,
|
.base = null,
|
||||||
@ -1377,12 +1386,12 @@ fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) LoweringError!void {
|
|||||||
opc.encode(encoder);
|
opc.encode(encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
if (tag == .ret_far or tag == .ret_near) {
|
if (tag == .ret_far or tag == .ret_near) {
|
||||||
const encoder = try Encoder.init(code, 3);
|
const encoder = try Encoder.init(code, 3);
|
||||||
const opc = getOpCode(tag, .i, false).?;
|
const opc = getOpCode(tag, .i, false).?;
|
||||||
opc.encode(encoder);
|
opc.encode(encoder);
|
||||||
encoder.imm16(@intCast(i16, imm));
|
encoder.imm16(@bitCast(i16, @truncate(u16, imm)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;
|
const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;
|
||||||
@ -1410,11 +1419,11 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!
|
|||||||
opc.encodeWithReg(encoder, reg);
|
opc.encodeWithReg(encoder, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
const opc = getOpCode(tag, .d, false).?;
|
const opc = getOpCode(tag, .d, false).?;
|
||||||
const encoder = try Encoder.init(code, 6);
|
const encoder = try Encoder.init(code, 6);
|
||||||
opc.encode(encoder);
|
opc.encode(encoder);
|
||||||
encoder.imm32(imm);
|
encoder.imm32(@bitCast(i32, imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
@ -1467,19 +1476,19 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToTdEnc(tag: Tag, moffs: i64, reg: Register, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToTdEnc(tag: Tag, moffs: u64, reg: Register, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
return lowerToTdFdEnc(tag, reg, moffs, code, true);
|
return lowerToTdFdEnc(tag, reg, moffs, code, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
return lowerToTdFdEnc(tag, reg, moffs, code, false);
|
return lowerToTdFdEnc(tag, reg, moffs, code, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), td: bool) LoweringError!void {
|
fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) LoweringError!void {
|
||||||
if (reg.lowId() != Register.rax.lowId()) {
|
if (reg.lowId() != Register.rax.lowId()) {
|
||||||
return error.RaxOperandExpected;
|
return error.RaxOperandExpected;
|
||||||
}
|
}
|
||||||
if (reg.size() != immOpSize(moffs)) {
|
if (reg.size() != imm64OpSize(moffs)) {
|
||||||
return error.OperandSizeMismatch;
|
return error.OperandSizeMismatch;
|
||||||
}
|
}
|
||||||
const opc = if (td)
|
const opc = if (td)
|
||||||
@ -1495,27 +1504,16 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
|
|||||||
});
|
});
|
||||||
opc.encode(encoder);
|
opc.encode(encoder);
|
||||||
switch (reg.size()) {
|
switch (reg.size()) {
|
||||||
8 => {
|
8 => encoder.imm8(@bitCast(i8, @truncate(u8, moffs))),
|
||||||
const moffs8 = try math.cast(i8, moffs);
|
16 => encoder.imm16(@bitCast(i16, @truncate(u16, moffs))),
|
||||||
encoder.imm8(moffs8);
|
32 => encoder.imm32(@bitCast(i32, @truncate(u32, moffs))),
|
||||||
},
|
64 => encoder.imm64(moffs),
|
||||||
16 => {
|
|
||||||
const moffs16 = try math.cast(i16, moffs);
|
|
||||||
encoder.imm16(moffs16);
|
|
||||||
},
|
|
||||||
32 => {
|
|
||||||
const moffs32 = try math.cast(i32, moffs);
|
|
||||||
encoder.imm32(moffs32);
|
|
||||||
},
|
|
||||||
64 => {
|
|
||||||
encoder.imm64(@bitCast(u64, moffs));
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
if (reg.size() != immOpSize(imm)) {
|
if (reg.size() != imm64OpSize(imm)) {
|
||||||
return error.OperandSizeMismatch;
|
return error.OperandSizeMismatch;
|
||||||
}
|
}
|
||||||
const opc = getOpCode(tag, .oi, reg.size() == 8).?;
|
const opc = getOpCode(tag, .oi, reg.size() == 8).?;
|
||||||
@ -1529,26 +1527,15 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Low
|
|||||||
});
|
});
|
||||||
opc.encodeWithReg(encoder, reg);
|
opc.encodeWithReg(encoder, reg);
|
||||||
switch (reg.size()) {
|
switch (reg.size()) {
|
||||||
8 => {
|
8 => encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
|
||||||
const imm8 = try math.cast(i8, imm);
|
16 => encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
|
||||||
encoder.imm8(imm8);
|
32 => encoder.imm32(@bitCast(i32, @truncate(u32, imm))),
|
||||||
},
|
64 => encoder.imm64(imm),
|
||||||
16 => {
|
|
||||||
const imm16 = try math.cast(i16, imm);
|
|
||||||
encoder.imm16(imm16);
|
|
||||||
},
|
|
||||||
32 => {
|
|
||||||
const imm32 = try math.cast(i32, imm);
|
|
||||||
encoder.imm32(imm32);
|
|
||||||
},
|
|
||||||
64 => {
|
|
||||||
encoder.imm64(@bitCast(u64, imm));
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.ArrayList(u8)) LoweringError!void {
|
fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: u32, code: *std.ArrayList(u8)) LoweringError!void {
|
||||||
const modrm_ext = getModRmExt(tag).?;
|
const modrm_ext = getModRmExt(tag).?;
|
||||||
switch (reg_or_mem) {
|
switch (reg_or_mem) {
|
||||||
.register => |dst_reg| {
|
.register => |dst_reg| {
|
||||||
@ -1700,7 +1687,7 @@ fn lowerToRmiEnc(
|
|||||||
tag: Tag,
|
tag: Tag,
|
||||||
reg: Register,
|
reg: Register,
|
||||||
reg_or_mem: RegisterOrMemory,
|
reg_or_mem: RegisterOrMemory,
|
||||||
imm: i32,
|
imm: u32,
|
||||||
code: *std.ArrayList(u8),
|
code: *std.ArrayList(u8),
|
||||||
) LoweringError!void {
|
) LoweringError!void {
|
||||||
if (reg.size() == 8) {
|
if (reg.size() == 8) {
|
||||||
@ -1804,7 +1791,10 @@ test "lower MI encoding" {
|
|||||||
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");
|
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");
|
||||||
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, isel.code());
|
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");
|
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");
|
||||||
try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = -8, .base = .rdx }), 0x10, isel.code());
|
try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -8)),
|
||||||
|
.base = .rdx,
|
||||||
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");
|
try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");
|
||||||
try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{
|
try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{
|
||||||
.disp = 0x10000000,
|
.disp = 0x10000000,
|
||||||
@ -1836,15 +1826,24 @@ test "lower MI encoding" {
|
|||||||
isel.lowered(),
|
isel.lowered(),
|
||||||
"mov qword ptr [rip + 0x10], 0x10",
|
"mov qword ptr [rip + 0x10], 0x10",
|
||||||
);
|
);
|
||||||
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -8, .base = .rbp }), 0x10, isel.code());
|
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -8)),
|
||||||
|
.base = .rbp,
|
||||||
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x48\xc7\x45\xf8\x10\x00\x00\x00",
|
"\x48\xc7\x45\xf8\x10\x00\x00\x00",
|
||||||
isel.lowered(),
|
isel.lowered(),
|
||||||
"mov qword ptr [rbp - 8], 0x10",
|
"mov qword ptr [rbp - 8], 0x10",
|
||||||
);
|
);
|
||||||
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{ .disp = -2, .base = .rbp }), 0x10, isel.code());
|
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -2)),
|
||||||
|
.base = .rbp,
|
||||||
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");
|
try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");
|
||||||
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{ .disp = -1, .base = .rbp }), 0x10, isel.code());
|
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -1)),
|
||||||
|
.base = .rbp,
|
||||||
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");
|
try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");
|
||||||
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
|
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
.disp = 0x10000000,
|
.disp = 0x10000000,
|
||||||
@ -1897,12 +1896,15 @@ test "lower RM encoding" {
|
|||||||
isel.lowered(),
|
isel.lowered(),
|
||||||
"sub r11, qword ptr [r12 + 0x10000000]",
|
"sub r11, qword ptr [r12 + 0x10000000]",
|
||||||
);
|
);
|
||||||
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), isel.code());
|
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -4)),
|
||||||
|
.base = .rbp,
|
||||||
|
}), isel.code());
|
||||||
try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");
|
try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");
|
||||||
try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
|
try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
|
||||||
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");
|
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");
|
||||||
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
.disp = -8,
|
.disp = @bitCast(u32, @as(i32, -8)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
.scale_index = .{
|
.scale_index = .{
|
||||||
.scale = 0,
|
.scale = 0,
|
||||||
@ -1911,7 +1913,7 @@ test "lower RM encoding" {
|
|||||||
}), isel.code());
|
}), isel.code());
|
||||||
try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
|
try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
|
||||||
try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
|
try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
|
||||||
.disp = -4,
|
.disp = @bitCast(u32, @as(i32, -4)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
.scale_index = .{
|
.scale_index = .{
|
||||||
.scale = 2,
|
.scale = 2,
|
||||||
@ -1920,7 +1922,7 @@ test "lower RM encoding" {
|
|||||||
}), isel.code());
|
}), isel.code());
|
||||||
try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
|
try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
|
||||||
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
.disp = -8,
|
.disp = @bitCast(u32, @as(i32, -8)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
.scale_index = .{
|
.scale_index = .{
|
||||||
.scale = 3,
|
.scale = 3,
|
||||||
@ -1929,7 +1931,7 @@ test "lower RM encoding" {
|
|||||||
}), isel.code());
|
}), isel.code());
|
||||||
try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
|
try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
|
||||||
try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{
|
try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{
|
||||||
.disp = -24,
|
.disp = @bitCast(u32, @as(i32, -24)),
|
||||||
.base = .rsi,
|
.base = .rsi,
|
||||||
.scale_index = .{
|
.scale_index = .{
|
||||||
.scale = 0,
|
.scale = 0,
|
||||||
@ -1953,7 +1955,10 @@ test "lower MR encoding" {
|
|||||||
defer isel.deinit();
|
defer isel.deinit();
|
||||||
try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
|
try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
|
||||||
try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");
|
try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");
|
||||||
try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), .r11, isel.code());
|
try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
|
.disp = @bitCast(u32, @as(i32, -4)),
|
||||||
|
.base = .rbp,
|
||||||
|
}), .r11, isel.code());
|
||||||
try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");
|
try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");
|
||||||
try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, isel.code());
|
try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, isel.code());
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
@ -2063,7 +2068,7 @@ test "lower RMI encoding" {
|
|||||||
var isel = TestIsel.init();
|
var isel = TestIsel.init();
|
||||||
defer isel.deinit();
|
defer isel.deinit();
|
||||||
try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
|
||||||
.disp = -8,
|
.disp = @bitCast(u32, @as(i32, -8)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
}), 0x10, isel.code());
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
@ -2072,12 +2077,12 @@ test "lower RMI encoding" {
|
|||||||
"imul rax, qword ptr [rbp - 8], 0x10",
|
"imul rax, qword ptr [rbp - 8], 0x10",
|
||||||
);
|
);
|
||||||
try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
|
try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
|
||||||
.disp = -4,
|
.disp = @bitCast(u32, @as(i32, -4)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
}), 0x10, isel.code());
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
|
try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
|
||||||
try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
|
try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
|
||||||
.disp = -2,
|
.disp = @bitCast(u32, @as(i32, -2)),
|
||||||
.base = .rbp,
|
.base = .rbp,
|
||||||
}), 0x10, isel.code());
|
}), 0x10, isel.code());
|
||||||
try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
|
try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
|
||||||
|
|||||||
@ -302,7 +302,7 @@ pub const Inst = struct {
|
|||||||
/// Another instruction.
|
/// Another instruction.
|
||||||
inst: Index,
|
inst: Index,
|
||||||
/// A 32-bit immediate value.
|
/// A 32-bit immediate value.
|
||||||
imm: i32,
|
imm: u32,
|
||||||
/// An extern function.
|
/// An extern function.
|
||||||
/// Index into the linker's string table.
|
/// Index into the linker's string table.
|
||||||
extern_fn: u32,
|
extern_fn: u32,
|
||||||
@ -324,8 +324,8 @@ pub const Inst = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const ImmPair = struct {
|
pub const ImmPair = struct {
|
||||||
dest_off: i32,
|
dest_off: u32,
|
||||||
operand: i32,
|
operand: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Imm64 = struct {
|
pub const Imm64 = struct {
|
||||||
|
|||||||
@ -1700,6 +1700,36 @@ pub fn addCases(ctx: *TestContext) !void {
|
|||||||
\\ if (!ok) unreachable;
|
\\ if (!ok) unreachable;
|
||||||
\\}
|
\\}
|
||||||
, "");
|
, "");
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub fn main() void {
|
||||||
|
\\ var x: u16 = undefined;
|
||||||
|
\\ set(&x);
|
||||||
|
\\ assert(x == 123);
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\fn set(x: *u16) void {
|
||||||
|
\\ x.* = 123;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\fn assert(ok: bool) void {
|
||||||
|
\\ if (!ok) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub fn main() void {
|
||||||
|
\\ var x: u8 = undefined;
|
||||||
|
\\ set(&x);
|
||||||
|
\\ assert(x == 123);
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\fn set(x: *u8) void {
|
||||||
|
\\ x.* = 123;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\fn assert(ok: bool) void {
|
||||||
|
\\ if (!ok) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user