authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-29 22:04:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-29 22:06:38+01:00
log4ecc5956f62166708f3f47522e326452b0166dda
tree908340c747ac198e9c9530fb66774b5dd8d77f38
parentb7e223597395358dc63cf88c92ace5eaa455cf89

stage2: update PrintMir with latest instructions and Isel changes


2 files changed, 113 insertions(+), 272 deletions(-)

src/arch/x86_64/CodeGen.zig+5-1
......@@ -329,7 +329,11 @@ pub fn generate(
329329 if (builtin.mode == .Debug and bin_file.options.module.?.comp.verbose_mir) {
330330 const w = std.io.getStdErr().writer();
331331 w.print("# Begin Function MIR: {s}:\n", .{module_fn.owner_decl.name}) catch {};
332 const print = @import("./PrintMir.zig"){ .mir = mir };
332 const PrintMir = @import("PrintMir.zig");
333 const print = PrintMir{
334 .mir = mir,
335 .bin_file = bin_file,
336 };
333337 print.printMir(w, function.mir_to_air_map, air) catch {}; // we don't care if the debug printing fails
334338 w.print("# End Function MIR: {s}\n\n", .{module_fn.owner_decl.name}) catch {};
335339 }
src/arch/x86_64/PrintMir.zig+108-271
......@@ -25,6 +25,7 @@ const Type = @import("../../type.zig").Type;
2525const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
2626
2727mir: Mir,
28bin_file: *link.File,
2829
2930pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index), air: Air) !void {
3031 const instruction_bytes = print.mir.instructions.len *
......@@ -116,15 +117,15 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap
116117 .jmp => try print.mirJmpCall(.jmp, inst, w),
117118 .call => try print.mirJmpCall(.call, inst, w),
118119
119 // .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w),
120 // .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w),
121 // .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w),
120 .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w),
121 .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w),
122 .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w),
122123
123 // .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w),
124 // .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w),
125 // .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w),
124 .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w),
125 .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w),
126 .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w),
126127
127 // .@"test" => try print.mirTest(inst, w),
128 .@"test" => try print.mirTest(inst, w),
128129
129130 .brk => try w.writeAll("brk\n"),
130131 .ret => try w.writeAll("ret\n"),
......@@ -209,254 +210,24 @@ fn mirJmpCall(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: a
209210 try w.print("{s}\n", .{@tagName(ops.reg1)});
210211}
211212
212const CondType = enum {
213 /// greater than or equal
214 gte,
215
216 /// greater than
217 gt,
218
219 /// less than
220 lt,
221
222 /// less than or equal
223 lte,
224
225 /// above or equal
226 ae,
227
228 /// above
229 a,
230
231 /// below
232 b,
233
234 /// below or equal
235 be,
236
237 /// not equal
238 ne,
239
240 /// equal
241 eq,
242
243 fn fromTagAndFlags(tag: Mir.Inst.Tag, flags: u2) CondType {
244 return switch (tag) {
245 .cond_jmp_greater_less,
246 .cond_set_byte_greater_less,
247 => switch (flags) {
248 0b00 => CondType.gte,
249 0b01 => CondType.gt,
250 0b10 => CondType.lt,
251 0b11 => CondType.lte,
252 },
253 .cond_jmp_above_below,
254 .cond_set_byte_above_below,
255 => switch (flags) {
256 0b00 => CondType.ae,
257 0b01 => CondType.a,
258 0b10 => CondType.b,
259 0b11 => CondType.be,
260 },
261 .cond_jmp_eq_ne,
262 .cond_set_byte_eq_ne,
263 => switch (@truncate(u1, flags)) {
264 0b0 => CondType.ne,
265 0b1 => CondType.eq,
266 },
267 else => unreachable,
268 };
269 }
270};
271
272inline fn getCondOpCode(tag: Mir.Inst.Tag, cond: CondType) u8 {
273 switch (cond) {
274 .gte => return switch (tag) {
275 .cond_jmp_greater_less => 0x8d,
276 .cond_set_byte_greater_less => 0x9d,
277 else => unreachable,
278 },
279 .gt => return switch (tag) {
280 .cond_jmp_greater_less => 0x8f,
281 .cond_set_byte_greater_less => 0x9f,
282 else => unreachable,
283 },
284 .lt => return switch (tag) {
285 .cond_jmp_greater_less => 0x8c,
286 .cond_set_byte_greater_less => 0x9c,
287 else => unreachable,
288 },
289 .lte => return switch (tag) {
290 .cond_jmp_greater_less => 0x8e,
291 .cond_set_byte_greater_less => 0x9e,
292 else => unreachable,
293 },
294 .ae => return switch (tag) {
295 .cond_jmp_above_below => 0x83,
296 .cond_set_byte_above_below => 0x93,
297 else => unreachable,
298 },
299 .a => return switch (tag) {
300 .cond_jmp_above_below => 0x87,
301 .cond_set_byte_greater_less => 0x97,
302 else => unreachable,
303 },
304 .b => return switch (tag) {
305 .cond_jmp_above_below => 0x82,
306 .cond_set_byte_greater_less => 0x92,
307 else => unreachable,
308 },
309 .be => return switch (tag) {
310 .cond_jmp_above_below => 0x86,
311 .cond_set_byte_greater_less => 0x96,
312 else => unreachable,
313 },
314 .eq => return switch (tag) {
315 .cond_jmp_eq_ne => 0x84,
316 .cond_set_byte_eq_ne => 0x94,
317 else => unreachable,
318 },
319 .ne => return switch (tag) {
320 .cond_jmp_eq_ne => 0x85,
321 .cond_set_byte_eq_ne => 0x95,
322 else => unreachable,
323 },
324 }
325}
326
327213fn mirCondJmp(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
328 _ = w; // TODO
329 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
330 const target = print.mir.instructions.items(.data)[inst].inst;
331 const cond = CondType.fromTagAndFlags(tag, ops.flags);
332 const opc = getCondOpCode(tag, cond);
333 const source = print.code.items.len;
334 const encoder = try Encoder.init(print.code, 6);
335 encoder.opcode_2byte(0x0f, opc);
336 try print.relocs.append(print.bin_file.allocator, .{
337 .source = source,
338 .target = target,
339 .offset = print.code.items.len,
340 .length = 6,
341 });
342 encoder.imm32(0);
214 _ = print;
215 _ = tag;
216 _ = inst;
217 try w.writeAll("TODO print mirCondJmp\n");
343218}
344219
345220fn mirCondSetByte(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
346 _ = w; // TODO
347 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
348 const cond = CondType.fromTagAndFlags(tag, ops.flags);
349 const opc = getCondOpCode(tag, cond);
350 const encoder = try Encoder.init(print.code, 4);
351 encoder.rex(.{
352 .w = true,
353 .b = ops.reg1.isExtended(),
354 });
355 encoder.opcode_2byte(0x0f, opc);
356 encoder.modRm_direct(0x0, ops.reg1.lowId());
221 _ = tag;
222 _ = inst;
223 _ = print;
224 try w.writeAll("TODO print mirCondSetByte\n");
357225}
358226
359227fn mirTest(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
360 _ = w; // TODO
361 const tag = print.mir.instructions.items(.tag)[inst];
362 assert(tag == .@"test");
363 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
364 switch (ops.flags) {
365 0b00 => blk: {
366 if (ops.reg2 == .none) {
367 // TEST r/m64, imm32
368 const imm = print.mir.instructions.items(.data)[inst].imm;
369 if (ops.reg1.to64() == .rax) {
370 // TODO reduce the size of the instruction if the immediate
371 // is smaller than 32 bits
372 const encoder = try Encoder.init(print.code, 6);
373 encoder.rex(.{
374 .w = true,
375 });
376 encoder.opcode_1byte(0xa9);
377 encoder.imm32(imm);
378 break :blk;
379 }
380 const opc: u8 = if (ops.reg1.size() == 8) 0xf6 else 0xf7;
381 const encoder = try Encoder.init(print.code, 7);
382 encoder.rex(.{
383 .w = true,
384 .b = ops.reg1.isExtended(),
385 });
386 encoder.opcode_1byte(opc);
387 encoder.modRm_direct(0, ops.reg1.lowId());
388 encoder.imm8(@intCast(i8, imm));
389 break :blk;
390 }
391 // TEST r/m64, r64
392 return print.fail("TODO TEST r/m64, r64", .{});
393 },
394 else => return print.fail("TODO more TEST alternatives", .{}),
395 }
396}
397
398const EncType = enum {
399 /// OP r/m64, imm32
400 mi,
401
402 /// OP r/m64, r64
403 mr,
404
405 /// OP r64, r/m64
406 rm,
407};
408
409const OpCode = struct {
410 opc: u8,
411 /// Only used if `EncType == .mi`.
412 modrm_ext: u3,
413};
414
415inline fn getArithOpCode(tag: Mir.Inst.Tag, enc: EncType) OpCode {
416 switch (enc) {
417 .mi => return switch (tag) {
418 .adc => .{ .opc = 0x81, .modrm_ext = 0x2 },
419 .add => .{ .opc = 0x81, .modrm_ext = 0x0 },
420 .sub => .{ .opc = 0x81, .modrm_ext = 0x5 },
421 .xor => .{ .opc = 0x81, .modrm_ext = 0x6 },
422 .@"and" => .{ .opc = 0x81, .modrm_ext = 0x4 },
423 .@"or" => .{ .opc = 0x81, .modrm_ext = 0x1 },
424 .sbb => .{ .opc = 0x81, .modrm_ext = 0x3 },
425 .cmp => .{ .opc = 0x81, .modrm_ext = 0x7 },
426 .mov => .{ .opc = 0xc7, .modrm_ext = 0x0 },
427 else => unreachable,
428 },
429 .mr => {
430 const opc: u8 = switch (tag) {
431 .adc => 0x11,
432 .add => 0x01,
433 .sub => 0x29,
434 .xor => 0x31,
435 .@"and" => 0x21,
436 .@"or" => 0x09,
437 .sbb => 0x19,
438 .cmp => 0x39,
439 .mov => 0x89,
440 else => unreachable,
441 };
442 return .{ .opc = opc, .modrm_ext = undefined };
443 },
444 .rm => {
445 const opc: u8 = switch (tag) {
446 .adc => 0x13,
447 .add => 0x03,
448 .sub => 0x2b,
449 .xor => 0x33,
450 .@"and" => 0x23,
451 .@"or" => 0x0b,
452 .sbb => 0x1b,
453 .cmp => 0x3b,
454 .mov => 0x8b,
455 else => unreachable,
456 };
457 return .{ .opc = opc, .modrm_ext = undefined };
458 },
459 }
228 _ = print;
229 _ = inst;
230 try w.writeAll("TODO print mirTest\n");
460231}
461232
462233fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
......@@ -473,36 +244,61 @@ fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: any
473244 0b01 => {
474245 const imm = print.mir.instructions.items(.data)[inst].imm;
475246 if (ops.reg2 == .none) {
476 try w.print("{s}, [ds:{d}]", .{ @tagName(ops.reg1), imm });
247 try w.print("{s}, ", .{@tagName(ops.reg1)});
248 switch (ops.reg1.size()) {
249 8 => try w.print("byte ptr ", .{}),
250 16 => try w.print("word ptr ", .{}),
251 32 => try w.print("dword ptr ", .{}),
252 64 => try w.print("qword ptr ", .{}),
253 else => unreachable,
254 }
255 try w.print("[ds:{d}]", .{imm});
477256 } else {
478 try w.print("{s}, [{s} + {d}]", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
257 try w.print("{s}, ", .{@tagName(ops.reg1)});
258 switch (ops.reg1.size()) {
259 8 => try w.print("byte ptr ", .{}),
260 16 => try w.print("word ptr ", .{}),
261 32 => try w.print("dword ptr ", .{}),
262 64 => try w.print("qword ptr ", .{}),
263 else => unreachable,
264 }
265 try w.print("[{s} + {d}]", .{ @tagName(ops.reg2), imm });
479266 }
480267 },
481268 0b10 => {
482269 const imm = print.mir.instructions.items(.data)[inst].imm;
483270 if (ops.reg2 == .none) {
484 try w.print("[{s} + 0], {d}", .{ @tagName(ops.reg1), imm });
271 try w.writeAll("unused variant");
485272 } else {
273 switch (ops.reg2.size()) {
274 8 => try w.print("byte ptr ", .{}),
275 16 => try w.print("word ptr ", .{}),
276 32 => try w.print("dword ptr ", .{}),
277 64 => try w.print("qword ptr ", .{}),
278 else => unreachable,
279 }
486280 try w.print("[{s} + {d}], {s}", .{ @tagName(ops.reg1), imm, @tagName(ops.reg2) });
487281 }
488282 },
489283 0b11 => {
490 if (ops.reg2 == .none) {
491 const payload = print.mir.instructions.items(.data)[inst].payload;
492 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
493 try w.print("[{s} + {d}], {d}", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand });
494 }
495 try w.writeAll("TODO");
284 try w.writeAll("unused variant");
496285 },
497286 }
498287 try w.writeByte('\n');
499288}
500289
501290fn mirArithMemImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
502 _ = print;
503 _ = tag;
504 _ = inst;
505 return w.writeAll("TODO mirArithMemImm\n");
291 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
292 const payload = print.mir.instructions.items(.data)[inst].payload;
293 const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data;
294 try w.print("{s} ", .{@tagName(tag)});
295 switch (ops.flags) {
296 0b00 => try w.print("byte ptr ", .{}),
297 0b01 => try w.print("word ptr ", .{}),
298 0b10 => try w.print("dword ptr ", .{}),
299 0b11 => try w.print("qword ptr ", .{}),
300 }
301 try w.print("[{s} + {d}], {d}\n", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand });
506302}
507303
508304fn mirArithScaleSrc(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
......@@ -575,16 +371,57 @@ fn mirIMulComplex(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
575371}
576372
577373fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
578 _ = print;
579 _ = inst;
580 return w.writeAll("TODO lea\n");
581 // const tag = print.mir.instructions.items(.tag)[inst];
582 // assert(tag == .lea);
583 // const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
584 // assert(ops.flags == 0b01);
585 // const imm = print.mir.instructions.items(.data)[inst].imm;
586
587 // try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm });
374 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
375 try w.writeAll("lea ");
376 switch (ops.flags) {
377 0b00 => {
378 const imm = print.mir.instructions.items(.data)[inst].imm;
379 try w.print("{s} [", .{@tagName(ops.reg1)});
380 if (ops.reg2 != .none) {
381 try w.print("{s} + ", .{@tagName(ops.reg2)});
382 } else {
383 try w.print("ds:", .{});
384 }
385 try w.print("{d}]\n", .{imm});
386 },
387 0b01 => {
388 try w.print("{s}, ", .{@tagName(ops.reg1)});
389 switch (ops.reg1.size()) {
390 8 => try w.print("byte ptr ", .{}),
391 16 => try w.print("word ptr ", .{}),
392 32 => try w.print("dword ptr ", .{}),
393 64 => try w.print("qword ptr ", .{}),
394 else => unreachable,
395 }
396 try w.print("[rip + 0x0] ", .{});
397 const payload = print.mir.instructions.items(.data)[inst].payload;
398 const imm = print.mir.extraData(Mir.Imm64, payload).data.decode();
399 try w.print("target@{x}", .{imm});
400 },
401 0b10 => {
402 try w.print("{s}, ", .{@tagName(ops.reg1)});
403 switch (ops.reg1.size()) {
404 8 => try w.print("byte ptr ", .{}),
405 16 => try w.print("word ptr ", .{}),
406 32 => try w.print("dword ptr ", .{}),
407 64 => try w.print("qword ptr ", .{}),
408 else => unreachable,
409 }
410 try w.print("[rip + 0x0] ", .{});
411 const got_entry = print.mir.instructions.items(.data)[inst].got_entry;
412 if (print.bin_file.cast(link.File.MachO)) |macho_file| {
413 const target = macho_file.locals.items[got_entry];
414 const target_name = macho_file.getString(target.n_strx);
415 try w.print("target@{s}", .{target_name});
416 } else {
417 try w.writeAll("TODO lea reg, [rip + reloc] for linking backends different than MachO");
418 }
419 },
420 0b11 => {
421 try w.writeAll("unused variant\n");
422 },
423 }
424 try w.writeAll("\n");
588425}
589426
590427fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {