From bc06e19828428ed9c2fc3698f418d46e62e327f5 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Tue, 27 Apr 2021 16:12:59 +0800 Subject: [PATCH] stage2 riscv64: cleanup code and add tests --- src/codegen/riscv64.zig | 57 +++++++++++++++++++++++++++++++++-------- test/stage2/riscv64.zig | 45 ++++++++++++++++++++++++++++++++ test/stage2/test.zig | 46 +++------------------------------ 3 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 test/stage2/riscv64.zig diff --git a/src/codegen/riscv64.zig b/src/codegen/riscv64.zig index 96b9c58f9c..a01f38289a 100644 --- a/src/codegen/riscv64.zig +++ b/src/codegen/riscv64.zig @@ -1,5 +1,7 @@ const std = @import("std"); const DW = std.dwarf; +const assert = std.debug.assert; +const testing = std.testing; // TODO: this is only tagged to facilitate the monstrosity. // Once packed structs work make it packed. @@ -110,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 = @bitCast(u13, imm); - if (umm % 2 != 0) @panic("Internal error: misaligned branch target"); + assert(umm % 2 == 0); // misaligned branch target return Instruction{ .B = .{ @@ -140,15 +142,15 @@ pub const Instruction = union(enum) { } fn jType(op: u7, rd: Register, imm: i21) Instruction { - const umm = @bitcast(u21, imm); - if (umm % 2 != 0) @panic("Internal error: misaligned jump target"); + const umm = @bitCast(u21, imm); + assert(umm % 2 == 0); // misaligned jump target return Instruction{ .J = .{ .opcode = op, .rd = @enumToInt(rd), .imm1_10 = @truncate(u10, umm >> 1), - .imm11 = @truncate(u1, umm >> 1), + .imm11 = @truncate(u1, umm >> 11), .imm12_19 = @truncate(u8, umm >> 12), .imm20 = @truncate(u1, umm >> 20), }, @@ -340,27 +342,27 @@ pub const Instruction = union(enum) { // Branch - pub fn beq(r1: Register, r2: Register, offset: u13) Instruction { + pub fn beq(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b000, r1, r2, offset); } - pub fn bne(r1: Register, r2: Register, offset: u13) Instruction { + pub fn bne(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b001, r1, r2, offset); } - pub fn blt(r1: Register, r2: Register, offset: u13) Instruction { + pub fn blt(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b100, r1, r2, offset); } - pub fn bge(r1: Register, r2: Register, offset: u13) Instruction { + pub fn bge(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b101, r1, r2, offset); } - pub fn bltu(r1: Register, r2: Register, offset: u13) Instruction { + pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b110, r1, r2, offset); } - pub fn bgeu(r1: Register, r2: Register, offset: u13) Instruction { + pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction { return bType(0b1100011, 0b111, r1, r2, offset); } @@ -431,3 +433,38 @@ pub const Register = enum(u5) { pub const callee_preserved_regs = [_]Register{ .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, }; + +test "serialize instructions" { + const Testcase = struct { + inst: Instruction, + expected: u32, + }; + + const testcases = [_]Testcase{ + .{ // add t6, zero, zero + .inst = Instruction.add(.t6, .zero, .zero), + .expected = 0b0000000_00000_00000_000_11111_0110011, + }, + .{ // sd s0, 0x7f(s0) + .inst = Instruction.sd(.s0, 0x7f, .s0), + .expected = 0b0000011_01000_01000_011_11111_0100011, + }, + .{ // bne s0, s1, 0x42 + .inst = Instruction.bne(.s0, .s1, 0x42), + .expected = 0b0_000010_01001_01000_001_0001_0_1100011, + }, + .{ // j 0x1a + .inst = Instruction.jal(.zero, 0x1a), + .expected = 0b0_0000001101_0_00000000_00000_1101111, + }, + .{ // ebreak + .inst = Instruction.ebreak, + .expected = 0b000000000001_00000_000_00000_1110011, + }, + }; + + for (testcases) |case| { + const actual = case.inst.toU32(); + testing.expectEqual(case.expected, actual); + } +} diff --git a/test/stage2/riscv64.zig b/test/stage2/riscv64.zig new file mode 100644 index 0000000000..e2035be47a --- /dev/null +++ b/test/stage2/riscv64.zig @@ -0,0 +1,45 @@ +const std = @import("std"); +const TestContext = @import("../../src/test.zig").TestContext; + +const linux_riscv64 = std.zig.CrossTarget{ + .cpu_arch = .riscv64, + .os_tag = .linux, +}; + +pub fn addCases(ctx: *TestContext) !void { + { + var case = ctx.exe("riscv64 hello world", linux_riscv64); + // Regular old hello world + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (64), + \\ [arg1] "{a0}" (1), + \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{a2}" ("Hello, World!\n".len) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (94), + \\ [arg1] "{a0}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + } +} diff --git a/test/stage2/test.zig b/test/stage2/test.zig index b4bc1a413e..c8b9b0cc96 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -11,11 +11,6 @@ const linux_x64 = std.zig.CrossTarget{ .os_tag = .linux, }; -const linux_riscv64 = std.zig.CrossTarget{ - .cpu_arch = .riscv64, - .os_tag = .linux, -}; - pub fn addCases(ctx: *TestContext) !void { try @import("cbe.zig").addCases(ctx); try @import("spu-ii.zig").addCases(ctx); @@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void { try @import("llvm.zig").addCases(ctx); try @import("wasm.zig").addCases(ctx); try @import("darwin.zig").addCases(ctx); + try @import("riscv64.zig").addCases(ctx); { var case = ctx.exe("hello world with updates", linux_x64); @@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { ); } - { - var case = ctx.exe("riscv64 hello world", linux_riscv64); - // Regular old hello world - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (64), - \\ [arg1] "{a0}" (1), - \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{a2}" ("Hello, World!\n".len) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (94), - \\ [arg1] "{a0}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - } - { var case = ctx.exe("adding numbers at comptime", linux_x64); case.addCompareOutput( @@ -1048,7 +1008,7 @@ pub fn addCases(ctx: *TestContext) !void { "Hello, World!\n", ); try case.files.append(.{ - .src = + .src = \\pub fn print() void { \\ asm volatile ("syscall" \\ : @@ -1085,7 +1045,7 @@ pub fn addCases(ctx: *TestContext) !void { &.{":2:25: error: 'print' is private"}, ); try case.files.append(.{ - .src = + .src = \\fn print() void { \\ asm volatile ("syscall" \\ :