From 13fca53b925e7de00b63efbf6ac3723a4df732a8 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 6 Mar 2022 17:54:26 +0100 Subject: [PATCH] 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. --- src/arch/wasm/CodeGen.zig | 48 +++++++++++++++++++++++++++++++-------- src/codegen.zig | 5 ++-- src/link/Wasm.zig | 37 ++++++++++++++---------------- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index b1214f3bd8..b293d20db9 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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 diff --git a/src/codegen.zig b/src/codegen.zig index 27f1891caf..20b2968c48 100644 --- a/src/codegen.zig +++ b/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."), } } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 4a5d9323a1..41930cc8db 100644 --- a/src/link/Wasm.zig +++ b/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