authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 00:36:44+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 00:43:38+01:00
log1167e248ef8ab94aac3c4218574a09ba9346d34f
tree180b7188d0b3de1581370698a626e8ee2612f3ef
parent362eccf539db6bb89e222916f3c4a45b0eb2bece

stage2: add lowering of D encoding

Example of such encoding includes a near/far call and jmp instructions.

1 files changed, 118 insertions(+), 110 deletions(-)

src/arch/x86_64/Emit.zig+118-110
......@@ -66,40 +66,45 @@ pub fn emitMir(emit: *Emit) InnerError!void {
6666 const inst = @intCast(u32, index);
6767 try emit.code_offset_mapping.putNoClobber(emit.bin_file.allocator, inst, emit.code.items.len);
6868 switch (tag) {
69 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp, .mov => try emit.mirArith(tag, inst),
70
71 .adc_scale_src,
72 .add_scale_src,
73 .sub_scale_src,
74 .xor_scale_src,
75 .and_scale_src,
76 .or_scale_src,
77 .sbb_scale_src,
78 .cmp_scale_src,
79 .mov_scale_src,
80 => try emit.mirArithScaleSrc(tag, inst),
81
82 .adc_scale_dst,
83 .add_scale_dst,
84 .sub_scale_dst,
85 .xor_scale_dst,
86 .and_scale_dst,
87 .or_scale_dst,
88 .sbb_scale_dst,
89 .cmp_scale_dst,
90 .mov_scale_dst,
91 => try emit.mirArithScaleDst(tag, inst),
92
93 .adc_scale_imm,
94 .add_scale_imm,
95 .sub_scale_imm,
96 .xor_scale_imm,
97 .and_scale_imm,
98 .or_scale_imm,
99 .sbb_scale_imm,
100 .cmp_scale_imm,
101 .mov_scale_imm,
102 => try emit.mirArithScaleImm(tag, inst),
69 .adc => try emit.mirArith(.adc, inst),
70 .add => try emit.mirArith(.add, inst),
71 .sub => try emit.mirArith(.sub, inst),
72 .xor => try emit.mirArith(.xor, inst),
73 .@"and" => try emit.mirArith(.@"and", inst),
74 .@"or" => try emit.mirArith(.@"or", inst),
75 .sbb => try emit.mirArith(.sbb, inst),
76 .cmp => try emit.mirArith(.cmp, inst),
77 .mov => try emit.mirArith(.mov, inst),
78
79 .adc_scale_src => try emit.mirArithScaleSrc(.adc, inst),
80 .add_scale_src => try emit.mirArithScaleSrc(.add, inst),
81 .sub_scale_src => try emit.mirArithScaleSrc(.sub, inst),
82 .xor_scale_src => try emit.mirArithScaleSrc(.xor, inst),
83 .and_scale_src => try emit.mirArithScaleSrc(.@"and", inst),
84 .or_scale_src => try emit.mirArithScaleSrc(.@"or", inst),
85 .sbb_scale_src => try emit.mirArithScaleSrc(.sbb, inst),
86 .cmp_scale_src => try emit.mirArithScaleSrc(.cmp, inst),
87 .mov_scale_src => try emit.mirArithScaleSrc(.mov, inst),
88
89 .adc_scale_dst => try emit.mirArithScaleDst(.adc, inst),
90 .add_scale_dst => try emit.mirArithScaleDst(.add, inst),
91 .sub_scale_dst => try emit.mirArithScaleDst(.sub, inst),
92 .xor_scale_dst => try emit.mirArithScaleDst(.xor, inst),
93 .and_scale_dst => try emit.mirArithScaleDst(.@"and", inst),
94 .or_scale_dst => try emit.mirArithScaleDst(.@"or", inst),
95 .sbb_scale_dst => try emit.mirArithScaleDst(.sbb, inst),
96 .cmp_scale_dst => try emit.mirArithScaleDst(.cmp, inst),
97 .mov_scale_dst => try emit.mirArithScaleDst(.mov, inst),
98
99 .adc_scale_imm => try emit.mirArithScaleImm(.adc, inst),
100 .add_scale_imm => try emit.mirArithScaleImm(.add, inst),
101 .sub_scale_imm => try emit.mirArithScaleImm(.sub, inst),
102 .xor_scale_imm => try emit.mirArithScaleImm(.xor, inst),
103 .and_scale_imm => try emit.mirArithScaleImm(.@"and", inst),
104 .or_scale_imm => try emit.mirArithScaleImm(.@"or", inst),
105 .sbb_scale_imm => try emit.mirArithScaleImm(.sbb, inst),
106 .cmp_scale_imm => try emit.mirArithScaleImm(.cmp, inst),
107 .mov_scale_imm => try emit.mirArithScaleImm(.mov, inst),
103108
104109 .movabs => try emit.mirMovabs(inst),
105110
......@@ -110,7 +115,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
110115
111116 .push, .pop => try emit.mirPushPop(tag, inst),
112117
113 .jmp, .call => try emit.mirJmpCall(tag, inst),
118 .jmp => try emit.mirJmpCall(.jmp_near, inst),
119 .call => try emit.mirJmpCall(.call_near, inst),
114120
115121 .cond_jmp_greater_less,
116122 .cond_jmp_above_below,
......@@ -283,31 +289,24 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Mir.Inst.Tag, inst: M
283289 }
284290}
285291
286fn mirJmpCall(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
292fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
287293 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
288294 const flag = @truncate(u1, ops.flags);
289295 if (flag == 0) {
290296 const target = emit.mir.instructions.items(.data)[inst].inst;
291 const opc: u8 = switch (tag) {
292 .jmp => 0xe9,
293 .call => 0xe8,
294 else => unreachable,
295 };
296297 const source = emit.code.items.len;
297 const encoder = try Encoder.init(emit.code, 5);
298 encoder.opcode_1byte(opc);
298 try lowerToDEnc(tag, 0, emit.code);
299299 try emit.relocs.append(emit.bin_file.allocator, .{
300300 .source = source,
301301 .target = target,
302 .offset = emit.code.items.len,
302 .offset = emit.code.items.len - 4,
303303 .length = 5,
304304 });
305 encoder.imm32(0x0);
306305 return;
307306 }
308307 const modrm_ext: u3 = switch (tag) {
309 .jmp => 0x4,
310 .call => 0x2,
308 .jmp_near => 0x4,
309 .call_near => 0x2,
311310 else => unreachable,
312311 };
313312 if (ops.reg1 == .none) {
......@@ -532,7 +531,28 @@ fn mirRet(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
532531 }
533532}
534533
534const Tag = enum {
535 adc,
536 add,
537 sub,
538 xor,
539 @"and",
540 @"or",
541 sbb,
542 cmp,
543 mov,
544 lea,
545 jmp_near,
546 call_near,
547};
548
535549const Encoding = enum {
550 /// OP rel32
551 d,
552
553 /// OP r/m64
554 m,
555
536556 /// OP r/m64, imm32
537557 mi,
538558
......@@ -552,12 +572,21 @@ const Encoding = enum {
552572 td,
553573};
554574
555inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
575inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 {
556576 switch (enc) {
577 .d => return switch (tag) {
578 .jmp_near => 0xe9,
579 .call_near => 0xe8,
580 else => null,
581 },
582 .m => return switch (tag) {
583 .jmp_near, .call_near => 0xff,
584 else => null,
585 },
557586 .mi => return switch (tag) {
558587 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81,
559588 .mov => 0xc7,
560 else => unreachable,
589 else => null,
561590 },
562591 .mr => return switch (tag) {
563592 .adc => 0x11,
......@@ -569,7 +598,7 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
569598 .sbb => 0x19,
570599 .cmp => 0x39,
571600 .mov => 0x89,
572 else => unreachable,
601 else => null,
573602 },
574603 .rm => return switch (tag) {
575604 .adc => 0x13,
......@@ -582,24 +611,24 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
582611 .cmp => 0x3b,
583612 .mov => 0x8b,
584613 .lea => 0x8d,
585 else => unreachable,
614 else => null,
586615 },
587616 .oi => return switch (tag) {
588617 .mov => 0xb8,
589 else => unreachable,
618 else => null,
590619 },
591620 .fd => return switch (tag) {
592621 .mov => 0xa1,
593 else => unreachable,
622 else => null,
594623 },
595624 .td => return switch (tag) {
596625 .mov => 0xa3,
597 else => unreachable,
626 else => null,
598627 },
599628 }
600629}
601630
602inline fn getMiModRmExt(tag: Mir.Inst.Tag) u3 {
631inline fn getModRmExt(tag: Tag) u3 {
603632 return switch (tag) {
604633 .adc => 0x2,
605634 .add => 0x0,
......@@ -610,6 +639,7 @@ inline fn getMiModRmExt(tag: Mir.Inst.Tag) u3 {
610639 .sbb => 0x3,
611640 .cmp => 0x7,
612641 .mov => 0x0,
642 .call_near => 0x2,
613643 else => unreachable,
614644 };
615645}
......@@ -655,34 +685,25 @@ const RegisterOrMemory = union(enum) {
655685 }
656686};
657687
658fn lowerToTdEnc(
659 tag: Mir.Inst.Tag,
660 moffs: i64,
661 reg: Register,
662 code: *std.ArrayList(u8),
663) InnerError!void {
688fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
689 const opc = getOpCode(tag, .d).?;
690 const encoder = try Encoder.init(code, 5);
691 encoder.opcode_1byte(opc);
692 encoder.imm32(imm);
693}
694
695fn lowerToTdEnc(tag: Tag, moffs: i64, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
664696 return lowerToTdFdEnc(tag, reg, moffs, code, true);
665697}
666698
667fn lowerToFdEnc(
668 tag: Mir.Inst.Tag,
669 reg: Register,
670 moffs: i64,
671 code: *std.ArrayList(u8),
672) InnerError!void {
699fn lowerToFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8)) InnerError!void {
673700 return lowerToTdFdEnc(tag, reg, moffs, code, false);
674701}
675702
676fn lowerToTdFdEnc(
677 tag: Mir.Inst.Tag,
678 reg: Register,
679 moffs: i64,
680 code: *std.ArrayList(u8),
681 td: bool,
682) InnerError!void {
703fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), td: bool) InnerError!void {
683704 if (reg.lowId() != Register.rax.lowId()) return error.EmitFail;
684705 if (reg.size() != immOpSize(moffs)) return error.EmitFail;
685 var opc = if (td) getOpCode(tag, .td) else getOpCode(tag, .fd);
706 var opc = if (td) getOpCode(tag, .td).? else getOpCode(tag, .fd).?;
686707 if (reg.size() == 8) {
687708 opc -= 1;
688709 }
......@@ -714,13 +735,8 @@ fn lowerToTdFdEnc(
714735 }
715736}
716737
717fn lowerToOiEnc(
718 tag: Mir.Inst.Tag,
719 reg: Register,
720 imm: i64,
721 code: *std.ArrayList(u8),
722) InnerError!void {
723 var opc = getOpCode(tag, .oi);
738fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) InnerError!void {
739 var opc = getOpCode(tag, .oi).?;
724740 if (reg.size() != immOpSize(imm)) return error.EmitFail;
725741 if (reg.size() == 8) {
726742 opc -= 8;
......@@ -754,14 +770,9 @@ fn lowerToOiEnc(
754770 }
755771}
756772
757fn lowerToMiEnc(
758 tag: Mir.Inst.Tag,
759 reg_or_mem: RegisterOrMemory,
760 imm: i32,
761 code: *std.ArrayList(u8),
762) InnerError!void {
763 var opc = getOpCode(tag, .mi);
764 const modrm_ext = getMiModRmExt(tag);
773fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
774 var opc = getOpCode(tag, .mi).?;
775 const modrm_ext = getModRmExt(tag);
765776 switch (reg_or_mem) {
766777 .register => |dst_reg| {
767778 if (dst_reg.size() == 8) {
......@@ -839,12 +850,12 @@ fn lowerToMiEnc(
839850}
840851
841852fn lowerToRmEnc(
842 tag: Mir.Inst.Tag,
853 tag: Tag,
843854 reg: Register,
844855 reg_or_mem: RegisterOrMemory,
845856 code: *std.ArrayList(u8),
846857) InnerError!void {
847 var opc = getOpCode(tag, .rm);
858 var opc = getOpCode(tag, .rm).?;
848859 if (reg.size() == 8) {
849860 opc -= 1;
850861 }
......@@ -909,7 +920,7 @@ fn lowerToRmEnc(
909920}
910921
911922fn lowerToMrEnc(
912 tag: Mir.Inst.Tag,
923 tag: Tag,
913924 reg_or_mem: RegisterOrMemory,
914925 reg: Register,
915926 code: *std.ArrayList(u8),
......@@ -920,7 +931,7 @@ fn lowerToMrEnc(
920931 // * reg is 32bit - dword ptr
921932 // * reg is 16bit - word ptr
922933 // * reg is 8bit - byte ptr
923 var opc = getOpCode(tag, .mr);
934 var opc = getOpCode(tag, .mr).?;
924935 if (reg.size() == 8) {
925936 opc -= 1;
926937 }
......@@ -982,7 +993,7 @@ fn lowerToMrEnc(
982993 }
983994}
984995
985fn mirArith(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
996fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
986997 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
987998 switch (ops.flags) {
988999 0b00 => {
......@@ -1053,11 +1064,11 @@ fn immOpSize(imm: i64) u8 {
10531064 return 64;
10541065}
10551066
1056fn mirArithScaleSrc(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
1067fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
10571068 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
10581069 const scale = ops.flags;
10591070 // OP reg1, [reg2 + scale*rcx + imm32]
1060 var opc = getOpCode(tag, .rm);
1071 var opc = getOpCode(tag, .rm).?;
10611072 if (ops.reg1.size() == 8) {
10621073 opc -= 1;
10631074 }
......@@ -1080,15 +1091,15 @@ fn mirArithScaleSrc(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
10801091 }
10811092}
10821093
1083fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
1094fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
10841095 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
10851096 const scale = ops.flags;
10861097 const imm = emit.mir.instructions.items(.data)[inst].imm;
10871098
10881099 if (ops.reg2 == .none) {
10891100 // OP [reg1 + scale*rax + 0], imm32
1090 var opc = getOpCode(tag, .mi);
1091 const modrm_ext = getMiModRmExt(tag);
1101 var opc = getOpCode(tag, .mi).?;
1102 const modrm_ext = getModRmExt(tag);
10921103 if (ops.reg1.size() == 8) {
10931104 opc -= 1;
10941105 }
......@@ -1111,7 +1122,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
11111122 }
11121123
11131124 // OP [reg1 + scale*rax + imm32], reg2
1114 var opc = getOpCode(tag, .mr);
1125 var opc = getOpCode(tag, .mr).?;
11151126 if (ops.reg1.size() == 8) {
11161127 opc -= 1;
11171128 }
......@@ -1133,16 +1144,16 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
11331144 }
11341145}
11351146
1136fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
1147fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
11371148 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
11381149 const scale = ops.flags;
11391150 const payload = emit.mir.instructions.items(.data)[inst].payload;
11401151 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
1141 var opc = getOpCode(tag, .mi);
1152 var opc = getOpCode(tag, .mi).?;
11421153 if (ops.reg1.size() == 8) {
11431154 opc -= 1;
11441155 }
1145 const modrm_ext = getMiModRmExt(tag);
1156 const modrm_ext = getModRmExt(tag);
11461157 const encoder = try Encoder.init(emit.code, 2);
11471158 encoder.rex(.{
11481159 .w = ops.reg1.size() == 64,
......@@ -1230,7 +1241,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
12301241 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
12311242 assert(ops.flags == 0b01);
12321243 const imm = emit.mir.instructions.items(.data)[inst].imm;
1233 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ops.reg2, imm), emit.code);
1244 return lowerToRmEnc(.lea, ops.reg1, RegisterOrMemory.mem(ops.reg2, imm), emit.code);
12341245}
12351246
12361247fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
......@@ -1272,12 +1283,9 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
12721283 assert(tag == .call_extern);
12731284 const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;
12741285 const offset = blk: {
1275 const offset = @intCast(u32, emit.code.items.len + 1);
12761286 // callq
1277 const encoder = try Encoder.init(emit.code, 5);
1278 encoder.opcode_1byte(0xe8);
1279 encoder.imm32(0x0);
1280 break :blk offset;
1287 try lowerToDEnc(.call_near, 0, emit.code);
1288 break :blk @intCast(u32, emit.code.items.len) - 4;
12811289 };
12821290 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
12831291 // Add relocation to the decl.