authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-28 21:43:54+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-28 21:43:54+01:00
log0f63f3eeb742c13ecf8f218f13ce1d3fd06c1be8
treef42646c1b5f1770f15435a1eaae10a2052b6da05
parentaa61e03f244a72ea01f05c3ceea7c5fb5aadf1ff
parentdde5f15b494e97cbe54621f330f79cdcb3ee9439
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10223 from g-w1/print-mir

stage2: initial implementation of print_mir

4 files changed, 606 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,
......@@ -1525,6 +1527,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
15251527 .clang_preprocessor_mode = options.clang_preprocessor_mode,
15261528 .verbose_cc = options.verbose_cc,
15271529 .verbose_air = options.verbose_air,
1530 .verbose_mir = options.verbose_mir,
15281531 .verbose_llvm_ir = options.verbose_llvm_ir,
15291532 .verbose_cimport = options.verbose_cimport,
15301533 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
src/arch/x86_64/CodeGen.zig+16
......@@ -86,6 +86,9 @@ next_stack_offset: u32 = 0,
8686/// Debug field, used to find bugs in the compiler.
8787air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
8888
89/// For mir debug info, maps a mir index to a air index
90mir_to_air_map: if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index) else void,
91
8992const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
9093
9194pub const MCValue = union(enum) {
......@@ -272,12 +275,14 @@ pub fn generate(
272275 .stack_align = undefined,
273276 .end_di_line = module_fn.rbrace_line,
274277 .end_di_column = module_fn.rbrace_column,
278 .mir_to_air_map = if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) else {},
275279 };
276280 defer function.stack.deinit(bin_file.allocator);
277281 defer function.blocks.deinit(bin_file.allocator);
278282 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
279283 defer function.mir_instructions.deinit(bin_file.allocator);
280284 defer function.mir_extra.deinit(bin_file.allocator);
285 defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit();
281286
282287 var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {
283288 error.CodegenFail => return FnResult{ .fail = function.err_msg.? },
......@@ -319,6 +324,14 @@ pub fn generate(
319324 else => |e| return e,
320325 };
321326
327 if (builtin.mode == .Debug and bin_file.options.module.?.comp.verbose_mir) {
328 const w = std.io.getStdErr().writer();
329 w.print("# Begin Function MIR: {s}:\n", .{module_fn.owner_decl.name}) catch {};
330 const print = @import("./PrintMir.zig"){ .mir = mir };
331 print.printMir(w, function.mir_to_air_map, air) catch {}; // we don't care if the debug printing fails
332 w.print("# End Function MIR: {s}\n\n", .{module_fn.owner_decl.name}) catch {};
333 }
334
322335 if (function.err_msg) |em| {
323336 return FnResult{ .fail = em };
324337 } else {
......@@ -517,6 +530,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
517530 for (body) |inst| {
518531 const old_air_bookkeeping = self.air_bookkeeping;
519532 try self.ensureProcessDeathCapacity(Liveness.bpi);
533 if (builtin.mode == .Debug) {
534 try self.mir_to_air_map.put(@intCast(u32, self.mir_instructions.len), inst);
535 }
520536
521537 switch (air_tags[inst]) {
522538 // zig fmt: off
src/arch/x86_64/PrintMir.zig created+582
......@@ -0,0 +1,582 @@
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, mir_to_air_map: std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index), air: Air) !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 const inst = @intCast(u32, index);
53 if (mir_to_air_map.get(inst)) |air_index| {
54 try w.print("air index %{} ({}) for following mir inst(s)\n", .{ air_index, air.instructions.items(.tag)[air_index] });
55 }
56 try w.writeAll(" ");
57 switch (tag) {
58 .adc => try print.mirArith(.adc, inst, w),
59 .add => try print.mirArith(.add, inst, w),
60 .sub => try print.mirArith(.sub, inst, w),
61 .xor => try print.mirArith(.xor, inst, w),
62 .@"and" => try print.mirArith(.@"and", inst, w),
63 .@"or" => try print.mirArith(.@"or", inst, w),
64 .sbb => try print.mirArith(.sbb, inst, w),
65 .cmp => try print.mirArith(.cmp, inst, w),
66
67 .adc_scale_src => try print.mirArithScaleSrc(.adc, inst, w),
68 .add_scale_src => try print.mirArithScaleSrc(.add, inst, w),
69 .sub_scale_src => try print.mirArithScaleSrc(.sub, inst, w),
70 .xor_scale_src => try print.mirArithScaleSrc(.xor, inst, w),
71 .and_scale_src => try print.mirArithScaleSrc(.@"and", inst, w),
72 .or_scale_src => try print.mirArithScaleSrc(.@"or", inst, w),
73 .sbb_scale_src => try print.mirArithScaleSrc(.sbb, inst, w),
74 .cmp_scale_src => try print.mirArithScaleSrc(.cmp, inst, w),
75
76 .adc_scale_dst => try print.mirArithScaleDst(.adc, inst, w),
77 .add_scale_dst => try print.mirArithScaleDst(.add, inst, w),
78 .sub_scale_dst => try print.mirArithScaleDst(.sub, inst, w),
79 .xor_scale_dst => try print.mirArithScaleDst(.xor, inst, w),
80 .and_scale_dst => try print.mirArithScaleDst(.@"and", inst, w),
81 .or_scale_dst => try print.mirArithScaleDst(.@"or", inst, w),
82 .sbb_scale_dst => try print.mirArithScaleDst(.sbb, inst, w),
83 .cmp_scale_dst => try print.mirArithScaleDst(.cmp, inst, w),
84
85 .adc_scale_imm => try print.mirArithScaleImm(.adc, inst, w),
86 .add_scale_imm => try print.mirArithScaleImm(.add, inst, w),
87 .sub_scale_imm => try print.mirArithScaleImm(.sub, inst, w),
88 .xor_scale_imm => try print.mirArithScaleImm(.xor, inst, w),
89 .and_scale_imm => try print.mirArithScaleImm(.@"and", inst, w),
90 .or_scale_imm => try print.mirArithScaleImm(.@"or", inst, w),
91 .sbb_scale_imm => try print.mirArithScaleImm(.sbb, inst, w),
92 .cmp_scale_imm => try print.mirArithScaleImm(.cmp, inst, w),
93
94 .mov => try print.mirArith(.mov, inst, w),
95 .mov_scale_src => try print.mirArithScaleSrc(.mov, inst, w),
96 .mov_scale_dst => try print.mirArithScaleDst(.mov, inst, w),
97 .mov_scale_imm => try print.mirArithScaleImm(.mov, inst, w),
98 .movabs => try print.mirMovabs(inst, w),
99
100 .lea => try print.mirLea(inst, w),
101 .lea_rip => try print.mirLeaRip(inst, w),
102
103 .imul_complex => try print.mirIMulComplex(inst, w),
104
105 .push => try print.mirPushPop(.push, inst, w),
106 .pop => try print.mirPushPop(.pop, inst, w),
107
108 .jmp => try print.mirJmpCall(.jmp, inst, w),
109 .call => try print.mirJmpCall(.call, inst, w),
110
111 // .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w),
112 // .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w),
113 // .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w),
114
115 // .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w),
116 // .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w),
117 // .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w),
118
119 // .@"test" => try print.mirTest(inst, w),
120
121 .brk => try w.writeAll("brk\n"),
122 .ret => try w.writeAll("ret\n"),
123 .nop => try w.writeAll("nop\n"),
124 .syscall => try w.writeAll("syscall\n"),
125
126 .call_extern => try print.mirCallExtern(inst, w),
127
128 .dbg_line, .dbg_prologue_end, .dbg_epilogue_begin, .arg_dbg_info => try w.print("{s}\n", .{@tagName(tag)}),
129
130 .push_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.push, inst, w),
131 .pop_regs_from_callee_preserved_regs => try print.mirPushPopRegsFromCalleePreservedRegs(.pop, inst, w),
132
133 else => {
134 try w.print("TODO emit asm for {s}\n", .{@tagName(tag)});
135 },
136 }
137 }
138}
139
140fn mirPushPop(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
141 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
142 switch (ops.flags) {
143 0b00 => {
144 // PUSH/POP reg
145 try w.print("{s} {s}", .{ @tagName(tag), @tagName(ops.reg1) });
146 },
147 0b01 => {
148 // PUSH/POP r/m64
149 const imm = print.mir.instructions.items(.data)[inst].imm;
150 try w.print("{s} [{s} + {d}]", .{ @tagName(tag), @tagName(ops.reg1), imm });
151 },
152 0b10 => {
153 const imm = print.mir.instructions.items(.data)[inst].imm;
154 // PUSH imm32
155 assert(tag == .push);
156 try w.print("{s} {d}", .{ @tagName(tag), imm });
157 },
158 0b11 => unreachable,
159 }
160 try w.writeByte('\n');
161}
162fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
163 const callee_preserved_regs = bits.callee_preserved_regs;
164 // PUSH/POP reg
165
166 const regs = print.mir.instructions.items(.data)[inst].regs_to_push_or_pop;
167 if (regs == 0) return w.writeAll("push/pop no regs from callee_preserved_regs\n");
168 if (tag == .push) {
169 try w.writeAll("push ");
170 for (callee_preserved_regs) |reg, i| {
171 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
172 try w.print("{s}, ", .{@tagName(reg)});
173 }
174 } else {
175 // pop in the reverse direction
176 var i = callee_preserved_regs.len;
177 try w.writeAll("pop ");
178 while (i > 0) : (i -= 1) {
179 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;
180 const reg = callee_preserved_regs[i - 1];
181 try w.print("{s}, ", .{@tagName(reg)});
182 }
183 }
184 try w.writeByte('\n');
185}
186
187fn mirJmpCall(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
188 try w.print("{s} ", .{@tagName(tag)});
189 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
190 const flag = @truncate(u1, ops.flags);
191 if (flag == 0) {
192 return w.writeAll("TODO target\n");
193 }
194 if (ops.reg1 == .none) {
195 // JMP/CALL [imm]
196 const imm = print.mir.instructions.items(.data)[inst].imm;
197 try w.print("[{x}]\n", .{imm});
198 return;
199 }
200 // JMP/CALL reg
201 try w.print("{s}\n", .{@tagName(ops.reg1)});
202}
203
204const CondType = enum {
205 /// greater than or equal
206 gte,
207
208 /// greater than
209 gt,
210
211 /// less than
212 lt,
213
214 /// less than or equal
215 lte,
216
217 /// above or equal
218 ae,
219
220 /// above
221 a,
222
223 /// below
224 b,
225
226 /// below or equal
227 be,
228
229 /// not equal
230 ne,
231
232 /// equal
233 eq,
234
235 fn fromTagAndFlags(tag: Mir.Inst.Tag, flags: u2) CondType {
236 return switch (tag) {
237 .cond_jmp_greater_less,
238 .cond_set_byte_greater_less,
239 => switch (flags) {
240 0b00 => CondType.gte,
241 0b01 => CondType.gt,
242 0b10 => CondType.lt,
243 0b11 => CondType.lte,
244 },
245 .cond_jmp_above_below,
246 .cond_set_byte_above_below,
247 => switch (flags) {
248 0b00 => CondType.ae,
249 0b01 => CondType.a,
250 0b10 => CondType.b,
251 0b11 => CondType.be,
252 },
253 .cond_jmp_eq_ne,
254 .cond_set_byte_eq_ne,
255 => switch (@truncate(u1, flags)) {
256 0b0 => CondType.ne,
257 0b1 => CondType.eq,
258 },
259 else => unreachable,
260 };
261 }
262};
263
264inline fn getCondOpCode(tag: Mir.Inst.Tag, cond: CondType) u8 {
265 switch (cond) {
266 .gte => return switch (tag) {
267 .cond_jmp_greater_less => 0x8d,
268 .cond_set_byte_greater_less => 0x9d,
269 else => unreachable,
270 },
271 .gt => return switch (tag) {
272 .cond_jmp_greater_less => 0x8f,
273 .cond_set_byte_greater_less => 0x9f,
274 else => unreachable,
275 },
276 .lt => return switch (tag) {
277 .cond_jmp_greater_less => 0x8c,
278 .cond_set_byte_greater_less => 0x9c,
279 else => unreachable,
280 },
281 .lte => return switch (tag) {
282 .cond_jmp_greater_less => 0x8e,
283 .cond_set_byte_greater_less => 0x9e,
284 else => unreachable,
285 },
286 .ae => return switch (tag) {
287 .cond_jmp_above_below => 0x83,
288 .cond_set_byte_above_below => 0x93,
289 else => unreachable,
290 },
291 .a => return switch (tag) {
292 .cond_jmp_above_below => 0x87,
293 .cond_set_byte_greater_less => 0x97,
294 else => unreachable,
295 },
296 .b => return switch (tag) {
297 .cond_jmp_above_below => 0x82,
298 .cond_set_byte_greater_less => 0x92,
299 else => unreachable,
300 },
301 .be => return switch (tag) {
302 .cond_jmp_above_below => 0x86,
303 .cond_set_byte_greater_less => 0x96,
304 else => unreachable,
305 },
306 .eq => return switch (tag) {
307 .cond_jmp_eq_ne => 0x84,
308 .cond_set_byte_eq_ne => 0x94,
309 else => unreachable,
310 },
311 .ne => return switch (tag) {
312 .cond_jmp_eq_ne => 0x85,
313 .cond_set_byte_eq_ne => 0x95,
314 else => unreachable,
315 },
316 }
317}
318
319fn mirCondJmp(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
320 _ = w; // TODO
321 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
322 const target = print.mir.instructions.items(.data)[inst].inst;
323 const cond = CondType.fromTagAndFlags(tag, ops.flags);
324 const opc = getCondOpCode(tag, cond);
325 const source = print.code.items.len;
326 const encoder = try Encoder.init(print.code, 6);
327 encoder.opcode_2byte(0x0f, opc);
328 try print.relocs.append(print.bin_file.allocator, .{
329 .source = source,
330 .target = target,
331 .offset = print.code.items.len,
332 .length = 6,
333 });
334 encoder.imm32(0);
335}
336
337fn mirCondSetByte(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
338 _ = w; // TODO
339 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
340 const cond = CondType.fromTagAndFlags(tag, ops.flags);
341 const opc = getCondOpCode(tag, cond);
342 const encoder = try Encoder.init(print.code, 4);
343 encoder.rex(.{
344 .w = true,
345 .b = ops.reg1.isExtended(),
346 });
347 encoder.opcode_2byte(0x0f, opc);
348 encoder.modRm_direct(0x0, ops.reg1.lowId());
349}
350
351fn mirTest(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
352 _ = w; // TODO
353 const tag = print.mir.instructions.items(.tag)[inst];
354 assert(tag == .@"test");
355 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
356 switch (ops.flags) {
357 0b00 => blk: {
358 if (ops.reg2 == .none) {
359 // TEST r/m64, imm32
360 const imm = print.mir.instructions.items(.data)[inst].imm;
361 if (ops.reg1.to64() == .rax) {
362 // TODO reduce the size of the instruction if the immediate
363 // is smaller than 32 bits
364 const encoder = try Encoder.init(print.code, 6);
365 encoder.rex(.{
366 .w = true,
367 });
368 encoder.opcode_1byte(0xa9);
369 encoder.imm32(imm);
370 break :blk;
371 }
372 const opc: u8 = if (ops.reg1.size() == 8) 0xf6 else 0xf7;
373 const encoder = try Encoder.init(print.code, 7);
374 encoder.rex(.{
375 .w = true,
376 .b = ops.reg1.isExtended(),
377 });
378 encoder.opcode_1byte(opc);
379 encoder.modRm_direct(0, ops.reg1.lowId());
380 encoder.imm8(@intCast(i8, imm));
381 break :blk;
382 }
383 // TEST r/m64, r64
384 return print.fail("TODO TEST r/m64, r64", .{});
385 },
386 else => return print.fail("TODO more TEST alternatives", .{}),
387 }
388}
389
390const EncType = enum {
391 /// OP r/m64, imm32
392 mi,
393
394 /// OP r/m64, r64
395 mr,
396
397 /// OP r64, r/m64
398 rm,
399};
400
401const OpCode = struct {
402 opc: u8,
403 /// Only used if `EncType == .mi`.
404 modrm_ext: u3,
405};
406
407inline fn getArithOpCode(tag: Mir.Inst.Tag, enc: EncType) OpCode {
408 switch (enc) {
409 .mi => return switch (tag) {
410 .adc => .{ .opc = 0x81, .modrm_ext = 0x2 },
411 .add => .{ .opc = 0x81, .modrm_ext = 0x0 },
412 .sub => .{ .opc = 0x81, .modrm_ext = 0x5 },
413 .xor => .{ .opc = 0x81, .modrm_ext = 0x6 },
414 .@"and" => .{ .opc = 0x81, .modrm_ext = 0x4 },
415 .@"or" => .{ .opc = 0x81, .modrm_ext = 0x1 },
416 .sbb => .{ .opc = 0x81, .modrm_ext = 0x3 },
417 .cmp => .{ .opc = 0x81, .modrm_ext = 0x7 },
418 .mov => .{ .opc = 0xc7, .modrm_ext = 0x0 },
419 else => unreachable,
420 },
421 .mr => {
422 const opc: u8 = switch (tag) {
423 .adc => 0x11,
424 .add => 0x01,
425 .sub => 0x29,
426 .xor => 0x31,
427 .@"and" => 0x21,
428 .@"or" => 0x09,
429 .sbb => 0x19,
430 .cmp => 0x39,
431 .mov => 0x89,
432 else => unreachable,
433 };
434 return .{ .opc = opc, .modrm_ext = undefined };
435 },
436 .rm => {
437 const opc: u8 = switch (tag) {
438 .adc => 0x13,
439 .add => 0x03,
440 .sub => 0x2b,
441 .xor => 0x33,
442 .@"and" => 0x23,
443 .@"or" => 0x0b,
444 .sbb => 0x1b,
445 .cmp => 0x3b,
446 .mov => 0x8b,
447 else => unreachable,
448 };
449 return .{ .opc = opc, .modrm_ext = undefined };
450 },
451 }
452}
453
454fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
455 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
456 try w.writeAll(@tagName(tag));
457 try w.writeByte(' ');
458 switch (ops.flags) {
459 0b00 => {
460 if (ops.reg2 == .none) {
461 const imm = print.mir.instructions.items(.data)[inst].imm;
462 try w.print("{s}, {d}", .{ @tagName(ops.reg1), imm });
463 } else try w.print("{s}, {s}", .{ @tagName(ops.reg1), @tagName(ops.reg2) });
464 },
465 0b01 => {
466 const imm = print.mir.instructions.items(.data)[inst].imm;
467 if (ops.reg2 == .none) {
468 try w.print("{s}, [ds:{d}]", .{ @tagName(ops.reg1), imm });
469 } else {
470 try w.print("{s}, [{s} + {d}]", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
471 }
472 },
473 0b10 => {
474 const imm = print.mir.instructions.items(.data)[inst].imm;
475 if (ops.reg2 == .none) {
476 try w.print("[{s} + 0], {d}", .{ @tagName(ops.reg1), imm });
477 } else {
478 try w.print("[{s} + {d}], {s}", .{ @tagName(ops.reg1), imm, @tagName(ops.reg2) });
479 }
480 },
481 0b11 => {
482 if (ops.reg2 == .none) {
483 const payload = print.mir.instructions.items(.data)[inst].payload;
484 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
485 try w.print("[{s} + {d}], {d}", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand });
486 }
487 try w.writeAll("TODO");
488 },
489 }
490 try w.writeByte('\n');
491}
492
493fn mirArithScaleSrc(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
494 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
495 const scale = ops.flags;
496 // OP reg1, [reg2 + scale*rcx + imm32]
497 const imm = print.mir.instructions.items(.data)[inst].imm;
498 try w.print("{s} {s}, [{s} + {d}*rcx + {d}]\n", .{ @tagName(tag), @tagName(ops.reg1), @tagName(ops.reg2), scale, imm });
499}
500
501fn mirArithScaleDst(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
502 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
503 const scale = ops.flags;
504 const imm = print.mir.instructions.items(.data)[inst].imm;
505
506 if (ops.reg2 == .none) {
507 // OP [reg1 + scale*rax + 0], imm32
508 try w.print("{s} [{s} + {d}*rcx + 0], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm });
509 }
510
511 // OP [reg1 + scale*rax + imm32], reg2
512 try w.print("{s} [{s} + {d}*rcx + {d}], {s}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm, @tagName(ops.reg2) });
513}
514
515fn mirArithScaleImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
516 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
517 const scale = ops.flags;
518 const payload = print.mir.instructions.items(.data)[inst].payload;
519 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
520 try w.print("{s} [{s} + {d}*rcx + {d}], {d}\n", .{ @tagName(tag), @tagName(ops.reg1), scale, imm_pair.dest_off, imm_pair.operand });
521}
522
523fn mirMovabs(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
524 const tag = print.mir.instructions.items(.tag)[inst];
525 assert(tag == .movabs);
526 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
527
528 const is_64 = ops.reg1.size() == 64;
529 const imm: i128 = if (is_64) blk: {
530 const payload = print.mir.instructions.items(.data)[inst].payload;
531 const imm64 = print.mir.extraData(Mir.Imm64, payload).data;
532 break :blk imm64.decode();
533 } else print.mir.instructions.items(.data)[inst].imm;
534 if (ops.flags == 0b00) {
535 // movabs reg, imm64
536 try w.print("movabs {s}, {d}\n", .{ @tagName(ops.reg1), imm });
537 }
538 if (ops.reg1 == .none) {
539 try w.writeAll("movabs moffs64, rax\n");
540 } else {
541 // movabs rax, moffs64
542 try w.writeAll("movabs rax, moffs64\n");
543 }
544}
545
546fn mirIMulComplex(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
547 const tag = print.mir.instructions.items(.tag)[inst];
548 assert(tag == .imul_complex);
549 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
550 switch (ops.flags) {
551 0b00 => {
552 try w.print("imul {s}, {s}\n", .{ @tagName(ops.reg1), @tagName(ops.reg2) });
553 },
554 0b10 => {
555 const imm = print.mir.instructions.items(.data)[inst].imm;
556 try w.print("imul {s}, {s}, {d}\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
557 },
558 else => return w.writeAll("TODO implement imul\n"),
559 }
560}
561
562fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
563 const tag = print.mir.instructions.items(.tag)[inst];
564 assert(tag == .lea);
565 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
566 assert(ops.flags == 0b01);
567 const imm = print.mir.instructions.items(.data)[inst].imm;
568
569 try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
570}
571
572fn mirLeaRip(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
573 _ = print;
574 _ = inst;
575 return w.writeAll("TODO lea_rip\n");
576}
577
578fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
579 _ = print;
580 _ = inst;
581 return w.writeAll("TODO call_extern");
582}
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;
......@@ -1180,6 +1182,8 @@ fn buildOutputType(
11801182 verbose_cc = true;
11811183 } else if (mem.eql(u8, arg, "--verbose-air")) {
11821184 verbose_air = true;
1185 } else if (mem.eql(u8, arg, "--verbose-mir")) {
1186 verbose_mir = true;
11831187 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
11841188 verbose_llvm_ir = true;
11851189 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
......@@ -2447,6 +2451,7 @@ fn buildOutputType(
24472451 .verbose_cc = verbose_cc,
24482452 .verbose_link = verbose_link,
24492453 .verbose_air = verbose_air,
2454 .verbose_mir = verbose_mir,
24502455 .verbose_llvm_ir = verbose_llvm_ir,
24512456 .verbose_cimport = verbose_cimport,
24522457 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,