stage2: add separate tag for MI encoding

To request memory-immediate encoding at the MIR side, we should now
use a new tag such as `mov_mem_imm` where the size of the memory
pointer is encoded as the flags:

```
0b00 => .byte_ptr,
0b01 => .word_ptr,
0b10 => .dword_ptr,
0b11 => .qword_ptr,
```
This commit is contained in:
Jakub Konka 2021-12-29 13:38:49 +01:00
parent be5130ec53
commit 08ea1a2eab
4 changed files with 796 additions and 589 deletions

View File

@ -1646,7 +1646,7 @@ fn genBinMathOpMir(
_ = try self.addInst(.{
.tag = mir_tag,
.ops = (Mir.Ops{
.reg1 = registerAlias(dst_reg, 4),
.reg1 = dst_reg.to32(),
}).encode(),
.data = .{ .imm = @intCast(i32, imm) },
});
@ -2807,10 +2807,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.operand = @bitCast(i32, @intCast(u32, x_big)),
});
_ = try self.addInst(.{
.tag = .mov,
.tag = .mov_mem_imm,
.ops = (Mir.Ops{
.reg1 = .rbp,
.flags = 0b11,
.flags = 0b10,
}).encode(),
.data = .{ .payload = payload },
});
@ -2828,10 +2828,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.operand = @bitCast(i32, @truncate(u32, x_big >> 32)),
});
_ = try self.addInst(.{
.tag = .mov,
.tag = .mov_mem_imm,
.ops = (Mir.Ops{
.reg1 = .rbp,
.flags = 0b11,
.flags = 0b10,
}).encode(),
.data = .{ .payload = payload },
});
@ -2842,10 +2842,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.operand = @bitCast(i32, @truncate(u32, x_big)),
});
_ = try self.addInst(.{
.tag = .mov,
.tag = .mov_mem_imm,
.ops = (Mir.Ops{
.reg1 = .rbp,
.flags = 0b11,
.flags = 0b10,
}).encode(),
.data = .{ .payload = payload },
});
@ -2955,11 +2955,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
}
if (x <= math.maxInt(i32)) {
// Next best case: if we set the lower four bytes, the upper four will be zeroed.
// TODO I am not quite sure why we need to set the size of the register here...
_ = try self.addInst(.{
.tag = .mov,
.ops = (Mir.Ops{
.reg1 = registerAlias(reg, 4),
.reg1 = reg.to32(),
}).encode(),
.data = .{ .imm = @intCast(i32, x) },
});
@ -2985,9 +2984,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
// We need the offset from RIP in a signed i32 twos complement.
const payload = try self.addExtra(Mir.Imm64.encode(code_offset));
_ = try self.addInst(.{
.tag = .lea_rip,
.tag = .lea,
.ops = (Mir.Ops{
.reg1 = reg,
.flags = 0b01,
}).encode(),
.data = .{ .payload = payload },
});
@ -3011,10 +3011,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
if (self.bin_file.options.pie) {
// TODO we should flag up `x` as GOT symbol entry explicitly rather than as a hack.
_ = try self.addInst(.{
.tag = .lea_rip,
.tag = .lea,
.ops = (Mir.Ops{
.reg1 = reg,
.flags = 0b01,
.flags = 0b10,
}).encode(),
.data = .{ .got_entry = @intCast(u32, x) },
});

File diff suppressed because it is too large Load Diff

View File

@ -38,13 +38,18 @@ pub const Inst = struct {
/// 0b01 reg1, [reg2 + imm32]
/// 0b01 reg1, [ds:imm32]
/// 0b10 [reg1 + imm32], reg2
/// 0b10 [reg1 + 0], imm32
/// 0b11 [reg1 + imm32], imm32
/// Notes:
/// * If reg2 is `none` then it means Data field `imm` is used as the immediate.
/// * When two imm32 values are required, Data field `payload` points at `ImmPair`.
adc,
/// ops flags: form:
/// 0b00 byte ptr [reg1 + imm32], imm8
/// 0b01 word ptr [reg1 + imm32], imm16
/// 0b10 dword ptr [reg1 + imm32], imm32
/// 0b11 qword ptr [reg1 + imm32], imm32 (sign-extended to imm64)
adc_mem_imm,
/// form: reg1, [reg2 + scale*rcx + imm32]
/// ops flags scale
/// 0b00 1
@ -77,74 +82,95 @@ pub const Inst = struct {
// The following instructions all have the same encoding as `adc`.
add,
add_mem_imm,
add_scale_src,
add_scale_dst,
add_scale_imm,
sub,
sub_mem_imm,
sub_scale_src,
sub_scale_dst,
sub_scale_imm,
xor,
xor_mem_imm,
xor_scale_src,
xor_scale_dst,
xor_scale_imm,
@"and",
and_mem_imm,
and_scale_src,
and_scale_dst,
and_scale_imm,
@"or",
or_mem_imm,
or_scale_src,
or_scale_dst,
or_scale_imm,
rol,
rol_mem_imm,
rol_scale_src,
rol_scale_dst,
rol_scale_imm,
ror,
ror_mem_imm,
ror_scale_src,
ror_scale_dst,
ror_scale_imm,
rcl,
rcl_mem_imm,
rcl_scale_src,
rcl_scale_dst,
rcl_scale_imm,
rcr,
rcr_mem_imm,
rcr_scale_src,
rcr_scale_dst,
rcr_scale_imm,
shl,
shl_mem_imm,
shl_scale_src,
shl_scale_dst,
shl_scale_imm,
sal,
sal_mem_imm,
sal_scale_src,
sal_scale_dst,
sal_scale_imm,
shr,
shr_mem_imm,
shr_scale_src,
shr_scale_dst,
shr_scale_imm,
sar,
sar_mem_imm,
sar_scale_src,
sar_scale_dst,
sar_scale_imm,
sbb,
sbb_mem_imm,
sbb_scale_src,
sbb_scale_dst,
sbb_scale_imm,
cmp,
cmp_mem_imm,
cmp_scale_src,
cmp_scale_dst,
cmp_scale_imm,
mov,
mov_mem_imm,
mov_scale_src,
mov_scale_dst,
mov_scale_imm,
/// ops flags: form:
/// 0b00 reg1, [reg2 + imm32]
/// 0b00 reg1, [ds:imm32]
/// 0b01 reg1, [rip + imm32]
/// 0b10 reg1, [rip + reloc]
/// Notes:
/// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate
/// a valid relocation for.
lea,
lea_scale_src,
lea_scale_dst,
lea_scale_imm,
/// ops flags: form:
/// 0bX0 reg1
@ -160,15 +186,6 @@ pub const Inst = struct {
/// 0b11 reg1, [reg2 + imm32], imm32
imul_complex,
/// ops flags: form:
/// 0bX0 reg1, [rip + imm32]
/// 0bX1 reg1, [rip + reloc]
/// Notes:
/// * if flags are 0bX1, `Data` contains `got_entry` for linker to generate
/// valid relocation for.
/// TODO handle more cases
lea_rip,
/// ops flags: form:
/// 0bX0 reg1, imm64
/// 0bX1 rax, moffs64
@ -233,16 +250,8 @@ pub const Inst = struct {
syscall,
/// ops flags: form:
/// 0b00 reg1, reg2
/// 0b00 reg1, imm32
/// 0b01 reg1, [reg2 + imm32]
/// 0b01 reg1, [ds:imm32]
/// 0b10 [reg1 + imm32], reg2
/// 0b10 [reg1 + 0], imm32
/// 0b11 [reg1 + imm32], imm32
/// Notes:
/// * If reg2 is `none` then it means Data field `imm` is used as the immediate.
/// * When two imm32 values are required, Data field `payload` points at `ImmPair`.
/// TODO handle more cases
@"test",
/// Breakpoint

View File

@ -64,6 +64,15 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
.sbb => try print.mirArith(.sbb, inst, w),
.cmp => try print.mirArith(.cmp, inst, w),
.adc_mem_imm => try print.mirArithMemImm(.adc, inst, w),
.add_mem_imm => try print.mirArithMemImm(.add, inst, w),
.sub_mem_imm => try print.mirArithMemImm(.sub, inst, w),
.xor_mem_imm => try print.mirArithMemImm(.xor, inst, w),
.and_mem_imm => try print.mirArithMemImm(.@"and", inst, w),
.or_mem_imm => try print.mirArithMemImm(.@"or", inst, w),
.sbb_mem_imm => try print.mirArithMemImm(.sbb, inst, w),
.cmp_mem_imm => try print.mirArithMemImm(.cmp, inst, w),
.adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w),
.add_scale_src => try print.mirArithScaleSrc(.add, inst, w),
.sub_scale_src => try print.mirArithScaleSrc(.sub, inst, w),
@ -98,7 +107,6 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
.movabs => try print.mirMovabs(inst, w),
.lea => try print.mirLea(inst, w),
.lea_rip => try print.mirLeaRip(inst, w),
.imul_complex => try print.mirIMulComplex(inst, w),
@ -490,6 +498,13 @@ fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: any
try w.writeByte('\n');
}
fn mirArithMemImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
_ = print;
_ = tag;
_ = inst;
return w.writeAll("TODO mirArithMemImm\n");
}
fn mirArithScaleSrc(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
const scale = ops.flags;
@ -560,19 +575,16 @@ fn mirIMulComplex(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
}
fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
const tag = print.mir.instructions.items(.tag)[inst];
assert(tag == .lea);
const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
assert(ops.flags == 0b01);
const imm = print.mir.instructions.items(.data)[inst].imm;
try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
}
fn mirLeaRip(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
_ = print;
_ = inst;
return w.writeAll("TODO lea_rip\n");
return w.writeAll("TODO lea\n");
// const tag = print.mir.instructions.items(.tag)[inst];
// assert(tag == .lea);
// const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
// assert(ops.flags == 0b01);
// const imm = print.mir.instructions.items(.data)[inst].imm;
// try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
}
fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {