authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-11-25 20:10:27-05:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-11-27 10:56:04-05:00
logbd19f5e611da33d8ae236781a9725de636f0b201
tree8bd2e99311e328df9fefc76560776b5d529d2aa2
parentc9352ef9d6d9f1bca94c25710e11de0ae171605f

initial implementation of print_mir


4 files changed, 595 insertions(+), 0 deletions(-)

src/Compilation.zig+3
......@@ -81,6 +81,7 @@ clang_preprocessor_mode: ClangPreprocessorMode,
8181/// Whether to print clang argvs to stdout.
8282verbose_cc: bool,
8383verbose_air: bool,
84verbose_mir: bool,
8485verbose_llvm_ir: bool,
8586verbose_cimport: bool,
8687verbose_llvm_cpu_features: bool,
......@@ -743,6 +744,7 @@ pub const InitOptions = struct {
743744 verbose_cc: bool = false,
744745 verbose_link: bool = false,
745746 verbose_air: bool = false,
747 verbose_mir: bool = false,
746748 verbose_llvm_ir: bool = false,
747749 verbose_cimport: bool = false,
748750 verbose_llvm_cpu_features: bool = false,
......@@ -1526,6 +1528,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
15261528 .clang_preprocessor_mode = options.clang_preprocessor_mode,
15271529 .verbose_cc = options.verbose_cc,
15281530 .verbose_air = options.verbose_air,
1531 .verbose_mir = options.verbose_mir,
15291532 .verbose_llvm_ir = options.verbose_llvm_ir,
15301533 .verbose_cimport = options.verbose_cimport,
15311534 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
src/arch/x86_64/CodeGen.zig+8
......@@ -319,6 +319,14 @@ pub fn generate(
319319 else => |e| return e,
320320 };
321321
322 if (builtin.mode == .Debug and bin_file.options.module.?.comp.verbose_mir) {
323 const w = std.io.getStdErr().writer();
324 w.print("# Begin Function MIR: {s}:\n", .{module_fn.owner_decl.name}) catch {};
325 const print = @import("./PrintMir.zig"){ .mir = mir };
326 print.printMir(w) catch {}; // we don't care if the debug printing fails
327 w.print("# End Function MIR: {s}:\n\n", .{module_fn.owner_decl.name}) catch {};
328 }
329
322330 if (function.err_msg) |em| {
323331 return FnResult{ .fail = em };
324332 } else {
src/arch/x86_64/PrintMir.zig created+579
......@@ -0,0 +1,579 @@
1//! This file contains the functionality for print x86_64 MIR in a debug way, interleaved with AIR
2
3const Print = @This();
4
5const std = @import("std");
6const assert = std.debug.assert;
7const bits = @import("bits.zig");
8const leb128 = std.leb;
9const link = @import("../../link.zig");
10const log = std.log.scoped(.codegen);
11const math = std.math;
12const mem = std.mem;
13
14const Air = @import("../../Air.zig");
15const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
16const DW = std.dwarf;
17const Encoder = bits.Encoder;
18const ErrorMsg = Module.ErrorMsg;
19const MCValue = @import("CodeGen.zig").MCValue;
20const Mir = @import("Mir.zig");
21const Module = @import("../../Module.zig");
22const Instruction = bits.Instruction;
23const Register = bits.Register;
24const Type = @import("../../type.zig").Type;
25const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
26
27mir: Mir,
28
29pub fn printMir(print: *const Print, w: anytype) !void {
30 const instruction_bytes = print.mir.instructions.len *
31 // Here we don't use @sizeOf(Mir.Inst.Data) because it would include
32 // the debug safety tag but we want to measure release size.
33 (@sizeOf(Mir.Inst.Tag) + 2 + 8);
34 const extra_bytes = print.mir.extra.len * @sizeOf(u32);
35 const total_bytes = @sizeOf(Mir) + instruction_bytes + extra_bytes;
36
37 // zig fmt: off
38 std.debug.print(
39 \\# Total MIR bytes: {}
40 \\# MIR Instructions: {d} ({})
41 \\# MIR Extra Data: {d} ({})
42 \\
43 , .{
44 fmtIntSizeBin(total_bytes),
45 print.mir.instructions.len, fmtIntSizeBin(instruction_bytes),
46 print.mir.extra.len, fmtIntSizeBin(extra_bytes),
47 });
48 // zig fmt: on
49 const mir_tags = print.mir.instructions.items(.tag);
50
51 for (mir_tags) |tag, index| {
52 try w.writeAll(" ");
53 const inst = @intCast(u32, index);
54 switch (tag) {
55 .adc => try print.mirArith(.adc, inst, w),
56 .add => try print.mirArith(.add, inst, w),
57 .sub => try print.mirArith(.sub, inst, w),
58 .xor => try print.mirArith(.xor, inst, w),
59 .@"and" => try print.mirArith(.@"and", inst, w),
60 .@"or" => try print.mirArith(.@"or", inst, w),
61 .sbb => try print.mirArith(.sbb, inst, w),
62 .cmp => try print.mirArith(.cmp, inst, w),
63
64 .adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w),
65 .add_scale_src => try print.mirArithScaleSrc(.add, inst, w),
66 .sub_scale_src => try print.mirArithScaleSrc(.sub, inst, w),
67 .xor_scale_src => try print.mirArithScaleSrc(.xor, inst, w),
68 .and_scale_src => try print.mirArithScaleSrc(.@"and", inst, w),
69 .or_scale_src => try print.mirArithScaleSrc(.@"or", inst, w),
70 .sbb_scale_src => try print.mirArithScaleSrc(.sbb, inst, w),
71 .cmp_scale_src => try print.mirArithScaleSrc(.cmp, inst, w),
72
73 .adc_scale_dst => try print.mirArithScaleDst(.adc, inst, w),
74 .add_scale_dst => try print.mirArithScaleDst(.add, inst, w),
75 .sub_scale_dst => try print.mirArithScaleDst(.sub, inst, w),
76 .xor_scale_dst => try print.mirArithScaleDst(.xor, inst, w),
77 .and_scale_dst => try print.mirArithScaleDst(.@"and", inst, w),
78 .or_scale_dst => try print.mirArithScaleDst(.@"or", inst, w),
79 .sbb_scale_dst => try print.mirArithScaleDst(.sbb, inst, w),
80 .cmp_scale_dst => try print.mirArithScaleDst(.cmp, inst, w),
81
82 .adc_scale_imm => try print.mirArithScaleImm(.adc, inst, w),
83 .add_scale_imm => try print.mirArithScaleImm(.add, inst, w),
84 .sub_scale_imm => try print.mirArithScaleImm(.sub, inst, w),
85 .xor_scale_imm => try print.mirArithScaleImm(.xor, inst, w),
86 .and_scale_imm => try print.mirArithScaleImm(.@"and", inst, w),
87 .or_scale_imm => try print.mirArithScaleImm(.@"or", inst, w),
88 .sbb_scale_imm => try print.mirArithScaleImm(.sbb, inst, w),
89 .cmp_scale_imm => try print.mirArithScaleImm(.cmp, inst, w),
90
91 .mov => try print.mirArith(.mov, inst, w),
92 .mov_scale_src => try print.mirArithScaleSrc(.mov, inst, w),
93 .mov_scale_dst => try print.mirArithScaleDst(.mov, inst, w),
94 .mov_scale_imm => try print.mirArithScaleImm(.mov, inst, w),
95 .movabs => try print.mirMovabs(inst, w),
96
97 .lea => try print.mirLea(inst, w),
98 .lea_rip => try print.mirLeaRip(inst, w),
99
100 .imul_complex => try print.mirIMulComplex(inst, w),
101
102 .push => try print.mirPushPop(.push, inst, w),
103 .pop => try print.mirPushPop(.pop, inst, w),
104
105 .jmp => try print.mirJmpCall(.jmp, inst, w),
106 .call => try print.mirJmpCall(.call, inst, w),
107
108 // .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w),
109 // .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w),
110 // .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w),
111
112 // .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w),
113 // .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w),
114 // .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w),
115
116 // .@"test" => try print.mirTest(inst, w),
117
118 .brk => try w.writeAll("brk\n"),
119 .ret => try w.writeAll("ret\n"),
120 .nop => try w.writeAll("nop\n"),
121 .syscall => try w.writeAll("syscall\n"),
122
123 .call_extern => try print.mirCallExtern(inst, w),
124
125 .dbg_line, .dbg_prologue_end, .dbg_epilogue_begin, .arg_dbg_info => try w.print("{s}\n", .{@tagName(tag)}),
126
127 .push_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.push, inst, w),
128 .pop_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.pop, inst, w),
129
130 else => {
131 try w.print("TODO emit asm for {s}\n", .{@tagName(tag)});
132 },
133 }
134 }
135}
136
137fn mirPushPop(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
138 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
139 switch (ops.flags) {
140 0b00 => {
141 // PUSH/POP reg
142 try w.print("{s} {s}", .{ @tagName(tag), @tagName(ops.reg1) });
143 },
144 0b01 => {
145 // PUSH/POP r/m64
146 const imm = print.mir.instructions.items(.data)[inst].imm;
147 try w.print("{s} [{s} + {d}]", .{ @tagName(tag), @tagName(ops.reg1), imm });
148 },
149 0b10 => {
150 const imm = print.mir.instructions.items(.data)[inst].imm;
151 // PUSH imm32
152 assert(tag == .push);
153 try w.print("{s} {d}", .{ @tagName(tag), imm });
154 },
155 0b11 => unreachable,
156 }
157 try w.writeByte('\n');
158}
159fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
160 const callee_preserved_regs = bits.callee_preserved_regs;
161 // PUSH/POP reg
162
163 const regs = print.mir.instructions.items(.data)[inst].regs_to_push_or_pop;
164 if (regs == 0) return w.writeAll("push/pop no regs from callee_preserved_regs\n");
165 if (tag == .push) {
166 try w.writeAll("push ");
167 for (callee_preserved_regs) |reg, i| {
168 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
169 try w.print("{s}, ", .{@tagName(reg)});
170 }
171 } else {
172 // pop in the reverse direction
173 var i = callee_preserved_regs.len;
174 try w.writeAll("pop ");
175 while (i > 0) : (i -= 1) {
176 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;
177 const reg = callee_preserved_regs[i - 1];
178 try w.print("{s}, ", .{@tagName(reg)});
179 }
180 }
181 try w.writeByte('\n');
182}
183
184fn mirJmpCall(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
185 try w.print("{s} ", .{@tagName(tag)});
186 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
187 const flag = @truncate(u1, ops.flags);
188 if (flag == 0) {
189 return w.writeAll("TODO target\n");
190 }
191 if (ops.reg1 == .none) {
192 // JMP/CALL [imm]
193 const imm = print.mir.instructions.items(.data)[inst].imm;
194 try w.print("[{x}]\n", .{imm});
195 return;
196 }
197 // JMP/CALL reg
198 try w.print("{s}\n", .{@tagName(ops.reg1)});
199}
200
201const CondType = enum {
202 /// greater than or equal
203 gte,
204
205 /// greater than
206 gt,
207
208 /// less than
209 lt,
210
211 /// less than or equal
212 lte,
213
214 /// above or equal
215 ae,
216
217 /// above
218 a,
219
220 /// below
221 b,
222
223 /// below or equal
224 be,
225
226 /// not equal
227 ne,
228
229 /// equal
230 eq,
231
232 fn fromTagAndFlags(tag: Mir.Inst.Tag, flags: u2) CondType {
233 return switch (tag) {
234 .cond_jmp_greater_less,
235 .cond_set_byte_greater_less,
236 => switch (flags) {
237 0b00 => CondType.gte,
238 0b01 => CondType.gt,
239 0b10 => CondType.lt,
240 0b11 => CondType.lte,
241 },
242 .cond_jmp_above_below,
243 .cond_set_byte_above_below,
244 => switch (flags) {
245 0b00 => CondType.ae,
246 0b01 => CondType.a,
247 0b10 => CondType.b,
248 0b11 => CondType.be,
249 },
250 .cond_jmp_eq_ne,
251 .cond_set_byte_eq_ne,
252 => switch (@truncate(u1, flags)) {
253 0b0 => CondType.ne,
254 0b1 => CondType.eq,
255 },
256 else => unreachable,
257 };
258 }
259};
260
261inline fn getCondOpCode(tag: Mir.Inst.Tag, cond: CondType) u8 {
262 switch (cond) {
263 .gte => return switch (tag) {
264 .cond_jmp_greater_less => 0x8d,
265 .cond_set_byte_greater_less => 0x9d,
266 else => unreachable,
267 },
268 .gt => return switch (tag) {
269 .cond_jmp_greater_less => 0x8f,
270 .cond_set_byte_greater_less => 0x9f,
271 else => unreachable,
272 },
273 .lt => return switch (tag) {
274 .cond_jmp_greater_less => 0x8c,
275 .cond_set_byte_greater_less => 0x9c,
276 else => unreachable,
277 },
278 .lte => return switch (tag) {
279 .cond_jmp_greater_less => 0x8e,
280 .cond_set_byte_greater_less => 0x9e,
281 else => unreachable,
282 },
283 .ae => return switch (tag) {
284 .cond_jmp_above_below => 0x83,
285 .cond_set_byte_above_below => 0x93,
286 else => unreachable,
287 },
288 .a => return switch (tag) {
289 .cond_jmp_above_below => 0x87,
290 .cond_set_byte_greater_less => 0x97,
291 else => unreachable,
292 },
293 .b => return switch (tag) {
294 .cond_jmp_above_below => 0x82,
295 .cond_set_byte_greater_less => 0x92,
296 else => unreachable,
297 },
298 .be => return switch (tag) {
299 .cond_jmp_above_below => 0x86,
300 .cond_set_byte_greater_less => 0x96,
301 else => unreachable,
302 },
303 .eq => return switch (tag) {
304 .cond_jmp_eq_ne => 0x84,
305 .cond_set_byte_eq_ne => 0x94,
306 else => unreachable,
307 },
308 .ne => return switch (tag) {
309 .cond_jmp_eq_ne => 0x85,
310 .cond_set_byte_eq_ne => 0x95,
311 else => unreachable,
312 },
313 }
314}
315
316fn mirCondJmp(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
317 _ = w; // TODO
318 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
319 const target = print.mir.instructions.items(.data)[inst].inst;
320 const cond = CondType.fromTagAndFlags(tag, ops.flags);
321 const opc = getCondOpCode(tag, cond);
322 const source = print.code.items.len;
323 const encoder = try Encoder.init(print.code, 6);
324 encoder.opcode_2byte(0x0f, opc);
325 try print.relocs.append(print.bin_file.allocator, .{
326 .source = source,
327 .target = target,
328 .offset = print.code.items.len,
329 .length = 6,
330 });
331 encoder.imm32(0);
332}
333
334fn mirCondSetByte(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
335 _ = w; // TODO
336 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
337 const cond = CondType.fromTagAndFlags(tag, ops.flags);
338 const opc = getCondOpCode(tag, cond);
339 const encoder = try Encoder.init(print.code, 4);
340 encoder.rex(.{
341 .w = true,
342 .b = ops.reg1.isExtended(),
343 });
344 encoder.opcode_2byte(0x0f, opc);
345 encoder.modRm_direct(0x0, ops.reg1.lowId());
346}
347
348fn mirTest(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
349 _ = w; // TODO
350 const tag = print.mir.instructions.items(.tag)[inst];
351 assert(tag == .@"test");
352 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
353 switch (ops.flags) {
354 0b00 => blk: {
355 if (ops.reg2 == .none) {
356 // TEST r/m64, imm32
357 const imm = print.mir.instructions.items(.data)[inst].imm;
358 if (ops.reg1.to64() == .rax) {
359 // TODO reduce the size of the instruction if the immediate
360 // is smaller than 32 bits
361 const encoder = try Encoder.init(print.code, 6);
362 encoder.rex(.{
363 .w = true,
364 });
365 encoder.opcode_1byte(0xa9);
366 encoder.imm32(imm);
367 break :blk;
368 }
369 const opc: u8 = if (ops.reg1.size() == 8) 0xf6 else 0xf7;
370 const encoder = try Encoder.init(print.code, 7);
371 encoder.rex(.{
372 .w = true,
373 .b = ops.reg1.isExtended(),
374 });
375 encoder.opcode_1byte(opc);
376 encoder.modRm_direct(0, ops.reg1.lowId());
377 encoder.imm8(@intCast(i8, imm));
378 break :blk;
379 }
380 // TEST r/m64, r64
381 return print.fail("TODO TEST r/m64, r64", .{});
382 },
383 else => return print.fail("TODO more TEST alternatives", .{}),
384 }
385}
386
387const EncType = enum {
388 /// OP r/m64, imm32
389 mi,
390
391 /// OP r/m64, r64
392 mr,
393
394 /// OP r64, r/m64
395 rm,
396};
397
398const OpCode = struct {
399 opc: u8,
400 /// Only used if `EncType == .mi`.
401 modrm_ext: u3,
402};
403
404inline fn getArithOpCode(tag: Mir.Inst.Tag, enc: EncType) OpCode {
405 switch (enc) {
406 .mi => return switch (tag) {
407 .adc => .{ .opc = 0x81, .modrm_ext = 0x2 },
408 .add => .{ .opc = 0x81, .modrm_ext = 0x0 },
409 .sub => .{ .opc = 0x81, .modrm_ext = 0x5 },
410 .xor => .{ .opc = 0x81, .modrm_ext = 0x6 },
411 .@"and" => .{ .opc = 0x81, .modrm_ext = 0x4 },
412 .@"or" => .{ .opc = 0x81, .modrm_ext = 0x1 },
413 .sbb => .{ .opc = 0x81, .modrm_ext = 0x3 },
414 .cmp => .{ .opc = 0x81, .modrm_ext = 0x7 },
415 .mov => .{ .opc = 0xc7, .modrm_ext = 0x0 },
416 else => unreachable,
417 },
418 .mr => {
419 const opc: u8 = switch (tag) {
420 .adc => 0x11,
421 .add => 0x01,
422 .sub => 0x29,
423 .xor => 0x31,
424 .@"and" => 0x21,
425 .@"or" => 0x09,
426 .sbb => 0x19,
427 .cmp => 0x39,
428 .mov => 0x89,
429 else => unreachable,
430 };
431 return .{ .opc = opc, .modrm_ext = undefined };
432 },
433 .rm => {
434 const opc: u8 = switch (tag) {
435 .adc => 0x13,
436 .add => 0x03,
437 .sub => 0x2b,
438 .xor => 0x33,
439 .@"and" => 0x23,
440 .@"or" => 0x0b,
441 .sbb => 0x1b,
442 .cmp => 0x3b,
443 .mov => 0x8b,
444 else => unreachable,
445 };
446 return .{ .opc = opc, .modrm_ext = undefined };
447 },
448 }
449}
450
451fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
452 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
453 try w.writeAll(@tagName(tag));
454 try w.writeByte(' ');
455 switch (ops.flags) {
456 0b00 => {
457 if (ops.reg2 == .none) {
458 const imm = print.mir.instructions.items(.data)[inst].imm;
459 try w.print("{s}, {d}", .{ @tagName(ops.reg1), imm });
460 } else try w.print("{s}, {s}", .{ @tagName(ops.reg1), @tagName(ops.reg2) });
461 },
462 0b01 => {
463 const imm = print.mir.instructions.items(.data)[inst].imm;
464 if (ops.reg2 == .none) {
465 try w.print("{s}, [ds:{d}]", .{ @tagName(ops.reg1), imm });
466 } else {
467 try w.print("{s}, [{s} + {d}]", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
468 }
469 },
470 0b10 => {
471 const imm = print.mir.instructions.items(.data)[inst].imm;
472 if (ops.reg2 == .none) {
473 try w.print("[{s} + 0], {d}", .{ @tagName(ops.reg1), imm });
474 } else {
475 try w.print("[{s} + {d}], {s}", .{ @tagName(ops.reg1), imm, @tagName(ops.reg2) });
476 }
477 },
478 0b11 => {
479 if (ops.reg2 == .none) {
480 const payload = print.mir.instructions.items(.data)[inst].payload;
481 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
482 try w.print("[{s} + {d}], {d}", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand });
483 }
484 try w.writeAll("TODO");
485 },
486 }
487 try w.writeByte('\n');
488}
489
490fn mirArithScaleSrc(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
491 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
492 const scale = ops.flags;
493 // OP reg1, [reg2 + scale*rcx + imm32]
494 const imm = print.mir.instructions.items(.data)[inst].imm;
495 try w.print("{s} {s}, [{s} + {d}*rcx + {d}]\n", .{ @tagName(tag), @tagName(ops.reg1), @tagName(ops.reg2), scale, imm });
496}
497
498fn mirArithScaleDst(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
499 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
500 const scale = ops.flags;
501 const imm = print.mir.instructions.items(.data)[inst].imm;
502
503 if (ops.reg2 == .none) {
504 // OP [reg1 + scale*rax + 0], imm32
505 try w.print("{s} [{s} + {d}*rcx + 0], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm });
506 }
507
508 // OP [reg1 + scale*rax + imm32], reg2
509 try w.print("{s} [{s} + {d}*rcx + {d}], {s}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm, @tagName(ops.reg2) });
510}
511
512fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
513 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
514 const scale = ops.flags;
515 const payload = print.mir.instructions.items(.data)[inst].payload;
516 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
517 try w.print("{s} [{s} + {d}*rcx + {d}], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm_pair.dest_off, imm_pair.operand });
518}
519
520fn mirMovabs(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
521 const tag = print.mir.instructions.items(.tag)[inst];
522 assert(tag == .movabs);
523 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
524
525 const is_64 = ops.reg1.size() == 64;
526 const imm: i128 = if (is_64) blk: {
527 const payload = print.mir.instructions.items(.data)[inst].payload;
528 const imm64 = print.mir.extraData(Mir.Imm64, payload).data;
529 break :blk imm64.decode();
530 } else print.mir.instructions.items(.data)[inst].imm;
531 if (ops.flags == 0b00) {
532 // movabs reg, imm64
533 try w.print("movabs {s}, {d}\n", .{ @tagName(ops.reg1), imm });
534 }
535 if (ops.reg1 == .none) {
536 try w.writeAll("movabs moffs64, rax\n");
537 } else {
538 // movabs rax, moffs64
539 try w.writeAll("movabs rax, moffs64\n");
540 }
541}
542
543fn mirIMulComplex(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
544 const tag = print.mir.instructions.items(.tag)[inst];
545 assert(tag == .imul_complex);
546 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
547 switch (ops.flags) {
548 0b00 => {
549 try w.print("imul {s}, {s}\n", .{ @tagName(ops.reg1), @tagName(ops.reg2) });
550 },
551 0b10 => {
552 const imm = print.mir.instructions.items(.data)[inst].imm;
553 try w.print("imul {s}, {s}, {d}\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
554 },
555 else => return w.writeAll("TODO implement imul\n"),
556 }
557}
558
559fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
560 const tag = print.mir.instructions.items(.tag)[inst];
561 assert(tag == .lea);
562 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
563 assert(ops.flags == 0b01);
564 const imm = print.mir.instructions.items(.data)[inst].imm;
565
566 try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
567}
568
569fn mirLeaRip(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
570 _ = print;
571 _ = inst;
572 return w.writeAll("TODO lea_rip\n");
573}
574
575fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
576 _ = print;
577 _ = inst;
578 return w.writeAll("TODO call_extern");
579}
src/main.zig+5
......@@ -448,6 +448,7 @@ const usage_build_generic =
448448 \\ --verbose-link Display linker invocations
449449 \\ --verbose-cc Display C compiler invocations
450450 \\ --verbose-air Enable compiler debug output for Zig AIR
451 \\ --verbose-mir Enable compiler debug output for Zig MIR
451452 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
452453 \\ --verbose-cimport Enable compiler debug output for C imports
453454 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
......@@ -575,6 +576,7 @@ fn buildOutputType(
575576 var verbose_link = std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK");
576577 var verbose_cc = std.process.hasEnvVarConstant("ZIG_VERBOSE_CC");
577578 var verbose_air = false;
579 var verbose_mir = false;
578580 var verbose_llvm_ir = false;
579581 var verbose_cimport = false;
580582 var verbose_llvm_cpu_features = false;
......@@ -1170,6 +1172,8 @@ fn buildOutputType(
11701172 verbose_cc = true;
11711173 } else if (mem.eql(u8, arg, "--verbose-air")) {
11721174 verbose_air = true;
1175 } else if (mem.eql(u8, arg, "--verbose-mir")) {
1176 verbose_mir = true;
11731177 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
11741178 verbose_llvm_ir = true;
11751179 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
......@@ -2333,6 +2337,7 @@ fn buildOutputType(
23332337 .verbose_cc = verbose_cc,
23342338 .verbose_link = verbose_link,
23352339 .verbose_air = verbose_air,
2340 .verbose_mir = verbose_mir,
23362341 .verbose_llvm_ir = verbose_llvm_ir,
23372342 .verbose_cimport = verbose_cimport,
23382343 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,