| author | |
| committer | |
| log | d19b77d63f0d02ab9c0a0928391891ae4a77744c |
| tree | f32cd14c27295517503576ccb16caa46bccaf141 |
| parent | cc204e2365547c19f7c9e1a836a3ea8c18e3a6ea |
9 files changed, 179 insertions(+), 28 deletions(-)
lib/std/builtin.zig+9-1| ... | ... | @@ -775,7 +775,15 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr |
| 775 | 775 | } |
| 776 | 776 | |
| 777 | 777 | if (builtin.zig_backend == .stage2_riscv64) { |
| 778 | unreachable; | |
| 778 | asm volatile ("ecall" | |
| 779 | : | |
| 780 | : [number] "{a7}" (64), | |
| 781 | [arg1] "{a0}" (1), | |
| 782 | [arg2] "{a1}" (@intFromPtr(msg.ptr)), | |
| 783 | [arg3] "{a2}" (msg.len), | |
| 784 | : "memory" | |
| 785 | ); | |
| 786 | std.posix.exit(127); | |
| 779 | 787 | } |
| 780 | 788 | |
| 781 | 789 | switch (builtin.os.tag) { |
src/arch/riscv64/CodeGen.zig+25-5| ... | ... | @@ -1513,7 +1513,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type { |
| 1513 | 1513 | }, |
| 1514 | 1514 | else => unreachable, |
| 1515 | 1515 | }, |
| 1516 | else => break, | |
| 1516 | else => return self.fail("TODO: splitType class {}", .{class}), | |
| 1517 | 1517 | }; |
| 1518 | 1518 | } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts; |
| 1519 | 1519 | return self.fail("TODO implement splitType for {}", .{ty.fmt(zcu)}); |
| ... | ... | @@ -3434,6 +3434,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3434 | 3434 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 3435 | 3435 | const src_mcv = self.args[arg_index]; |
| 3436 | 3436 | |
| 3437 | const arg_ty = self.typeOfIndex(inst); | |
| 3438 | ||
| 3437 | 3439 | const dst_mcv = switch (src_mcv) { |
| 3438 | 3440 | .register => dst: { |
| 3439 | 3441 | const frame = try self.allocFrameIndex(FrameAlloc.init(.{ |
| ... | ... | @@ -3441,9 +3443,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3441 | 3443 | .alignment = Type.usize.abiAlignment(zcu), |
| 3442 | 3444 | })); |
| 3443 | 3445 | const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; |
| 3444 | ||
| 3445 | 3446 | try self.genCopy(Type.usize, dst_mcv, src_mcv); |
| 3446 | ||
| 3447 | break :dst dst_mcv; | |
| 3448 | }, | |
| 3449 | .register_pair => dst: { | |
| 3450 | const frame = try self.allocFrameIndex(FrameAlloc.init(.{ | |
| 3451 | .size = Type.usize.abiSize(zcu) * 2, | |
| 3452 | .alignment = Type.usize.abiAlignment(zcu), | |
| 3453 | })); | |
| 3454 | const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; | |
| 3455 | try self.genCopy(arg_ty, dst_mcv, src_mcv); | |
| 3447 | 3456 | break :dst dst_mcv; |
| 3448 | 3457 | }, |
| 3449 | 3458 | .load_frame => src_mcv, |
| ... | ... | @@ -4506,6 +4515,17 @@ fn genSetStack( |
| 4506 | 4515 | else => unreachable, // register can hold a max of 8 bytes |
| 4507 | 4516 | } |
| 4508 | 4517 | }, |
| 4518 | .register_pair => |pair| { | |
| 4519 | var part_disp: i32 = frame.off; | |
| 4520 | for (try self.splitType(ty), pair) |src_ty, src_reg| { | |
| 4521 | try self.genSetStack( | |
| 4522 | src_ty, | |
| 4523 | .{ .index = frame.index, .off = part_disp }, | |
| 4524 | .{ .register = src_reg }, | |
| 4525 | ); | |
| 4526 | part_disp += @intCast(src_ty.abiSize(zcu)); | |
| 4527 | } | |
| 4528 | }, | |
| 4509 | 4529 | .load_frame, |
| 4510 | 4530 | .indirect, |
| 4511 | 4531 | .load_symbol, |
| ... | ... | @@ -4564,8 +4584,8 @@ fn genInlineMemcpy( |
| 4564 | 4584 | .ops = .rri, |
| 4565 | 4585 | .data = .{ |
| 4566 | 4586 | .i_type = .{ |
| 4567 | .rd = tmp, | |
| 4568 | .rs1 = dst, | |
| 4587 | .rd = dst, | |
| 4588 | .rs1 = tmp, | |
| 4569 | 4589 | .imm12 = Immediate.s(0), |
| 4570 | 4590 | }, |
| 4571 | 4591 | }, |
src/arch/riscv64/Emit.zig+31-1| ... | ... | @@ -41,7 +41,35 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 41 | 41 | .offset = 0, |
| 42 | 42 | .enc = std.meta.activeTag(lowered_inst.encoding.data), |
| 43 | 43 | }), |
| 44 | else => |x| return emit.fail("TODO: emitMir {s}", .{@tagName(x)}), | |
| 44 | .load_symbol_reloc => |symbol| { | |
| 45 | if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 46 | const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; | |
| 47 | const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); | |
| 48 | const sym = elf_file.symbol(sym_index); | |
| 49 | ||
| 50 | var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | |
| 51 | var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | |
| 52 | ||
| 53 | if (sym.flags.needs_zig_got) { | |
| 54 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 55 | ||
| 56 | hi_r_type = Elf.R_ZIG_GOT_HI20; | |
| 57 | lo_r_type = Elf.R_ZIG_GOT_LO12; | |
| 58 | } | |
| 59 | ||
| 60 | try atom_ptr.addReloc(elf_file, .{ | |
| 61 | .r_offset = start_offset, | |
| 62 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, | |
| 63 | .r_addend = 0, | |
| 64 | }); | |
| 65 | ||
| 66 | try atom_ptr.addReloc(elf_file, .{ | |
| 67 | .r_offset = start_offset + 4, | |
| 68 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, | |
| 69 | .r_addend = 0, | |
| 70 | }); | |
| 71 | } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); | |
| 72 | }, | |
| 45 | 73 | }; |
| 46 | 74 | } |
| 47 | 75 | std.debug.assert(lowered_relocs.len == 0); |
| ... | ... | @@ -120,6 +148,7 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 120 | 148 | |
| 121 | 149 | switch (reloc.enc) { |
| 122 | 150 | .J => riscv_util.writeInstJ(code, @bitCast(disp)), |
| 151 | .B => riscv_util.writeInstB(code, @bitCast(disp)), | |
| 123 | 152 | else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}), |
| 124 | 153 | } |
| 125 | 154 | } |
| ... | ... | @@ -161,3 +190,4 @@ const Lower = @import("Lower.zig"); |
| 161 | 190 | const Mir = @import("Mir.zig"); |
| 162 | 191 | const riscv_util = @import("../../link/riscv.zig"); |
| 163 | 192 | const Encoding = @import("Encoding.zig"); |
| 193 | const Elf = @import("../../link/Elf.zig"); |
src/arch/riscv64/Encoding.zig+39-9| ... | ... | @@ -29,6 +29,9 @@ pub const Mnemonic = enum { |
| 29 | 29 | // J Type |
| 30 | 30 | jal, |
| 31 | 31 | |
| 32 | // B Type | |
| 33 | beq, | |
| 34 | ||
| 32 | 35 | // System |
| 33 | 36 | ecall, |
| 34 | 37 | ebreak, |
| ... | ... | @@ -58,7 +61,9 @@ pub const Mnemonic = enum { |
| 58 | 61 | .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null }, |
| 59 | 62 | .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null }, |
| 60 | 63 | |
| 61 | .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null }, | |
| 64 | .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null }, | |
| 65 | ||
| 66 | .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null }, | |
| 62 | 67 | |
| 63 | 68 | .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, |
| 64 | 69 | .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, |
| ... | ... | @@ -107,6 +112,9 @@ pub const InstEnc = enum { |
| 107 | 112 | .jal, |
| 108 | 113 | => .J, |
| 109 | 114 | |
| 115 | .beq, | |
| 116 | => .B, | |
| 117 | ||
| 110 | 118 | .ecall, |
| 111 | 119 | .ebreak, |
| 112 | 120 | .unimp, |
| ... | ... | @@ -114,15 +122,17 @@ pub const InstEnc = enum { |
| 114 | 122 | }; |
| 115 | 123 | } |
| 116 | 124 | |
| 117 | pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) { | |
| 125 | pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) { | |
| 118 | 126 | return switch (enc) { |
| 119 | .R => .{ .reg, .reg, .reg, .none }, | |
| 120 | .I => .{ .reg, .reg, .imm, .none }, | |
| 121 | .S => .{ .reg, .reg, .imm, .none }, | |
| 122 | .B => .{ .imm, .reg, .reg, .imm }, | |
| 123 | .U => .{ .reg, .imm, .none, .none }, | |
| 124 | .J => .{ .reg, .imm, .none, .none }, | |
| 125 | .system => .{ .none, .none, .none, .none }, | |
| 127 | // zig fmt: off | |
| 128 | .R => .{ .reg, .reg, .reg, }, | |
| 129 | .I => .{ .reg, .reg, .imm, }, | |
| 130 | .S => .{ .reg, .reg, .imm, }, | |
| 131 | .B => .{ .reg, .reg, .imm, }, | |
| 132 | .U => .{ .reg, .imm, .none, }, | |
| 133 | .J => .{ .reg, .imm, .none, }, | |
| 134 | .system => .{ .none, .none, .none, }, | |
| 135 | // zig fmt: on | |
| 126 | 136 | }; |
| 127 | 137 | } |
| 128 | 138 | }; |
| ... | ... | @@ -292,6 +302,26 @@ pub const Data = union(InstEnc) { |
| 292 | 302 | }, |
| 293 | 303 | }; |
| 294 | 304 | }, |
| 305 | .B => { | |
| 306 | assert(ops.len == 3); | |
| 307 | ||
| 308 | const umm = ops[2].imm.asBits(u13); | |
| 309 | assert(umm % 4 == 0); // misaligned branch target | |
| 310 | ||
| 311 | return .{ | |
| 312 | .B = .{ | |
| 313 | .rs1 = ops[0].reg.id(), | |
| 314 | .rs2 = ops[1].reg.id(), | |
| 315 | .imm1_4 = @truncate(umm >> 1), | |
| 316 | .imm5_10 = @truncate(umm >> 5), | |
| 317 | .imm11 = @truncate(umm >> 11), | |
| 318 | .imm12 = @truncate(umm >> 12), | |
| 319 | ||
| 320 | .opcode = enc.opcode, | |
| 321 | .funct3 = enc.funct3.?, | |
| 322 | }, | |
| 323 | }; | |
| 324 | }, | |
| 295 | 325 | |
| 296 | 326 | else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), |
| 297 | 327 | } |
src/arch/riscv64/Lower.zig+44-3| ... | ... | @@ -31,7 +31,9 @@ pub const Reloc = struct { |
| 31 | 31 | |
| 32 | 32 | const Target = union(enum) { |
| 33 | 33 | inst: Mir.Inst.Index, |
| 34 | linker_reloc: bits.Symbol, | |
| 34 | ||
| 35 | /// Relocs the lowered_inst_index and the next one. | |
| 36 | load_symbol_reloc: bits.Symbol, | |
| 35 | 37 | }; |
| 36 | 38 | }; |
| 37 | 39 | |
| ... | ... | @@ -59,6 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 59 | 61 | .pseudo_dbg_prologue_end, |
| 60 | 62 | .pseudo_dead, |
| 61 | 63 | => {}, |
| 64 | ||
| 62 | 65 | .pseudo_load_rm, .pseudo_store_rm => { |
| 63 | 66 | const rm = inst.data.rm; |
| 64 | 67 | |
| ... | ... | @@ -106,6 +109,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 106 | 109 | .{ .imm = Immediate.s(0) }, |
| 107 | 110 | }); |
| 108 | 111 | }, |
| 112 | ||
| 109 | 113 | .pseudo_ret => { |
| 110 | 114 | try lower.emit(.jalr, &.{ |
| 111 | 115 | .{ .reg = .zero }, |
| ... | ... | @@ -113,6 +117,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 113 | 117 | .{ .imm = Immediate.s(0) }, |
| 114 | 118 | }); |
| 115 | 119 | }, |
| 120 | ||
| 116 | 121 | .pseudo_j => { |
| 117 | 122 | try lower.emit(.jal, &.{ |
| 118 | 123 | .{ .reg = .zero }, |
| ... | ... | @@ -123,7 +128,38 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 123 | 128 | .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list), |
| 124 | 129 | .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list), |
| 125 | 130 | |
| 126 | else => return lower.fail("TODO: psuedo {s}", .{@tagName(inst.ops)}), | |
| 131 | .pseudo_load_symbol => { | |
| 132 | const payload = inst.data.payload; | |
| 133 | const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data; | |
| 134 | ||
| 135 | try lower.emit(.lui, &.{ | |
| 136 | .{ .reg = @enumFromInt(data.register) }, | |
| 137 | .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{ | |
| 138 | .atom_index = data.atom_index, | |
| 139 | .sym_index = data.sym_index, | |
| 140 | } }) }, | |
| 141 | }); | |
| 142 | ||
| 143 | // the above reloc implies this one | |
| 144 | try lower.emit(.addi, &.{ | |
| 145 | .{ .reg = @enumFromInt(data.register) }, | |
| 146 | .{ .reg = @enumFromInt(data.register) }, | |
| 147 | .{ .imm = Immediate.s(0) }, | |
| 148 | }); | |
| 149 | }, | |
| 150 | ||
| 151 | .pseudo_lea_rm => { | |
| 152 | const rm = inst.data.rm; | |
| 153 | const frame = rm.m.toFrameLoc(lower.mir); | |
| 154 | ||
| 155 | try lower.emit(.addi, &.{ | |
| 156 | .{ .reg = rm.r }, | |
| 157 | .{ .reg = frame.base }, | |
| 158 | .{ .imm = Immediate.s(frame.disp) }, | |
| 159 | }); | |
| 160 | }, | |
| 161 | ||
| 162 | else => return lower.fail("TODO Lower: psuedo {s}", .{@tagName(inst.ops)}), | |
| 127 | 163 | }, |
| 128 | 164 | } |
| 129 | 165 | |
| ... | ... | @@ -135,7 +171,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 135 | 171 | |
| 136 | 172 | fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 137 | 173 | const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse { |
| 138 | return lower.fail("generic inst name {s}-{s} doesn't match with a mnemonic", .{ | |
| 174 | return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{ | |
| 139 | 175 | @tagName(inst.tag), |
| 140 | 176 | @tagName(inst.ops), |
| 141 | 177 | }); |
| ... | ... | @@ -151,6 +187,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 151 | 187 | .{ .reg = inst.data.i_type.rs1 }, |
| 152 | 188 | .{ .imm = inst.data.i_type.imm12 }, |
| 153 | 189 | }, |
| 190 | .rr_inst => &.{ | |
| 191 | .{ .reg = inst.data.b_type.rs1 }, | |
| 192 | .{ .reg = inst.data.b_type.rs2 }, | |
| 193 | .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) }, | |
| 194 | }, | |
| 154 | 195 | else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), |
| 155 | 196 | }); |
| 156 | 197 | } |
src/arch/riscv64/bits.zig+13-5| ... | ... | @@ -65,17 +65,25 @@ pub const Memory = struct { |
| 65 | 65 | |
| 66 | 66 | /// Asserts `mem` can be represented as a `FrameLoc`. |
| 67 | 67 | pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc { |
| 68 | const offset: i32 = switch (mem.mod) { | |
| 69 | .off => |off| @intCast(off), | |
| 70 | .rm => |rm| rm.disp, | |
| 71 | }; | |
| 72 | ||
| 68 | 73 | switch (mem.base) { |
| 69 | 74 | .reg => |reg| { |
| 70 | 75 | return .{ |
| 71 | 76 | .base = reg, |
| 72 | .disp = switch (mem.mod) { | |
| 73 | .off => unreachable, // TODO: toFrameLoc disp.off | |
| 74 | .rm => |rm| rm.disp, | |
| 75 | }, | |
| 77 | .disp = offset, | |
| 78 | }; | |
| 79 | }, | |
| 80 | .frame => |index| { | |
| 81 | const base_loc = mir.frame_locs.get(@intFromEnum(index)); | |
| 82 | return .{ | |
| 83 | .base = base_loc.base, | |
| 84 | .disp = base_loc.disp + offset, | |
| 76 | 85 | }; |
| 77 | 86 | }, |
| 78 | .frame => |index| return mir.frame_locs.get(@intFromEnum(index)), | |
| 79 | 87 | .reloc => unreachable, |
| 80 | 88 | } |
| 81 | 89 | } |
src/arch/riscv64/encoder.zig+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | pub const Instruction = struct { |
| 2 | 2 | encoding: Encoding, |
| 3 | ops: [4]Operand = .{.none} ** 4, | |
| 3 | ops: [3]Operand = .{.none} ** 3, | |
| 4 | 4 | |
| 5 | 5 | pub const Operand = union(enum) { |
| 6 | 6 | none, |
| ... | ... | @@ -11,7 +11,7 @@ pub const Instruction = struct { |
| 11 | 11 | |
| 12 | 12 | pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction { |
| 13 | 13 | const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse { |
| 14 | log.err("no encoding found for: {s} {s} {s} {s} {s}", .{ | |
| 14 | std.log.err("no encoding found for: {s} {s} {s} {s} {s}", .{ | |
| 15 | 15 | @tagName(mnemonic), |
| 16 | 16 | @tagName(if (ops.len > 0) ops[0] else .none), |
| 17 | 17 | @tagName(if (ops.len > 1) ops[1] else .none), |
| ... | ... | @@ -21,7 +21,7 @@ pub const Instruction = struct { |
| 21 | 21 | return error.InvalidInstruction; |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | var result_ops: [4]Operand = .{.none} ** 4; | |
| 24 | var result_ops: [3]Operand = .{.none} ** 3; | |
| 25 | 25 | @memcpy(result_ops[0..ops.len], ops); |
| 26 | 26 | |
| 27 | 27 | return .{ |
src/link/riscv.zig+14| ... | ... | @@ -73,6 +73,20 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void { |
| 73 | 73 | mem.writeInt(u32, code, data.toU32(), .little); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | pub fn writeInstB(code: *[4]u8, value: u32) void { | |
| 77 | var data = Encoding.Data{ | |
| 78 | .B = mem.bytesToValue(std.meta.TagPayload( | |
| 79 | Encoding.Data, | |
| 80 | Encoding.Data.B, | |
| 81 | ), code), | |
| 82 | }; | |
| 83 | data.B.imm1_4 = bitSlice(value, 4, 1); | |
| 84 | data.B.imm5_10 = bitSlice(value, 10, 5); | |
| 85 | data.B.imm11 = bitSlice(value, 11, 11); | |
| 86 | data.B.imm12 = bitSlice(value, 12, 12); | |
| 87 | mem.writeInt(u32, code, data.toU32(), .little); | |
| 88 | } | |
| 89 | ||
| 76 | 90 | fn bitSlice( |
| 77 | 91 | value: anytype, |
| 78 | 92 | comptime high: comptime_int, |
src/target.zig+1-1| ... | ... | @@ -526,7 +526,7 @@ pub fn backendSupportsFeature( |
| 526 | 526 | feature: Feature, |
| 527 | 527 | ) bool { |
| 528 | 528 | return switch (feature) { |
| 529 | .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64, | |
| 529 | .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64 or cpu_arch == .riscv64, | |
| 530 | 530 | .panic_unwrap_error => ofmt == .c or use_llvm, |
| 531 | 531 | .safety_check_formatted => ofmt == .c or use_llvm, |
| 532 | 532 | .error_return_trace => use_llvm, |