aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-01-15 22:27:56 +0100
committerGitHub <noreply@github.com>2022-01-15 22:27:56 +0100
commit3901b6fb000b909e90347f6910ea6315ee03e220 (patch)
tree2ff3fac79d429e6442c755717905a7a79a38f910 /src
parente23f7c01ee91321bd7845397d45f189a3e161806 (diff)
parent3af4e28dda7e4537255516fd1d575c2a34d904e7 (diff)
downloadzig-3901b6fb000b909e90347f6910ea6315ee03e220.tar.gz
zig-3901b6fb000b909e90347f6910ea6315ee03e220.zip
Merge pull request #10598 from ziglang/stage2-x86_64-imm-sizes
stage2: rename Isel back to Emit, and fix immediate casts in Emit for x86 64
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig102
-rw-r--r--src/arch/x86_64/Emit.zig (renamed from src/arch/x86_64/Isel.zig)996
-rw-r--r--src/arch/x86_64/Mir.zig6
3 files changed, 545 insertions, 559 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 9f4feb56e6..f4ecc001e8 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -17,7 +17,7 @@ const DW = std.dwarf;
const ErrorMsg = Module.ErrorMsg;
const FnResult = @import("../../codegen.zig").FnResult;
const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
-const Isel = @import("Isel.zig");
+const Emit = @import("Emit.zig");
const Liveness = @import("../../Liveness.zig");
const Mir = @import("Mir.zig");
const Module = @import("../../Module.zig");
@@ -309,7 +309,7 @@ pub fn generate(
};
defer mir.deinit(bin_file.allocator);
- var isel = Isel{
+ var emit = Emit{
.mir = mir,
.bin_file = bin_file,
.debug_output = debug_output,
@@ -320,9 +320,9 @@ pub fn generate(
.prev_di_line = module_fn.lbrace_line,
.prev_di_column = module_fn.lbrace_column,
};
- defer isel.deinit();
- isel.lowerMir() catch |err| switch (err) {
- error.IselFail => return FnResult{ .fail = isel.err_msg.? },
+ defer emit.deinit();
+ emit.lowerMir() catch |err| switch (err) {
+ error.EmitFail => return FnResult{ .fail = emit.err_msg.? },
else => |e| return e,
};
@@ -497,14 +497,14 @@ fn gen(self: *Self) InnerError!void {
.ops = (Mir.Ops{
.reg1 = .rsp,
}).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, .{
.tag = .add,
.ops = (Mir.Ops{
.reg1 = .rsp,
}).encode(),
- .data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment },
+ .data = .{ .imm = @bitCast(u32, @intCast(i32, aligned_stack_end) + stack_adjustment) },
});
}
} else {
@@ -1347,7 +1347,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
.reg2 = .rbp,
.flags = 0b01,
}).encode(),
- .data = .{ .imm = -@intCast(i32, off + 16) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },
});
// add addr, offset
_ = 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) });
return self.genInlineMemcpy(
- -@intCast(i32, off + abi_size),
+ @bitCast(u32, -@intCast(i32, off + abi_size)),
registerAlias(addr_reg, @divExact(reg.size(), 8)),
count_reg.to64(),
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
const payload = try self.addExtra(Mir.ImmPair{
.dest_off = 0,
- .operand = @bitCast(i32, @intCast(u32, imm)),
+ .operand = @truncate(u32, imm),
});
_ = try self.addInst(.{
.tag = .mov_mem_imm,
@@ -1821,11 +1821,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
const dst_ty = self.air.typeOfIndex(inst);
const air_tags = self.air.instructions.items(.tag);
switch (air_tags[inst]) {
- .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
- .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
- .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
- .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv),
- .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv),
+ .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, .unsigned, dst_mcv, src_mcv),
+ .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, .unsigned, dst_mcv, src_mcv),
+ .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, .unsigned, dst_mcv, src_mcv),
+ .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, .unsigned, dst_mcv, src_mcv),
+ .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, .unsigned, dst_mcv, src_mcv),
.mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
else => unreachable,
}
@@ -1837,6 +1837,7 @@ fn genBinMathOpMir(
self: *Self,
mir_tag: Mir.Inst.Tag,
dst_ty: Type,
+ signedness: std.builtin.Signedness,
dst_mcv: MCValue,
src_mcv: MCValue,
) !void {
@@ -1856,11 +1857,16 @@ fn genBinMathOpMir(
.ptr_stack_offset => unreachable,
.ptr_embedded_in_code => unreachable,
.register => |src_reg| {
+ // TODO think more carefully about this: is this actually correct?
+ const reg_size = if (mir_tag == .cmp and signedness == .signed)
+ @divExact(dst_reg.size(), 8)
+ else
+ @divExact(src_reg.size(), 8);
_ = try self.addInst(.{
.tag = mir_tag,
.ops = (Mir.Ops{
- .reg1 = registerAlias(dst_reg, @divExact(src_reg.size(), 8)),
- .reg2 = src_reg,
+ .reg1 = registerAlias(dst_reg, reg_size),
+ .reg2 = registerAlias(src_reg, reg_size),
}).encode(),
.data = undefined,
});
@@ -1872,7 +1878,7 @@ fn genBinMathOpMir(
.ops = (Mir.Ops{
.reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
}).encode(),
- .data = .{ .imm = @intCast(i32, imm) },
+ .data = .{ .imm = @truncate(u32, imm) },
});
},
.embedded_in_code, .memory => {
@@ -1891,7 +1897,7 @@ fn genBinMathOpMir(
.reg2 = .rbp,
.flags = 0b01,
}).encode(),
- .data = .{ .imm = -@intCast(i32, adj_off) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
});
},
.compare_flags_unsigned => {
@@ -1926,7 +1932,7 @@ fn genBinMathOpMir(
.reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
.flags = 0b10,
}).encode(),
- .data = .{ .imm = -@intCast(i32, adj_off) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
});
},
.immediate => |imm| {
@@ -1947,8 +1953,8 @@ fn genBinMathOpMir(
else => unreachable,
};
const payload = try self.addExtra(Mir.ImmPair{
- .dest_off = -@intCast(i32, adj_off),
- .operand = @bitCast(i32, @intCast(u32, imm)),
+ .dest_off = @bitCast(u32, -@intCast(i32, adj_off)),
+ .operand = @truncate(u32, imm),
});
_ = try self.addInst(.{
.tag = tag,
@@ -2015,7 +2021,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
.reg2 = dst_reg.to32(),
.flags = 0b10,
}).encode(),
- .data = .{ .imm = @intCast(i32, imm) },
+ .data = .{ .imm = @truncate(u32, imm) },
});
} else {
// TODO verify we don't spill and assign to the same register as dst_mcv
@@ -2088,7 +2094,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const mcv = self.args[arg_index];
const payload = try self.addExtra(Mir.ArgDbgInfo{
.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(.{
.tag = .arg_dbg_info,
@@ -2196,7 +2202,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
.ops = (Mir.Ops{
.flags = 0b01,
}).encode(),
- .data = .{ .imm = @bitCast(i32, got_addr) },
+ .data = .{ .imm = @truncate(u32, got_addr) },
});
} else if (func_value.castTag(.extern_fn)) |_| {
return self.fail("TODO implement calling extern functions", .{});
@@ -2446,7 +2452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
// This instruction supports only signed 32-bit immediates at most.
const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
- try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv);
+ try self.genBinMathOpMir(.cmp, ty, signedness, dst_mcv, src_mcv);
break :result switch (signedness) {
.signed => MCValue{ .compare_flags_signed = op },
.unsigned => MCValue{ .compare_flags_unsigned = op },
@@ -2669,7 +2675,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
}
fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
- try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 });
+ try self.genBinMathOpMir(.cmp, ty, .unsigned, operand, MCValue{ .immediate = 0 });
return MCValue{ .compare_flags_unsigned = .eq };
}
@@ -2686,7 +2692,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
return MCValue{ .immediate = 0 }; // always false
} else if (!payload_type.hasCodeGenBits()) {
if (err_type.abiSize(self.target.*) <= 8) {
- try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
+ try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
return MCValue{ .compare_flags_unsigned = .gt };
} else {
return self.fail("TODO isErr for errors with size larger than register size", .{});
@@ -3121,8 +3127,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.
// mov [rbp+offset], immediate
const payload = try self.addExtra(Mir.ImmPair{
- .dest_off = -@intCast(i32, adj_off),
- .operand = @bitCast(i32, @intCast(u32, x_big)),
+ .dest_off = @bitCast(u32, -@intCast(i32, adj_off)),
+ .operand = @truncate(u32, x_big),
});
_ = try self.addInst(.{
.tag = .mov_mem_imm,
@@ -3147,8 +3153,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
// insted just use two 32 bit writes to avoid register allocation
{
const payload = try self.addExtra(Mir.ImmPair{
- .dest_off = negative_offset + 4,
- .operand = @bitCast(i32, @truncate(u32, x_big >> 32)),
+ .dest_off = @bitCast(u32, negative_offset + 4),
+ .operand = @truncate(u32, x_big >> 32),
});
_ = try self.addInst(.{
.tag = .mov_mem_imm,
@@ -3161,8 +3167,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
}
{
const payload = try self.addExtra(Mir.ImmPair{
- .dest_off = negative_offset,
- .operand = @bitCast(i32, @truncate(u32, x_big)),
+ .dest_off = @bitCast(u32, negative_offset),
+ .operand = @truncate(u32, x_big),
});
_ = try self.addInst(.{
.tag = .mov_mem_imm,
@@ -3192,7 +3198,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.reg2 = registerAlias(reg, @intCast(u32, abi_size)),
.flags = 0b10,
}).encode(),
- .data = .{ .imm = -@intCast(i32, adj_off) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },
});
},
.memory, .embedded_in_code => {
@@ -3228,14 +3234,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.reg1 = addr_reg.to64(),
.reg2 = .rbp,
}).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
try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
return self.genInlineMemcpy(
- -@intCast(i32, stack_offset + abi_size),
+ @bitCast(u32, -@intCast(i32, stack_offset + abi_size)),
addr_reg.to64(),
count_reg.to64(),
tmp_reg.to8(),
@@ -3246,7 +3252,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
fn genInlineMemcpy(
self: *Self,
- stack_offset: i32,
+ stack_offset: u32,
addr_reg: Register,
count_reg: Register,
tmp_reg: Register,
@@ -3361,7 +3367,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)),
.reg2 = .rbp,
}).encode(),
- .data = .{ .imm = -@intCast(i32, off) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
});
},
.ptr_embedded_in_code => unreachable,
@@ -3378,7 +3384,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
else => unreachable,
}
},
- .compare_flags_unsigned => |op| {
+ .compare_flags_unsigned,
+ .compare_flags_signed,
+ => |op| {
const tag: Mir.Inst.Tag = switch (op) {
.gte, .gt, .lt, .lte => .cond_set_byte_above_below,
.eq, .neq => .cond_set_byte_eq_ne,
@@ -3400,10 +3408,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.data = undefined,
});
},
- .compare_flags_signed => |op| {
- _ = op;
- return self.fail("TODO set register with compare flags value (signed)", .{});
- },
.immediate => |x| {
// 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
// register is the fastest way to zero a register.
@@ -3426,7 +3430,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.ops = (Mir.Ops{
.reg1 = registerAlias(reg, @intCast(u32, abi_size)),
}).encode(),
- .data = .{ .imm = @intCast(i32, x) },
+ .data = .{ .imm = @truncate(u32, x) },
});
return;
}
@@ -3441,7 +3445,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
_ = try self.addInst(.{
.tag = .movabs,
.ops = (Mir.Ops{
- .reg1 = reg,
+ .reg1 = reg.to64(),
}).encode(),
.data = .{ .payload = payload },
});
@@ -3482,7 +3486,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.reg1 = reg,
.flags = 0b10,
}).encode(),
- .data = .{ .got_entry = @intCast(u32, x) },
+ .data = .{ .got_entry = @truncate(u32, x) },
});
// MOV reg, [reg]
_ = try self.addInst(.{
@@ -3502,7 +3506,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.reg1 = reg,
.flags = 0b01,
}).encode(),
- .data = .{ .imm = @intCast(i32, x) },
+ .data = .{ .imm = @truncate(u32, x) },
});
} else {
// If this is RAX, we can use a direct load.
@@ -3561,7 +3565,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.reg2 = .rbp,
.flags = 0b01,
}).encode(),
- .data = .{ .imm = -@intCast(i32, off) },
+ .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
});
},
}
diff --git a/src/arch/x86_64/Isel.zig b/src/arch/x86_64/Emit.zig
index acae794563..d192288dc4 100644
--- a/src/arch/x86_64/Isel.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -1,7 +1,7 @@
//! This file contains the functionality for lowering x86_64 MIR into
//! machine code
-const Isel = @This();
+const Emit = @This();
const std = @import("std");
const assert = std.debug.assert;
@@ -44,185 +44,183 @@ relocs: std.ArrayListUnmanaged(Reloc) = .{},
const InnerError = error{
OutOfMemory,
- Overflow,
- IselFail,
+ EmitFail,
};
const Reloc = struct {
/// Offset of the instruction.
- source: u64,
+ source: usize,
/// Target of the relocation.
target: Mir.Inst.Index,
/// Offset of the relocation within the instruction.
- offset: u64,
+ offset: usize,
/// Length of the instruction.
length: u5,
};
-pub fn lowerMir(isel: *Isel) InnerError!void {
- const mir_tags = isel.mir.instructions.items(.tag);
+pub fn lowerMir(emit: *Emit) InnerError!void {
+ const mir_tags = emit.mir.instructions.items(.tag);
for (mir_tags) |tag, index| {
const inst = @intCast(u32, index);
- try isel.code_offset_mapping.putNoClobber(isel.bin_file.allocator, inst, isel.code.items.len);
+ try emit.code_offset_mapping.putNoClobber(emit.bin_file.allocator, inst, emit.code.items.len);
switch (tag) {
- .adc => try isel.mirArith(.adc, inst),
- .add => try isel.mirArith(.add, inst),
- .sub => try isel.mirArith(.sub, inst),
- .xor => try isel.mirArith(.xor, inst),
- .@"and" => try isel.mirArith(.@"and", inst),
- .@"or" => try isel.mirArith(.@"or", inst),
- .sbb => try isel.mirArith(.sbb, inst),
- .cmp => try isel.mirArith(.cmp, inst),
- .mov => try isel.mirArith(.mov, inst),
-
- .adc_mem_imm => try isel.mirArithMemImm(.adc, inst),
- .add_mem_imm => try isel.mirArithMemImm(.add, inst),
- .sub_mem_imm => try isel.mirArithMemImm(.sub, inst),
- .xor_mem_imm => try isel.mirArithMemImm(.xor, inst),
- .and_mem_imm => try isel.mirArithMemImm(.@"and", inst),
- .or_mem_imm => try isel.mirArithMemImm(.@"or", inst),
- .sbb_mem_imm => try isel.mirArithMemImm(.sbb, inst),
- .cmp_mem_imm => try isel.mirArithMemImm(.cmp, inst),
- .mov_mem_imm => try isel.mirArithMemImm(.mov, inst),
-
- .adc_scale_src => try isel.mirArithScaleSrc(.adc, inst),
- .add_scale_src => try isel.mirArithScaleSrc(.add, inst),
- .sub_scale_src => try isel.mirArithScaleSrc(.sub, inst),
- .xor_scale_src => try isel.mirArithScaleSrc(.xor, inst),
- .and_scale_src => try isel.mirArithScaleSrc(.@"and", inst),
- .or_scale_src => try isel.mirArithScaleSrc(.@"or", inst),
- .sbb_scale_src => try isel.mirArithScaleSrc(.sbb, inst),
- .cmp_scale_src => try isel.mirArithScaleSrc(.cmp, inst),
- .mov_scale_src => try isel.mirArithScaleSrc(.mov, inst),
-
- .adc_scale_dst => try isel.mirArithScaleDst(.adc, inst),
- .add_scale_dst => try isel.mirArithScaleDst(.add, inst),
- .sub_scale_dst => try isel.mirArithScaleDst(.sub, inst),
- .xor_scale_dst => try isel.mirArithScaleDst(.xor, inst),
- .and_scale_dst => try isel.mirArithScaleDst(.@"and", inst),
- .or_scale_dst => try isel.mirArithScaleDst(.@"or", inst),
- .sbb_scale_dst => try isel.mirArithScaleDst(.sbb, inst),
- .cmp_scale_dst => try isel.mirArithScaleDst(.cmp, inst),
- .mov_scale_dst => try isel.mirArithScaleDst(.mov, inst),
-
- .adc_scale_imm => try isel.mirArithScaleImm(.adc, inst),
- .add_scale_imm => try isel.mirArithScaleImm(.add, inst),
- .sub_scale_imm => try isel.mirArithScaleImm(.sub, inst),
- .xor_scale_imm => try isel.mirArithScaleImm(.xor, inst),
- .and_scale_imm => try isel.mirArithScaleImm(.@"and", inst),
- .or_scale_imm => try isel.mirArithScaleImm(.@"or", inst),
- .sbb_scale_imm => try isel.mirArithScaleImm(.sbb, inst),
- .cmp_scale_imm => try isel.mirArithScaleImm(.cmp, inst),
- .mov_scale_imm => try isel.mirArithScaleImm(.mov, inst),
-
- .movabs => try isel.mirMovabs(inst),
-
- .lea => try isel.mirLea(inst),
-
- .imul_complex => try isel.mirIMulComplex(inst),
-
- .push => try isel.mirPushPop(.push, inst),
- .pop => try isel.mirPushPop(.pop, inst),
-
- .jmp => try isel.mirJmpCall(.jmp_near, inst),
- .call => try isel.mirJmpCall(.call_near, inst),
+ .adc => try emit.mirArith(.adc, inst),
+ .add => try emit.mirArith(.add, inst),
+ .sub => try emit.mirArith(.sub, inst),
+ .xor => try emit.mirArith(.xor, inst),
+ .@"and" => try emit.mirArith(.@"and", inst),
+ .@"or" => try emit.mirArith(.@"or", inst),
+ .sbb => try emit.mirArith(.sbb, inst),
+ .cmp => try emit.mirArith(.cmp, inst),
+ .mov => try emit.mirArith(.mov, inst),
+
+ .adc_mem_imm => try emit.mirArithMemImm(.adc, inst),
+ .add_mem_imm => try emit.mirArithMemImm(.add, inst),
+ .sub_mem_imm => try emit.mirArithMemImm(.sub, inst),
+ .xor_mem_imm => try emit.mirArithMemImm(.xor, inst),
+ .and_mem_imm => try emit.mirArithMemImm(.@"and", inst),
+ .or_mem_imm => try emit.mirArithMemImm(.@"or", inst),
+ .sbb_mem_imm => try emit.mirArithMemImm(.sbb, inst),
+ .cmp_mem_imm => try emit.mirArithMemImm(.cmp, inst),
+ .mov_mem_imm => try emit.mirArithMemImm(.mov, inst),
+
+ .adc_scale_src => try emit.mirArithScaleSrc(.adc, inst),
+ .add_scale_src => try emit.mirArithScaleSrc(.add, inst),
+ .sub_scale_src => try emit.mirArithScaleSrc(.sub, inst),
+ .xor_scale_src => try emit.mirArithScaleSrc(.xor, inst),
+ .and_scale_src => try emit.mirArithScaleSrc(.@"and", inst),
+ .or_scale_src => try emit.mirArithScaleSrc(.@"or", inst),
+ .sbb_scale_src => try emit.mirArithScaleSrc(.sbb, inst),
+ .cmp_scale_src => try emit.mirArithScaleSrc(.cmp, inst),
+ .mov_scale_src => try emit.mirArithScaleSrc(.mov, inst),
+
+ .adc_scale_dst => try emit.mirArithScaleDst(.adc, inst),
+ .add_scale_dst => try emit.mirArithScaleDst(.add, inst),
+ .sub_scale_dst => try emit.mirArithScaleDst(.sub, inst),
+ .xor_scale_dst => try emit.mirArithScaleDst(.xor, inst),
+ .and_scale_dst => try emit.mirArithScaleDst(.@"and", inst),
+ .or_scale_dst => try emit.mirArithScaleDst(.@"or", inst),
+ .sbb_scale_dst => try emit.mirArithScaleDst(.sbb, inst),
+ .cmp_scale_dst => try emit.mirArithScaleDst(.cmp, inst),
+ .mov_scale_dst => try emit.mirArithScaleDst(.mov, inst),
+
+ .adc_scale_imm => try emit.mirArithScaleImm(.adc, inst),
+ .add_scale_imm => try emit.mirArithScaleImm(.add, inst),
+ .sub_scale_imm => try emit.mirArithScaleImm(.sub, inst),
+ .xor_scale_imm => try emit.mirArithScaleImm(.xor, inst),
+ .and_scale_imm => try emit.mirArithScaleImm(.@"and", inst),
+ .or_scale_imm => try emit.mirArithScaleImm(.@"or", inst),
+ .sbb_scale_imm => try emit.mirArithScaleImm(.sbb, inst),
+ .cmp_scale_imm => try emit.mirArithScaleImm(.cmp, inst),
+ .mov_scale_imm => try emit.mirArithScaleImm(.mov, inst),
+
+ .movabs => try emit.mirMovabs(inst),
+
+ .lea => try emit.mirLea(inst),
+
+ .imul_complex => try emit.mirIMulComplex(inst),
+
+ .push => try emit.mirPushPop(.push, inst),
+ .pop => try emit.mirPushPop(.pop, inst),
+
+ .jmp => try emit.mirJmpCall(.jmp_near, inst),
+ .call => try emit.mirJmpCall(.call_near, inst),
.cond_jmp_greater_less,
.cond_jmp_above_below,
.cond_jmp_eq_ne,
- => try isel.mirCondJmp(tag, inst),
+ => try emit.mirCondJmp(tag, inst),
.cond_set_byte_greater_less,
.cond_set_byte_above_below,
.cond_set_byte_eq_ne,
- => try isel.mirCondSetByte(tag, inst),
+ => try emit.mirCondSetByte(tag, inst),
- .ret => try isel.mirRet(inst),
+ .ret => try emit.mirRet(inst),
- .syscall => try isel.mirSyscall(),
+ .syscall => try emit.mirSyscall(),
- .@"test" => try isel.mirTest(inst),
+ .@"test" => try emit.mirTest(inst),
- .brk => try isel.mirBrk(),
- .nop => try isel.mirNop(),
+ .brk => try emit.mirBrk(),
+ .nop => try emit.mirNop(),
- .call_extern => try isel.mirCallExtern(inst),
+ .call_extern => try emit.mirCallExtern(inst),
- .dbg_line => try isel.mirDbgLine(inst),
- .dbg_prologue_end => try isel.mirDbgPrologueEnd(inst),
- .dbg_epilogue_begin => try isel.mirDbgEpilogueBegin(inst),
- .arg_dbg_info => try isel.mirArgDbgInfo(inst),
+ .dbg_line => try emit.mirDbgLine(inst),
+ .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
+ .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
+ .arg_dbg_info => try emit.mirArgDbgInfo(inst),
- .push_regs_from_callee_preserved_regs => try isel.mirPushPopRegsFromCalleePreservedRegs(.push, inst),
- .pop_regs_from_callee_preserved_regs => try isel.mirPushPopRegsFromCalleePreservedRegs(.pop, inst),
+ .push_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.push, inst),
+ .pop_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.pop, inst),
else => {
- return isel.fail("Implement MIR->Isel lowering for x86_64 for pseudo-inst: {s}", .{tag});
+ return emit.fail("Implement MIR->Emit lowering for x86_64 for pseudo-inst: {s}", .{tag});
},
}
}
- try isel.fixupRelocs();
+ try emit.fixupRelocs();
}
-pub fn deinit(isel: *Isel) void {
- isel.relocs.deinit(isel.bin_file.allocator);
- isel.code_offset_mapping.deinit(isel.bin_file.allocator);
- isel.* = undefined;
+pub fn deinit(emit: *Emit) void {
+ emit.relocs.deinit(emit.bin_file.allocator);
+ emit.code_offset_mapping.deinit(emit.bin_file.allocator);
+ emit.* = undefined;
}
-fn fail(isel: *Isel, comptime format: []const u8, args: anytype) InnerError {
+fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
@setCold(true);
- assert(isel.err_msg == null);
- isel.err_msg = try ErrorMsg.create(isel.bin_file.allocator, isel.src_loc, format, args);
- return error.IselFail;
+ assert(emit.err_msg == null);
+ emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);
+ return error.EmitFail;
}
-fn failWithLoweringError(isel: *Isel, err: LoweringError) InnerError {
+fn failWithLoweringError(emit: *Emit, err: LoweringError) InnerError {
return switch (err) {
- error.RaxOperandExpected => isel.fail("Register.rax expected as destination operand", .{}),
- error.OperandSizeMismatch => isel.fail("operand size mismatch", .{}),
+ error.RaxOperandExpected => emit.fail("Register.rax expected as destination operand", .{}),
+ error.OperandSizeMismatch => emit.fail("operand size mismatch", .{}),
else => |e| e,
};
}
-fn fixupRelocs(isel: *Isel) InnerError!void {
+fn fixupRelocs(emit: *Emit) InnerError!void {
// TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
// This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
// possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
// until the entire decl is correctly emitted with all JMP/CALL instructions within range.
- for (isel.relocs.items) |reloc| {
- const offset = try math.cast(usize, reloc.offset);
- const target = isel.code_offset_mapping.get(reloc.target) orelse
- return isel.fail("JMP/CALL relocation target not found!", .{});
+ for (emit.relocs.items) |reloc| {
+ const target = emit.code_offset_mapping.get(reloc.target) orelse
+ return emit.fail("JMP/CALL relocation target not found!", .{});
const disp = @intCast(i32, @intCast(i64, target) - @intCast(i64, reloc.source + reloc.length));
- mem.writeIntLittle(i32, isel.code.items[offset..][0..4], disp);
+ mem.writeIntLittle(i32, emit.code.items[reloc.offset..][0..4], disp);
}
}
-fn mirBrk(isel: *Isel) InnerError!void {
- return lowerToZoEnc(.brk, isel.code) catch |err| isel.failWithLoweringError(err);
+fn mirBrk(emit: *Emit) InnerError!void {
+ return lowerToZoEnc(.brk, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirNop(isel: *Isel) InnerError!void {
- return lowerToZoEnc(.nop, isel.code) catch |err| isel.failWithLoweringError(err);
+fn mirNop(emit: *Emit) InnerError!void {
+ return lowerToZoEnc(.nop, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirSyscall(isel: *Isel) InnerError!void {
- return lowerToZoEnc(.syscall, isel.code) catch |err| isel.failWithLoweringError(err);
+fn mirSyscall(emit: *Emit) InnerError!void {
+ return lowerToZoEnc(.syscall, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirPushPop(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 => {
// PUSH/POP reg
- return lowerToOEnc(tag, ops.reg1, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToOEnc(tag, ops.reg1, emit.code) catch |err| emit.failWithLoweringError(err);
},
0b01 => {
// PUSH/POP r/m64
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {
16 => .word_ptr,
else => .qword_ptr,
@@ -230,26 +228,26 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
.disp = imm,
.base = ops.reg1,
- }), isel.code) catch |err| isel.failWithLoweringError(err);
+ }), emit.code) catch |err| emit.failWithLoweringError(err);
},
0b10 => {
// PUSH imm32
assert(tag == .push);
- const imm = isel.mir.instructions.items(.data)[inst].imm;
- return lowerToIEnc(.push, imm, isel.code) catch |err|
- isel.failWithLoweringError(err);
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
+ return lowerToIEnc(.push, imm, emit.code) catch |err|
+ emit.failWithLoweringError(err);
},
0b11 => unreachable,
}
}
-fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
+fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
const callee_preserved_regs = bits.callee_preserved_regs;
- const regs = isel.mir.instructions.items(.data)[inst].regs_to_push_or_pop;
+ const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop;
if (tag == .push) {
for (callee_preserved_regs) |reg, i| {
if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
- lowerToOEnc(.push, reg, isel.code) catch |err|
- return isel.failWithLoweringError(err);
+ lowerToOEnc(.push, reg, emit.code) catch |err|
+ return emit.failWithLoweringError(err);
}
} else {
// pop in the reverse direction
@@ -257,56 +255,56 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I
while (i > 0) : (i -= 1) {
const reg = callee_preserved_regs[i - 1];
if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;
- lowerToOEnc(.pop, reg, isel.code) catch |err|
- return isel.failWithLoweringError(err);
+ lowerToOEnc(.pop, reg, emit.code) catch |err|
+ return emit.failWithLoweringError(err);
}
}
}
-fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirJmpCall(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 => {
- const target = isel.mir.instructions.items(.data)[inst].inst;
- const source = isel.code.items.len;
- lowerToDEnc(tag, 0, isel.code) catch |err|
- return isel.failWithLoweringError(err);
- try isel.relocs.append(isel.bin_file.allocator, .{
+ const target = emit.mir.instructions.items(.data)[inst].inst;
+ const source = emit.code.items.len;
+ lowerToDEnc(tag, 0, emit.code) catch |err|
+ return emit.failWithLoweringError(err);
+ try emit.relocs.append(emit.bin_file.allocator, .{
.source = source,
.target = target,
- .offset = isel.code.items.len - 4,
+ .offset = emit.code.items.len - 4,
.length = 5,
});
},
0b01 => {
if (ops.reg1 == .none) {
// JMP/CALL [imm]
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) {
16 => .word_ptr,
else => .qword_ptr,
};
- return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code) catch |err|
+ emit.failWithLoweringError(err);
}
// JMP/CALL reg
- return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code) catch |err| emit.failWithLoweringError(err);
},
0b10 => {
// JMP/CALL r/m64
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
.disp = imm,
.base = ops.reg1,
- }), isel.code) catch |err| isel.failWithLoweringError(err);
+ }), emit.code) catch |err| emit.failWithLoweringError(err);
},
- 0b11 => return isel.fail("TODO unused JMP/CALL variant 0b11", .{}),
+ 0b11 => return emit.fail("TODO unused JMP/CALL variant 0b11", .{}),
}
}
-fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
- const target = isel.mir.instructions.items(.data)[inst].inst;
+fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
+ const target = emit.mir.instructions.items(.data)[inst].inst;
const tag = switch (mir_tag) {
.cond_jmp_greater_less => switch (ops.flags) {
0b00 => Tag.jge,
@@ -326,19 +324,19 @@ fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerErr
},
else => unreachable,
};
- const source = isel.code.items.len;
- lowerToDEnc(tag, 0, isel.code) catch |err|
- return isel.failWithLoweringError(err);
- try isel.relocs.append(isel.bin_file.allocator, .{
+ const source = emit.code.items.len;
+ lowerToDEnc(tag, 0, emit.code) catch |err|
+ return emit.failWithLoweringError(err);
+ try emit.relocs.append(emit.bin_file.allocator, .{
.source = source,
.target = target,
- .offset = isel.code.items.len - 4,
+ .offset = emit.code.items.len - 4,
.length = 6,
});
}
-fn mirCondSetByte(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
const tag = switch (mir_tag) {
.cond_set_byte_greater_less => switch (ops.flags) {
0b00 => Tag.setge,
@@ -358,111 +356,111 @@ fn mirCondSetByte(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne
},
else => unreachable,
};
- return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code) catch |err|
+ emit.failWithLoweringError(err);
}
-fn mirTest(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .@"test");
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
switch (ops.flags) {
0b00 => {
if (ops.reg2 == .none) {
// TEST r/m64, imm32
// MI
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
if (ops.reg1.to64() == .rax) {
// TEST rax, imm32
// I
- return lowerToIEnc(.@"test", imm, isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToIEnc(.@"test", imm, emit.code) catch |err|
+ emit.failWithLoweringError(err);
}
- return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code) catch |err|
+ emit.failWithLoweringError(err);
}
// TEST r/m64, r64
- return isel.fail("TODO TEST r/m64, r64", .{});
+ return emit.fail("TODO TEST r/m64, r64", .{});
},
- else => return isel.fail("TODO more TEST alternatives", .{}),
+ else => return emit.fail("TODO more TEST alternatives", .{}),
}
}
-fn mirRet(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .ret);
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
switch (ops.flags) {
0b00 => {
// RETF imm16
// I
- const imm = isel.mir.instructions.items(.data)[inst].imm;
- return lowerToIEnc(.ret_far, imm, isel.code) catch |err| isel.failWithLoweringError(err);
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
+ return lowerToIEnc(.ret_far, imm, emit.code) catch |err| emit.failWithLoweringError(err);
},
0b01 => {
- return lowerToZoEnc(.ret_far, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToZoEnc(.ret_far, emit.code) catch |err| emit.failWithLoweringError(err);
},
0b10 => {
// RET imm16
// I
- const imm = isel.mir.instructions.items(.data)[inst].imm;
- return lowerToIEnc(.ret_near, imm, isel.code) catch |err| isel.failWithLoweringError(err);
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
+ return lowerToIEnc(.ret_near, imm, emit.code) catch |err| emit.failWithLoweringError(err);
},
0b11 => {
- return lowerToZoEnc(.ret_near, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToZoEnc(.ret_near, emit.code) catch |err| emit.failWithLoweringError(err);
},
}
}
-fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirArith(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 => {
if (ops.reg2 == .none) {
// mov reg1, imm32
// MI
- const imm = isel.mir.instructions.items(.data)[inst].imm;
- return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, isel.code) catch |err|
- isel.failWithLoweringError(err);
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
+ return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code) catch |err|
+ emit.failWithLoweringError(err);
}
// mov reg1, reg2
// RM
- return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code) catch |err|
+ emit.failWithLoweringError(err);
},
0b01 => {
// mov reg1, [reg2 + imm32]
// RM
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
.disp = imm,
.base = src_reg,
- }), isel.code) catch |err| isel.failWithLoweringError(err);
+ }), emit.code) catch |err| emit.failWithLoweringError(err);
},
0b10 => {
if (ops.reg2 == .none) {
- return isel.fail("TODO unused variant: mov reg1, none, 0b10", .{});
+ return emit.fail("TODO unused variant: mov reg1, none, 0b10", .{});
}
// mov [reg1 + imm32], reg2
// MR
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
.disp = imm,
.base = ops.reg1,
- }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
+ }), ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err);
},
0b11 => {
- return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
+ return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
},
}
}
-fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
assert(ops.reg2 == .none);
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
const ptr_size: Memory.PtrSize = switch (ops.flags) {
0b00 => .byte_ptr,
0b01 => .word_ptr,
@@ -472,7 +470,7 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{
.disp = imm_pair.dest_off,
.base = ops.reg1,
- }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
+ }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err);
}
inline fn setRexWRegister(reg: Register) bool {
@@ -483,26 +481,21 @@ inline fn setRexWRegister(reg: Register) bool {
};
}
-inline fn immOpSize(imm: i64) u8 {
- blk: {
- _ = math.cast(i8, imm) catch break :blk;
+inline fn immOpSize(u_imm: u32) u8 {
+ const imm = @bitCast(i32, u_imm);
+ if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
return 8;
}
- blk: {
- _ = math.cast(i16, imm) catch break :blk;
+ if (math.minInt(i16) <= imm and imm <= math.maxInt(i16)) {
return 16;
}
- blk: {
- _ = math.cast(i32, imm) catch break :blk;
- return 32;
- }
- return 64;
+ return 32;
}
-fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
const scale = ops.flags;
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
// OP reg1, [reg2 + scale*rcx + imm32]
const scale_index = ScaleIndex{
.scale = scale,
@@ -512,13 +505,13 @@ fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
.disp = imm,
.base = ops.reg2,
.scale_index = scale_index,
- }), isel.code) catch |err| isel.failWithLoweringError(err);
+ }), emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
const scale = ops.flags;
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const scale_index = ScaleIndex{
.scale = scale,
.index = .rax,
@@ -529,21 +522,21 @@ fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
.disp = 0,
.base = ops.reg1,
.scale_index = scale_index,
- }), imm, isel.code) catch |err| isel.failWithLoweringError(err);
+ }), imm, emit.code) catch |err| emit.failWithLoweringError(err);
}
// OP [reg1 + scale*rax + imm32], reg2
return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
.disp = imm,
.base = ops.reg1,
.scale_index = scale_index,
- }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
+ }), ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
const scale = ops.flags;
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
const scale_index = ScaleIndex{
.scale = scale,
.index = .rax,
@@ -553,60 +546,60 @@ fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void
.disp = imm_pair.dest_off,
.base = ops.reg1,
.scale_index = scale_index,
- }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
+ }), imm_pair.operand, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .movabs);
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
- const imm: i64 = if (ops.reg1.size() == 64) blk: {
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const imm = isel.mir.extraData(Mir.Imm64, payload).data;
- break :blk @bitCast(i64, imm.decode());
- } else isel.mir.instructions.items(.data)[inst].imm;
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
+ const imm: u64 = if (ops.reg1.size() == 64) blk: {
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const imm = emit.mir.extraData(Mir.Imm64, payload).data;
+ break :blk imm.decode();
+ } else emit.mir.instructions.items(.data)[inst].imm;
if (ops.flags == 0b00) {
// movabs reg, imm64
// OI
- return lowerToOiEnc(.mov, ops.reg1, imm, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToOiEnc(.mov, ops.reg1, imm, emit.code) catch |err| emit.failWithLoweringError(err);
}
if (ops.reg1 == .none) {
// movabs moffs64, rax
// TD
- return lowerToTdEnc(.mov, imm, ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToTdEnc(.mov, imm, ops.reg2, emit.code) catch |err| emit.failWithLoweringError(err);
}
// movabs rax, moffs64
// FD
- return lowerToFdEnc(.mov, ops.reg1, imm, isel.code) catch |err| isel.failWithLoweringError(err);
+ return lowerToFdEnc(.mov, ops.reg1, imm, emit.code) catch |err| emit.failWithLoweringError(err);
}
-fn mirIMulComplex(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .imul_complex);
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
switch (ops.flags) {
0b00 => {
- return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), isel.code) catch |err|
- isel.failWithLoweringError(err);
+ return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code) catch |err|
+ emit.failWithLoweringError(err);
},
0b10 => {
- const imm = isel.mir.instructions.items(.data)[inst].imm;
- return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, isel.code) catch |err|
- isel.failWithLoweringError(err);
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
+ return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, emit.code) catch |err|
+ emit.failWithLoweringError(err);
},
- else => return isel.fail("TODO implement imul", .{}),
+ else => return emit.fail("TODO implement imul", .{}),
}
}
-fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .lea);
- const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
+ const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
switch (ops.flags) {
0b00 => {
// lea reg1, [reg2 + imm32]
// RM
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
return lowerToRmEnc(
.lea,
@@ -615,25 +608,25 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
.disp = imm,
.base = src_reg,
}),
- isel.code,
- ) catch |err| isel.failWithLoweringError(err);
+ emit.code,
+ ) catch |err| emit.failWithLoweringError(err);
},
0b01 => {
// lea reg1, [rip + imm32]
// RM
- const start_offset = isel.code.items.len;
+ const start_offset = emit.code.items.len;
lowerToRmEnc(
.lea,
ops.reg1,
RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
- isel.code,
- ) catch |err| return isel.failWithLoweringError(err);
- const end_offset = isel.code.items.len;
+ emit.code,
+ ) catch |err| return emit.failWithLoweringError(err);
+ const end_offset = emit.code.items.len;
// Backpatch the displacement
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const imm = isel.mir.extraData(Mir.Imm64, payload).data.decode();
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const imm = emit.mir.extraData(Mir.Imm64, payload).data.decode();
const disp = @intCast(i32, @intCast(i64, imm) - @intCast(i64, end_offset - start_offset));
- mem.writeIntLittle(i32, isel.code.items[end_offset - 4 ..][0..4], disp);
+ mem.writeIntLittle(i32, emit.code.items[end_offset - 4 ..][0..4], disp);
},
0b10 => {
// lea reg1, [rip + reloc]
@@ -642,14 +635,14 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
.lea,
ops.reg1,
RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
- isel.code,
- ) catch |err| return isel.failWithLoweringError(err);
- const end_offset = isel.code.items.len;
- const got_entry = isel.mir.instructions.items(.data)[inst].got_entry;
- if (isel.bin_file.cast(link.File.MachO)) |macho_file| {
+ emit.code,
+ ) catch |err| return emit.failWithLoweringError(err);
+ const end_offset = emit.code.items.len;
+ const got_entry = emit.mir.instructions.items(.data)[inst].got_entry;
+ if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
// TODO I think the reloc might be in the wrong place.
const decl = macho_file.active_decl.?;
- try decl.link.macho.relocs.append(isel.bin_file.allocator, .{
+ try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
.offset = @intCast(u32, end_offset - 4),
.target = .{ .local = got_entry },
.addend = 0,
@@ -659,7 +652,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
.@"type" = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
});
} else {
- return isel.fail(
+ return emit.fail(
"TODO implement lea reg, [rip + reloc] for linking backends different than MachO",
.{},
);
@@ -667,7 +660,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
},
0b11 => {
// lea reg, [rbp + rcx + imm32]
- const imm = isel.mir.instructions.items(.data)[inst].imm;
+ const imm = emit.mir.instructions.items(.data)[inst].imm;
const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
const scale_index = ScaleIndex{
.scale = 0,
@@ -681,25 +674,25 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
.base = src_reg,
.scale_index = scale_index,
}),
- isel.code,
- ) catch |err| isel.failWithLoweringError(err);
+ emit.code,
+ ) catch |err| emit.failWithLoweringError(err);
},
}
}
-fn mirCallExtern(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .call_extern);
- const n_strx = isel.mir.instructions.items(.data)[inst].extern_fn;
+ const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;
const offset = blk: {
// callq
- lowerToDEnc(.call_near, 0, isel.code) catch |err|
- return isel.failWithLoweringError(err);
- break :blk @intCast(u32, isel.code.items.len) - 4;
+ lowerToDEnc(.call_near, 0, emit.code) catch |err|
+ return emit.failWithLoweringError(err);
+ break :blk @intCast(u32, emit.code.items.len) - 4;
};
- if (isel.bin_file.cast(link.File.MachO)) |macho_file| {
+ if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
// Add relocation to the decl.
- try macho_file.active_decl.?.link.macho.relocs.append(isel.bin_file.allocator, .{
+ try macho_file.active_decl.?.link.macho.relocs.append(emit.bin_file.allocator, .{
.offset = offset,
.target = .{ .global = n_strx },
.addend = 0,
@@ -709,22 +702,22 @@ fn mirCallExtern(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
.@"type" = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),
});
} else {
- return isel.fail("TODO implement call_extern for linking backends different than MachO", .{});
+ return emit.fail("TODO implement call_extern for linking backends different than MachO", .{});
}
}
-fn mirDbgLine(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .dbg_line);
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const dbg_line_column = isel.mir.extraData(Mir.DbgLineColumn, payload).data;
- try isel.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column);
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const dbg_line_column = emit.mir.extraData(Mir.DbgLineColumn, payload).data;
+ try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column);
}
-fn dbgAdvancePCAndLine(isel: *Isel, line: u32, column: u32) InnerError!void {
- const delta_line = @intCast(i32, line) - @intCast(i32, isel.prev_di_line);
- const delta_pc: usize = isel.code.items.len - isel.prev_di_pc;
- switch (isel.debug_output) {
+fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
+ const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line);
+ const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
+ switch (emit.debug_output) {
.dwarf => |dbg_out| {
// TODO Look into using the DWARF special opcodes to compress this data.
// It lets you emit single-byte opcodes that add different numbers to
@@ -737,15 +730,15 @@ fn dbgAdvancePCAndLine(isel: *Isel, line: u32, column: u32) InnerError!void {
leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
}
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
- isel.prev_di_pc = isel.code.items.len;
- isel.prev_di_line = line;
- isel.prev_di_column = column;
- isel.prev_di_pc = isel.code.items.len;
+ emit.prev_di_pc = emit.code.items.len;
+ emit.prev_di_line = line;
+ emit.prev_di_column = column;
+ emit.prev_di_pc = emit.code.items.len;
},
.plan9 => |dbg_out| {
if (delta_pc <= 0) return; // only do this when the pc changes
// we have already checked the target in the linker to make sure it is compatable
- const quant = @import("../../link/Plan9/aout.zig").getPCQuant(isel.target.cpu.arch) catch unreachable;
+ const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.target.cpu.arch) catch unreachable;
// increasing the line number
try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
@@ -770,62 +763,62 @@ fn dbgAdvancePCAndLine(isel: *Isel, line: u32, column: u32) InnerError!void {
// we don't need to do anything, because adding the quant does it for us
} else unreachable;
if (dbg_out.start_line.* == null)
- dbg_out.start_line.* = isel.prev_di_line;
+ dbg_out.start_line.* = emit.prev_di_line;
dbg_out.end_line.* = line;
// only do this if the pc changed
- isel.prev_di_line = line;
- isel.prev_di_column = column;
- isel.prev_di_pc = isel.code.items.len;
+ emit.prev_di_line = line;
+ emit.prev_di_column = column;
+ emit.prev_di_pc = emit.code.items.len;
},
.none => {},
}
}
-fn mirDbgPrologueEnd(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .dbg_prologue_end);
- switch (isel.debug_output) {
+ switch (emit.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
- try isel.dbgAdvancePCAndLine(isel.prev_di_line, isel.prev_di_column);
+ try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.plan9 => {},
.none => {},
}
}
-fn mirDbgEpilogueBegin(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .dbg_epilogue_begin);
- switch (isel.debug_output) {
+ switch (emit.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
- try isel.dbgAdvancePCAndLine(isel.prev_di_line, isel.prev_di_column);
+ try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.plan9 => {},
.none => {},
}
}
-fn mirArgDbgInfo(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
- const tag = isel.mir.instructions.items(.tag)[inst];
+fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .arg_dbg_info);
- const payload = isel.mir.instructions.items(.data)[inst].payload;
- const arg_dbg_info = isel.mir.extraData(Mir.ArgDbgInfo, payload).data;
- const mcv = isel.mir.function.args[arg_dbg_info.arg_index];
- try isel.genArgDbgInfo(arg_dbg_info.air_inst, mcv);
+ const payload = emit.mir.instructions.items(.data)[inst].payload;
+ const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
+ const mcv = emit.mir.function.args[arg_dbg_info.arg_index];
+ try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv);
}
-fn genArgDbgInfo(isel: *Isel, inst: Air.Inst.Index, mcv: MCValue) !void {
- const ty_str = isel.mir.function.air.instructions.items(.data)[inst].ty_str;
- const zir = &isel.mir.function.mod_fn.owner_decl.getFileScope().zir;
+fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
+ const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;
+ const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;
const name = zir.nullTerminatedString(ty_str.str);
const name_with_null = name.ptr[0 .. name.len + 1];
- const ty = isel.mir.function.air.getRefType(ty_str.ty);
+ const ty = emit.mir.function.air.getRefType(ty_str.ty);
switch (mcv) {
.register => |reg| {
- switch (isel.debug_output) {
+ switch (emit.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.dbg_info.ensureUnusedCapacity(3);
dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
@@ -834,7 +827,7 @@ fn genArgDbgInfo(isel: *Isel, inst: Air.Inst.Index, mcv: MCValue) !void {
reg.dwarfLocOp(),
});
try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try isel.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
+ try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
@@ -842,7 +835,7 @@ fn genArgDbgInfo(isel: *Isel, inst: Air.Inst.Index, mcv: MCValue) !void {
}
},
.stack_offset => {
- switch (isel.debug_output) {
+ switch (emit.debug_output) {
.dwarf => {},
.plan9 => {},
.none => {},
@@ -854,21 +847,21 @@ fn genArgDbgInfo(isel: *Isel, inst: Air.Inst.Index, mcv: MCValue) !void {
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(isel: *Isel, ty: Type) !void {
- switch (isel.debug_output) {
+fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
+ switch (emit.debug_output) {
.dwarf => |dbg_out| {
assert(ty.hasCodeGenBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const gop = try dbg_out.dbg_info_type_relocs.getOrPut(isel.bin_file.allocator, ty);
+ const gop = try dbg_out.dbg_info_type_relocs.getOrPut(emit.bin_file.allocator, ty);
if (!gop.found_existing) {
gop.value_ptr.* = .{
.off = undefined,
.relocs = .{},
};
}
- try gop.value_ptr.relocs.append(isel.bin_file.allocator, @intCast(u32, index));
+ try gop.value_ptr.relocs.append(emit.bin_file.allocator, @intCast(u32, index));
},
.plan9 => {},
.none => {},
@@ -1233,7 +1226,7 @@ const ScaleIndex = struct {
const Memory = struct {
base: ?Register,
rip: bool = false,
- disp: i32,
+ disp: u32,
ptr_size: PtrSize,
scale_index: ?ScaleIndex = null,
@@ -1283,7 +1276,7 @@ const Memory = struct {
} else {
encoder.sib_baseDisp8(dst);
}
- encoder.disp8(@intCast(i8, mem_op.disp));
+ encoder.disp8(@bitCast(i8, @truncate(u8, mem_op.disp)));
} else {
encoder.modRm_SIBDisp32(src);
if (mem_op.scale_index) |si| {
@@ -1291,17 +1284,17 @@ const Memory = struct {
} else {
encoder.sib_baseDisp32(dst);
}
- encoder.disp32(mem_op.disp);
+ encoder.disp32(@bitCast(i32, mem_op.disp));
}
} else {
if (mem_op.disp == 0) {
encoder.modRm_indirectDisp0(src, dst);
} else if (immOpSize(mem_op.disp) == 8) {
encoder.modRm_indirectDisp8(src, dst);
- encoder.disp8(@intCast(i8, mem_op.disp));
+ encoder.disp8(@bitCast(i8, @truncate(u8, mem_op.disp)));
} else {
encoder.modRm_indirectDisp32(src, dst);
- encoder.disp32(mem_op.disp);
+ encoder.disp32(@bitCast(i32, mem_op.disp));
}
}
} else {
@@ -1315,16 +1308,16 @@ const Memory = struct {
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) {
- 8 => encoder.imm8(@intCast(i8, imm)),
- 16 => encoder.imm16(@intCast(i16, imm)),
- 32, 64 => encoder.imm32(imm),
+ 8 => encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
+ 16 => encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
+ 32, 64 => encoder.imm32(@bitCast(i32, imm)),
else => unreachable,
}
}
@@ -1338,7 +1331,7 @@ const RegisterOrMemory = union(enum) {
}
fn mem(ptr_size: Memory.PtrSize, args: struct {
- disp: i32,
+ disp: u32,
base: ?Register = null,
scale_index: ?ScaleIndex = null,
}) RegisterOrMemory {
@@ -1352,7 +1345,7 @@ const RegisterOrMemory = union(enum) {
};
}
- fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory {
+ fn rip(ptr_size: Memory.PtrSize, disp: u32) RegisterOrMemory {
return .{
.memory = .{
.base = null,
@@ -1366,7 +1359,6 @@ const RegisterOrMemory = union(enum) {
const LoweringError = error{
OutOfMemory,
- Overflow,
OperandSizeMismatch,
RaxOperandExpected,
};
@@ -1377,12 +1369,12 @@ fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) LoweringError!void {
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) {
const encoder = try Encoder.init(code, 3);
const opc = getOpCode(tag, .i, false).?;
opc.encode(encoder);
- encoder.imm16(@intCast(i16, imm));
+ encoder.imm16(@bitCast(i16, @truncate(u16, imm)));
return;
}
const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;
@@ -1410,11 +1402,11 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) LoweringError!
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 encoder = try Encoder.init(code, 6);
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 {
@@ -1467,21 +1459,18 @@ 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);
}
-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);
}
-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()) {
return error.RaxOperandExpected;
}
- if (reg.size() != immOpSize(moffs)) {
- return error.OperandSizeMismatch;
- }
const opc = if (td)
getOpCode(tag, .td, reg.size() == 8).?
else
@@ -1495,29 +1484,15 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
});
opc.encode(encoder);
switch (reg.size()) {
- 8 => {
- const moffs8 = try math.cast(i8, moffs);
- encoder.imm8(moffs8);
- },
- 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));
- },
+ 8 => encoder.imm8(@bitCast(i8, @truncate(u8, moffs))),
+ 16 => encoder.imm16(@bitCast(i16, @truncate(u16, moffs))),
+ 32 => encoder.imm32(@bitCast(i32, @truncate(u32, moffs))),
+ 64 => encoder.imm64(moffs),
else => unreachable,
}
}
-fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) LoweringError!void {
- if (reg.size() != immOpSize(imm)) {
- return error.OperandSizeMismatch;
- }
+fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) LoweringError!void {
const opc = getOpCode(tag, .oi, reg.size() == 8).?;
const encoder = try Encoder.init(code, 10);
if (reg.size() == 16) {
@@ -1529,26 +1504,15 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Low
});
opc.encodeWithReg(encoder, reg);
switch (reg.size()) {
- 8 => {
- const imm8 = try math.cast(i8, imm);
- encoder.imm8(imm8);
- },
- 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));
- },
+ 8 => encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
+ 16 => encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
+ 32 => encoder.imm32(@bitCast(i32, @truncate(u32, imm))),
+ 64 => encoder.imm64(imm),
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).?;
switch (reg_or_mem) {
.register => |dst_reg| {
@@ -1700,7 +1664,7 @@ fn lowerToRmiEnc(
tag: Tag,
reg: Register,
reg_or_mem: RegisterOrMemory,
- imm: i32,
+ imm: u32,
code: *std.ArrayList(u8),
) LoweringError!void {
if (reg.size() == 8) {
@@ -1772,171 +1736,186 @@ fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []co
return error.TestFailed;
}
-const TestIsel = struct {
+const TestEmit = struct {
code_buffer: std.ArrayList(u8),
next: usize = 0,
- fn init() TestIsel {
+ fn init() TestEmit {
return .{
.code_buffer = std.ArrayList(u8).init(testing.allocator),
};
}
- fn deinit(isel: *TestIsel) void {
- isel.code_buffer.deinit();
- isel.next = undefined;
+ fn deinit(emit: *TestEmit) void {
+ emit.code_buffer.deinit();
+ emit.next = undefined;
}
- fn code(isel: *TestIsel) *std.ArrayList(u8) {
- isel.next = isel.code_buffer.items.len;
- return &isel.code_buffer;
+ fn code(emit: *TestEmit) *std.ArrayList(u8) {
+ emit.next = emit.code_buffer.items.len;
+ return &emit.code_buffer;
}
- fn lowered(isel: TestIsel) []const u8 {
- return isel.code_buffer.items[isel.next..];
+ fn lowered(emit: TestEmit) []const u8 {
+ return emit.code_buffer.items[emit.next..];
}
};
test "lower MI encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());
- 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 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 expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, emit.code());
+ try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", emit.lowered(), "mov rax, 0x10");
+ try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, emit.code());
+ try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", emit.lowered(), "mov dword ptr [r11 + 0], 0x10");
+ try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{
+ .disp = @bitCast(u32, @as(i32, -8)),
+ .base = .rdx,
+ }), 0x10, emit.code());
+ try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", emit.lowered(), "add dword ptr [rdx - 8], 0x10");
try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{
.disp = 0x10000000,
.base = .r11,
- }), 0x10, isel.code());
+ }), 0x10, emit.code());
try expectEqualHexStrings(
"\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"sub dword ptr [r11 + 0x10000000], 0x10",
);
- try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), 0x10, isel.code());
+ try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), 0x10, emit.code());
try expectEqualHexStrings(
"\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"and dword ptr [ds:0x10000000], 0x10",
);
try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{
.disp = 0x10000000,
.base = .r12,
- }), 0x10, isel.code());
+ }), 0x10, emit.code());
try expectEqualHexStrings(
"\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"and dword ptr [r12 + 0x10000000], 0x10",
);
- try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, isel.code());
+ try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, emit.code());
try expectEqualHexStrings(
"\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"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, emit.code());
try expectEqualHexStrings(
"\x48\xc7\x45\xf8\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"mov qword ptr [rbp - 8], 0x10",
);
- try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{ .disp = -2, .base = .rbp }), 0x10, isel.code());
- 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 expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");
+ try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{
+ .disp = @bitCast(u32, @as(i32, -2)),
+ .base = .rbp,
+ }), 0x10, emit.code());
+ try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", emit.lowered(), "mov word ptr [rbp - 2], 0x10");
+ try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{
+ .disp = @bitCast(u32, @as(i32, -1)),
+ .base = .rbp,
+ }), 0x10, emit.code());
+ try expectEqualHexStrings("\xC6\x45\xFF\x10", emit.lowered(), "mov byte ptr [rbp - 1], 0x10");
try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0x10000000,
.scale_index = .{
.scale = 1,
.index = .rcx,
},
- }), 0x10, isel.code());
+ }), 0x10, emit.code());
try expectEqualHexStrings(
"\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"mov qword ptr [rcx*2 + 0x10000000], 0x10",
);
}
test "lower RM encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());
- try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx");
- try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), isel.code());
- try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]");
- try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), isel.code());
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), emit.code());
+ try expectEqualHexStrings("\x48\x8b\xc3", emit.lowered(), "mov rax, rbx");
+ try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), emit.code());
+ try expectEqualHexStrings("\x49\x8b\x03", emit.lowered(), "mov rax, qword ptr [r11 + 0]");
+ try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), emit.code());
try expectEqualHexStrings(
"\x4C\x03\x1C\x25\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"add r11, qword ptr [ds:0x10000000]",
);
- try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), isel.code());
+ try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), emit.code());
try expectEqualHexStrings(
"\x44\x02\x24\x25\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"add r11b, byte ptr [ds:0x10000000]",
);
try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0x10000000,
.base = .r13,
- }), isel.code());
+ }), emit.code());
try expectEqualHexStrings(
"\x4D\x2B\x9D\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"sub r11, qword ptr [r13 + 0x10000000]",
);
try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0x10000000,
.base = .r12,
- }), isel.code());
+ }), emit.code());
try expectEqualHexStrings(
"\x4D\x2B\x9C\x24\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"sub r11, qword ptr [r12 + 0x10000000]",
);
- try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), isel.code());
- 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 expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
- .disp = -8,
+ .disp = @bitCast(u32, @as(i32, -4)),
+ .base = .rbp,
+ }), emit.code());
+ try expectEqualHexStrings("\x48\x8B\x45\xFC", emit.lowered(), "mov rax, qword ptr [rbp - 4]");
+ try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
+ try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", emit.lowered(), "lea rax, [rip + 0x10]");
+ try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
+ .disp = @bitCast(u32, @as(i32, -8)),
.base = .rbp,
.scale_index = .{
.scale = 0,
.index = .rcx,
},
- }), isel.code());
- try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
+ }), emit.code());
+ try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
- .disp = -4,
+ .disp = @bitCast(u32, @as(i32, -4)),
.base = .rbp,
.scale_index = .{
.scale = 2,
.index = .rdx,
},
- }), isel.code());
- try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
+ }), emit.code());
+ try expectEqualHexStrings("\x8B\x44\x95\xFC", emit.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
- .disp = -8,
+ .disp = @bitCast(u32, @as(i32, -8)),
.base = .rbp,
.scale_index = .{
.scale = 3,
.index = .rcx,
},
- }), isel.code());
- try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
+ }), emit.code());
+ try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{
- .disp = -24,
+ .disp = @bitCast(u32, @as(i32, -24)),
.base = .rsi,
.scale_index = .{
.scale = 0,
.index = .rcx,
},
- }), isel.code());
- try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", isel.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
+ }), emit.code());
+ try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", emit.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0,
.base = .rbp,
@@ -1944,145 +1923,148 @@ test "lower RM encoding" {
.scale = 0,
.index = .rcx,
},
- }), isel.code());
- try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", isel.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");
+ }), emit.code());
+ try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", emit.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]");
}
test "lower MR encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
- 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 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());
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, emit.code());
+ try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx");
+ try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
+ .disp = @bitCast(u32, @as(i32, -4)),
+ .base = .rbp,
+ }), .r11, emit.code());
+ try expectEqualHexStrings("\x4c\x89\x5d\xfc", emit.lowered(), "mov qword ptr [rbp - 4], r11");
+ try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, emit.code());
try expectEqualHexStrings(
"\x44\x00\x24\x25\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"add byte ptr [ds:0x10000000], r12b",
);
- try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, isel.code());
+ try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, emit.code());
try expectEqualHexStrings(
"\x44\x01\x24\x25\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"add dword ptr [ds:0x10000000], r12d",
);
try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0x10000000,
.base = .r11,
- }), .r12, isel.code());
+ }), .r12, emit.code());
try expectEqualHexStrings(
"\x4D\x29\xA3\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"sub qword ptr [r11 + 0x10000000], r12",
);
- try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, isel.code());
- try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");
+ try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, emit.code());
+ try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12");
}
test "lower OI encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToOiEnc(.mov, .rax, 0x1000000000000000, isel.code());
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToOiEnc(.mov, .rax, 0x1000000000000000, emit.code());
try expectEqualHexStrings(
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"movabs rax, 0x1000000000000000",
);
- try lowerToOiEnc(.mov, .r11, 0x1000000000000000, isel.code());
+ try lowerToOiEnc(.mov, .r11, 0x1000000000000000, emit.code());
try expectEqualHexStrings(
"\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"movabs r11, 0x1000000000000000",
);
- try lowerToOiEnc(.mov, .r11d, 0x10000000, isel.code());
- try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", isel.lowered(), "mov r11d, 0x10000000");
- try lowerToOiEnc(.mov, .r11w, 0x1000, isel.code());
- try expectEqualHexStrings("\x66\x41\xBB\x00\x10", isel.lowered(), "mov r11w, 0x1000");
- try lowerToOiEnc(.mov, .r11b, 0x10, isel.code());
- try expectEqualHexStrings("\x41\xB3\x10", isel.lowered(), "mov r11b, 0x10");
+ try lowerToOiEnc(.mov, .r11d, 0x10000000, emit.code());
+ try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", emit.lowered(), "mov r11d, 0x10000000");
+ try lowerToOiEnc(.mov, .r11w, 0x1000, emit.code());
+ try expectEqualHexStrings("\x66\x41\xBB\x00\x10", emit.lowered(), "mov r11w, 0x1000");
+ try lowerToOiEnc(.mov, .r11b, 0x10, emit.code());
+ try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10");
}
test "lower FD/TD encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToFdEnc(.mov, .rax, 0x1000000000000000, isel.code());
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToFdEnc(.mov, .rax, 0x1000000000000000, emit.code());
try expectEqualHexStrings(
"\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",
- isel.lowered(),
+ emit.lowered(),
"mov rax, ds:0x1000000000000000",
);
- try lowerToFdEnc(.mov, .eax, 0x10000000, isel.code());
- try expectEqualHexStrings("\xa1\x00\x00\x00\x10", isel.lowered(), "mov eax, ds:0x10000000");
- try lowerToFdEnc(.mov, .ax, 0x1000, isel.code());
- try expectEqualHexStrings("\x66\xa1\x00\x10", isel.lowered(), "mov ax, ds:0x1000");
- try lowerToFdEnc(.mov, .al, 0x10, isel.code());
- try expectEqualHexStrings("\xa0\x10", isel.lowered(), "mov al, ds:0x10");
+ try lowerToFdEnc(.mov, .eax, 0x10000000, emit.code());
+ try expectEqualHexStrings("\xa1\x00\x00\x00\x10", emit.lowered(), "mov eax, ds:0x10000000");
+ try lowerToFdEnc(.mov, .ax, 0x1000, emit.code());
+ try expectEqualHexStrings("\x66\xa1\x00\x10", emit.lowered(), "mov ax, ds:0x1000");
+ try lowerToFdEnc(.mov, .al, 0x10, emit.code());
+ try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10");
}
test "lower M encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12), isel.code());
- try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");
- try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());
- try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w");
- try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
- try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]");
- try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.word_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
- try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]");
- try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10, .base = .r12 }), isel.code());
- try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]");
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12), emit.code());
+ try expectEqualHexStrings("\x41\xFF\xE4", emit.lowered(), "jmp r12");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), emit.code());
+ try expectEqualHexStrings("\x66\x41\xFF\xE4", emit.lowered(), "jmp r12w");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r12 }), emit.code());
+ try expectEqualHexStrings("\x41\xFF\x24\x24", emit.lowered(), "jmp qword ptr [r12]");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.word_ptr, .{ .disp = 0, .base = .r12 }), emit.code());
+ try expectEqualHexStrings("\x66\x41\xFF\x24\x24", emit.lowered(), "jmp word ptr [r12]");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10, .base = .r12 }), emit.code());
+ try expectEqualHexStrings("\x41\xFF\x64\x24\x10", emit.lowered(), "jmp qword ptr [r12 + 0x10]");
try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{
.disp = 0x1000,
.base = .r12,
- }), isel.code());
+ }), emit.code());
try expectEqualHexStrings(
"\x41\xFF\xA4\x24\x00\x10\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"jmp qword ptr [r12 + 0x1000]",
);
- try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
- try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]");
- try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10 }), isel.code());
- try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");
- try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());
- try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
+ try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", emit.lowered(), "jmp qword ptr [rip + 0x10]");
+ try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10 }), emit.code());
+ try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", emit.lowered(), "jmp qword ptr [ds:0x10]");
+ try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), emit.code());
+ try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");
}
test "lower O encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
- try lowerToOEnc(.pop, .r12, isel.code());
- try expectEqualHexStrings("\x41\x5c", isel.lowered(), "pop r12");
- try lowerToOEnc(.push, .r12w, isel.code());
- try expectEqualHexStrings("\x66\x41\x54", isel.lowered(), "push r12w");
+ var emit = TestEmit.init();
+ defer emit.deinit();
+ try lowerToOEnc(.pop, .r12, emit.code());
+ try expectEqualHexStrings("\x41\x5c", emit.lowered(), "pop r12");
+ try lowerToOEnc(.push, .r12w, emit.code());
+ try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w");
}
test "lower RMI encoding" {
- var isel = TestIsel.init();
- defer isel.deinit();
+ var emit = TestEmit.init();
+ defer emit.deinit();
try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
- .disp = -8,
+ .disp = @bitCast(u32, @as(i32, -8)),
.base = .rbp,
- }), 0x10, isel.code());
+ }), 0x10, emit.code());
try expectEqualHexStrings(
"\x48\x69\x45\xF8\x10\x00\x00\x00",
- isel.lowered(),
+ emit.lowered(),
"imul rax, qword ptr [rbp - 8], 0x10",
);
try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
- .disp = -4,
+ .disp = @bitCast(u32, @as(i32, -4)),
.base = .rbp,
- }), 0x10, isel.code());
- try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
+ }), 0x10, emit.code());
+ try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", emit.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
- .disp = -2,
+ .disp = @bitCast(u32, @as(i32, -2)),
.base = .rbp,
- }), 0x10, isel.code());
- try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
- try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());
- try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");
- try lowerToRmiEnc(.imul, .r12w, RegisterOrMemory.reg(.r12w), 0x10, isel.code());
- try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", isel.lowered(), "imul r12w, r12w, 0x10");
+ }), 0x10, emit.code());
+ try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", emit.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
+ try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, emit.code());
+ try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", emit.lowered(), "imul r12, r12, 0x10");
+ try lowerToRmiEnc(.imul, .r12w, RegisterOrMemory.reg(.r12w), 0x10, emit.code());
+ try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10");
}
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index c5f595a86e..5ea4646c64 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -302,7 +302,7 @@ pub const Inst = struct {
/// Another instruction.
inst: Index,
/// A 32-bit immediate value.
- imm: i32,
+ imm: u32,
/// An extern function.
/// Index into the linker's string table.
extern_fn: u32,
@@ -324,8 +324,8 @@ pub const Inst = struct {
};
pub const ImmPair = struct {
- dest_off: i32,
- operand: i32,
+ dest_off: u32,
+ operand: u32,
};
pub const Imm64 = struct {