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 @@
11const std = @import("std");
22const DW = std.dwarf;
3const assert = std.debug.assert;
4const testing = std.testing;
35
46// TODO: this is only tagged to facilitate the monstrosity.
57// Once packed structs work make it packed.
......@@ -110,7 +112,7 @@ pub const Instruction = union(enum) {
110112 // -- less burden on callsite, bonus semantic checking
111113 fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction {
112114 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
115117 return Instruction{
116118 .B = .{
......@@ -140,15 +142,15 @@ pub const Instruction = union(enum) {
140142 }
141143
142144 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
145147
146148 return Instruction{
147149 .J = .{
148150 .opcode = op,
149151 .rd = @enumToInt(rd),
150152 .imm1_10 = @truncate(u10, umm >> 1),
151 .imm11 = @truncate(u1, umm >> 1),
153 .imm11 = @truncate(u1, umm >> 11),
152154 .imm12_19 = @truncate(u8, umm >> 12),
153155 .imm20 = @truncate(u1, umm >> 20),
154156 },
......@@ -340,27 +342,27 @@ pub const Instruction = union(enum) {
340342
341343 // Branch
342344
343 pub fn beq(r1: Register, r2: Register, offset: u13) Instruction {
345 pub fn beq(r1: Register, r2: Register, offset: i13) Instruction {
344346 return bType(0b1100011, 0b000, r1, r2, offset);
345347 }
346348
347 pub fn bne(r1: Register, r2: Register, offset: u13) Instruction {
349 pub fn bne(r1: Register, r2: Register, offset: i13) Instruction {
348350 return bType(0b1100011, 0b001, r1, r2, offset);
349351 }
350352
351 pub fn blt(r1: Register, r2: Register, offset: u13) Instruction {
353 pub fn blt(r1: Register, r2: Register, offset: i13) Instruction {
352354 return bType(0b1100011, 0b100, r1, r2, offset);
353355 }
354356
355 pub fn bge(r1: Register, r2: Register, offset: u13) Instruction {
357 pub fn bge(r1: Register, r2: Register, offset: i13) Instruction {
356358 return bType(0b1100011, 0b101, r1, r2, offset);
357359 }
358360
359 pub fn bltu(r1: Register, r2: Register, offset: u13) Instruction {
361 pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction {
360362 return bType(0b1100011, 0b110, r1, r2, offset);
361363 }
362364
363 pub fn bgeu(r1: Register, r2: Register, offset: u13) Instruction {
365 pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction {
364366 return bType(0b1100011, 0b111, r1, r2, offset);
365367 }
366368
......@@ -431,3 +433,38 @@ pub const Register = enum(u5) {
431433pub const callee_preserved_regs = [_]Register{
432434 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
433435};
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{
1111 .os_tag = .linux,
1212};
1313
14const linux_riscv64 = std.zig.CrossTarget{
15 .cpu_arch = .riscv64,
16 .os_tag = .linux,
17};
18
1914pub fn addCases(ctx: *TestContext) !void {
2015 try @import("cbe.zig").addCases(ctx);
2116 try @import("spu-ii.zig").addCases(ctx);
......@@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void {
2419 try @import("llvm.zig").addCases(ctx);
2520 try @import("wasm.zig").addCases(ctx);
2621 try @import("darwin.zig").addCases(ctx);
22 try @import("riscv64.zig").addCases(ctx);
2723
2824 {
2925 var case = ctx.exe("hello world with updates", linux_x64);
......@@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {
137133 );
138134 }
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
176136 {
177137 var case = ctx.exe("adding numbers at comptime", linux_x64);
178138 case.addCompareOutput(
......@@ -1048,7 +1008,7 @@ pub fn addCases(ctx: *TestContext) !void {
10481008 "Hello, World!\n",
10491009 );
10501010 try case.files.append(.{
1051 .src =
1011 .src =
10521012 \\pub fn print() void {
10531013 \\ asm volatile ("syscall"
10541014 \\ :
......@@ -1085,7 +1045,7 @@ pub fn addCases(ctx: *TestContext) !void {
10851045 &.{":2:25: error: 'print' is private"},
10861046 );
10871047 try case.files.append(.{
1088 .src =
1048 .src =
10891049 \\fn print() void {
10901050 \\ asm volatile ("syscall"
10911051 \\ :