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;
2525const Mir = @import("Mir.zig");
2626const Module = @import("../../Module.zig");
2727const Instruction = bits.Instruction;
28const Register = bits.Register;
28const GpRegister = bits.Register;
29const AvxRegister = bits.Register;
2930const Type = @import("../../type.zig").Type;
3031
3132mir: Mir,
......@@ -248,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
248249 switch (ops.flags) {
249250 0b00 => {
250251 // PUSH/POP reg
251 return lowerToOEnc(tag, ops.reg1, emit.code);
252 return lowerToOEnc(tag, .{ .register = ops.reg1 }, emit.code);
252253 },
253254 0b01 => {
254255 // PUSH/POP r/m64
......@@ -271,6 +272,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
271272 0b11 => unreachable,
272273 }
273274}
275
274276fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
275277 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
276278 const payload = emit.mir.instructions.items(.data)[inst].payload;
......@@ -283,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
283285 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
284286 .disp = @bitCast(u32, -@intCast(i32, disp)),
285287 .base = ops.reg1,
286 }), reg.to64(), emit.code);
288 }), .{ .register = reg.to64() }, emit.code);
287289 } else {
288 try lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{
290 try lowerToRmEnc(.mov, .{ .register = reg.to64() }, RegisterOrMemory.mem(.qword_ptr, .{
289291 .disp = @bitCast(u32, -@intCast(i32, disp)),
290292 .base = ops.reg1,
291293 }), emit.code);
......@@ -319,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
319321 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code);
320322 }
321323 // JMP/CALL reg
322 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
324 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
323325 },
324326 0b10 => {
325327 // JMP/CALL r/m64
......@@ -392,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne
392394 },
393395 else => unreachable,
394396 };
395 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);
397 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1.to8() }), emit.code);
396398}
397399
398400fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
399401 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
400402 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);
402404 }
403405 const imm = emit.mir.instructions.items(.data)[inst].imm;
404406 const ptr_size: Memory.PtrSize = switch (ops.flags) {
......@@ -407,7 +409,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
407409 0b10 => .dword_ptr,
408410 0b11 => .qword_ptr,
409411 };
410 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ptr_size, .{
412 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(ptr_size, .{
411413 .disp = imm,
412414 .base = ops.reg2,
413415 }), emit.code);
......@@ -428,10 +430,15 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
428430 // I
429431 return lowerToIEnc(.@"test", imm, emit.code);
430432 }
431 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code);
433 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);
432434 }
433435 // 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 );
435442 },
436443 else => return emit.fail("TODO more TEST alternatives", .{}),
437444 }
......@@ -471,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
471478 // mov reg1, imm32
472479 // MI
473480 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);
475482 }
476483 // mov reg1, reg2
477484 // 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);
479486 },
480487 0b01 => {
481488 // mov reg1, [reg2 + imm32]
482489 // RM
483490 const imm = emit.mir.instructions.items(.data)[inst].imm;
484 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
485 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
491 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
492 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
486493 .disp = imm,
487494 .base = src_reg,
488495 }), emit.code);
......@@ -497,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
497504 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
498505 .disp = imm,
499506 .base = ops.reg1,
500 }), ops.reg2, emit.code);
507 }), .{ .register = ops.reg2 }, emit.code);
501508 },
502509 0b11 => {
503510 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 {
523530}
524531
525532inline fn setRexWRegister(reg: Register) bool {
526 if (reg.size() == 64) return true;
527 return switch (reg) {
528 .ah, .bh, .ch, .dh => true,
529 else => false,
530 };
533 switch (reg) {
534 .avx_register => return false,
535 .register => |r| {
536 if (r.size() == 64) return true;
537 return switch (r) {
538 .ah, .bh, .ch, .dh => true,
539 else => false,
540 };
541 },
542 }
531543}
532544
533545inline fn immOpSize(u_imm: u32) u8 {
......@@ -550,7 +562,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
550562 .scale = scale,
551563 .index = .rcx,
552564 };
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()), .{
554566 .disp = imm,
555567 .base = ops.reg2,
556568 .scale_index = scale_index,
......@@ -578,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
578590 .disp = imm,
579591 .base = ops.reg1,
580592 .scale_index = scale_index,
581 }), ops.reg2, emit.code);
593 }), .{ .register = ops.reg2 }, emit.code);
582594}
583595
584596fn 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 {
629641 switch (ops.flags) {
630642 0b00 => {
631643 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 );
633650 },
634651 0b01 => {
635 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{
652 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{
636653 .disp = imm,
637654 .base = ops.reg2,
638655 }), emit.code);
639656 },
640657 0b10 => {
641 return lowerToRmEnc(.movsx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{
658 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{
642659 .disp = imm,
643660 .base = ops.reg2,
644661 }), emit.code);
645662 },
646663 0b11 => {
647 return lowerToRmEnc(.movsxd, ops.reg1, RegisterOrMemory.mem(.dword_ptr, .{
664 return lowerToRmEnc(.movsxd, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.dword_ptr, .{
648665 .disp = imm,
649666 .base = ops.reg2,
650667 }), emit.code);
......@@ -659,16 +676,21 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
659676 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;
660677 switch (ops.flags) {
661678 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 );
663685 },
664686 0b01 => {
665 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.byte_ptr, .{
687 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{
666688 .disp = imm,
667689 .base = ops.reg2,
668690 }), emit.code);
669691 },
670692 0b10 => {
671 return lowerToRmEnc(.movzx, ops.reg1, RegisterOrMemory.mem(.word_ptr, .{
693 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{
672694 .disp = imm,
673695 .base = ops.reg2,
674696 }), emit.code);
......@@ -691,16 +713,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
691713 if (ops.flags == 0b00) {
692714 // movabs reg, imm64
693715 // OI
694 return lowerToOiEnc(.mov, ops.reg1, imm, emit.code);
716 return lowerToOiEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);
695717 }
696718 if (ops.reg1 == .none) {
697719 // movabs moffs64, rax
698720 // TD
699 return lowerToTdEnc(.mov, imm, ops.reg2, emit.code);
721 return lowerToTdEnc(.mov, imm, .{ .register = ops.reg2 }, emit.code);
700722 }
701723 // movabs rax, moffs64
702724 // FD
703 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
725 return lowerToFdEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);
704726}
705727
706728fn 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 {
751773 0b00 => {
752774 // sal reg1, 1
753775 // M1
754 return lowerToM1Enc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
776 return lowerToM1Enc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
755777 },
756778 0b01 => {
757779 // sal reg1, .cl
758780 // MC
759 return lowerToMcEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
781 return lowerToMcEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);
760782 },
761783 0b10 => {
762784 // sal reg1, imm8
763785 // MI
764786 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);
766788 },
767789 0b11 => {
768790 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 {
774796 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
775797 if (ops.reg1 != .none) {
776798 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);
778800 }
779801 assert(ops.reg1 == .none);
780802 assert(ops.reg2 != .none);
......@@ -797,24 +819,35 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
797819 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
798820 switch (ops.flags) {
799821 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 );
801828 },
802829 0b01 => {
803830 const imm = emit.mir.instructions.items(.data)[inst].imm;
804 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
805 return lowerToRmEnc(.imul, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{
831 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
832 return lowerToRmEnc(.imul, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.qword_ptr, .{
806833 .disp = imm,
807834 .base = src_reg,
808835 }), emit.code);
809836 },
810837 0b10 => {
811838 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 );
813846 },
814847 0b11 => {
815848 const payload = emit.mir.instructions.items(.data)[inst].payload;
816849 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, .{
818851 .disp = imm_pair.dest_off,
819852 .base = ops.reg2,
820853 }), imm_pair.operand, emit.code);
......@@ -842,10 +875,10 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
842875 // lea reg1, [reg2 + imm32]
843876 // RM
844877 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;
846879 return lowerToRmEnc(
847880 .lea,
848 ops.reg1,
881 .{ .register = ops.reg1 },
849882 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
850883 .disp = imm,
851884 .base = src_reg,
......@@ -859,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
859892 const start_offset = emit.code.items.len;
860893 try lowerToRmEnc(
861894 .lea,
862 ops.reg1,
895 .{ .register = ops.reg1 },
863896 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
864897 emit.code,
865898 );
......@@ -873,14 +906,14 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
873906 0b10 => {
874907 // lea reg, [rbp + rcx + imm32]
875908 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;
877910 const scale_index = ScaleIndex{
878911 .scale = 0,
879912 .index = .rcx,
880913 };
881914 return lowerToRmEnc(
882915 .lea,
883 ops.reg1,
916 .{ .register = ops.reg1 },
884917 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
885918 .disp = imm,
886919 .base = src_reg,
......@@ -903,7 +936,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
903936 // RM
904937 try lowerToRmEnc(
905938 .lea,
906 ops.reg1,
939 .{ .register = ops.reg1 },
907940 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
908941 emit.code,
909942 );
......@@ -1489,11 +1522,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
14891522
14901523const ScaleIndex = struct {
14911524 scale: u2,
1492 index: Register,
1525 index: GpRegister,
14931526};
14941527
14951528const Memory = struct {
1496 base: ?Register,
1529 base: ?GpRegister,
14971530 rip: bool = false,
14981531 disp: u32,
14991532 ptr_size: PtrSize,
......@@ -1595,6 +1628,40 @@ fn encodeImm(encoder: Encoder, imm: u32, size: u64) void {
15951628 }
15961629}
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
15981665const RegisterOrMemory = union(enum) {
15991666 register: Register,
16001667 memory: Memory,
......@@ -1605,7 +1672,7 @@ const RegisterOrMemory = union(enum) {
16051672
16061673 fn mem(ptr_size: Memory.PtrSize, args: struct {
16071674 disp: u32,
1608 base: ?Register = null,
1675 base: ?GpRegister = null,
16091676 scale_index: ?ScaleIndex = null,
16101677 }) RegisterOrMemory {
16111678 return .{
src/arch/x86_64/bits.zig+5
......@@ -151,6 +151,11 @@ pub const AvxRegister = enum(u6) {
151151 };
152152 }
153153
154 /// Returns whether the register is *extended*.
155 pub fn isExtended(self: Register) bool {
156 return @enumToInt(self) & 0x08 != 0;
157 }
158
154159 /// This returns the 4-bit register ID.
155160 pub fn id(self: AvxRegister) u4 {
156161 return @truncate(u4, @enumToInt(self));