| author | |
| committer | |
| log | bc06e19828428ed9c2fc3698f418d46e62e327f5 |
| tree | 548505ed9a0bd1e769a2fc59a80098ec610ff9c4 |
| parent | da9da76e3f91bf1b7e0dc89cb6d1b79dd0f0ad4b |
3 files changed, 95 insertions(+), 53 deletions(-)
src/codegen/riscv64.zig+47-10| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const DW = std.dwarf; |
| 3 | const assert = std.debug.assert; | |
| 4 | const testing = std.testing; | |
| 3 | 5 | |
| 4 | 6 | // TODO: this is only tagged to facilitate the monstrosity. |
| 5 | 7 | // Once packed structs work make it packed. |
| ... | ... | @@ -110,7 +112,7 @@ pub const Instruction = union(enum) { |
| 110 | 112 | // -- less burden on callsite, bonus semantic checking |
| 111 | 113 | fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction { |
| 112 | 114 | const umm = @bitCast(u13, imm); |
| 113 | if (umm % 2 != 0) @panic("Internal error: misaligned branch target"); | |
| 115 | assert(umm % 2 == 0); // misaligned branch target | |
| 114 | 116 | |
| 115 | 117 | return Instruction{ |
| 116 | 118 | .B = .{ |
| ... | ... | @@ -140,15 +142,15 @@ pub const Instruction = union(enum) { |
| 140 | 142 | } |
| 141 | 143 | |
| 142 | 144 | fn jType(op: u7, rd: Register, imm: i21) Instruction { |
| 143 | const umm = @bitcast(u21, imm); | |
| 144 | if (umm % 2 != 0) @panic("Internal error: misaligned jump target"); | |
| 145 | const umm = @bitCast(u21, imm); | |
| 146 | assert(umm % 2 == 0); // misaligned jump target | |
| 145 | 147 | |
| 146 | 148 | return Instruction{ |
| 147 | 149 | .J = .{ |
| 148 | 150 | .opcode = op, |
| 149 | 151 | .rd = @enumToInt(rd), |
| 150 | 152 | .imm1_10 = @truncate(u10, umm >> 1), |
| 151 | .imm11 = @truncate(u1, umm >> 1), | |
| 153 | .imm11 = @truncate(u1, umm >> 11), | |
| 152 | 154 | .imm12_19 = @truncate(u8, umm >> 12), |
| 153 | 155 | .imm20 = @truncate(u1, umm >> 20), |
| 154 | 156 | }, |
| ... | ... | @@ -340,27 +342,27 @@ pub const Instruction = union(enum) { |
| 340 | 342 | |
| 341 | 343 | // Branch |
| 342 | 344 | |
| 343 | pub fn beq(r1: Register, r2: Register, offset: u13) Instruction { | |
| 345 | pub fn beq(r1: Register, r2: Register, offset: i13) Instruction { | |
| 344 | 346 | return bType(0b1100011, 0b000, r1, r2, offset); |
| 345 | 347 | } |
| 346 | 348 | |
| 347 | pub fn bne(r1: Register, r2: Register, offset: u13) Instruction { | |
| 349 | pub fn bne(r1: Register, r2: Register, offset: i13) Instruction { | |
| 348 | 350 | return bType(0b1100011, 0b001, r1, r2, offset); |
| 349 | 351 | } |
| 350 | 352 | |
| 351 | pub fn blt(r1: Register, r2: Register, offset: u13) Instruction { | |
| 353 | pub fn blt(r1: Register, r2: Register, offset: i13) Instruction { | |
| 352 | 354 | return bType(0b1100011, 0b100, r1, r2, offset); |
| 353 | 355 | } |
| 354 | 356 | |
| 355 | pub fn bge(r1: Register, r2: Register, offset: u13) Instruction { | |
| 357 | pub fn bge(r1: Register, r2: Register, offset: i13) Instruction { | |
| 356 | 358 | return bType(0b1100011, 0b101, r1, r2, offset); |
| 357 | 359 | } |
| 358 | 360 | |
| 359 | pub fn bltu(r1: Register, r2: Register, offset: u13) Instruction { | |
| 361 | pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction { | |
| 360 | 362 | return bType(0b1100011, 0b110, r1, r2, offset); |
| 361 | 363 | } |
| 362 | 364 | |
| 363 | pub fn bgeu(r1: Register, r2: Register, offset: u13) Instruction { | |
| 365 | pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction { | |
| 364 | 366 | return bType(0b1100011, 0b111, r1, r2, offset); |
| 365 | 367 | } |
| 366 | 368 | |
| ... | ... | @@ -431,3 +433,38 @@ pub const Register = enum(u5) { |
| 431 | 433 | pub const callee_preserved_regs = [_]Register{ |
| 432 | 434 | .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, |
| 433 | 435 | }; |
| 436 | ||
| 437 | test "serialize instructions" { | |
| 438 | const Testcase = struct { | |
| 439 | inst: Instruction, | |
| 440 | expected: u32, | |
| 441 | }; | |
| 442 | ||
| 443 | const testcases = [_]Testcase{ | |
| 444 | .{ // add t6, zero, zero | |
| 445 | .inst = Instruction.add(.t6, .zero, .zero), | |
| 446 | .expected = 0b0000000_00000_00000_000_11111_0110011, | |
| 447 | }, | |
| 448 | .{ // sd s0, 0x7f(s0) | |
| 449 | .inst = Instruction.sd(.s0, 0x7f, .s0), | |
| 450 | .expected = 0b0000011_01000_01000_011_11111_0100011, | |
| 451 | }, | |
| 452 | .{ // bne s0, s1, 0x42 | |
| 453 | .inst = Instruction.bne(.s0, .s1, 0x42), | |
| 454 | .expected = 0b0_000010_01001_01000_001_0001_0_1100011, | |
| 455 | }, | |
| 456 | .{ // j 0x1a | |
| 457 | .inst = Instruction.jal(.zero, 0x1a), | |
| 458 | .expected = 0b0_0000001101_0_00000000_00000_1101111, | |
| 459 | }, | |
| 460 | .{ // ebreak | |
| 461 | .inst = Instruction.ebreak, | |
| 462 | .expected = 0b000000000001_00000_000_00000_1110011, | |
| 463 | }, | |
| 464 | }; | |
| 465 | ||
| 466 | for (testcases) |case| { | |
| 467 | const actual = case.inst.toU32(); | |
| 468 | testing.expectEqual(case.expected, actual); | |
| 469 | } | |
| 470 | } |
test/stage2/riscv64.zig created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | const std = @import("std"); | |
| 2 | const TestContext = @import("../../src/test.zig").TestContext; | |
| 3 | ||
| 4 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 5 | .cpu_arch = .riscv64, | |
| 6 | .os_tag = .linux, | |
| 7 | }; | |
| 8 | ||
| 9 | pub fn addCases(ctx: *TestContext) !void { | |
| 10 | { | |
| 11 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | |
| 12 | // Regular old hello world | |
| 13 | case.addCompareOutput( | |
| 14 | \\export fn _start() noreturn { | |
| 15 | \\ print(); | |
| 16 | \\ | |
| 17 | \\ exit(); | |
| 18 | \\} | |
| 19 | \\ | |
| 20 | \\fn print() void { | |
| 21 | \\ asm volatile ("ecall" | |
| 22 | \\ : | |
| 23 | \\ : [number] "{a7}" (64), | |
| 24 | \\ [arg1] "{a0}" (1), | |
| 25 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | |
| 26 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | |
| 27 | \\ : "rcx", "r11", "memory" | |
| 28 | \\ ); | |
| 29 | \\ return; | |
| 30 | \\} | |
| 31 | \\ | |
| 32 | \\fn exit() noreturn { | |
| 33 | \\ asm volatile ("ecall" | |
| 34 | \\ : | |
| 35 | \\ : [number] "{a7}" (94), | |
| 36 | \\ [arg1] "{a0}" (0) | |
| 37 | \\ : "rcx", "r11", "memory" | |
| 38 | \\ ); | |
| 39 | \\ unreachable; | |
| 40 | \\} | |
| 41 | , | |
| 42 | "Hello, World!\n", | |
| 43 | ); | |
| 44 | } | |
| 45 | } |
test/stage2/test.zig+3-43| ... | ... | @@ -11,11 +11,6 @@ const linux_x64 = std.zig.CrossTarget{ |
| 11 | 11 | .os_tag = .linux, |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 15 | .cpu_arch = .riscv64, | |
| 16 | .os_tag = .linux, | |
| 17 | }; | |
| 18 | ||
| 19 | 14 | pub fn addCases(ctx: *TestContext) !void { |
| 20 | 15 | try @import("cbe.zig").addCases(ctx); |
| 21 | 16 | try @import("spu-ii.zig").addCases(ctx); |
| ... | ... | @@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 24 | 19 | try @import("llvm.zig").addCases(ctx); |
| 25 | 20 | try @import("wasm.zig").addCases(ctx); |
| 26 | 21 | try @import("darwin.zig").addCases(ctx); |
| 22 | try @import("riscv64.zig").addCases(ctx); | |
| 27 | 23 | |
| 28 | 24 | { |
| 29 | 25 | var case = ctx.exe("hello world with updates", linux_x64); |
| ... | ... | @@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 137 | 133 | ); |
| 138 | 134 | } |
| 139 | 135 | |
| 140 | { | |
| 141 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | |
| 142 | // Regular old hello world | |
| 143 | case.addCompareOutput( | |
| 144 | \\export fn _start() noreturn { | |
| 145 | \\ print(); | |
| 146 | \\ | |
| 147 | \\ exit(); | |
| 148 | \\} | |
| 149 | \\ | |
| 150 | \\fn print() void { | |
| 151 | \\ asm volatile ("ecall" | |
| 152 | \\ : | |
| 153 | \\ : [number] "{a7}" (64), | |
| 154 | \\ [arg1] "{a0}" (1), | |
| 155 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | |
| 156 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | |
| 157 | \\ : "rcx", "r11", "memory" | |
| 158 | \\ ); | |
| 159 | \\ return; | |
| 160 | \\} | |
| 161 | \\ | |
| 162 | \\fn exit() noreturn { | |
| 163 | \\ asm volatile ("ecall" | |
| 164 | \\ : | |
| 165 | \\ : [number] "{a7}" (94), | |
| 166 | \\ [arg1] "{a0}" (0) | |
| 167 | \\ : "rcx", "r11", "memory" | |
| 168 | \\ ); | |
| 169 | \\ unreachable; | |
| 170 | \\} | |
| 171 | , | |
| 172 | "Hello, World!\n", | |
| 173 | ); | |
| 174 | } | |
| 175 | ||
| 176 | 136 | { |
| 177 | 137 | var case = ctx.exe("adding numbers at comptime", linux_x64); |
| 178 | 138 | case.addCompareOutput( |
| ... | ... | @@ -1048,7 +1008,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1048 | 1008 | "Hello, World!\n", |
| 1049 | 1009 | ); |
| 1050 | 1010 | try case.files.append(.{ |
| 1051 | .src = | |
| 1011 | .src = | |
| 1052 | 1012 | \\pub fn print() void { |
| 1053 | 1013 | \\ asm volatile ("syscall" |
| 1054 | 1014 | \\ : |
| ... | ... | @@ -1085,7 +1045,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1085 | 1045 | &.{":2:25: error: 'print' is private"}, |
| 1086 | 1046 | ); |
| 1087 | 1047 | try case.files.append(.{ |
| 1088 | .src = | |
| 1048 | .src = | |
| 1089 | 1049 | \\fn print() void { |
| 1090 | 1050 | \\ asm volatile ("syscall" |
| 1091 | 1051 | \\ : |