| ... | @@ -5,6 +5,8 @@ const math = std.math; | ... | @@ -5,6 +5,8 @@ const math = std.math; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const Air = @import("../../Air.zig"); | 6 | const Air = @import("../../Air.zig"); |
| 7 | const Zir = @import("../../Zir.zig"); | 7 | const Zir = @import("../../Zir.zig"); |
| | 8 | const Mir = @import("Mir.zig"); |
| | 9 | const Emit = @import("Emit.zig"); |
| 8 | const Liveness = @import("../../Liveness.zig"); | 10 | const Liveness = @import("../../Liveness.zig"); |
| 9 | const Type = @import("../../type.zig").Type; | 11 | const Type = @import("../../type.zig").Type; |
| 10 | const Value = @import("../../value.zig").Value; | 12 | const Value = @import("../../value.zig").Value; |
| ... | @@ -47,13 +49,14 @@ arg_index: usize, | ... | @@ -47,13 +49,14 @@ arg_index: usize, |
| 47 | src_loc: Module.SrcLoc, | 49 | src_loc: Module.SrcLoc, |
| 48 | stack_align: u32, | 50 | stack_align: u32, |
| 49 | | 51 | |
| 50 | prev_di_line: u32, | 52 | /// MIR Instructions |
| 51 | prev_di_column: u32, | 53 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| | 54 | /// MIR extra data |
| | 55 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, |
| | 56 | |
| 52 | /// Byte offset within the source file of the ending curly. | 57 | /// Byte offset within the source file of the ending curly. |
| 53 | end_di_line: u32, | 58 | end_di_line: u32, |
| 54 | end_di_column: u32, | 59 | end_di_column: u32, |
| 55 | /// Relative to the beginning of `code`. | | |
| 56 | prev_di_pc: usize, | | |
| 57 | | 60 | |
| 58 | /// The value is an offset into the `Function` `code` from the beginning. | 61 | /// The value is an offset into the `Function` `code` from the beginning. |
| 59 | /// To perform the reloc, write 32-bit signed little-endian integer | 62 | /// To perform the reloc, write 32-bit signed little-endian integer |
| ... | @@ -276,9 +279,6 @@ pub fn generate( | ... | @@ -276,9 +279,6 @@ pub fn generate( |
| 276 | .branch_stack = &branch_stack, | 279 | .branch_stack = &branch_stack, |
| 277 | .src_loc = src_loc, | 280 | .src_loc = src_loc, |
| 278 | .stack_align = undefined, | 281 | .stack_align = undefined, |
| 279 | .prev_di_pc = 0, | | |
| 280 | .prev_di_line = module_fn.lbrace_line, | | |
| 281 | .prev_di_column = module_fn.lbrace_column, | | |
| 282 | .end_di_line = module_fn.rbrace_line, | 282 | .end_di_line = module_fn.rbrace_line, |
| 283 | .end_di_column = module_fn.rbrace_column, | 283 | .end_di_column = module_fn.rbrace_column, |
| 284 | }; | 284 | }; |
| ... | @@ -302,6 +302,30 @@ pub fn generate( | ... | @@ -302,6 +302,30 @@ pub fn generate( |
| 302 | else => |e| return e, | 302 | else => |e| return e, |
| 303 | }; | 303 | }; |
| 304 | | 304 | |
| | 305 | var mir = Mir{ |
| | 306 | .instructions = function.mir_instructions.toOwnedSlice(), |
| | 307 | .extra = function.mir_extra.toOwnedSlice(bin_file.allocator), |
| | 308 | }; |
| | 309 | defer mir.deinit(bin_file.allocator); |
| | 310 | |
| | 311 | var emit = Emit{ |
| | 312 | .mir = mir, |
| | 313 | .bin_file = bin_file, |
| | 314 | .debug_output = debug_output, |
| | 315 | .target = &bin_file.options.target, |
| | 316 | .src_loc = src_loc, |
| | 317 | .code = code, |
| | 318 | .prev_di_pc = 0, |
| | 319 | .prev_di_line = module_fn.lbrace_line, |
| | 320 | .prev_di_column = module_fn.lbrace_column, |
| | 321 | }; |
| | 322 | defer emit.deinit(); |
| | 323 | |
| | 324 | emit.emitMir() catch |err| switch (err) { |
| | 325 | error.EmitFail => return FnResult{ .fail = emit.err_msg.? }, |
| | 326 | else => |e| return e, |
| | 327 | }; |
| | 328 | |
| 305 | if (function.err_msg) |em| { | 329 | if (function.err_msg) |em| { |
| 306 | return FnResult{ .fail = em }; | 330 | return FnResult{ .fail = em }; |
| 307 | } else { | 331 | } else { |
| ... | @@ -309,13 +333,56 @@ pub fn generate( | ... | @@ -309,13 +333,56 @@ pub fn generate( |
| 309 | } | 333 | } |
| 310 | } | 334 | } |
| 311 | | 335 | |
| | 336 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| | 337 | const gpa = self.gpa; |
| | 338 | |
| | 339 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| | 340 | |
| | 341 | const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len); |
| | 342 | self.mir_instructions.appendAssumeCapacity(inst); |
| | 343 | return result_index; |
| | 344 | } |
| | 345 | |
| | 346 | pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 { |
| | 347 | const fields = std.meta.fields(@TypeOf(extra)); |
| | 348 | try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len); |
| | 349 | return self.addExtraAssumeCapacity(extra); |
| | 350 | } |
| | 351 | |
| | 352 | pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| | 353 | const fields = std.meta.fields(@TypeOf(extra)); |
| | 354 | const result = @intCast(u32, self.mir_extra.items.len); |
| | 355 | inline for (fields) |field| { |
| | 356 | self.mir_extra.appendAssumeCapacity(switch (field.field_type) { |
| | 357 | u32 => @field(extra, field.name), |
| | 358 | i32 => @bitCast(u32, @field(extra, field.name)), |
| | 359 | else => @compileError("bad field type"), |
| | 360 | }); |
| | 361 | } |
| | 362 | return result; |
| | 363 | } |
| | 364 | |
| 312 | fn gen(self: *Self) !void { | 365 | fn gen(self: *Self) !void { |
| 313 | try self.dbgSetPrologueEnd(); | 366 | _ = try self.addInst(.{ |
| | 367 | .tag = .dbg_prologue_end, |
| | 368 | .data = .{ .nop = {} }, |
| | 369 | }); |
| | 370 | |
| 314 | try self.genBody(self.air.getMainBody()); | 371 | try self.genBody(self.air.getMainBody()); |
| 315 | try self.dbgSetEpilogueBegin(); | 372 | |
| | 373 | _ = try self.addInst(.{ |
| | 374 | .tag = .dbg_epilogue_begin, |
| | 375 | .data = .{ .nop = {} }, |
| | 376 | }); |
| 316 | | 377 | |
| 317 | // Drop them off at the rbrace. | 378 | // Drop them off at the rbrace. |
| 318 | try self.dbgAdvancePCAndLine(self.end_di_line, self.end_di_column); | 379 | _ = try self.addInst(.{ |
| | 380 | .tag = .dbg_line, |
| | 381 | .data = .{ .dbg_line_column = .{ |
| | 382 | .line = self.end_di_line, |
| | 383 | .column = self.end_di_column, |
| | 384 | } }, |
| | 385 | }); |
| 319 | } | 386 | } |
| 320 | | 387 | |
| 321 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 388 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| ... | @@ -456,79 +523,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -456,79 +523,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 456 | } | 523 | } |
| 457 | } | 524 | } |
| 458 | | 525 | |
| 459 | fn dbgSetPrologueEnd(self: *Self) InnerError!void { | | |
| 460 | switch (self.debug_output) { | | |
| 461 | .dwarf => |dbg_out| { | | |
| 462 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | | |
| 463 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); | | |
| 464 | }, | | |
| 465 | .plan9 => {}, | | |
| 466 | .none => {}, | | |
| 467 | } | | |
| 468 | } | | |
| 469 | | | |
| 470 | fn dbgSetEpilogueBegin(self: *Self) InnerError!void { | | |
| 471 | switch (self.debug_output) { | | |
| 472 | .dwarf => |dbg_out| { | | |
| 473 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | | |
| 474 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); | | |
| 475 | }, | | |
| 476 | .plan9 => {}, | | |
| 477 | .none => {}, | | |
| 478 | } | | |
| 479 | } | | |
| 480 | | | |
| 481 | fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void { | | |
| 482 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); | | |
| 483 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; | | |
| 484 | switch (self.debug_output) { | | |
| 485 | .dwarf => |dbg_out| { | | |
| 486 | // TODO Look into using the DWARF special opcodes to compress this data. | | |
| 487 | // It lets you emit single-byte opcodes that add different numbers to | | |
| 488 | // both the PC and the line number at the same time. | | |
| 489 | try dbg_out.dbg_line.ensureUnusedCapacity(11); | | |
| 490 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | | |
| 491 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | | |
| 492 | if (delta_line != 0) { | | |
| 493 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | | |
| 494 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | | |
| 495 | } | | |
| 496 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy); | | |
| 497 | self.prev_di_pc = self.code.items.len; | | |
| 498 | self.prev_di_line = line; | | |
| 499 | self.prev_di_column = column; | | |
| 500 | self.prev_di_pc = self.code.items.len; | | |
| 501 | }, | | |
| 502 | .plan9 => |dbg_out| { | | |
| 503 | if (delta_pc <= 0) return; // only do this when the pc changes | | |
| 504 | // we have already checked the target in the linker to make sure it is compatable | | |
| 505 | const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable; | | |
| 506 | | | |
| 507 | // increasing the line number | | |
| 508 | try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); | | |
| 509 | // increasing the pc | | |
| 510 | const d_pc_p9 = @intCast(i64, delta_pc) - quant; | | |
| 511 | if (d_pc_p9 > 0) { | | |
| 512 | // minus one because if its the last one, we want to leave space to change the line which is one quanta | | |
| 513 | try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant); | | |
| 514 | if (dbg_out.pcop_change_index.*) |pci| | | |
| 515 | dbg_out.dbg_line.items[pci] += 1; | | |
| 516 | dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1); | | |
| 517 | } else if (d_pc_p9 == 0) { | | |
| 518 | // we don't need to do anything, because adding the quant does it for us | | |
| 519 | } else unreachable; | | |
| 520 | if (dbg_out.start_line.* == null) | | |
| 521 | dbg_out.start_line.* = self.prev_di_line; | | |
| 522 | dbg_out.end_line.* = line; | | |
| 523 | // only do this if the pc changed | | |
| 524 | self.prev_di_line = line; | | |
| 525 | self.prev_di_column = column; | | |
| 526 | self.prev_di_pc = self.code.items.len; | | |
| 527 | }, | | |
| 528 | .none => {}, | | |
| 529 | } | | |
| 530 | } | | |
| 531 | | | |
| 532 | /// Asserts there is already capacity to insert into top branch inst_table. | 526 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 533 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 527 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 534 | const air_tags = self.air.instructions.items(.tag); | 528 | const air_tags = self.air.instructions.items(.tag); |
| ... | @@ -1291,7 +1285,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1291,7 +1285,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1291 | } | 1285 | } |
| 1292 | | 1286 | |
| 1293 | fn airBreakpoint(self: *Self) !void { | 1287 | fn airBreakpoint(self: *Self) !void { |
| 1294 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ebreak.toU32()); | 1288 | _ = try self.addInst(.{ |
| | 1289 | .tag = .ebreak, |
| | 1290 | .data = .{ .nop = {} }, |
| | 1291 | }); |
| 1295 | return self.finishAirBookkeeping(); | 1292 | return self.finishAirBookkeeping(); |
| 1296 | } | 1293 | } |
| 1297 | | 1294 | |
| ... | @@ -1330,7 +1327,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1330,7 +1327,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1330 | unreachable; | 1327 | unreachable; |
| 1331 | | 1328 | |
| 1332 | try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr }); | 1329 | try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr }); |
| 1333 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | 1330 | _ = try self.addInst(.{ |
| | 1331 | .tag = .jalr, |
| | 1332 | .data = .{ .i_type = .{ |
| | 1333 | .rd = .ra, |
| | 1334 | .rs1 = .ra, |
| | 1335 | .imm12 = 0, |
| | 1336 | } }, |
| | 1337 | }); |
| 1334 | } else if (func_value.castTag(.extern_fn)) |_| { | 1338 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 1335 | return self.fail("TODO implement calling extern functions", .{}); | 1339 | return self.fail("TODO implement calling extern functions", .{}); |
| 1336 | } else { | 1340 | } else { |
| ... | @@ -1375,7 +1379,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1375,7 +1379,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1375 | fn ret(self: *Self, mcv: MCValue) !void { | 1379 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1376 | const ret_ty = self.fn_type.fnReturnType(); | 1380 | const ret_ty = self.fn_type.fnReturnType(); |
| 1377 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 1381 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1378 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.zero, 0, .ra).toU32()); | 1382 | _ = try self.addInst(.{ |
| | 1383 | .tag = .jalr, |
| | 1384 | .data = .{ .i_type = .{ |
| | 1385 | .rd = .zero, |
| | 1386 | .rs1 = .ra, |
| | 1387 | .imm12 = 0, |
| | 1388 | } }, |
| | 1389 | }); |
| 1379 | } | 1390 | } |
| 1380 | | 1391 | |
| 1381 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 1392 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1414,7 +1425,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1414,7 +1425,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1414 | | 1425 | |
| 1415 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | 1426 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1416 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; | 1427 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; |
| 1417 | try self.dbgAdvancePCAndLine(dbg_stmt.line, dbg_stmt.column); | 1428 | |
| | 1429 | _ = try self.addInst(.{ |
| | 1430 | .tag = .dbg_line, |
| | 1431 | .data = .{ .dbg_line_column = .{ |
| | 1432 | .line = dbg_stmt.line, |
| | 1433 | .column = dbg_stmt.column, |
| | 1434 | } }, |
| | 1435 | }); |
| | 1436 | |
| 1418 | return self.finishAirBookkeeping(); | 1437 | return self.finishAirBookkeeping(); |
| 1419 | } | 1438 | } |
| 1420 | | 1439 | |
| ... | @@ -1706,7 +1725,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1706,7 +1725,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 1706 | } | 1725 | } |
| 1707 | | 1726 | |
| 1708 | if (mem.eql(u8, asm_source, "ecall")) { | 1727 | if (mem.eql(u8, asm_source, "ecall")) { |
| 1709 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ecall.toU32()); | 1728 | _ = try self.addInst(.{ |
| | 1729 | .tag = .ecall, |
| | 1730 | .data = .{ .nop = {} }, |
| | 1731 | }); |
| 1710 | } else { | 1732 | } else { |
| 1711 | return self.fail("TODO implement support for more riscv64 assembly instructions", .{}); | 1733 | return self.fail("TODO implement support for more riscv64 assembly instructions", .{}); |
| 1712 | } | 1734 | } |
| ... | @@ -1785,29 +1807,54 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -1785,29 +1807,54 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 1785 | .immediate => |unsigned_x| { | 1807 | .immediate => |unsigned_x| { |
| 1786 | const x = @bitCast(i64, unsigned_x); | 1808 | const x = @bitCast(i64, unsigned_x); |
| 1787 | if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { | 1809 | if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { |
| 1788 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.addi(reg, .zero, @truncate(i12, x)).toU32()); | 1810 | _ = try self.addInst(.{ |
| 1789 | return; | 1811 | .tag = .addi, |
| 1790 | } | 1812 | .data = .{ .i_type = .{ |
| 1791 | if (math.minInt(i32) <= x and x <= math.maxInt(i32)) { | 1813 | .rd = reg, |
| | 1814 | .rs1 = .zero, |
| | 1815 | .imm12 = @intCast(i12, x), |
| | 1816 | } }, |
| | 1817 | }); |
| | 1818 | } else if (math.minInt(i32) <= x and x <= math.maxInt(i32)) { |
| 1792 | const lo12 = @truncate(i12, x); | 1819 | const lo12 = @truncate(i12, x); |
| 1793 | const carry: i32 = if (lo12 < 0) 1 else 0; | 1820 | const carry: i32 = if (lo12 < 0) 1 else 0; |
| 1794 | const hi20 = @truncate(i20, (x >> 12) +% carry); | 1821 | const hi20 = @truncate(i20, (x >> 12) +% carry); |
| 1795 | | 1822 | |
| 1796 | // TODO: add test case for 32-bit immediate | 1823 | // TODO: add test case for 32-bit immediate |
| 1797 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.lui(reg, hi20).toU32()); | 1824 | _ = try self.addInst(.{ |
| 1798 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.addi(reg, reg, lo12).toU32()); | 1825 | .tag = .lui, |
| 1799 | return; | 1826 | .data = .{ .u_type = .{ |
| | 1827 | .rd = reg, |
| | 1828 | .imm20 = hi20, |
| | 1829 | } }, |
| | 1830 | }); |
| | 1831 | _ = try self.addInst(.{ |
| | 1832 | .tag = .addi, |
| | 1833 | .data = .{ .i_type = .{ |
| | 1834 | .rd = reg, |
| | 1835 | .rs1 = reg, |
| | 1836 | .imm12 = lo12, |
| | 1837 | } }, |
| | 1838 | }); |
| | 1839 | } else { |
| | 1840 | // li rd, immediate |
| | 1841 | // "Myriad sequences" |
| | 1842 | return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf |
| 1800 | } | 1843 | } |
| 1801 | // li rd, immediate | | |
| 1802 | // "Myriad sequences" | | |
| 1803 | return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf | | |
| 1804 | }, | 1844 | }, |
| 1805 | .memory => |addr| { | 1845 | .memory => |addr| { |
| 1806 | // The value is in memory at a hard-coded address. | 1846 | // The value is in memory at a hard-coded address. |
| 1807 | // If the type is a pointer, it means the pointer address is at this memory location. | 1847 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 1808 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 1848 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 1809 | | 1849 | |
| 1810 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32()); | 1850 | _ = try self.addInst(.{ |
| | 1851 | .tag = .ld, |
| | 1852 | .data = .{ .i_type = .{ |
| | 1853 | .rd = reg, |
| | 1854 | .rs1 = reg, |
| | 1855 | .imm12 = 0, |
| | 1856 | } }, |
| | 1857 | }); |
| 1811 | // LOAD imm=[i12 offset = 0], rs1 = | 1858 | // LOAD imm=[i12 offset = 0], rs1 = |
| 1812 | | 1859 | |
| 1813 | // return self.fail("TODO implement genSetReg memory for riscv64"); | 1860 | // return self.fail("TODO implement genSetReg memory for riscv64"); |