authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-23 22:45:51+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-25 09:33:15+01:00
logf4adb53bcfff18c24758bf4ea2968efd17911e02
treee8af179bb1a842b1e7dbf6fa63614583bb359667
parent27eb42c15e4e9ab547eaf02cca8810cc0e10e6bf

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.

3 files changed, 55 insertions(+), 45 deletions(-)

src/arch/wasm/CodeGen.zig+5-29
......@@ -645,31 +645,8 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
645645 // In the other cases, we will simply lower the constant to a value that fits
646646 // into a single local (such as a pointer, integer, bool, etc).
647647 const result = if (isByRef(ty, self.target)) blk: {
648 var value_bytes = std.ArrayList(u8).init(self.gpa);
649 defer value_bytes.deinit();
650
651 var decl_gen: DeclGen = .{
652 .bin_file = self.bin_file,
653 .decl = self.decl,
654 .err_msg = undefined,
655 .gpa = self.gpa,
656 .module = self.module,
657 .code = &value_bytes,
658 .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),
659 };
660 const result = decl_gen.genTypedValue(ty, val) catch |err| {
661 // When a codegen error occured, take ownership of the error message
662 if (err == error.CodegenFail) {
663 self.err_msg = decl_gen.err_msg;
664 }
665 return err;
666 };
667 const code = switch (result) {
668 .appended => value_bytes.items,
669 .externally_managed => |data| data,
670 };
671 try self.bin_file.updateLocalSymbolCode(self.decl, decl_gen.symbol_index, code);
672 break :blk WValue{ .memory = decl_gen.symbol_index };
648 const sym_index = try self.bin_file.lowerUnnamedConst(self.decl, .{ .ty = ty, .val = val });
649 break :blk WValue{ .memory = sym_index };
673650 } else try self.lowerConstant(val, ty);
674651
675652 gop.value_ptr.* = result;
......@@ -986,7 +963,7 @@ pub const DeclGen = struct {
986963 }
987964
988965 /// Generates the wasm bytecode for the declaration belonging to `Context`
989 fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
966 pub fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
990967 log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });
991968
992969 const writer = self.code.writer();
......@@ -1324,10 +1301,9 @@ pub const DeclGen = struct {
13241301 try writer.writeIntLittle(u32, 0);
13251302 } else {
13261303 try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(
1327 self.decl, // The decl containing the source symbol index
1328 decl.ty, // type we generate the address of
1304 self.decl, // parent decl that owns the atom of the symbol
13291305 self.symbol_index, // source symbol index
1330 decl.link.wasm.sym_index, // target symbol index
1306 decl, // target decl that contains the target symbol
13311307 @intCast(u32, self.code.items.len), // offset
13321308 @intCast(u32, offset), // addend
13331309 ));
src/link/Wasm.zig+48-15
......@@ -21,6 +21,7 @@ const build_options = @import("build_options");
2121const wasi_libc = @import("../wasi_libc.zig");
2222const Cache = @import("../Cache.zig");
2323const Type = @import("../type.zig").Type;
24const TypedValue = @import("../TypedValue.zig");
2425const LlvmObject = @import("../codegen/llvm.zig").Object;
2526const Air = @import("../Air.zig");
2627const Liveness = @import("../Liveness.zig");
......@@ -497,10 +498,13 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
497498 try atom.code.appendSlice(self.base.allocator, code);
498499}
499500
500/// Creates a new local symbol for a given type (and its bytes it's represented by)
501/// and then append it as a 'contained' atom onto the Decl.
502pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
503 assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
501/// Lowers a constant typed value to a local symbol and atom.
502/// Returns the symbol index of the local
503/// The given `decl` is the parent decl whom owns the constant.
504pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 {
505 assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
506
507 // Create and initialize a new local symbol and atom
504508 const local_index = decl.link.wasm.locals.items.len;
505509 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
506510 var symbol: Symbol = .{
......@@ -510,10 +514,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
510514 .index = undefined,
511515 };
512516 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
513 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
514517
515 var atom = Atom.empty;
516 atom.alignment = ty.abiAlignment(self.base.options.target);
518 const atom = try decl.link.wasm.locals.addOne(self.base.allocator);
519 atom.* = Atom.empty;
520 atom.alignment = tv.ty.abiAlignment(self.base.options.target);
517521 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
518522
519523 if (self.symbols_free_list.popOrNull()) |index| {
......@@ -528,14 +532,36 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
528532 .index = atom.sym_index,
529533 }, {});
530534
531 try decl.link.wasm.locals.append(self.base.allocator, atom);
532 return atom.sym_index;
533}
535 var value_bytes = std.ArrayList(u8).init(self.base.allocator);
536 defer value_bytes.deinit();
537
538 const module = self.base.options.module.?;
539 var decl_gen: CodeGen.DeclGen = .{
540 .bin_file = self,
541 .decl = decl,
542 .err_msg = undefined,
543 .gpa = self.base.allocator,
544 .module = module,
545 .code = &value_bytes,
546 .symbol_index = atom.sym_index,
547 };
548
549 const result = decl_gen.genTypedValue(tv.ty, tv.val) catch |err| switch (err) {
550 error.CodegenFail => {
551 decl.analysis = .codegen_failure;
552 try module.failed_decls.put(module.gpa, decl, decl_gen.err_msg);
553 return error.AnalysisFail;
554 },
555 else => |e| return e,
556 };
557 const code = switch (result) {
558 .appended => value_bytes.items,
559 .externally_managed => |data| data,
560 };
534561
535pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32, code: []const u8) !void {
536 const atom = decl.link.wasm.symbolAtom(symbol_index);
537562 atom.size = @intCast(u32, code.len);
538563 try atom.code.appendSlice(self.base.allocator, code);
564 return atom.sym_index;
539565}
540566
541567/// 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,
543569pub fn getDeclVAddr(
544570 self: *Wasm,
545571 decl: *Module.Decl,
546 ty: Type,
547572 symbol_index: u32,
548 target_symbol_index: u32,
573 target_decl: *Module.Decl,
549574 offset: u32,
550575 addend: u32,
551576) !u32 {
577 const target_symbol_index = target_decl.link.wasm.sym_index;
552578 assert(target_symbol_index != 0);
579 assert(symbol_index != 0);
580
553581 const atom = decl.link.wasm.symbolAtom(symbol_index);
554582 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
555 if (ty.zigTypeTag() == .Fn) {
583 if (target_decl.ty.zigTypeTag() == .Fn) {
556584 assert(addend == 0); // addend not allowed for function relocations
557585 // We found a function pointer, so add it to our table,
558586 // as function pointers are not allowed to be stored inside the data section.
......@@ -1192,6 +1220,11 @@ fn resetState(self: *Wasm) void {
11921220 const atom = &decl.*.link.wasm;
11931221 atom.next = null;
11941222 atom.prev = null;
1223
1224 for (atom.locals.items) |*local_atom| {
1225 local_atom.next = null;
1226 local_atom.prev = null;
1227 }
11951228 }
11961229 self.functions.clearRetainingCapacity();
11971230 self.exports.clearRetainingCapacity();
src/link/Wasm/Atom.zig+2-1
......@@ -170,9 +170,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
170170 .R_WASM_MEMORY_ADDR_SLEB,
171171 .R_WASM_MEMORY_ADDR_SLEB64,
172172 => {
173 if (symbol.isUndefined() and (symbol.tag == .data or symbol.isWeak())) {
173 if (symbol.isUndefined() and symbol.isWeak()) {
174174 return 0;
175175 }
176 std.debug.assert(symbol.tag == .data);
176177 const merge_segment = wasm_bin.base.options.output_mode != .Obj;
177178 const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
178179 const atom_index = wasm_bin.data_segments.get(segment_name).?;