diff options
| author | David Rubin <daviru007@icloud.com> | 2024-04-13 19:30:10 -0700 |
|---|---|---|
| committer | David Rubin <daviru007@icloud.com> | 2024-05-11 02:17:11 -0700 |
| commit | d19b77d63f0d02ab9c0a0928391891ae4a77744c (patch) | |
| tree | f32cd14c27295517503576ccb16caa46bccaf141 /src | |
| parent | cc204e2365547c19f7c9e1a836a3ea8c18e3a6ea (diff) | |
| download | zig-d19b77d63f0d02ab9c0a0928391891ae4a77744c.tar.gz zig-d19b77d63f0d02ab9c0a0928391891ae4a77744c.zip | |
riscv: back to hello world panics
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 30 | ||||
| -rw-r--r-- | src/arch/riscv64/Emit.zig | 32 | ||||
| -rw-r--r-- | src/arch/riscv64/Encoding.zig | 48 | ||||
| -rw-r--r-- | src/arch/riscv64/Lower.zig | 47 | ||||
| -rw-r--r-- | src/arch/riscv64/bits.zig | 18 | ||||
| -rw-r--r-- | src/arch/riscv64/encoder.zig | 6 | ||||
| -rw-r--r-- | src/link/riscv.zig | 14 | ||||
| -rw-r--r-- | src/target.zig | 2 |
8 files changed, 170 insertions, 27 deletions
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 285aa88095..035ed1b611 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1513,7 +1513,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type { }, else => unreachable, }, - else => break, + else => return self.fail("TODO: splitType class {}", .{class}), }; } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts; return self.fail("TODO implement splitType for {}", .{ty.fmt(zcu)}); @@ -3434,6 +3434,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const src_mcv = self.args[arg_index]; + const arg_ty = self.typeOfIndex(inst); + const dst_mcv = switch (src_mcv) { .register => dst: { const frame = try self.allocFrameIndex(FrameAlloc.init(.{ @@ -3441,9 +3443,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { .alignment = Type.usize.abiAlignment(zcu), })); const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; - try self.genCopy(Type.usize, dst_mcv, src_mcv); - + break :dst dst_mcv; + }, + .register_pair => dst: { + const frame = try self.allocFrameIndex(FrameAlloc.init(.{ + .size = Type.usize.abiSize(zcu) * 2, + .alignment = Type.usize.abiAlignment(zcu), + })); + const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; + try self.genCopy(arg_ty, dst_mcv, src_mcv); break :dst dst_mcv; }, .load_frame => src_mcv, @@ -4506,6 +4515,17 @@ fn genSetStack( else => unreachable, // register can hold a max of 8 bytes } }, + .register_pair => |pair| { + var part_disp: i32 = frame.off; + for (try self.splitType(ty), pair) |src_ty, src_reg| { + try self.genSetStack( + src_ty, + .{ .index = frame.index, .off = part_disp }, + .{ .register = src_reg }, + ); + part_disp += @intCast(src_ty.abiSize(zcu)); + } + }, .load_frame, .indirect, .load_symbol, @@ -4564,8 +4584,8 @@ fn genInlineMemcpy( .ops = .rri, .data = .{ .i_type = .{ - .rd = tmp, - .rs1 = dst, + .rd = dst, + .rs1 = tmp, .imm12 = Immediate.s(0), }, }, diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 0e1decd42f..ec256fefb3 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -41,7 +41,35 @@ pub fn emitMir(emit: *Emit) Error!void { .offset = 0, .enc = std.meta.activeTag(lowered_inst.encoding.data), }), - else => |x| return emit.fail("TODO: emitMir {s}", .{@tagName(x)}), + .load_symbol_reloc => |symbol| { + if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; + const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); + const sym = elf_file.symbol(sym_index); + + var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); + var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); + + if (sym.flags.needs_zig_got) { + _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + + hi_r_type = Elf.R_ZIG_GOT_HI20; + lo_r_type = Elf.R_ZIG_GOT_LO12; + } + + try atom_ptr.addReloc(elf_file, .{ + .r_offset = start_offset, + .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, + .r_addend = 0, + }); + + try atom_ptr.addReloc(elf_file, .{ + .r_offset = start_offset + 4, + .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, + .r_addend = 0, + }); + } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); + }, }; } std.debug.assert(lowered_relocs.len == 0); @@ -120,6 +148,7 @@ fn fixupRelocs(emit: *Emit) Error!void { switch (reloc.enc) { .J => riscv_util.writeInstJ(code, @bitCast(disp)), + .B => riscv_util.writeInstB(code, @bitCast(disp)), else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}), } } @@ -161,3 +190,4 @@ const Lower = @import("Lower.zig"); const Mir = @import("Mir.zig"); const riscv_util = @import("../../link/riscv.zig"); const Encoding = @import("Encoding.zig"); +const Elf = @import("../../link/Elf.zig"); diff --git a/src/arch/riscv64/Encoding.zig b/src/arch/riscv64/Encoding.zig index 1510185944..ec113d9b91 100644 --- a/src/arch/riscv64/Encoding.zig +++ b/src/arch/riscv64/Encoding.zig @@ -29,6 +29,9 @@ pub const Mnemonic = enum { // J Type jal, + // B Type + beq, + // System ecall, ebreak, @@ -58,7 +61,9 @@ pub const Mnemonic = enum { .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null }, .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null }, - .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null }, + .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null }, + + .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null }, .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, @@ -107,6 +112,9 @@ pub const InstEnc = enum { .jal, => .J, + .beq, + => .B, + .ecall, .ebreak, .unimp, @@ -114,15 +122,17 @@ pub const InstEnc = enum { }; } - pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) { + pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) { return switch (enc) { - .R => .{ .reg, .reg, .reg, .none }, - .I => .{ .reg, .reg, .imm, .none }, - .S => .{ .reg, .reg, .imm, .none }, - .B => .{ .imm, .reg, .reg, .imm }, - .U => .{ .reg, .imm, .none, .none }, - .J => .{ .reg, .imm, .none, .none }, - .system => .{ .none, .none, .none, .none }, + // zig fmt: off + .R => .{ .reg, .reg, .reg, }, + .I => .{ .reg, .reg, .imm, }, + .S => .{ .reg, .reg, .imm, }, + .B => .{ .reg, .reg, .imm, }, + .U => .{ .reg, .imm, .none, }, + .J => .{ .reg, .imm, .none, }, + .system => .{ .none, .none, .none, }, + // zig fmt: on }; } }; @@ -292,6 +302,26 @@ pub const Data = union(InstEnc) { }, }; }, + .B => { + assert(ops.len == 3); + + const umm = ops[2].imm.asBits(u13); + assert(umm % 4 == 0); // misaligned branch target + + return .{ + .B = .{ + .rs1 = ops[0].reg.id(), + .rs2 = ops[1].reg.id(), + .imm1_4 = @truncate(umm >> 1), + .imm5_10 = @truncate(umm >> 5), + .imm11 = @truncate(umm >> 11), + .imm12 = @truncate(umm >> 12), + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + }, + }; + }, else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), } diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index 5a3e375e05..714f3a43ad 100644 --- a/src/arch/riscv64/Lower.zig +++ b/src/arch/riscv64/Lower.zig @@ -31,7 +31,9 @@ pub const Reloc = struct { const Target = union(enum) { inst: Mir.Inst.Index, - linker_reloc: bits.Symbol, + + /// Relocs the lowered_inst_index and the next one. + load_symbol_reloc: bits.Symbol, }; }; @@ -59,6 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_dbg_prologue_end, .pseudo_dead, => {}, + .pseudo_load_rm, .pseudo_store_rm => { const rm = inst.data.rm; @@ -106,6 +109,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(0) }, }); }, + .pseudo_ret => { try lower.emit(.jalr, &.{ .{ .reg = .zero }, @@ -113,6 +117,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(0) }, }); }, + .pseudo_j => { try lower.emit(.jal, &.{ .{ .reg = .zero }, @@ -123,7 +128,38 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list), .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list), - else => return lower.fail("TODO: psuedo {s}", .{@tagName(inst.ops)}), + .pseudo_load_symbol => { + const payload = inst.data.payload; + const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data; + + try lower.emit(.lui, &.{ + .{ .reg = @enumFromInt(data.register) }, + .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{ + .atom_index = data.atom_index, + .sym_index = data.sym_index, + } }) }, + }); + + // the above reloc implies this one + try lower.emit(.addi, &.{ + .{ .reg = @enumFromInt(data.register) }, + .{ .reg = @enumFromInt(data.register) }, + .{ .imm = Immediate.s(0) }, + }); + }, + + .pseudo_lea_rm => { + const rm = inst.data.rm; + const frame = rm.m.toFrameLoc(lower.mir); + + try lower.emit(.addi, &.{ + .{ .reg = rm.r }, + .{ .reg = frame.base }, + .{ .imm = Immediate.s(frame.disp) }, + }); + }, + + else => return lower.fail("TODO Lower: psuedo {s}", .{@tagName(inst.ops)}), }, } @@ -135,7 +171,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { fn generic(lower: *Lower, inst: Mir.Inst) Error!void { const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse { - return lower.fail("generic inst name {s}-{s} doesn't match with a mnemonic", .{ + return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{ @tagName(inst.tag), @tagName(inst.ops), }); @@ -151,6 +187,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .reg = inst.data.i_type.rs1 }, .{ .imm = inst.data.i_type.imm12 }, }, + .rr_inst => &.{ + .{ .reg = inst.data.b_type.rs1 }, + .{ .reg = inst.data.b_type.rs2 }, + .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) }, + }, else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), }); } diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 83651432a6..d3dd78cf3e 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -65,17 +65,25 @@ pub const Memory = struct { /// Asserts `mem` can be represented as a `FrameLoc`. pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc { + const offset: i32 = switch (mem.mod) { + .off => |off| @intCast(off), + .rm => |rm| rm.disp, + }; + switch (mem.base) { .reg => |reg| { return .{ .base = reg, - .disp = switch (mem.mod) { - .off => unreachable, // TODO: toFrameLoc disp.off - .rm => |rm| rm.disp, - }, + .disp = offset, + }; + }, + .frame => |index| { + const base_loc = mir.frame_locs.get(@intFromEnum(index)); + return .{ + .base = base_loc.base, + .disp = base_loc.disp + offset, }; }, - .frame => |index| return mir.frame_locs.get(@intFromEnum(index)), .reloc => unreachable, } } diff --git a/src/arch/riscv64/encoder.zig b/src/arch/riscv64/encoder.zig index 4eadcb0e8c..ddd4f5f437 100644 --- a/src/arch/riscv64/encoder.zig +++ b/src/arch/riscv64/encoder.zig @@ -1,6 +1,6 @@ pub const Instruction = struct { encoding: Encoding, - ops: [4]Operand = .{.none} ** 4, + ops: [3]Operand = .{.none} ** 3, pub const Operand = union(enum) { none, @@ -11,7 +11,7 @@ pub const Instruction = struct { pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction { const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse { - log.err("no encoding found for: {s} {s} {s} {s} {s}", .{ + std.log.err("no encoding found for: {s} {s} {s} {s} {s}", .{ @tagName(mnemonic), @tagName(if (ops.len > 0) ops[0] else .none), @tagName(if (ops.len > 1) ops[1] else .none), @@ -21,7 +21,7 @@ pub const Instruction = struct { return error.InvalidInstruction; }; - var result_ops: [4]Operand = .{.none} ** 4; + var result_ops: [3]Operand = .{.none} ** 3; @memcpy(result_ops[0..ops.len], ops); return .{ diff --git a/src/link/riscv.zig b/src/link/riscv.zig index 0f87131367..e78cb84cdf 100644 --- a/src/link/riscv.zig +++ b/src/link/riscv.zig @@ -73,6 +73,20 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void { mem.writeInt(u32, code, data.toU32(), .little); } +pub fn writeInstB(code: *[4]u8, value: u32) void { + var data = Encoding.Data{ + .B = mem.bytesToValue(std.meta.TagPayload( + Encoding.Data, + Encoding.Data.B, + ), code), + }; + data.B.imm1_4 = bitSlice(value, 4, 1); + data.B.imm5_10 = bitSlice(value, 10, 5); + data.B.imm11 = bitSlice(value, 11, 11); + data.B.imm12 = bitSlice(value, 12, 12); + mem.writeInt(u32, code, data.toU32(), .little); +} + fn bitSlice( value: anytype, comptime high: comptime_int, diff --git a/src/target.zig b/src/target.zig index ea58111bc1..8f61b2ba03 100644 --- a/src/target.zig +++ b/src/target.zig @@ -526,7 +526,7 @@ pub fn backendSupportsFeature( feature: Feature, ) bool { return switch (feature) { - .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64, + .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64 or cpu_arch == .riscv64, .panic_unwrap_error => ofmt == .c or use_llvm, .safety_check_formatted => ofmt == .c or use_llvm, .error_return_trace => use_llvm, |
