| ... | @@ -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 reg | 206 | // 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/m64 | 210 | // 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 | } |
| 241 | fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { | 232 | fn 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 direction | 241 | // 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/m64 | 502 | /// OP r/m64 |
| 527 | m, | 503 | m, |
| 528 | | 504 | |
| | 505 | /// OP r64 |
| | 506 | o, |
| | 507 | |
| 529 | /// OP r/m64, imm32 | 508 | /// OP r/m64, imm32 |
| 530 | mi, | 509 | mi, |
| 531 | | 510 | |
| ... | @@ -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 | }; |
| 664 | | 648 | |
| | 649 | fn 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 | |
| 665 | fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { | 663 | fn 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 | |
| | 1729 | test "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 | } |