authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 09:47:38+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 09:47:38+01:00
logb657956c440b355abab9fdf01a1517f99dd1ec90
tree81ebea3ec5da3eb409a35c817376c7ae8cfefc9e
parent603f826779bf0cd7fcd3b6f27a7ee6df8d158d8a

stage2: add lowering to O encoding

Example includes push/pop register.

1 files changed, 34 insertions(+), 27 deletions(-)

src/arch/x86_64/Emit.zig+34-27
...@@ -204,16 +204,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -204,16 +204,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
204 switch (ops.flags) {204 switch (ops.flags) {
205 0b00 => {205 0b00 => {
206 // PUSH/POP reg206 // PUSH/POP reg
207 const opc: u8 = switch (tag) {207 return lowerToOEnc(tag, ops.reg1, emit.code);
208 .push => 0x50,
209 .pop => 0x58,
210 else => unreachable,
211 };
212 const encoder = try Encoder.init(emit.code, 2);
213 encoder.rex(.{
214 .b = ops.reg1.isExtended(),
215 });
216 encoder.opcode_withReg(opc, ops.reg1.lowId());
217 },208 },
218 0b01 => {209 0b01 => {
219 // PUSH/POP r/m64210 // PUSH/POP r/m64
...@@ -240,22 +231,11 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -240,22 +231,11 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
240}231}
241fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {232fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
242 const callee_preserved_regs = bits.callee_preserved_regs;233 const callee_preserved_regs = bits.callee_preserved_regs;
243 // PUSH/POP reg
244 const opc: u8 = switch (tag) {
245 .push => 0x50,
246 .pop => 0x58,
247 else => unreachable,
248 };
249
250 const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop;234 const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop;
251 if (tag == .push) {235 if (tag == .push) {
252 for (callee_preserved_regs) |reg, i| {236 for (callee_preserved_regs) |reg, i| {
253 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;237 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
254 const encoder = try Encoder.init(emit.code, 2);238 try lowerToOEnc(.push, reg, emit.code);
255 encoder.rex(.{
256 .b = reg.isExtended(),
257 });
258 encoder.opcode_withReg(opc, reg.lowId());
259 }239 }
260 } else {240 } else {
261 // pop in the reverse direction241 // pop in the reverse direction
...@@ -263,11 +243,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -263,11 +243,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
263 while (i > 0) : (i -= 1) {243 while (i > 0) : (i -= 1) {
264 const reg = callee_preserved_regs[i - 1];244 const reg = callee_preserved_regs[i - 1];
265 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;245 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;
266 const encoder = try Encoder.init(emit.code, 2);246 try lowerToOEnc(.pop, reg, emit.code);
267 encoder.rex(.{
268 .b = reg.isExtended(),
269 });
270 encoder.opcode_withReg(opc, reg.lowId());
271 }247 }
272 }248 }
273}249}
...@@ -526,6 +502,9 @@ const Encoding = enum {...@@ -526,6 +502,9 @@ const Encoding = enum {
526 /// OP r/m64502 /// OP r/m64
527 m,503 m,
528504
505 /// OP r64
506 o,
507
529 /// OP r/m64, imm32508 /// OP r/m64, imm32
530 mi,509 mi,
531510
...@@ -557,6 +536,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 {...@@ -557,6 +536,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 {
557 .pop => 0x8f,536 .pop => 0x8f,
558 else => null,537 else => null,
559 },538 },
539 .o => return switch (tag) {
540 .push => 0x50,
541 .pop => 0x58,
542 else => null,
543 },
560 .mi => return switch (tag) {544 .mi => return switch (tag) {
561 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81,545 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81,
562 .mov => 0xc7,546 .mov => 0xc7,
...@@ -662,6 +646,20 @@ const RegisterOrMemory = union(enum) {...@@ -662,6 +646,20 @@ const RegisterOrMemory = union(enum) {
662 }646 }
663};647};
664648
649fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
650 if (reg.size() != 16 and reg.size() != 64) return error.EmitFail; // TODO correct for push/pop, but is it universal?
651 const opc = getOpCode(tag, .o).?;
652 const encoder = try Encoder.init(code, 3);
653 if (reg.size() == 16) {
654 encoder.opcode_1byte(0x66);
655 }
656 encoder.rex(.{
657 .w = false,
658 .b = reg.isExtended(),
659 });
660 encoder.opcode_withReg(opc, reg.lowId());
661}
662
665fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {663fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
666 const opc = getOpCode(tag, .d).?;664 const opc = getOpCode(tag, .d).?;
667 const encoder = try Encoder.init(code, 5);665 const encoder = try Encoder.init(code, 5);
...@@ -1727,3 +1725,12 @@ test "lower M encoding" {...@@ -1727,3 +1725,12 @@ test "lower M encoding" {
1727 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer());1725 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer());
1728 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [ds:0x10]");1726 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", code.emitted(), "jmp qword ptr [ds:0x10]");
1729}1727}
1728
1729test "lower O encoding" {
1730 var code = TestEmitCode.init();
1731 defer code.deinit();
1732 try lowerToOEnc(.pop, .r12, code.buffer());
1733 try expectEqualHexStrings("\x41\x5c", code.emitted(), "pop r12");
1734 try lowerToOEnc(.push, .r12w, code.buffer());
1735 try expectEqualHexStrings("\x66\x41\x54", code.emitted(), "push r12w");
1736}