riscv: add enough components to get a test runner working

This commit is contained in:
David Rubin 2024-03-30 05:49:16 -07:00
parent c0629c3539
commit 8ac239ebce
6 changed files with 783 additions and 285 deletions

View File

@ -12,9 +12,9 @@ var cmdline_buffer: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
pub fn main() void {
if (builtin.zig_backend == .stage2_aarch64 or
builtin.zig_backend == .stage2_riscv64)
{
if (builtin.zig_backend == .stage2_riscv64) return mainExtraSimple() catch @panic("test failure");
if (builtin.zig_backend == .stage2_aarch64) {
return mainSimple() catch @panic("test failure");
}
@ -249,3 +249,17 @@ pub fn mainSimple() anyerror!void {
if (failed != 0) std.process.exit(1);
}
}
pub fn mainExtraSimple() !void {
var pass_count: u8 = 0;
for (builtin.test_functions) |test_fn| {
test_fn.func() catch |err| {
if (err != error.SkipZigTest) {
@panic(test_fn.name);
}
continue;
};
pass_count += 1;
}
}

View File

@ -20,7 +20,6 @@ pub const simplified_logic =
builtin.zig_backend == .stage2_x86 or
builtin.zig_backend == .stage2_aarch64 or
builtin.zig_backend == .stage2_arm or
builtin.zig_backend == .stage2_riscv64 or
builtin.zig_backend == .stage2_sparc64 or
builtin.cpu.arch == .spirv32 or
builtin.cpu.arch == .spirv64;
@ -61,6 +60,10 @@ comptime {
} else if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
@export(main, .{ .name = "main" });
}
} else if (native_arch.isRISCV()) {
if (!@hasDecl(root, "_start")) {
@export(riscv_start, .{ .name = "_start" });
}
} else if (native_os == .windows) {
if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
!@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
@ -151,14 +154,6 @@ fn exit2(code: usize) noreturn {
: "memory", "cc"
);
},
.riscv64 => {
asm volatile ("ecall"
:
: [number] "{a7}" (94),
[arg1] "{a0}" (code),
: "rcx", "r11", "memory"
);
},
.sparc64 => {
asm volatile ("ta 0x6d"
:
@ -212,6 +207,11 @@ fn wasi_start() callconv(.C) void {
}
}
fn riscv_start() callconv(.C) noreturn {
const code = @call(.always_inline, callMain, .{});
std.process.exit(code);
}
fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize {
uefi.handle = handle;
uefi.system_table = system_table;

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@
mir: Mir,
bin_file: *link.File,
debug_output: DebugInfoOutput,
output_mode: std.builtin.OutputMode,
link_mode: std.builtin.LinkMode,
target: *const std.Target,
err_msg: ?*ErrorMsg = null,
src_loc: Module.SrcLoc,
@ -47,6 +49,7 @@ pub fn emitMir(
switch (tag) {
.add => try emit.mirRType(inst),
.sub => try emit.mirRType(inst),
.mul => try emit.mirRType(inst),
.@"or" => try emit.mirRType(inst),
.cmp_eq => try emit.mirRType(inst),
@ -56,7 +59,9 @@ pub fn emitMir(
.cmp_lt => try emit.mirRType(inst),
.cmp_imm_gte => try emit.mirRType(inst),
.cmp_imm_eq => try emit.mirIType(inst),
.cmp_imm_neq => try emit.mirIType(inst),
.cmp_imm_lte => try emit.mirIType(inst),
.cmp_imm_lt => try emit.mirIType(inst),
.beq => try emit.mirBType(inst),
.bne => try emit.mirBType(inst),
@ -186,6 +191,7 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
switch (tag) {
.add => try emit.writeInstruction(Instruction.add(rd, rs1, rs2)),
.sub => try emit.writeInstruction(Instruction.sub(rd, rs1, rs2)),
.mul => try emit.writeInstruction(Instruction.mul(rd, rs1, rs2)),
.cmp_gt => {
// rs1 > rs2
try emit.writeInstruction(Instruction.sltu(rd, rs2, rs1));
@ -284,6 +290,14 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
try emit.writeInstruction(Instruction.xori(rd, rs1, imm12));
try emit.writeInstruction(Instruction.sltiu(rd, rd, 1));
},
.cmp_imm_neq => {
try emit.writeInstruction(Instruction.xori(rd, rs1, imm12));
try emit.writeInstruction(Instruction.sltu(rd, .x0, rd));
},
.cmp_imm_lt => {
try emit.writeInstruction(Instruction.slti(rd, rs1, imm12));
},
.cmp_imm_lte => {
try emit.writeInstruction(Instruction.sltiu(rd, rs1, @bitCast(imm12)));
@ -447,6 +461,7 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
const start_offset = @as(u32, @intCast(emit.code.items.len));
try emit.writeInstruction(Instruction.lui(reg, 0));
try emit.writeInstruction(Instruction.addi(reg, reg, 0));
switch (emit.bin_file.tag) {
.elf => {
@ -463,12 +478,6 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
hi_r_type = Elf.R_ZIG_GOT_HI20;
lo_r_type = Elf.R_ZIG_GOT_LO12;
// we need to deref once if we are getting from zig_got, as itll
// reloc an address of the address in the got.
try emit.writeInstruction(Instruction.ld(reg, 0, reg));
} else {
try emit.writeInstruction(Instruction.addi(reg, reg, 0));
}
try atom_ptr.addReloc(elf_file, .{
@ -544,6 +553,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
.cmp_eq,
.cmp_neq,
.cmp_imm_eq,
.cmp_imm_neq,
.cmp_gte,
.load_symbol,
.abs,

View File

@ -33,6 +33,8 @@ pub const Inst = struct {
add,
/// Subtraction
sub,
/// Multiply, uses r_type. Needs the M extension.
mul,
/// Absolute Value, uses i_type payload.
abs,
@ -76,8 +78,12 @@ pub const Inst = struct {
/// Immediate `==`, uses i_type
cmp_imm_eq,
/// Immediate `!=`, uses i_type.
cmp_imm_neq,
/// Immediate `<=`, uses i_type
cmp_imm_lte,
/// Immediate `<`, uses i_type
cmp_imm_lt,
/// Branch if equal, Uses b_type
beq,

View File

@ -112,7 +112,7 @@ pub const Instruction = union(enum) {
// -- less burden on callsite, bonus semantic checking
fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction {
const umm = @as(u13, @bitCast(imm));
assert(umm % 2 == 0); // misaligned branch target
assert(umm % 4 == 0); // misaligned branch target
return Instruction{
.B = .{
@ -201,6 +201,12 @@ pub const Instruction = union(enum) {
return rType(0b0110011, 0b011, 0b0000000, rd, r1, r2);
}
// M extension operations
pub fn mul(rd: Register, r1: Register, r2: Register) Instruction {
return rType(0b0110011, 0b000, 0b0000001, rd, r1, r2);
}
// Arithmetic/Logical, Register-Register (32-bit)
pub fn addw(rd: Register, r1: Register, r2: Register) Instruction {