| ... | ... | @@ -5,6 +5,8 @@ const math = std.math; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | const Air = @import("../../Air.zig"); |
| 7 | 7 | const Zir = @import("../../Zir.zig"); |
| 8 | const Mir = @import("Mir.zig"); |
| 9 | const Emit = @import("Emit.zig"); |
| 8 | 10 | const Liveness = @import("../../Liveness.zig"); |
| 9 | 11 | const Type = @import("../../type.zig").Type; |
| 10 | 12 | const Value = @import("../../value.zig").Value; |
| ... | ... | @@ -47,13 +49,14 @@ arg_index: usize, |
| 47 | 49 | src_loc: Module.SrcLoc, |
| 48 | 50 | stack_align: u32, |
| 49 | 51 | |
| 50 | | prev_di_line: u32, |
| 51 | | prev_di_column: u32, |
| 52 | /// MIR Instructions |
| 53 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 54 | /// MIR extra data |
| 55 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 56 | |
| 52 | 57 | /// Byte offset within the source file of the ending curly. |
| 53 | 58 | end_di_line: u32, |
| 54 | 59 | end_di_column: u32, |
| 55 | | /// Relative to the beginning of `code`. |
| 56 | | prev_di_pc: usize, |
| 57 | 60 | |
| 58 | 61 | /// The value is an offset into the `Function` `code` from the beginning. |
| 59 | 62 | /// To perform the reloc, write 32-bit signed little-endian integer |
| ... | ... | @@ -276,9 +279,6 @@ pub fn generate( |
| 276 | 279 | .branch_stack = &branch_stack, |
| 277 | 280 | .src_loc = src_loc, |
| 278 | 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 | 282 | .end_di_line = module_fn.rbrace_line, |
| 283 | 283 | .end_di_column = module_fn.rbrace_column, |
| 284 | 284 | }; |
| ... | ... | @@ -302,6 +302,30 @@ pub fn generate( |
| 302 | 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 | 329 | if (function.err_msg) |em| { |
| 306 | 330 | return FnResult{ .fail = em }; |
| 307 | 331 | } else { |
| ... | ... | @@ -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 | 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 | 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 | 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 | 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 | 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 | 526 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 533 | 527 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 534 | 528 | const air_tags = self.air.instructions.items(.tag); |
| ... | ... | @@ -1291,7 +1285,10 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1291 | 1285 | } |
| 1292 | 1286 | |
| 1293 | 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 | 1292 | return self.finishAirBookkeeping(); |
| 1296 | 1293 | } |
| 1297 | 1294 | |
| ... | ... | @@ -1330,7 +1327,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1330 | 1327 | unreachable; |
| 1331 | 1328 | |
| 1332 | 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 | 1338 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 1335 | 1339 | return self.fail("TODO implement calling extern functions", .{}); |
| 1336 | 1340 | } else { |
| ... | ... | @@ -1375,7 +1379,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1375 | 1379 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1376 | 1380 | const ret_ty = self.fn_type.fnReturnType(); |
| 1377 | 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 | 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 | 1425 | |
| 1415 | 1426 | fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1416 | 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 | 1437 | return self.finishAirBookkeeping(); |
| 1419 | 1438 | } |
| 1420 | 1439 | |
| ... | ... | @@ -1706,7 +1725,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 1706 | 1725 | } |
| 1707 | 1726 | |
| 1708 | 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 | 1732 | } else { |
| 1711 | 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 | 1807 | .immediate => |unsigned_x| { |
| 1786 | 1808 | const x = @bitCast(i64, unsigned_x); |
| 1787 | 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()); |
| 1789 | | return; |
| 1790 | | } |
| 1791 | | if (math.minInt(i32) <= x and x <= math.maxInt(i32)) { |
| 1810 | _ = try self.addInst(.{ |
| 1811 | .tag = .addi, |
| 1812 | .data = .{ .i_type = .{ |
| 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 | 1819 | const lo12 = @truncate(i12, x); |
| 1793 | 1820 | const carry: i32 = if (lo12 < 0) 1 else 0; |
| 1794 | 1821 | const hi20 = @truncate(i20, (x >> 12) +% carry); |
| 1795 | 1822 | |
| 1796 | 1823 | // TODO: add test case for 32-bit immediate |
| 1797 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.lui(reg, hi20).toU32()); |
| 1798 | | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.addi(reg, reg, lo12).toU32()); |
| 1799 | | return; |
| 1824 | _ = try self.addInst(.{ |
| 1825 | .tag = .lui, |
| 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 | 1845 | .memory => |addr| { |
| 1806 | 1846 | // The value is in memory at a hard-coded address. |
| 1807 | 1847 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 1808 | 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 | 1858 | // LOAD imm=[i12 offset = 0], rs1 = |
| 1812 | 1859 | |
| 1813 | 1860 | // return self.fail("TODO implement genSetReg memory for riscv64"); |