diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-12-23 09:47:38 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-12-23 09:47:38 +0100 |
| commit | b657956c440b355abab9fdf01a1517f99dd1ec90 (patch) | |
| tree | 81ebea3ec5da3eb409a35c817376c7ae8cfefc9e /src | |
| parent | 603f826779bf0cd7fcd3b6f27a7ee6df8d158d8a (diff) | |
| download | zig-b657956c440b355abab9fdf01a1517f99dd1ec90.tar.gz zig-b657956c440b355abab9fdf01a1517f99dd1ec90.zip | |
stage2: add lowering to O encoding
Example includes push/pop register.
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 61 |
1 files changed, 34 insertions, 27 deletions
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 2849707643..c1331d7b51 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -204,16 +204,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { switch (ops.flags) { 0b00 => { // PUSH/POP reg - const opc: u8 = switch (tag) { - .push => 0x50, - .pop => 0x58, - else => unreachable, - }; - const encoder = try Encoder.init(emit.code, 2); - encoder.rex(.{ - .b = ops.reg1.isExtended(), - }); - encoder.opcode_withReg(opc, ops.reg1.lowId()); + return lowerToOEnc(tag, ops.reg1, emit.code); }, 0b01 => { // PUSH/POP r/m64 @@ -240,22 +231,11 @@ fn mirPushPop(emit: *Emit, 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; - // PUSH/POP reg - const opc: u8 = switch (tag) { - .push => 0x50, - .pop => 0x58, - else => unreachable, - }; - 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; - const encoder = try Encoder.init(emit.code, 2); - encoder.rex(.{ - .b = reg.isExtended(), - }); - encoder.opcode_withReg(opc, reg.lowId()); + try lowerToOEnc(.push, reg, emit.code); } } else { // pop in the reverse direction @@ -263,11 +243,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, 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; - const encoder = try Encoder.init(emit.code, 2); - encoder.rex(.{ - .b = reg.isExtended(), - }); - encoder.opcode_withReg(opc, reg.lowId()); + try lowerToOEnc(.pop, reg, emit.code); } } } @@ -526,6 +502,9 @@ const Encoding = enum { /// OP r/m64 m, + /// OP r64 + o, + /// OP r/m64, imm32 mi, @@ -557,6 +536,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 { .pop => 0x8f, else => null, }, + .o => return switch (tag) { + .push => 0x50, + .pop => 0x58, + else => null, + }, .mi => return switch (tag) { .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81, .mov => 0xc7, @@ -662,6 +646,20 @@ const RegisterOrMemory = union(enum) { } }; +fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void { + if (reg.size() != 16 and reg.size() != 64) return error.EmitFail; // TODO correct for push/pop, but is it universal? + const opc = getOpCode(tag, .o).?; + const encoder = try Encoder.init(code, 3); + if (reg.size() == 16) { + encoder.opcode_1byte(0x66); + } + encoder.rex(.{ + .w = false, + .b = reg.isExtended(), + }); + encoder.opcode_withReg(opc, reg.lowId()); +} + fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { const opc = getOpCode(tag, .d).?; const encoder = try Encoder.init(code, 5); @@ -1727,3 +1725,12 @@ test "lower M encoding" { try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer()); try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [ds:0x10]"); } + +test "lower O encoding" { + var code = TestEmitCode.init(); + defer code.deinit(); + try lowerToOEnc(.pop, .r12, code.buffer()); + try expectEqualHexStrings("\x41\x5c", code.emitted(), "pop r12"); + try lowerToOEnc(.push, .r12w, code.buffer()); + try expectEqualHexStrings("\x66\x41\x54", code.emitted(), "push r12w"); +} |
