| ... | ... | @@ -204,16 +204,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 204 | 204 | switch (ops.flags) { |
| 205 | 205 | 0b00 => { |
| 206 | 206 | // PUSH/POP reg |
| 207 | | const opc: u8 = switch (tag) { |
| 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()); |
| 207 | return lowerToOEnc(tag, ops.reg1, emit.code); |
| 217 | 208 | }, |
| 218 | 209 | 0b01 => { |
| 219 | 210 | // PUSH/POP r/m64 |
| ... | ... | @@ -240,22 +231,11 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 240 | 231 | } |
| 241 | 232 | fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 242 | 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 | 234 | const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop; |
| 251 | 235 | if (tag == .push) { |
| 252 | 236 | for (callee_preserved_regs) |reg, i| { |
| 253 | 237 | if ((regs >> @intCast(u5, i)) & 1 == 0) continue; |
| 254 | | const encoder = try Encoder.init(emit.code, 2); |
| 255 | | encoder.rex(.{ |
| 256 | | .b = reg.isExtended(), |
| 257 | | }); |
| 258 | | encoder.opcode_withReg(opc, reg.lowId()); |
| 238 | try lowerToOEnc(.push, reg, emit.code); |
| 259 | 239 | } |
| 260 | 240 | } else { |
| 261 | 241 | // pop in the reverse direction |
| ... | ... | @@ -263,11 +243,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I |
| 263 | 243 | while (i > 0) : (i -= 1) { |
| 264 | 244 | const reg = callee_preserved_regs[i - 1]; |
| 265 | 245 | if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue; |
| 266 | | const encoder = try Encoder.init(emit.code, 2); |
| 267 | | encoder.rex(.{ |
| 268 | | .b = reg.isExtended(), |
| 269 | | }); |
| 270 | | encoder.opcode_withReg(opc, reg.lowId()); |
| 246 | try lowerToOEnc(.pop, reg, emit.code); |
| 271 | 247 | } |
| 272 | 248 | } |
| 273 | 249 | } |
| ... | ... | @@ -526,6 +502,9 @@ const Encoding = enum { |
| 526 | 502 | /// OP r/m64 |
| 527 | 503 | m, |
| 528 | 504 | |
| 505 | /// OP r64 |
| 506 | o, |
| 507 | |
| 529 | 508 | /// OP r/m64, imm32 |
| 530 | 509 | mi, |
| 531 | 510 | |
| ... | ... | @@ -557,6 +536,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 { |
| 557 | 536 | .pop => 0x8f, |
| 558 | 537 | else => null, |
| 559 | 538 | }, |
| 539 | .o => return switch (tag) { |
| 540 | .push => 0x50, |
| 541 | .pop => 0x58, |
| 542 | else => null, |
| 543 | }, |
| 560 | 544 | .mi => return switch (tag) { |
| 561 | 545 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81, |
| 562 | 546 | .mov => 0xc7, |
| ... | ... | @@ -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 | 663 | fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 666 | 664 | const opc = getOpCode(tag, .d).?; |
| 667 | 665 | const encoder = try Encoder.init(code, 5); |
| ... | ... | @@ -1727,3 +1725,12 @@ test "lower M encoding" { |
| 1727 | 1725 | try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10), code.buffer()); |
| 1728 | 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 | } |