authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-12 17:40:54+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:36:35+02:00
log875a16030c2e58f9f8b9a2b66b43b565e3932cf5
tree03b35489b806dad9a2951a275753b25d7e104c31
parent70d809e0bbc51efa78b54838cc64158b4d4a2dd2

x64: extend Emit to allow for AVX registers


2 files changed, 122 insertions(+), 50 deletions(-)

src/arch/x86_64/Emit.zig+117-50
...@@ -25,7 +25,8 @@ const MCValue = @import("CodeGen.zig").MCValue;...@@ -25,7 +25,8 @@ const MCValue = @import("CodeGen.zig").MCValue;
25const Mir = @import("Mir.zig");25const Mir = @import("Mir.zig");
26const Module = @import("../../Module.zig");26const Module = @import("../../Module.zig");
27const Instruction = bits.Instruction;27const Instruction = bits.Instruction;
28const Register = bits.Register;28const GpRegister = bits.Register;
29const AvxRegister = bits.Register;
29const Type = @import("../../type.zig").Type;30const Type = @import("../../type.zig").Type;
3031
31mir: Mir,32mir: Mir,
...@@ -248,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -248,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
248 switch (ops.flags) {249 switch (ops.flags) {
249 0b00 => {250 0b00 => {
250 // PUSH/POP reg251 // PUSH/POP reg
251 return lowerToOEnc(tag, ops.reg1, emit.code);252 return lowerToOEnc(tag, .{ .register = ops.reg1 }, emit.code);
252 },253 },
253 0b01 => {254 0b01 => {
254 // PUSH/POP r/m64255 // PUSH/POP r/m64
...@@ -271,6 +272,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -271,6 +272,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
271 0b11 => unreachable,272 0b11 => unreachable,
272 }273 }
273}274}
275
274fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {276fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
275 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);277 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
276 const payload = emit.mir.instructions.items(.data)[inst].payload;278 const payload = emit.mir.instructions.items(.data)[inst].payload;
...@@ -283,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -283,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
283 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{285 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
284 .disp = @bitCast(u32, -@intCast(i32, disp)),286 .disp = @bitCast(u32, -@intCast(i32, disp)),
285 .base = ops.reg1,287 .base = ops.reg1,
286 }), reg.to64(), emit.code);288 }), .{ .register = reg.to64() }, emit.code);
287 } else {289 } else {
288 try lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{290 try lowerToRmEnc(.mov, .{ .register = reg.to64() }, RegisterOrMemory.mem(.qword_ptr, .{
289 .disp = @bitCast(u32, -@intCast(i32, disp)),291 .disp = @bitCast(u32, -@intCast(i32, disp)),
290 .base = ops.reg1,292 .base = ops.reg1,
291 }), emit.code);293 }), emit.code);
...@@ -319,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -319,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
319 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code);321 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code);
320 }322 }
321 // JMP/CALL reg323 // JMP/CALL reg
322 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);324 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
323 },325 },
324 0b10 => {326 0b10 => {
325 // JMP/CALL r/m64327 // JMP/CALL r/m64
...@@ -392,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne...@@ -392,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne
392 },394 },
393 else => unreachable,395 else => unreachable,
394 };396 };
395 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);397 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1.to8() }), emit.code);
396}398}
397399
398fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {400fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
399 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);401 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
400 if (ops.flags == 0b00) {402 if (ops.flags == 0b00) {
401 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);403 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.reg(.{ .register = ops.reg2 }), emit.code);
402 }404 }
403 const imm = emit.mir.instructions.items(.data)[inst].imm;405 const imm = emit.mir.instructions.items(.data)[inst].imm;
404 const ptr_size: Memory.PtrSize = switch (ops.flags) {406 const ptr_size: Memory.PtrSize = switch (ops.flags) {
...@@ -407,7 +409,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -407,7 +409,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
407 0b10 => .dword_ptr,409 0b10 => .dword_ptr,
408 0b11 => .qword_ptr,410 0b11 => .qword_ptr,
409 };411 };
410 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ptr_size, .{412 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(ptr_size, .{
411 .disp = imm,413 .disp = imm,
412 .base = ops.reg2,414 .base = ops.reg2,
413 }), emit.code);415 }), emit.code);
...@@ -428,10 +430,15 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -428,10 +430,15 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
428 // I430 // I
429 return lowerToIEnc(.@"test", imm, emit.code);431 return lowerToIEnc(.@"test", imm, emit.code);
430 }432 }
431 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code);433 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);
432 }434 }
433 // TEST r/m64, r64435 // TEST r/m64, r64
434 return lowerToMrEnc(.@"test", RegisterOrMemory.reg(ops.reg1), ops.reg2, emit.code);436 return lowerToMrEnc(
437 .@"test",
438 RegisterOrMemory.reg(.{ .register = ops.reg1 }),
439 .{ .register = ops.reg2 },
440 emit.code,
441 );
435 },442 },
436 else => return emit.fail("TODO more TEST alternatives", .{}),443 else => return emit.fail("TODO more TEST alternatives", .{}),
437 }444 }
...@@ -471,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -471,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
471 // mov reg1, imm32478 // mov reg1, imm32
472 // MI479 // MI
473 const imm = emit.mir.instructions.items(.data)[inst].imm;480 const imm = emit.mir.instructions.items(.data)[inst].imm;
474 return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);481 return lowerToMiEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);
475 }482 }
476 // mov reg1, reg2483 // mov reg1, reg2
477 // RM484 // RM
478 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);485 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.reg(.{ .register = ops.reg2 }), emit.code);
479 },486 },
480 0b01 => {487 0b01 => {
481 // mov reg1, [reg2 + imm32]488 // mov reg1, [reg2 + imm32]
482 // RM489 // RM
483 const imm = emit.mir.instructions.items(.data)[inst].imm;490 const imm = emit.mir.instructions.items(.data)[inst].imm;
484 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;491 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
485 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{492 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
486 .disp = imm,493 .disp = imm,
487 .base = src_reg,494 .base = src_reg,
488 }), emit.code);495 }), emit.code);
...@@ -497,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -497,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
497 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{504 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
498 .disp = imm,505 .disp = imm,
499 .base = ops.reg1,506 .base = ops.reg1,
500 }), ops.reg2, emit.code);507 }), .{ .register = ops.reg2 }, emit.code);
501 },508 },
502 0b11 => {509 0b11 => {
503 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});510 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
...@@ -523,11 +530,16 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -523,11 +530,16 @@ fn mirArithMemImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
523}530}
524531
525inline fn setRexWRegister(reg: Register) bool {532inline fn setRexWRegister(reg: Register) bool {
526 if (reg.size() == 64) return true;533 switch (reg) {
527 return switch (reg) {534 .avx_register => return false,
528 .ah, .bh, .ch, .dh => true,535 .register => |r| {
529 else => false,536 if (r.size() == 64) return true;
530 };537 return switch (r) {
538 .ah, .bh, .ch, .dh => true,
539 else => false,
540 };
541 },
542 }
531}543}
532544
533inline fn immOpSize(u_imm: u32) u8 {545inline fn immOpSize(u_imm: u32) u8 {
...@@ -550,7 +562,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -550,7 +562,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
550 .scale = scale,562 .scale = scale,
551 .index = .rcx,563 .index = .rcx,
552 };564 };
553 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{565 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
554 .disp = imm,566 .disp = imm,
555 .base = ops.reg2,567 .base = ops.reg2,
556 .scale_index = scale_index,568 .scale_index = scale_index,
...@@ -578,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -578,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
578 .disp = imm,590 .disp = imm,
579 .base = ops.reg1,591 .base = ops.reg1,
580 .scale_index = scale_index,592 .scale_index = scale_index,
581 }), ops.reg2, emit.code);593 }), .{ .register = ops.reg2 }, emit.code);
582}594}
583595
584fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {596fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
...@@ -629,22 +641,27 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -629,22 +641,27 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
629 switch (ops.flags) {641 switch (ops.flags) {
630 0b00 => {642 0b00 => {
631 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;643 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;
632 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);644 return lowerToRmEnc(
645 tag,
646 .{ .register = ops.reg1 },
647 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
648 emit.code,
649 );
633 },650 },
634 0b01 => {651 0b01 => {
635 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{652 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{
636 .disp = imm,653 .disp = imm,
637 .base = ops.reg2,654 .base = ops.reg2,
638 }), emit.code);655 }), emit.code);
639 },656 },
640 0b10 => {657 0b10 => {
641 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{658 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{
642 .disp = imm,659 .disp = imm,
643 .base = ops.reg2,660 .base = ops.reg2,
644 }), emit.code);661 }), emit.code);
645 },662 },
646 0b11 => {663 0b11 => {
647 return lowerToRmEnc(.movsxd, ops.reg1, RegisterOrMemory.mem(.dword_ptr, .{664 return lowerToRmEnc(.movsxd, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.dword_ptr, .{
648 .disp = imm,665 .disp = imm,
649 .base = ops.reg2,666 .base = ops.reg2,
650 }), emit.code);667 }), emit.code);
...@@ -659,16 +676,21 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -659,16 +676,21 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
659 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;676 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;
660 switch (ops.flags) {677 switch (ops.flags) {
661 0b00 => {678 0b00 => {
662 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);679 return lowerToRmEnc(
680 .movzx,
681 .{ .register = ops.reg1 },
682 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
683 emit.code,
684 );
663 },685 },
664 0b01 => {686 0b01 => {
665 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{687 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{
666 .disp = imm,688 .disp = imm,
667 .base = ops.reg2,689 .base = ops.reg2,
668 }), emit.code);690 }), emit.code);
669 },691 },
670 0b10 => {692 0b10 => {
671 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{693 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{
672 .disp = imm,694 .disp = imm,
673 .base = ops.reg2,695 .base = ops.reg2,
674 }), emit.code);696 }), emit.code);
...@@ -691,16 +713,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -691,16 +713,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
691 if (ops.flags == 0b00) {713 if (ops.flags == 0b00) {
692 // movabs reg, imm64714 // movabs reg, imm64
693 // OI715 // OI
694 return lowerToOiEnc(.mov, ops.reg1, imm, emit.code);716 return lowerToOiEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);
695 }717 }
696 if (ops.reg1 == .none) {718 if (ops.reg1 == .none) {
697 // movabs moffs64, rax719 // movabs moffs64, rax
698 // TD720 // TD
699 return lowerToTdEnc(.mov, imm, ops.reg2, emit.code);721 return lowerToTdEnc(.mov, imm, .{ .register = ops.reg2 }, emit.code);
700 }722 }
701 // movabs rax, moffs64723 // movabs rax, moffs64
702 // FD724 // FD
703 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);725 return lowerToFdEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);
704}726}
705727
706fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {728fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
...@@ -751,18 +773,18 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -751,18 +773,18 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
751 0b00 => {773 0b00 => {
752 // sal reg1, 1774 // sal reg1, 1
753 // M1775 // M1
754 return lowerToM1Enc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);776 return lowerToM1Enc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
755 },777 },
756 0b01 => {778 0b01 => {
757 // sal reg1, .cl779 // sal reg1, .cl
758 // MC780 // MC
759 return lowerToMcEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);781 return lowerToMcEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
760 },782 },
761 0b10 => {783 0b10 => {
762 // sal reg1, imm8784 // sal reg1, imm8
763 // MI785 // MI
764 const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);786 const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);
765 return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);787 return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);
766 },788 },
767 0b11 => {789 0b11 => {
768 return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});790 return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});
...@@ -774,7 +796,7 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -774,7 +796,7 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
774 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);796 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
775 if (ops.reg1 != .none) {797 if (ops.reg1 != .none) {
776 assert(ops.reg2 == .none);798 assert(ops.reg2 == .none);
777 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);799 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
778 }800 }
779 assert(ops.reg1 == .none);801 assert(ops.reg1 == .none);
780 assert(ops.reg2 != .none);802 assert(ops.reg2 != .none);
...@@ -797,24 +819,35 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -797,24 +819,35 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
797 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);819 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
798 switch (ops.flags) {820 switch (ops.flags) {
799 0b00 => {821 0b00 => {
800 return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);822 return lowerToRmEnc(
823 .imul,
824 .{ .register = ops.reg1 },
825 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
826 emit.code,
827 );
801 },828 },
802 0b01 => {829 0b01 => {
803 const imm = emit.mir.instructions.items(.data)[inst].imm;830 const imm = emit.mir.instructions.items(.data)[inst].imm;
804 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;831 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
805 return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{832 return lowerToRmEnc(.imul, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.qword_ptr, .{
806 .disp = imm,833 .disp = imm,
807 .base = src_reg,834 .base = src_reg,
808 }), emit.code);835 }), emit.code);
809 },836 },
810 0b10 => {837 0b10 => {
811 const imm = emit.mir.instructions.items(.data)[inst].imm;838 const imm = emit.mir.instructions.items(.data)[inst].imm;
812 return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.reg(ops.reg2), imm, emit.code);839 return lowerToRmiEnc(
840 .imul,
841 .{ .register = ops.reg1 },
842 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
843 imm,
844 emit.code,
845 );
813 },846 },
814 0b11 => {847 0b11 => {
815 const payload = emit.mir.instructions.items(.data)[inst].payload;848 const payload = emit.mir.instructions.items(.data)[inst].payload;
816 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;849 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
817 return lowerToRmiEnc(.imul, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{850 return lowerToRmiEnc(.imul, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.qword_ptr, .{
818 .disp = imm_pair.dest_off,851 .disp = imm_pair.dest_off,
819 .base = ops.reg2,852 .base = ops.reg2,
820 }), imm_pair.operand, emit.code);853 }), imm_pair.operand, emit.code);
...@@ -842,10 +875,10 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -842,10 +875,10 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
842 // lea reg1, [reg2 + imm32]875 // lea reg1, [reg2 + imm32]
843 // RM876 // RM
844 const imm = emit.mir.instructions.items(.data)[inst].imm;877 const imm = emit.mir.instructions.items(.data)[inst].imm;
845 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;878 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
846 return lowerToRmEnc(879 return lowerToRmEnc(
847 .lea,880 .lea,
848 ops.reg1,881 .{ .register = ops.reg1 },
849 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{882 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
850 .disp = imm,883 .disp = imm,
851 .base = src_reg,884 .base = src_reg,
...@@ -859,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -859,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
859 const start_offset = emit.code.items.len;892 const start_offset = emit.code.items.len;
860 try lowerToRmEnc(893 try lowerToRmEnc(
861 .lea,894 .lea,
862 ops.reg1,895 .{ .register = ops.reg1 },
863 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),896 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
864 emit.code,897 emit.code,
865 );898 );
...@@ -873,14 +906,14 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -873,14 +906,14 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
873 0b10 => {906 0b10 => {
874 // lea reg, [rbp + rcx + imm32]907 // lea reg, [rbp + rcx + imm32]
875 const imm = emit.mir.instructions.items(.data)[inst].imm;908 const imm = emit.mir.instructions.items(.data)[inst].imm;
876 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;909 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
877 const scale_index = ScaleIndex{910 const scale_index = ScaleIndex{
878 .scale = 0,911 .scale = 0,
879 .index = .rcx,912 .index = .rcx,
880 };913 };
881 return lowerToRmEnc(914 return lowerToRmEnc(
882 .lea,915 .lea,
883 ops.reg1,916 .{ .register = ops.reg1 },
884 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{917 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
885 .disp = imm,918 .disp = imm,
886 .base = src_reg,919 .base = src_reg,
...@@ -903,7 +936,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -903,7 +936,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
903 // RM936 // RM
904 try lowerToRmEnc(937 try lowerToRmEnc(
905 .lea,938 .lea,
906 ops.reg1,939 .{ .register = ops.reg1 },
907 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),940 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
908 emit.code,941 emit.code,
909 );942 );
...@@ -1489,11 +1522,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1489,11 +1522,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
14891522
1490const ScaleIndex = struct {1523const ScaleIndex = struct {
1491 scale: u2,1524 scale: u2,
1492 index: Register,1525 index: GpRegister,
1493};1526};
14941527
1495const Memory = struct {1528const Memory = struct {
1496 base: ?Register,1529 base: ?GpRegister,
1497 rip: bool = false,1530 rip: bool = false,
1498 disp: u32,1531 disp: u32,
1499 ptr_size: PtrSize,1532 ptr_size: PtrSize,
...@@ -1595,6 +1628,40 @@ fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {...@@ -1595,6 +1628,40 @@ fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {
1595 }1628 }
1596}1629}
15971630
1631const Register = union(enum) {
1632 register: GpRegister,
1633 avx_register: AvxRegister,
1634
1635 fn reg(register: GpRegister) Register {
1636 return .{ .register = register };
1637 }
1638
1639 fn avxReg(register: AvxRegister) Register {
1640 return .{ .avx_register = register };
1641 }
1642
1643 fn lowId(register: Register) u3 {
1644 return switch (register) {
1645 .register => |r| r.lowId(),
1646 .avx_register => |r| r.lowId(),
1647 };
1648 }
1649
1650 fn size(register: Register) u64 {
1651 return switch (register) {
1652 .register => |r| r.size(),
1653 .avx_register => |r| r.size(),
1654 };
1655 }
1656
1657 fn isExtended(register: Register) bool {
1658 return switch (register) {
1659 .register => |r| r.isExtended(),
1660 .avx_register => |r| r.isExtended(),
1661 };
1662 }
1663};
1664
1598const RegisterOrMemory = union(enum) {1665const RegisterOrMemory = union(enum) {
1599 register: Register,1666 register: Register,
1600 memory: Memory,1667 memory: Memory,
...@@ -1605,7 +1672,7 @@ const RegisterOrMemory = union(enum) {...@@ -1605,7 +1672,7 @@ const RegisterOrMemory = union(enum) {
16051672
1606 fn mem(ptr_size: Memory.PtrSize, args: struct {1673 fn mem(ptr_size: Memory.PtrSize, args: struct {
1607 disp: u32,1674 disp: u32,
1608 base: ?Register = null,1675 base: ?GpRegister = null,
1609 scale_index: ?ScaleIndex = null,1676 scale_index: ?ScaleIndex = null,
1610 }) RegisterOrMemory {1677 }) RegisterOrMemory {
1611 return .{1678 return .{
src/arch/x86_64/bits.zig+5
...@@ -151,6 +151,11 @@ pub const AvxRegister = enum(u6) {...@@ -151,6 +151,11 @@ pub const AvxRegister = enum(u6) {
151 };151 };
152 }152 }
153153
154 /// Returns whether the register is *extended*.
155 pub fn isExtended(self: Register) bool {
156 return @enumToInt(self) & 0x08 != 0;
157 }
158
154 /// This returns the 4-bit register ID.159 /// This returns the 4-bit register ID.
155 pub fn id(self: AvxRegister) u4 {160 pub fn id(self: AvxRegister) u4 {
156 return @truncate(u4, @enumToInt(self));161 return @truncate(u4, @enumToInt(self));