authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-04-13 19:30:10-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
logd19b77d63f0d02ab9c0a0928391891ae4a77744c
treef32cd14c27295517503576ccb16caa46bccaf141
parentcc204e2365547c19f7c9e1a836a3ea8c18e3a6ea

riscv: back to hello world panics


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,7 +775,15 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
775 }775 }
776776
777 if (builtin.zig_backend == .stage2_riscv64) {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 }
780788
781 switch (builtin.os.tag) {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,7 +1513,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type {
1513 },1513 },
1514 else => unreachable,1514 else => unreachable,
1515 },1515 },
1516 else => break,1516 else => return self.fail("TODO: splitType class {}", .{class}),
1517 };1517 };
1518 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;1518 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;
1519 return self.fail("TODO implement splitType for {}", .{ty.fmt(zcu)});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,6 +3434,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3434 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {3434 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3435 const src_mcv = self.args[arg_index];3435 const src_mcv = self.args[arg_index];
34363436
3437 const arg_ty = self.typeOfIndex(inst);
3438
3437 const dst_mcv = switch (src_mcv) {3439 const dst_mcv = switch (src_mcv) {
3438 .register => dst: {3440 .register => dst: {
3439 const frame = try self.allocFrameIndex(FrameAlloc.init(.{3441 const frame = try self.allocFrameIndex(FrameAlloc.init(.{
...@@ -3441,9 +3443,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3441,9 +3443,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3441 .alignment = Type.usize.abiAlignment(zcu),3443 .alignment = Type.usize.abiAlignment(zcu),
3442 }));3444 }));
3443 const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } };3445 const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } };
3444
3445 try self.genCopy(Type.usize, dst_mcv, src_mcv);3446 try self.genCopy(Type.usize, dst_mcv, src_mcv);
34463447 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 break :dst dst_mcv;3456 break :dst dst_mcv;
3448 },3457 },
3449 .load_frame => src_mcv,3458 .load_frame => src_mcv,
...@@ -4506,6 +4515,17 @@ fn genSetStack(...@@ -4506,6 +4515,17 @@ fn genSetStack(
4506 else => unreachable, // register can hold a max of 8 bytes4515 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 .load_frame,4529 .load_frame,
4510 .indirect,4530 .indirect,
4511 .load_symbol,4531 .load_symbol,
...@@ -4564,8 +4584,8 @@ fn genInlineMemcpy(...@@ -4564,8 +4584,8 @@ fn genInlineMemcpy(
4564 .ops = .rri,4584 .ops = .rri,
4565 .data = .{4585 .data = .{
4566 .i_type = .{4586 .i_type = .{
4567 .rd = tmp,4587 .rd = dst,
4568 .rs1 = dst,4588 .rs1 = tmp,
4569 .imm12 = Immediate.s(0),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,7 +41,35 @@ pub fn emitMir(emit: *Emit) Error!void {
41 .offset = 0,41 .offset = 0,
42 .enc = std.meta.activeTag(lowered_inst.encoding.data),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 std.debug.assert(lowered_relocs.len == 0);75 std.debug.assert(lowered_relocs.len == 0);
...@@ -120,6 +148,7 @@ fn fixupRelocs(emit: *Emit) Error!void {...@@ -120,6 +148,7 @@ fn fixupRelocs(emit: *Emit) Error!void {
120148
121 switch (reloc.enc) {149 switch (reloc.enc) {
122 .J => riscv_util.writeInstJ(code, @bitCast(disp)),150 .J => riscv_util.writeInstJ(code, @bitCast(disp)),
151 .B => riscv_util.writeInstB(code, @bitCast(disp)),
123 else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}),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,3 +190,4 @@ const Lower = @import("Lower.zig");
161const Mir = @import("Mir.zig");190const Mir = @import("Mir.zig");
162const riscv_util = @import("../../link/riscv.zig");191const riscv_util = @import("../../link/riscv.zig");
163const Encoding = @import("Encoding.zig");192const Encoding = @import("Encoding.zig");
193const Elf = @import("../../link/Elf.zig");
src/arch/riscv64/Encoding.zig+39-9
...@@ -29,6 +29,9 @@ pub const Mnemonic = enum {...@@ -29,6 +29,9 @@ pub const Mnemonic = enum {
29 // J Type29 // J Type
30 jal,30 jal,
3131
32 // B Type
33 beq,
34
32 // System35 // System
33 ecall,36 ecall,
34 ebreak,37 ebreak,
...@@ -58,7 +61,9 @@ pub const Mnemonic = enum {...@@ -58,7 +61,9 @@ pub const Mnemonic = enum {
58 .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null },61 .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null },
59 .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null },62 .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null },
6063
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 },
6267
63 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },68 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
64 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },69 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
...@@ -107,6 +112,9 @@ pub const InstEnc = enum {...@@ -107,6 +112,9 @@ pub const InstEnc = enum {
107 .jal,112 .jal,
108 => .J,113 => .J,
109114
115 .beq,
116 => .B,
117
110 .ecall,118 .ecall,
111 .ebreak,119 .ebreak,
112 .unimp,120 .unimp,
...@@ -114,15 +122,17 @@ pub const InstEnc = enum {...@@ -114,15 +122,17 @@ pub const InstEnc = enum {
114 };122 };
115 }123 }
116124
117 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {125 pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) {
118 return switch (enc) {126 return switch (enc) {
119 .R => .{ .reg, .reg, .reg, .none },127 // zig fmt: off
120 .I => .{ .reg, .reg, .imm, .none },128 .R => .{ .reg, .reg, .reg, },
121 .S => .{ .reg, .reg, .imm, .none },129 .I => .{ .reg, .reg, .imm, },
122 .B => .{ .imm, .reg, .reg, .imm },130 .S => .{ .reg, .reg, .imm, },
123 .U => .{ .reg, .imm, .none, .none },131 .B => .{ .reg, .reg, .imm, },
124 .J => .{ .reg, .imm, .none, .none },132 .U => .{ .reg, .imm, .none, },
125 .system => .{ .none, .none, .none, .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,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 },
295325
296 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),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,7 +31,9 @@ pub const Reloc = struct {
3131
32 const Target = union(enum) {32 const Target = union(enum) {
33 inst: Mir.Inst.Index,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};
3739
...@@ -59,6 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -59,6 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
59 .pseudo_dbg_prologue_end,61 .pseudo_dbg_prologue_end,
60 .pseudo_dead,62 .pseudo_dead,
61 => {},63 => {},
64
62 .pseudo_load_rm, .pseudo_store_rm => {65 .pseudo_load_rm, .pseudo_store_rm => {
63 const rm = inst.data.rm;66 const rm = inst.data.rm;
6467
...@@ -106,6 +109,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -106,6 +109,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
106 .{ .imm = Immediate.s(0) },109 .{ .imm = Immediate.s(0) },
107 });110 });
108 },111 },
112
109 .pseudo_ret => {113 .pseudo_ret => {
110 try lower.emit(.jalr, &.{114 try lower.emit(.jalr, &.{
111 .{ .reg = .zero },115 .{ .reg = .zero },
...@@ -113,6 +117,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -113,6 +117,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
113 .{ .imm = Immediate.s(0) },117 .{ .imm = Immediate.s(0) },
114 });118 });
115 },119 },
120
116 .pseudo_j => {121 .pseudo_j => {
117 try lower.emit(.jal, &.{122 try lower.emit(.jal, &.{
118 .{ .reg = .zero },123 .{ .reg = .zero },
...@@ -123,7 +128,38 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -123,7 +128,38 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
123 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),128 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),
124 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),129 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),
125130
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 }
129165
...@@ -135,7 +171,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -135,7 +171,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
135171
136fn generic(lower: *Lower, inst: Mir.Inst) Error!void {172fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
137 const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse {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 @tagName(inst.tag),175 @tagName(inst.tag),
140 @tagName(inst.ops),176 @tagName(inst.ops),
141 });177 });
...@@ -151,6 +187,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -151,6 +187,11 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
151 .{ .reg = inst.data.i_type.rs1 },187 .{ .reg = inst.data.i_type.rs1 },
152 .{ .imm = inst.data.i_type.imm12 },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 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),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,17 +65,25 @@ pub const Memory = struct {
6565
66 /// Asserts `mem` can be represented as a `FrameLoc`.66 /// Asserts `mem` can be represented as a `FrameLoc`.
67 pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc {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 switch (mem.base) {73 switch (mem.base) {
69 .reg => |reg| {74 .reg => |reg| {
70 return .{75 return .{
71 .base = reg,76 .base = reg,
72 .disp = switch (mem.mod) {77 .disp = offset,
73 .off => unreachable, // TODO: toFrameLoc disp.off78 };
74 .rm => |rm| rm.disp,79 },
75 },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 .reloc => unreachable,87 .reloc => unreachable,
80 }88 }
81 }89 }
src/arch/riscv64/encoder.zig+3-3
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1pub const Instruction = struct {1pub const Instruction = struct {
2 encoding: Encoding,2 encoding: Encoding,
3 ops: [4]Operand = .{.none} ** 4,3 ops: [3]Operand = .{.none} ** 3,
44
5 pub const Operand = union(enum) {5 pub const Operand = union(enum) {
6 none,6 none,
...@@ -11,7 +11,7 @@ pub const Instruction = struct {...@@ -11,7 +11,7 @@ pub const Instruction = struct {
1111
12 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {12 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
13 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {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 @tagName(mnemonic),15 @tagName(mnemonic),
16 @tagName(if (ops.len > 0) ops[0] else .none),16 @tagName(if (ops.len > 0) ops[0] else .none),
17 @tagName(if (ops.len > 1) ops[1] else .none),17 @tagName(if (ops.len > 1) ops[1] else .none),
...@@ -21,7 +21,7 @@ pub const Instruction = struct {...@@ -21,7 +21,7 @@ pub const Instruction = struct {
21 return error.InvalidInstruction;21 return error.InvalidInstruction;
22 };22 };
2323
24 var result_ops: [4]Operand = .{.none} ** 4;24 var result_ops: [3]Operand = .{.none} ** 3;
25 @memcpy(result_ops[0..ops.len], ops);25 @memcpy(result_ops[0..ops.len], ops);
2626
27 return .{27 return .{
src/link/riscv.zig+14
...@@ -73,6 +73,20 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void {...@@ -73,6 +73,20 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void {
73 mem.writeInt(u32, code, data.toU32(), .little);73 mem.writeInt(u32, code, data.toU32(), .little);
74}74}
7575
76pub 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
76fn bitSlice(90fn bitSlice(
77 value: anytype,91 value: anytype,
78 comptime high: comptime_int,92 comptime high: comptime_int,
src/target.zig+1-1
...@@ -526,7 +526,7 @@ pub fn backendSupportsFeature(...@@ -526,7 +526,7 @@ pub fn backendSupportsFeature(
526 feature: Feature,526 feature: Feature,
527) bool {527) bool {
528 return switch (feature) {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 .panic_unwrap_error => ofmt == .c or use_llvm,530 .panic_unwrap_error => ofmt == .c or use_llvm,
531 .safety_check_formatted => ofmt == .c or use_llvm,531 .safety_check_formatted => ofmt == .c or use_llvm,
532 .error_return_trace => use_llvm,532 .error_return_trace => use_llvm,