Commit 13fca53b92

Luuk de Gram <luuk@degram.dev>
2022-03-06 17:54:26
wasm: Unify function generation
Like decl code generation, also unify the wasm backend and the wasm linker to call into the general purpose `codegen.zig` to generate the code for a function.
1 parent 2faba40
Changed files (3)
src/arch/wasm/CodeGen.zig
@@ -8,6 +8,7 @@ const mem = std.mem;
 const wasm = std.wasm;
 const log = std.log.scoped(.codegen);
 
+const codegen = @import("../../codegen.zig");
 const Module = @import("../../Module.zig");
 const Decl = Module.Decl;
 const Type = @import("../../type.zig").Type;
@@ -546,7 +547,7 @@ blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, struct {
     value: WValue,
 }) = .{},
 /// `bytes` contains the wasm bytecode belonging to the 'code' section.
-code: ArrayList(u8),
+code: *ArrayList(u8),
 /// The index the next local generated will have
 /// NOTE: arguments share the index with locals therefore the first variable
 /// will have the index that comes after the last argument's index
@@ -566,9 +567,6 @@ locals: std.ArrayListUnmanaged(u8),
 target: std.Target,
 /// Represents the wasm binary file that is being linked.
 bin_file: *link.File.Wasm,
-/// Reference to the Module that this decl is part of.
-/// Used to find the error value.
-module: *Module,
 /// List of MIR Instructions
 mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
 /// Contains extra data for MIR
@@ -611,7 +609,6 @@ pub fn deinit(self: *Self) void {
     self.locals.deinit(self.gpa);
     self.mir_instructions.deinit(self.gpa);
     self.mir_extra.deinit(self.gpa);
-    self.code.deinit();
     self.* = undefined;
 }
 
@@ -822,7 +819,40 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
     };
 }
 
-pub fn genFunc(self: *Self) InnerError!void {
+pub fn generate(
+    bin_file: *link.File,
+    src_loc: Module.SrcLoc,
+    func: *Module.Fn,
+    air: Air,
+    liveness: Liveness,
+    code: *std.ArrayList(u8),
+    debug_output: codegen.DebugInfoOutput,
+) codegen.GenerateSymbolError!codegen.FnResult {
+    _ = debug_output; // TODO
+    _ = src_loc;
+    var code_gen: Self = .{
+        .gpa = bin_file.allocator,
+        .air = air,
+        .liveness = liveness,
+        .values = .{},
+        .code = code,
+        .decl = func.owner_decl,
+        .err_msg = undefined,
+        .locals = .{},
+        .target = bin_file.options.target,
+        .bin_file = bin_file.cast(link.File.Wasm).?,
+    };
+    defer code_gen.deinit();
+
+    genFunc(&code_gen) catch |err| switch (err) {
+        error.CodegenFail => return codegen.FnResult{ .fail = code_gen.err_msg },
+        else => |e| return e,
+    };
+
+    return codegen.FnResult{ .appended = {} };
+}
+
+fn genFunc(self: *Self) InnerError!void {
     var func_type = try genFunctype(self.gpa, self.decl.ty, self.target);
     defer func_type.deinit(self.gpa);
     self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
@@ -889,7 +919,7 @@ pub fn genFunc(self: *Self) InnerError!void {
     var emit: Emit = .{
         .mir = mir,
         .bin_file = &self.bin_file.base,
-        .code = &self.code,
+        .code = self.code,
         .locals = self.locals.items,
         .decl = self.decl,
     };
@@ -1761,7 +1791,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
         },
         .ErrorSet => switch (val.tag()) {
             .@"error" => {
-                const kv = try self.module.getErrorValue(val.getError().?);
+                const kv = try self.bin_file.base.options.module.?.getErrorValue(val.getError().?);
                 return WValue{ .imm32 = kv.value };
             },
             else => return WValue{ .imm32 = 0 },
@@ -1852,7 +1882,7 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 {
             .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())),
         },
         .ErrorSet => {
-            const kv = self.module.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
+            const kv = self.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
             return @bitCast(i32, kv.value);
         },
         else => unreachable, // Programmer called this function for an illegal type
src/link/Wasm.zig
@@ -505,31 +505,28 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
 
     decl.link.wasm.clear(self.base.allocator);
 
-    var codegen_: CodeGen = .{
-        .gpa = self.base.allocator,
-        .air = air,
-        .liveness = liveness,
-        .values = .{},
-        .code = std.ArrayList(u8).init(self.base.allocator),
-        .decl = decl,
-        .err_msg = undefined,
-        .locals = .{},
-        .target = self.base.options.target,
-        .bin_file = self,
-        .module = module,
-    };
-    defer codegen_.deinit();
+    var code_writer = std.ArrayList(u8).init(self.base.allocator);
+    defer code_writer.deinit();
+    const result = try codegen.generateFunction(
+        &self.base,
+        decl.srcLoc(),
+        func,
+        air,
+        liveness,
+        &code_writer,
+        .none,
+    );
 
-    // generate the 'code' section for the function declaration
-    codegen_.genFunc() catch |err| switch (err) {
-        error.CodegenFail => {
+    const code = switch (result) {
+        .appended => code_writer.items,
+        .fail => |em| {
             decl.analysis = .codegen_failure;
-            try module.failed_decls.put(module.gpa, decl, codegen_.err_msg);
+            try module.failed_decls.put(module.gpa, decl, em);
             return;
         },
-        else => |e| return e,
     };
-    return self.finishUpdateDecl(decl, codegen_.code.items);
+
+    return self.finishUpdateDecl(decl, code);
 }
 
 // Generate code for the Decl, storing it in memory to be later written to
src/codegen.zig
@@ -83,8 +83,6 @@ pub fn generateFunction(
     debug_output: DebugInfoOutput,
 ) GenerateSymbolError!FnResult {
     switch (bin_file.options.target.cpu.arch) {
-        .wasm32 => unreachable, // has its own code path
-        .wasm64 => unreachable, // has its own code path
         .arm,
         .armeb,
         => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
@@ -136,6 +134,9 @@ pub fn generateFunction(
         //.renderscript32 => return Function(.renderscript32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
         //.renderscript64 => return Function(.renderscript64).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
         //.ve => return Function(.ve).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
+        .wasm32,
+        .wasm64,
+        => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
         else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
     }
 }