Commit f4adb53bcf

Luuk de Gram <luuk@degram.dev>
2022-02-23 22:45:51
wasm: Refactor lowerUnnamedConst
Rather than ping ponging between codegen and the linker to generate the symbols/atoms for a local constant and its relocations. We now create all neccesary objects within the linker. This simplifies the code as we can now simply call `lowerUnnamedConst` from anywhere in codegen, allowing us to further improve lowering constants into .rodata so we do not have to sacrifice lowering certain types such as decl_ref's where its type is a slice.
1 parent 27eb42c
Changed files (3)
src
arch
link
src/arch/wasm/CodeGen.zig
@@ -645,31 +645,8 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
     // In the other cases, we will simply lower the constant to a value that fits
     // into a single local (such as a pointer, integer, bool, etc).
     const result = if (isByRef(ty, self.target)) blk: {
-        var value_bytes = std.ArrayList(u8).init(self.gpa);
-        defer value_bytes.deinit();
-
-        var decl_gen: DeclGen = .{
-            .bin_file = self.bin_file,
-            .decl = self.decl,
-            .err_msg = undefined,
-            .gpa = self.gpa,
-            .module = self.module,
-            .code = &value_bytes,
-            .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),
-        };
-        const result = decl_gen.genTypedValue(ty, val) catch |err| {
-            // When a codegen error occured, take ownership of the error message
-            if (err == error.CodegenFail) {
-                self.err_msg = decl_gen.err_msg;
-            }
-            return err;
-        };
-        const code = switch (result) {
-            .appended => value_bytes.items,
-            .externally_managed => |data| data,
-        };
-        try self.bin_file.updateLocalSymbolCode(self.decl, decl_gen.symbol_index, code);
-        break :blk WValue{ .memory = decl_gen.symbol_index };
+        const sym_index = try self.bin_file.lowerUnnamedConst(self.decl, .{ .ty = ty, .val = val });
+        break :blk WValue{ .memory = sym_index };
     } else try self.lowerConstant(val, ty);
 
     gop.value_ptr.* = result;
@@ -986,7 +963,7 @@ pub const DeclGen = struct {
     }
 
     /// Generates the wasm bytecode for the declaration belonging to `Context`
-    fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
+    pub fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
         log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });
 
         const writer = self.code.writer();
@@ -1324,10 +1301,9 @@ pub const DeclGen = struct {
             try writer.writeIntLittle(u32, 0);
         } else {
             try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(
-                self.decl, // The decl containing the source symbol index
-                decl.ty, // type we generate the address of
+                self.decl, // parent decl that owns the atom of the symbol
                 self.symbol_index, // source symbol index
-                decl.link.wasm.sym_index, // target symbol index
+                decl, // target decl that contains the target symbol
                 @intCast(u32, self.code.items.len), // offset
                 @intCast(u32, offset), // addend
             ));
src/link/Wasm/Atom.zig
@@ -170,9 +170,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
         .R_WASM_MEMORY_ADDR_SLEB,
         .R_WASM_MEMORY_ADDR_SLEB64,
         => {
-            if (symbol.isUndefined() and (symbol.tag == .data or symbol.isWeak())) {
+            if (symbol.isUndefined() and symbol.isWeak()) {
                 return 0;
             }
+            std.debug.assert(symbol.tag == .data);
             const merge_segment = wasm_bin.base.options.output_mode != .Obj;
             const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
             const atom_index = wasm_bin.data_segments.get(segment_name).?;
src/link/Wasm.zig
@@ -21,6 +21,7 @@ const build_options = @import("build_options");
 const wasi_libc = @import("../wasi_libc.zig");
 const Cache = @import("../Cache.zig");
 const Type = @import("../type.zig").Type;
+const TypedValue = @import("../TypedValue.zig");
 const LlvmObject = @import("../codegen/llvm.zig").Object;
 const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
@@ -497,10 +498,13 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
     try atom.code.appendSlice(self.base.allocator, code);
 }
 
-/// Creates a new local symbol for a given type (and its bytes it's represented by)
-/// and then append it as a 'contained' atom onto the Decl.
-pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
-    assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
+/// Lowers a constant typed value to a local symbol and atom.
+/// Returns the symbol index of the local
+/// The given `decl` is the parent decl whom owns the constant.
+pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 {
+    assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
+
+    // Create and initialize a new local symbol and atom
     const local_index = decl.link.wasm.locals.items.len;
     const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
     var symbol: Symbol = .{
@@ -510,10 +514,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
         .index = undefined,
     };
     symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
-    symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
 
-    var atom = Atom.empty;
-    atom.alignment = ty.abiAlignment(self.base.options.target);
+    const atom = try decl.link.wasm.locals.addOne(self.base.allocator);
+    atom.* = Atom.empty;
+    atom.alignment = tv.ty.abiAlignment(self.base.options.target);
     try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
 
     if (self.symbols_free_list.popOrNull()) |index| {
@@ -528,14 +532,36 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
         .index = atom.sym_index,
     }, {});
 
-    try decl.link.wasm.locals.append(self.base.allocator, atom);
-    return atom.sym_index;
-}
+    var value_bytes = std.ArrayList(u8).init(self.base.allocator);
+    defer value_bytes.deinit();
+
+    const module = self.base.options.module.?;
+    var decl_gen: CodeGen.DeclGen = .{
+        .bin_file = self,
+        .decl = decl,
+        .err_msg = undefined,
+        .gpa = self.base.allocator,
+        .module = module,
+        .code = &value_bytes,
+        .symbol_index = atom.sym_index,
+    };
+
+    const result = decl_gen.genTypedValue(tv.ty, tv.val) catch |err| switch (err) {
+        error.CodegenFail => {
+            decl.analysis = .codegen_failure;
+            try module.failed_decls.put(module.gpa, decl, decl_gen.err_msg);
+            return error.AnalysisFail;
+        },
+        else => |e| return e,
+    };
+    const code = switch (result) {
+        .appended => value_bytes.items,
+        .externally_managed => |data| data,
+    };
 
-pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32, code: []const u8) !void {
-    const atom = decl.link.wasm.symbolAtom(symbol_index);
     atom.size = @intCast(u32, code.len);
     try atom.code.appendSlice(self.base.allocator, code);
+    return atom.sym_index;
 }
 
 /// For a given decl, find the given symbol index's atom, and create a relocation for the type.
@@ -543,16 +569,18 @@ pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32,
 pub fn getDeclVAddr(
     self: *Wasm,
     decl: *Module.Decl,
-    ty: Type,
     symbol_index: u32,
-    target_symbol_index: u32,
+    target_decl: *Module.Decl,
     offset: u32,
     addend: u32,
 ) !u32 {
+    const target_symbol_index = target_decl.link.wasm.sym_index;
     assert(target_symbol_index != 0);
+    assert(symbol_index != 0);
+
     const atom = decl.link.wasm.symbolAtom(symbol_index);
     const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
-    if (ty.zigTypeTag() == .Fn) {
+    if (target_decl.ty.zigTypeTag() == .Fn) {
         assert(addend == 0); // addend not allowed for function relocations
         // We found a function pointer, so add it to our table,
         // as function pointers are not allowed to be stored inside the data section.
@@ -1192,6 +1220,11 @@ fn resetState(self: *Wasm) void {
         const atom = &decl.*.link.wasm;
         atom.next = null;
         atom.prev = null;
+
+        for (atom.locals.items) |*local_atom| {
+            local_atom.next = null;
+            local_atom.prev = null;
+        }
     }
     self.functions.clearRetainingCapacity();
     self.exports.clearRetainingCapacity();