| author | |
| committer | |
| log | 2be3033acda53389cac9f3e9a8ca0a3d41348eef |
| tree | af1a41562ca6ed1f7758c55d625d444509834241 |
| parent | 28df64cba45595a201f8c2312656922a8c28a67c |
we use a code offset map in Emit.zig to pre-compute what byte offset each MIR instruction is at. this is important because they can be
of different size4 files changed, 119 insertions(+), 42 deletions(-)
lib/std/builtin.zig+2-6| ... | ... | @@ -759,11 +759,6 @@ else |
| 759 | 759 | pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn { |
| 760 | 760 | @setCold(true); |
| 761 | 761 | |
| 762 | // stage2_riscv64 backend doesn't support loops yet. | |
| 763 | if (builtin.zig_backend == .stage2_riscv64) { | |
| 764 | unreachable; | |
| 765 | } | |
| 766 | ||
| 767 | 762 | // For backends that cannot handle the language features depended on by the |
| 768 | 763 | // default panic handler, we have a simpler panic handler: |
| 769 | 764 | if (builtin.zig_backend == .stage2_wasm or |
| ... | ... | @@ -772,7 +767,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr |
| 772 | 767 | builtin.zig_backend == .stage2_x86 or |
| 773 | 768 | (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or |
| 774 | 769 | builtin.zig_backend == .stage2_sparc64 or |
| 775 | builtin.zig_backend == .stage2_spirv64) | |
| 770 | builtin.zig_backend == .stage2_spirv64 or | |
| 771 | builtin.zig_backend == .stage2_riscv64) | |
| 776 | 772 | { |
| 777 | 773 | while (true) { |
| 778 | 774 | @breakpoint(); |
src/arch/riscv64/CodeGen.zig+29-22| ... | ... | @@ -301,6 +301,7 @@ pub fn generate( |
| 301 | 301 | .prev_di_line = func.lbrace_line, |
| 302 | 302 | .prev_di_column = func.lbrace_column, |
| 303 | 303 | .stack_size = @max(32, function.max_end_stack), |
| 304 | .code_offset_mapping = .{}, | |
| 304 | 305 | }; |
| 305 | 306 | defer emit.deinit(); |
| 306 | 307 | |
| ... | ... | @@ -929,21 +930,16 @@ fn binOpRegister( |
| 929 | 930 | .cmp_gt => .cmp_gt, |
| 930 | 931 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), |
| 931 | 932 | }; |
| 932 | const mir_data: Mir.Inst.Data = switch (tag) { | |
| 933 | .add, | |
| 934 | .sub, | |
| 935 | .cmp_eq, | |
| 936 | => .{ .r_type = .{ | |
| 937 | .rd = dest_reg, | |
| 938 | .rs1 = lhs_reg, | |
| 939 | .rs2 = rhs_reg, | |
| 940 | } }, | |
| 941 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), | |
| 942 | }; | |
| 943 | 933 | |
| 944 | 934 | _ = try self.addInst(.{ |
| 945 | 935 | .tag = mir_tag, |
| 946 | .data = mir_data, | |
| 936 | .data = .{ | |
| 937 | .r_type = .{ | |
| 938 | .rd = dest_reg, | |
| 939 | .rs1 = lhs_reg, | |
| 940 | .rs2 = rhs_reg, | |
| 941 | }, | |
| 942 | }, | |
| 947 | 943 | }); |
| 948 | 944 | |
| 949 | 945 | return MCValue{ .register = dest_reg }; |
| ... | ... | @@ -1636,7 +1632,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1636 | 1632 | |
| 1637 | 1633 | const dst_mcv = switch (src_mcv) { |
| 1638 | 1634 | .register => |src_reg| dst: { |
| 1639 | self.register_manager.getRegAssumeFree(src_reg, inst); | |
| 1635 | try self.register_manager.getReg(src_reg, inst); | |
| 1640 | 1636 | break :dst src_mcv; |
| 1641 | 1637 | }, |
| 1642 | 1638 | else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}), |
| ... | ... | @@ -1914,6 +1910,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1914 | 1910 | self.processDeath(operand); |
| 1915 | 1911 | } |
| 1916 | 1912 | try self.genBody(then_body); |
| 1913 | // point at the to-be-generated else case | |
| 1914 | try self.performReloc(reloc, @intCast(self.mir_instructions.len)); | |
| 1917 | 1915 | |
| 1918 | 1916 | // Revert to the previous register and stack allocation state. |
| 1919 | 1917 | |
| ... | ... | @@ -1929,7 +1927,6 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1929 | 1927 | self.next_stack_offset = parent_next_stack_offset; |
| 1930 | 1928 | self.register_manager.free_registers = parent_free_registers; |
| 1931 | 1929 | |
| 1932 | try self.performReloc(reloc); | |
| 1933 | 1930 | const else_branch = self.branch_stack.addOneAssumeCapacity(); |
| 1934 | 1931 | else_branch.* = .{}; |
| 1935 | 1932 | |
| ... | ... | @@ -2014,8 +2011,6 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2014 | 2011 | var item = self.branch_stack.pop(); |
| 2015 | 2012 | item.deinit(self.gpa); |
| 2016 | 2013 | } |
| 2017 | ||
| 2018 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | |
| 2019 | 2014 | } |
| 2020 | 2015 | |
| 2021 | 2016 | fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index { |
| ... | ... | @@ -2027,12 +2022,12 @@ fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index { |
| 2027 | 2022 | }; |
| 2028 | 2023 | |
| 2029 | 2024 | return try self.addInst(.{ |
| 2030 | .tag = .beq, | |
| 2025 | .tag = .bne, | |
| 2031 | 2026 | .data = .{ |
| 2032 | 2027 | .b_type = .{ |
| 2033 | 2028 | .rs1 = reg, |
| 2034 | 2029 | .rs2 = .zero, |
| 2035 | .imm12 = 0, // patched later. | |
| 2030 | .inst = undefined, | |
| 2036 | 2031 | }, |
| 2037 | 2032 | }, |
| 2038 | 2033 | }); |
| ... | ... | @@ -2218,7 +2213,13 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 2218 | 2213 | try self.genBody(body); |
| 2219 | 2214 | |
| 2220 | 2215 | for (self.blocks.getPtr(inst).?.relocs.items) |reloc| { |
| 2221 | try self.performReloc(reloc); | |
| 2216 | // here we are relocing to point at the instruction after the block. | |
| 2217 | // [then case] | |
| 2218 | // [jump to end] // this is reloced | |
| 2219 | // [else case] | |
| 2220 | // [jump to end] // this is reloced | |
| 2221 | // [this isn't generated yet] // point to here | |
| 2222 | try self.performReloc(reloc, @intCast(self.mir_instructions.len)); | |
| 2222 | 2223 | } |
| 2223 | 2224 | |
| 2224 | 2225 | const result = self.blocks.getPtr(inst).?.mcv; |
| ... | ... | @@ -2233,11 +2234,14 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2233 | 2234 | // return self.finishAir(inst, .dead, .{ condition, .none, .none }); |
| 2234 | 2235 | } |
| 2235 | 2236 | |
| 2236 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | |
| 2237 | fn performReloc(self: *Self, inst: Mir.Inst.Index, target: Mir.Inst.Index) !void { | |
| 2237 | 2238 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 2238 | 2239 | |
| 2239 | 2240 | switch (tag) { |
| 2240 | .beq => self.mir_instructions.items(.data)[inst].b_type.imm12 = @intCast(inst), | |
| 2241 | .bne, | |
| 2242 | .beq, | |
| 2243 | => self.mir_instructions.items(.data)[inst].b_type.inst = target, | |
| 2244 | .jal => self.mir_instructions.items(.data)[inst].j_type.inst = target, | |
| 2241 | 2245 | else => return self.fail("TODO: performReloc {s}", .{@tagName(tag)}), |
| 2242 | 2246 | } |
| 2243 | 2247 | } |
| ... | ... | @@ -2283,7 +2287,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void { |
| 2283 | 2287 | .data = .{ |
| 2284 | 2288 | .j_type = .{ |
| 2285 | 2289 | .rd = .ra, |
| 2286 | .imm21 = undefined, // populated later through performReloc | |
| 2290 | .inst = undefined, | |
| 2287 | 2291 | }, |
| 2288 | 2292 | }, |
| 2289 | 2293 | })); |
| ... | ... | @@ -2467,6 +2471,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner |
| 2467 | 2471 | } |
| 2468 | 2472 | }, |
| 2469 | 2473 | .stack_offset, .load_symbol => { |
| 2474 | if (true) | |
| 2475 | return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}); | |
| 2476 | ||
| 2470 | 2477 | if (abi_size <= 8) { |
| 2471 | 2478 | const reg = try self.copyToTmpRegister(ty, src_val); |
| 2472 | 2479 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
src/arch/riscv64/Emit.zig+86-12| ... | ... | @@ -26,8 +26,14 @@ prev_di_line: u32, |
| 26 | 26 | prev_di_column: u32, |
| 27 | 27 | /// Relative to the beginning of `code`. |
| 28 | 28 | prev_di_pc: usize, |
| 29 | ||
| 29 | /// Function's stack size. Used for backpatching. | |
| 30 | 30 | stack_size: u32, |
| 31 | /// For backward branches: stores the code offset of the target | |
| 32 | /// instruction | |
| 33 | /// | |
| 34 | /// For forward branches: stores the code offset of the branch | |
| 35 | /// instruction | |
| 36 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, | |
| 31 | 37 | |
| 32 | 38 | const log = std.log.scoped(.emit); |
| 33 | 39 | |
| ... | ... | @@ -100,6 +106,10 @@ pub fn emitMir( |
| 100 | 106 | } |
| 101 | 107 | |
| 102 | 108 | pub fn deinit(emit: *Emit) void { |
| 109 | const comp = emit.bin_file.comp; | |
| 110 | const gpa = comp.gpa; | |
| 111 | ||
| 112 | emit.code_offset_mapping.deinit(gpa); | |
| 103 | 113 | emit.* = undefined; |
| 104 | 114 | } |
| 105 | 115 | |
| ... | ... | @@ -118,10 +128,8 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 118 | 128 | } |
| 119 | 129 | |
| 120 | 130 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { |
| 121 | log.debug("Line: {} {}\n", .{ line, emit.prev_di_line }); | |
| 122 | 131 | const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line)); |
| 123 | 132 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 124 | log.debug("(advance pc={d} and line={d})", .{ delta_pc, delta_line }); | |
| 125 | 133 | switch (emit.debug_output) { |
| 126 | 134 | .dwarf => |dw| { |
| 127 | 135 | if (column != emit.prev_di_column) try dw.setColumn(column); |
| ... | ... | @@ -166,7 +174,7 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 166 | 174 | switch (tag) { |
| 167 | 175 | .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)), |
| 168 | 176 | .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)), |
| 169 | .cmp_eq => try emit.writeInstruction(Instruction.slt(r_type.rd, r_type.rs1, r_type.rs2)), | |
| 177 | .cmp_gt => try emit.writeInstruction(Instruction.slt(r_type.rd, r_type.rs1, r_type.rs2)), | |
| 170 | 178 | else => unreachable, |
| 171 | 179 | } |
| 172 | 180 | } |
| ... | ... | @@ -175,8 +183,17 @@ fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 175 | 183 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 176 | 184 | const b_type = emit.mir.instructions.items(.data)[inst].b_type; |
| 177 | 185 | |
| 186 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(b_type.inst).?)) - @as(i64, @intCast(emit.code.items.len)); | |
| 187 | ||
| 178 | 188 | switch (tag) { |
| 179 | .beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)), | |
| 189 | .beq => { | |
| 190 | log.debug("beq: {} offset={}", .{ inst, offset }); | |
| 191 | try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, @intCast(offset))); | |
| 192 | }, | |
| 193 | .bne => { | |
| 194 | log.debug("bne: {} offset={}", .{ inst, offset }); | |
| 195 | try emit.writeInstruction(Instruction.bne(b_type.rs1, b_type.rs2, @intCast(offset))); | |
| 196 | }, | |
| 180 | 197 | else => unreachable, |
| 181 | 198 | } |
| 182 | 199 | } |
| ... | ... | @@ -215,9 +232,12 @@ fn mirJType(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 215 | 232 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 216 | 233 | const j_type = emit.mir.instructions.items(.data)[inst].j_type; |
| 217 | 234 | |
| 235 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(j_type.inst).?)) - @as(i64, @intCast(emit.code.items.len)); | |
| 236 | ||
| 218 | 237 | switch (tag) { |
| 219 | 238 | .jal => { |
| 220 | try emit.writeInstruction(Instruction.jal(j_type.rd, j_type.imm21)); | |
| 239 | log.debug("jal: {} offset={}", .{ inst, offset }); | |
| 240 | try emit.writeInstruction(Instruction.jal(j_type.rd, @intCast(offset))); | |
| 221 | 241 | }, |
| 222 | 242 | else => unreachable, |
| 223 | 243 | } |
| ... | ... | @@ -304,12 +324,8 @@ fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 304 | 324 | }, |
| 305 | 325 | |
| 306 | 326 | .j => { |
| 307 | const target = data.inst; | |
| 308 | const offset: i12 = @intCast(emit.code.items.len); | |
| 309 | _ = target; | |
| 310 | ||
| 311 | try emit.writeInstruction(Instruction.jal(.s0, offset)); | |
| 312 | unreachable; // TODO: mirPsuedo j | |
| 327 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(data.inst).?)) - @as(i64, @intCast(emit.code.items.len)); | |
| 328 | try emit.writeInstruction(Instruction.jal(.s0, @intCast(offset))); | |
| 313 | 329 | }, |
| 314 | 330 | |
| 315 | 331 | else => unreachable, |
| ... | ... | @@ -401,7 +417,51 @@ fn isLoad(tag: Mir.Inst.Tag) bool { |
| 401 | 417 | }; |
| 402 | 418 | } |
| 403 | 419 | |
| 420 | pub fn isBranch(tag: Mir.Inst.Tag) bool { | |
| 421 | return switch (tag) { | |
| 422 | .beq => true, | |
| 423 | .bne => true, | |
| 424 | .jal => true, | |
| 425 | .j => true, | |
| 426 | else => false, | |
| 427 | }; | |
| 428 | } | |
| 429 | ||
| 430 | pub fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { | |
| 431 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 432 | const data = emit.mir.instructions.items(.data)[inst]; | |
| 433 | ||
| 434 | switch (tag) { | |
| 435 | .bne, | |
| 436 | .beq, | |
| 437 | => return data.b_type.inst, | |
| 438 | .jal => return data.j_type.inst, | |
| 439 | .j => return data.inst, | |
| 440 | else => std.debug.panic("branchTarget {s}", .{@tagName(tag)}), | |
| 441 | } | |
| 442 | } | |
| 443 | ||
| 444 | fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { | |
| 445 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 446 | ||
| 447 | return switch (tag) { | |
| 448 | .dbg_line, | |
| 449 | .dbg_epilogue_begin, | |
| 450 | .dbg_prologue_end, | |
| 451 | => 0, | |
| 452 | ||
| 453 | .psuedo_epilogue => 12, // 3 * 4 | |
| 454 | .psuedo_prologue => 16, // 4 * 4 | |
| 455 | ||
| 456 | .abs => 12, // 3 * 4 | |
| 457 | ||
| 458 | else => 4, | |
| 459 | }; | |
| 460 | } | |
| 461 | ||
| 404 | 462 | fn lowerMir(emit: *Emit) !void { |
| 463 | const comp = emit.bin_file.comp; | |
| 464 | const gpa = comp.gpa; | |
| 405 | 465 | const mir_tags = emit.mir.instructions.items(.tag); |
| 406 | 466 | const mir_datas = emit.mir.instructions.items(.data); |
| 407 | 467 | |
| ... | ... | @@ -419,5 +479,19 @@ fn lowerMir(emit: *Emit) !void { |
| 419 | 479 | mir_datas[inst].i_type.imm12 = -(casted_size - 12 - offset); |
| 420 | 480 | } |
| 421 | 481 | } |
| 482 | ||
| 483 | if (isBranch(tag)) { | |
| 484 | const target_inst = emit.branchTarget(inst); | |
| 485 | try emit.code_offset_mapping.put(gpa, target_inst, 0); | |
| 486 | } | |
| 487 | } | |
| 488 | var current_code_offset: usize = 0; | |
| 489 | ||
| 490 | for (0..mir_tags.len) |index| { | |
| 491 | const inst = @as(u32, @intCast(index)); | |
| 492 | if (emit.code_offset_mapping.getPtr(inst)) |offset| { | |
| 493 | offset.* = current_code_offset; | |
| 494 | } | |
| 495 | current_code_offset += emit.instructionSize(inst); | |
| 422 | 496 | } |
| 423 | 497 | } |
src/arch/riscv64/Mir.zig+2-2| ... | ... | @@ -158,14 +158,14 @@ pub const Inst = struct { |
| 158 | 158 | b_type: struct { |
| 159 | 159 | rs1: Register, |
| 160 | 160 | rs2: Register, |
| 161 | imm12: i13, | |
| 161 | inst: Inst.Index, | |
| 162 | 162 | }, |
| 163 | 163 | /// J-Type |
| 164 | 164 | /// |
| 165 | 165 | /// Used by e.g. jal |
| 166 | 166 | j_type: struct { |
| 167 | 167 | rd: Register, |
| 168 | imm21: i21, | |
| 168 | inst: Inst.Index, | |
| 169 | 169 | }, |
| 170 | 170 | /// U-Type |
| 171 | 171 | /// |