authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-04-27 16:12:59+08:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-28 07:20:45+02:00
logbc06e19828428ed9c2fc3698f418d46e62e327f5
tree548505ed9a0bd1e769a2fc59a80098ec610ff9c4
parentda9da76e3f91bf1b7e0dc89cb6d1b79dd0f0ad4b

stage2 riscv64: cleanup code and add tests


3 files changed, 95 insertions(+), 53 deletions(-)

src/codegen/riscv64.zig+47-10
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const DW = std.dwarf;2const DW = std.dwarf;
3const assert = std.debug.assert;
4const testing = std.testing;
35
4// TODO: this is only tagged to facilitate the monstrosity.6// TODO: this is only tagged to facilitate the monstrosity.
5// Once packed structs work make it packed.7// Once packed structs work make it packed.
...@@ -110,7 +112,7 @@ pub const Instruction = union(enum) {...@@ -110,7 +112,7 @@ pub const Instruction = union(enum) {
110 // -- less burden on callsite, bonus semantic checking112 // -- less burden on callsite, bonus semantic checking
111 fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction {113 fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction {
112 const umm = @bitCast(u13, imm);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
114116
115 return Instruction{117 return Instruction{
116 .B = .{118 .B = .{
...@@ -140,15 +142,15 @@ pub const Instruction = union(enum) {...@@ -140,15 +142,15 @@ pub const Instruction = union(enum) {
140 }142 }
141143
142 fn jType(op: u7, rd: Register, imm: i21) Instruction {144 fn jType(op: u7, rd: Register, imm: i21) Instruction {
143 const umm = @bitcast(u21, imm);145 const umm = @bitCast(u21, imm);
144 if (umm % 2 != 0) @panic("Internal error: misaligned jump target");146 assert(umm % 2 == 0); // misaligned jump target
145147
146 return Instruction{148 return Instruction{
147 .J = .{149 .J = .{
148 .opcode = op,150 .opcode = op,
149 .rd = @enumToInt(rd),151 .rd = @enumToInt(rd),
150 .imm1_10 = @truncate(u10, umm >> 1),152 .imm1_10 = @truncate(u10, umm >> 1),
151 .imm11 = @truncate(u1, umm >> 1),153 .imm11 = @truncate(u1, umm >> 11),
152 .imm12_19 = @truncate(u8, umm >> 12),154 .imm12_19 = @truncate(u8, umm >> 12),
153 .imm20 = @truncate(u1, umm >> 20),155 .imm20 = @truncate(u1, umm >> 20),
154 },156 },
...@@ -340,27 +342,27 @@ pub const Instruction = union(enum) {...@@ -340,27 +342,27 @@ pub const Instruction = union(enum) {
340342
341 // Branch343 // Branch
342344
343 pub fn beq(r1: Register, r2: Register, offset: u13) Instruction {345 pub fn beq(r1: Register, r2: Register, offset: i13) Instruction {
344 return bType(0b1100011, 0b000, r1, r2, offset);346 return bType(0b1100011, 0b000, r1, r2, offset);
345 }347 }
346348
347 pub fn bne(r1: Register, r2: Register, offset: u13) Instruction {349 pub fn bne(r1: Register, r2: Register, offset: i13) Instruction {
348 return bType(0b1100011, 0b001, r1, r2, offset);350 return bType(0b1100011, 0b001, r1, r2, offset);
349 }351 }
350352
351 pub fn blt(r1: Register, r2: Register, offset: u13) Instruction {353 pub fn blt(r1: Register, r2: Register, offset: i13) Instruction {
352 return bType(0b1100011, 0b100, r1, r2, offset);354 return bType(0b1100011, 0b100, r1, r2, offset);
353 }355 }
354356
355 pub fn bge(r1: Register, r2: Register, offset: u13) Instruction {357 pub fn bge(r1: Register, r2: Register, offset: i13) Instruction {
356 return bType(0b1100011, 0b101, r1, r2, offset);358 return bType(0b1100011, 0b101, r1, r2, offset);
357 }359 }
358360
359 pub fn bltu(r1: Register, r2: Register, offset: u13) Instruction {361 pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction {
360 return bType(0b1100011, 0b110, r1, r2, offset);362 return bType(0b1100011, 0b110, r1, r2, offset);
361 }363 }
362364
363 pub fn bgeu(r1: Register, r2: Register, offset: u13) Instruction {365 pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction {
364 return bType(0b1100011, 0b111, r1, r2, offset);366 return bType(0b1100011, 0b111, r1, r2, offset);
365 }367 }
366368
...@@ -431,3 +433,38 @@ pub const Register = enum(u5) {...@@ -431,3 +433,38 @@ pub const Register = enum(u5) {
431pub const callee_preserved_regs = [_]Register{433pub const callee_preserved_regs = [_]Register{
432 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,434 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
433};435};
436
437test "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 @@
1const std = @import("std");
2const TestContext = @import("../../src/test.zig").TestContext;
3
4const linux_riscv64 = std.zig.CrossTarget{
5 .cpu_arch = .riscv64,
6 .os_tag = .linux,
7};
8
9pub 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 +11,6 @@ const linux_x64 = std.zig.CrossTarget{
11 .os_tag = .linux,11 .os_tag = .linux,
12};12};
1313
14const linux_riscv64 = std.zig.CrossTarget{
15 .cpu_arch = .riscv64,
16 .os_tag = .linux,
17};
18
19pub fn addCases(ctx: *TestContext) !void {14pub fn addCases(ctx: *TestContext) !void {
20 try @import("cbe.zig").addCases(ctx);15 try @import("cbe.zig").addCases(ctx);
21 try @import("spu-ii.zig").addCases(ctx);16 try @import("spu-ii.zig").addCases(ctx);
...@@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void {
24 try @import("llvm.zig").addCases(ctx);19 try @import("llvm.zig").addCases(ctx);
25 try @import("wasm.zig").addCases(ctx);20 try @import("wasm.zig").addCases(ctx);
26 try @import("darwin.zig").addCases(ctx);21 try @import("darwin.zig").addCases(ctx);
22 try @import("riscv64.zig").addCases(ctx);
2723
28 {24 {
29 var case = ctx.exe("hello world with updates", linux_x64);25 var case = ctx.exe("hello world with updates", linux_x64);
...@@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {
137 );133 );
138 }134 }
139135
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 var case = ctx.exe("adding numbers at comptime", linux_x64);137 var case = ctx.exe("adding numbers at comptime", linux_x64);
178 case.addCompareOutput(138 case.addCompareOutput(
...@@ -1048,7 +1008,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1048,7 +1008,7 @@ pub fn addCases(ctx: *TestContext) !void {
1048 "Hello, World!\n",1008 "Hello, World!\n",
1049 );1009 );
1050 try case.files.append(.{1010 try case.files.append(.{
1051 .src =1011 .src =
1052 \\pub fn print() void {1012 \\pub fn print() void {
1053 \\ asm volatile ("syscall"1013 \\ asm volatile ("syscall"
1054 \\ :1014 \\ :
...@@ -1085,7 +1045,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1085,7 +1045,7 @@ pub fn addCases(ctx: *TestContext) !void {
1085 &.{":2:25: error: 'print' is private"},1045 &.{":2:25: error: 'print' is private"},
1086 );1046 );
1087 try case.files.append(.{1047 try case.files.append(.{
1088 .src =1048 .src =
1089 \\fn print() void {1049 \\fn print() void {
1090 \\ asm volatile ("syscall"1050 \\ asm volatile ("syscall"
1091 \\ :1051 \\ :