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 {...@@ -645,31 +645,8 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
645 // In the other cases, we will simply lower the constant to a value that fits645 // In the other cases, we will simply lower the constant to a value that fits
646 // into a single local (such as a pointer, integer, bool, etc).646 // into a single local (such as a pointer, integer, bool, etc).
647 const result = if (isByRef(ty, self.target)) blk: {647 const result = if (isByRef(ty, self.target)) blk: {
648 var value_bytes = std.ArrayList(u8).init(self.gpa);648 const sym_index = try self.bin_file.lowerUnnamedConst(self.decl, .{ .ty = ty, .val = val });
649 defer value_bytes.deinit();649 break :blk WValue{ .memory = sym_index };
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 };
673 } else try self.lowerConstant(val, ty);650 } else try self.lowerConstant(val, ty);
674651
675 gop.value_ptr.* = result;652 gop.value_ptr.* = result;
...@@ -986,7 +963,7 @@ pub const DeclGen = struct {...@@ -986,7 +963,7 @@ pub const DeclGen = struct {
986 }963 }
987964
988 /// Generates the wasm bytecode for the declaration belonging to `Context`965 /// 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 {
990 log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });967 log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });
991968
992 const writer = self.code.writer();969 const writer = self.code.writer();
...@@ -1324,10 +1301,9 @@ pub const DeclGen = struct {...@@ -1324,10 +1301,9 @@ pub const DeclGen = struct {
1324 try writer.writeIntLittle(u32, 0);1301 try writer.writeIntLittle(u32, 0);
1325 } else {1302 } else {
1326 try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(1303 try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(
1327 self.decl, // The decl containing the source symbol index1304 self.decl, // parent decl that owns the atom of the symbol
1328 decl.ty, // type we generate the address of
1329 self.symbol_index, // source symbol index1305 self.symbol_index, // source symbol index
1330 decl.link.wasm.sym_index, // target symbol index1306 decl, // target decl that contains the target symbol
1331 @intCast(u32, self.code.items.len), // offset1307 @intCast(u32, self.code.items.len), // offset
1332 @intCast(u32, offset), // addend1308 @intCast(u32, offset), // addend
1333 ));1309 ));
src/link/Wasm.zig+48-15
...@@ -21,6 +21,7 @@ const build_options = @import("build_options");...@@ -21,6 +21,7 @@ const build_options = @import("build_options");
21const wasi_libc = @import("../wasi_libc.zig");21const wasi_libc = @import("../wasi_libc.zig");
22const Cache = @import("../Cache.zig");22const Cache = @import("../Cache.zig");
23const Type = @import("../type.zig").Type;23const Type = @import("../type.zig").Type;
24const TypedValue = @import("../TypedValue.zig");
24const LlvmObject = @import("../codegen/llvm.zig").Object;25const LlvmObject = @import("../codegen/llvm.zig").Object;
25const Air = @import("../Air.zig");26const Air = @import("../Air.zig");
26const Liveness = @import("../Liveness.zig");27const Liveness = @import("../Liveness.zig");
...@@ -497,10 +498,13 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {...@@ -497,10 +498,13 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
497 try atom.code.appendSlice(self.base.allocator, code);498 try atom.code.appendSlice(self.base.allocator, code);
498}499}
499500
500/// Creates a new local symbol for a given type (and its bytes it's represented by)501/// Lowers a constant typed value to a local symbol and atom.
501/// and then append it as a 'contained' atom onto the Decl.502/// Returns the symbol index of the local
502pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {503/// The given `decl` is the parent decl whom owns the constant.
503 assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions504pub 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
504 const local_index = decl.link.wasm.locals.items.len;508 const local_index = decl.link.wasm.locals.items.len;
505 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });509 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
506 var symbol: Symbol = .{510 var symbol: Symbol = .{
...@@ -510,10 +514,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {...@@ -510,10 +514,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
510 .index = undefined,514 .index = undefined,
511 };515 };
512 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);516 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
513 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
514517
515 var atom = Atom.empty;518 const atom = try decl.link.wasm.locals.addOne(self.base.allocator);
516 atom.alignment = ty.abiAlignment(self.base.options.target);519 atom.* = Atom.empty;
520 atom.alignment = tv.ty.abiAlignment(self.base.options.target);
517 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);521 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
518522
519 if (self.symbols_free_list.popOrNull()) |index| {523 if (self.symbols_free_list.popOrNull()) |index| {
...@@ -528,14 +532,36 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {...@@ -528,14 +532,36 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
528 .index = atom.sym_index,532 .index = atom.sym_index,
529 }, {});533 }, {});
530534
531 try decl.link.wasm.locals.append(self.base.allocator, atom);535 var value_bytes = std.ArrayList(u8).init(self.base.allocator);
532 return atom.sym_index;536 defer value_bytes.deinit();
533}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);
537 atom.size = @intCast(u32, code.len);562 atom.size = @intCast(u32, code.len);
538 try atom.code.appendSlice(self.base.allocator, code);563 try atom.code.appendSlice(self.base.allocator, code);
564 return atom.sym_index;
539}565}
540566
541/// For a given decl, find the given symbol index's atom, and create a relocation for the type.567/// 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,...@@ -543,16 +569,18 @@ pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32,
543pub fn getDeclVAddr(569pub fn getDeclVAddr(
544 self: *Wasm,570 self: *Wasm,
545 decl: *Module.Decl,571 decl: *Module.Decl,
546 ty: Type,
547 symbol_index: u32,572 symbol_index: u32,
548 target_symbol_index: u32,573 target_decl: *Module.Decl,
549 offset: u32,574 offset: u32,
550 addend: u32,575 addend: u32,
551) !u32 {576) !u32 {
577 const target_symbol_index = target_decl.link.wasm.sym_index;
552 assert(target_symbol_index != 0);578 assert(target_symbol_index != 0);
579 assert(symbol_index != 0);
580
553 const atom = decl.link.wasm.symbolAtom(symbol_index);581 const atom = decl.link.wasm.symbolAtom(symbol_index);
554 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;582 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
555 if (ty.zigTypeTag() == .Fn) {583 if (target_decl.ty.zigTypeTag() == .Fn) {
556 assert(addend == 0); // addend not allowed for function relocations584 assert(addend == 0); // addend not allowed for function relocations
557 // We found a function pointer, so add it to our table,585 // We found a function pointer, so add it to our table,
558 // as function pointers are not allowed to be stored inside the data section.586 // as function pointers are not allowed to be stored inside the data section.
...@@ -1192,6 +1220,11 @@ fn resetState(self: *Wasm) void {...@@ -1192,6 +1220,11 @@ fn resetState(self: *Wasm) void {
1192 const atom = &decl.*.link.wasm;1220 const atom = &decl.*.link.wasm;
1193 atom.next = null;1221 atom.next = null;
1194 atom.prev = null;1222 atom.prev = null;
1223
1224 for (atom.locals.items) |*local_atom| {
1225 local_atom.next = null;
1226 local_atom.prev = null;
1227 }
1195 }1228 }
1196 self.functions.clearRetainingCapacity();1229 self.functions.clearRetainingCapacity();
1197 self.exports.clearRetainingCapacity();1230 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...@@ -170,9 +170,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
170 .R_WASM_MEMORY_ADDR_SLEB,170 .R_WASM_MEMORY_ADDR_SLEB,
171 .R_WASM_MEMORY_ADDR_SLEB64,171 .R_WASM_MEMORY_ADDR_SLEB64,
172 => {172 => {
173 if (symbol.isUndefined() and (symbol.tag == .data or symbol.isWeak())) {173 if (symbol.isUndefined() and symbol.isWeak()) {
174 return 0;174 return 0;
175 }175 }
176 std.debug.assert(symbol.tag == .data);
176 const merge_segment = wasm_bin.base.options.output_mode != .Obj;177 const merge_segment = wasm_bin.base.options.output_mode != .Obj;
177 const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);178 const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
178 const atom_index = wasm_bin.data_segments.get(segment_name).?;179 const atom_index = wasm_bin.data_segments.get(segment_name).?;