Commit 6c19aeddca

Luuk de Gram <Luukdegram@users.noreply.github.com>
2021-01-16 14:47:06
Add tests and move tests to wasm's own file
1 parent 4b2538f
Changed files (4)
src
codegen
link
test
src/codegen/wasm.zig
@@ -48,7 +48,7 @@ pub const Context = struct {
     /// Table to save `WValue`'s generated by an `Inst`
     values: ValueTable,
     /// `bytes` contains the wasm bytecode belonging to the 'code' section.
-    bytes: ArrayList(u8),
+    code: ArrayList(u8),
     /// Contains the generated function type bytecode for the current function
     /// found in `decl`
     func_type_data: ArrayList(u8),
@@ -56,8 +56,7 @@ pub const Context = struct {
     /// NOTE: arguments share the index with locals therefore the first variable
     /// will have the index that comes after the last argument's index
     local_index: u32 = 0,
-    /// If codegen fails, an error messages will be allocated and saved
-    /// in `err_msg`
+    /// If codegen fails, an error messages will be allocated and saved in `err_msg`
     err_msg: *Compilation.ErrorMsg,
 
     const InnerError = error{
@@ -74,6 +73,8 @@ pub const Context = struct {
     /// Resolves the `WValue` for the given instruction `inst`
     /// When the given instruction has a `Value`, it returns a constant instead
     fn resolveInst(self: Context, inst: *Inst) WValue {
+        if (!inst.ty.hasCodeGenBits()) return .none;
+
         if (inst.value()) |_| {
             return WValue{ .constant = inst };
         }
@@ -83,7 +84,7 @@ pub const Context = struct {
 
     /// Writes the bytecode depending on the given `WValue` in `val`
     fn emitWValue(self: *Context, val: WValue) InnerError!void {
-        const writer = self.bytes.writer();
+        const writer = self.code.writer();
         switch (val) {
             .none, .block_idx => {},
             .local => |idx| {
@@ -127,14 +128,14 @@ pub const Context = struct {
         }
     }
 
-    /// Generates the wasm bytecode for the given `code`
+    /// Generates the wasm bytecode for the function declaration belonging to `Context`
     pub fn gen(self: *Context) InnerError!void {
-        assert(self.bytes.items.len == 0);
+        assert(self.code.items.len == 0);
         try self.genFunctype();
-        const writer = self.bytes.writer();
+        const writer = self.code.writer();
 
         // Reserve space to write the size after generating the code
-        try self.bytes.resize(5);
+        try self.code.resize(5);
 
         // Write instructions
         // TODO: check for and handle death of instructions
@@ -170,8 +171,8 @@ pub const Context = struct {
 
         // Fill in the size of the generated code to the reserved space at the
         // beginning of the buffer.
-        const size = self.bytes.items.len - 5 + self.decl.fn_link.wasm.?.idx_refs.items.len * 5;
-        leb.writeUnsignedFixed(5, self.bytes.items[0..5], @intCast(u32, size));
+        const size = self.code.items.len - 5 + self.decl.fn_link.wasm.?.idx_refs.items.len * 5;
+        leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
     }
 
     fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
@@ -198,6 +199,7 @@ pub const Context = struct {
     }
 
     fn genRet(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
+        // TODO: Implement tail calls
         const operand = self.resolveInst(inst.operand);
         try self.emitWValue(operand);
         return WValue.none;
@@ -214,12 +216,12 @@ pub const Context = struct {
             try self.emitWValue(arg_val);
         }
 
-        try self.bytes.append(0x10); // call
+        try self.code.append(0x10); // call
 
         // The function index immediate argument will be filled in using this data
         // in link.Wasm.flush().
         try self.decl.fn_link.wasm.?.idx_refs.append(self.gpa, .{
-            .offset = @intCast(u32, self.bytes.items.len),
+            .offset = @intCast(u32, self.code.items.len),
             .decl = target,
         });
 
@@ -232,7 +234,7 @@ pub const Context = struct {
     }
 
     fn genStore(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
-        const writer = self.bytes.writer();
+        const writer = self.code.writer();
 
         const lhs = self.resolveInst(inst.lhs);
         const rhs = self.resolveInst(inst.rhs);
@@ -262,12 +264,12 @@ pub const Context = struct {
         try self.emitWValue(lhs);
         try self.emitWValue(rhs);
 
-        try self.bytes.append(0x6A); // i32.add
+        try self.code.append(0x6A); // i32.add
         return WValue.none;
     }
 
     fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {
-        const writer = self.bytes.writer();
+        const writer = self.code.writer();
         switch (inst.base.ty.tag()) {
             .u32 => {
                 try writer.writeByte(0x41); // i32.const
src/link/Wasm.zig
@@ -122,7 +122,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
     var context = codegen.Context{
         .gpa = self.base.allocator,
         .values = codegen.ValueTable.init(self.base.allocator),
-        .bytes = managed_code,
+        .code = managed_code,
         .func_type_data = managed_functype,
         .decl = decl,
         .err_msg = undefined,
@@ -140,7 +140,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
     };
 
     fn_data.functype = context.func_type_data.toUnmanaged();
-    fn_data.code = context.bytes.toUnmanaged();
+    fn_data.code = context.code.toUnmanaged();
 }
 
 pub fn updateDeclExports(
test/stage2/test.zig
@@ -21,17 +21,13 @@ const linux_riscv64 = std.zig.CrossTarget{
     .os_tag = .linux,
 };
 
-const wasi = std.zig.CrossTarget{
-    .cpu_arch = .wasm32,
-    .os_tag = .wasi,
-};
-
 pub fn addCases(ctx: *TestContext) !void {
     try @import("cbe.zig").addCases(ctx);
     try @import("spu-ii.zig").addCases(ctx);
     try @import("arm.zig").addCases(ctx);
     try @import("aarch64.zig").addCases(ctx);
     try @import("llvm.zig").addCases(ctx);
+    try @import("wasm.zig").addCases(ctx);
 
     {
         var case = ctx.exe("hello world with updates", linux_x64);
@@ -1158,62 +1154,6 @@ pub fn addCases(ctx: *TestContext) !void {
         });
     }
 
-    {
-        var case = ctx.exe("wasm function calls", wasi);
-
-        case.addCompareOutput(
-            \\export fn _start() u32 {
-            \\    foo();
-            \\    bar();
-            \\    return 42;
-            \\}
-            \\fn foo() void {
-            \\    bar();
-            \\    bar();
-            \\}
-            \\fn bar() void {}
-        ,
-            "42\n",
-        );
-
-        case.addCompareOutput(
-            \\export fn _start() i64 {
-            \\    bar();
-            \\    foo();
-            \\    foo();
-            \\    bar();
-            \\    foo();
-            \\    bar();
-            \\    return 42;
-            \\}
-            \\fn foo() void {
-            \\    bar();
-            \\}
-            \\fn bar() void {}
-        ,
-            "42\n",
-        );
-
-        case.addCompareOutput(
-            \\export fn _start() f32 {
-            \\    bar();
-            \\    foo();
-            \\    return 42.0;
-            \\}
-            \\fn foo() void {
-            \\    bar();
-            \\    bar();
-            \\    bar();
-            \\}
-            \\fn bar() void {}
-        ,
-        // This is what you get when you take the bits of the IEE-754
-        // representation of 42.0 and reinterpret them as an unsigned
-        // integer. Guess that's a bug in wasmtime.
-            "1109917696\n",
-        );
-    }
-
     ctx.compileError("function redefinition", linux_x64,
         \\fn entry() void {}
         \\fn entry() void {}
test/stage2/wasm.zig
@@ -0,0 +1,125 @@
+const std = @import("std");
+const TestContext = @import("../../src/test.zig").TestContext;
+
+const wasi = std.zig.CrossTarget{
+    .cpu_arch = .wasm32,
+    .os_tag = .wasi,
+};
+
+pub fn addCases(ctx: *TestContext) !void {
+    {
+        var case = ctx.exe("wasm function calls", wasi);
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    foo();
+            \\    bar();
+            \\    return 42;
+            \\}
+            \\fn foo() void {
+            \\    bar();
+            \\    bar();
+            \\}
+            \\fn bar() void {}
+        ,
+            "42\n",
+        );
+
+        case.addCompareOutput(
+            \\export fn _start() i64 {
+            \\    bar();
+            \\    foo();
+            \\    foo();
+            \\    bar();
+            \\    foo();
+            \\    bar();
+            \\    return 42;
+            \\}
+            \\fn foo() void {
+            \\    bar();
+            \\}
+            \\fn bar() void {}
+        ,
+            "42\n",
+        );
+
+        case.addCompareOutput(
+            \\export fn _start() f32 {
+            \\    bar();
+            \\    foo();
+            \\    return 42.0;
+            \\}
+            \\fn foo() void {
+            \\    bar();
+            \\    bar();
+            \\    bar();
+            \\}
+            \\fn bar() void {}
+        ,
+        // This is what you get when you take the bits of the IEE-754
+        // representation of 42.0 and reinterpret them as an unsigned
+        // integer. Guess that's a bug in wasmtime.
+            "1109917696\n",
+        );
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    foo(10, 20);
+            \\    return 5;
+            \\}
+            \\fn foo(x: u32, y: u32) void {}
+        , "5\n");
+    }
+
+    {
+        var case = ctx.exe("wasm locals", wasi);
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    var i: u32 = 5;
+            \\    var y: f32 = 42.0;
+            \\    var x: u32 = 10;
+            \\    return i;
+            \\}
+        , "5\n");
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    var i: u32 = 5;
+            \\    var y: f32 = 42.0;
+            \\    var x: u32 = 10;
+            \\    foo(i, x);
+            \\    i = x;
+            \\    return i;
+            \\}
+            \\fn foo(x: u32, y: u32) void {
+            \\    var i: u32 = 10;
+            \\    i = x;
+            \\}
+        , "10\n");
+    }
+
+    {
+        var case = ctx.exe("wasm binary operands", wasi);
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    var i: u32 = 5;
+            \\    i += 20;
+            \\    return i;
+            \\}
+        , "25\n");
+
+        case.addCompareOutput(
+            \\export fn _start() u32 {
+            \\    var i: u32 = 5;
+            \\    i += 20;
+            \\    var result: u32 = foo(i, 10);
+            \\    return result;
+            \\}
+            \\fn foo(x: u32, y: u32) u32 {
+            \\    return x + y;
+            \\}
+        , "35\n");
+    }
+}