authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-10-03 17:05:08+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 12:49:29-07:00
logde78caf9c404e8c93beb67fcb0daf42cb40cb1f9
treebfb5529dba01d053970f065bb6fbd44b110e302a
parentcbdf4858e887bdc647cd86b9d77ce111d710a0b8

wasm: implement lowering anon decls


2 files changed, 122 insertions(+), 29 deletions(-)

src/arch/wasm/CodeGen.zig+28-1
......@@ -3075,7 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
30753075 .decl => |decl_index| {
30763076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
30773077 },
3078 .anon_decl => @panic("TODO"),
3078 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
30793079 .mut_decl => |mut_decl| {
30803080 const decl_index = mut_decl.decl;
30813081 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
......@@ -3139,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
31393139 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
31403140}
31413141
3142fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue {
3143 const mod = func.bin_file.base.options.module.?;
3144 const ty = mod.intern_pool.typeOf(anon_decl).toType();
3145
3146 const is_fn_body = ty.zigTypeTag(mod) == .Fn;
3147 if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) {
3148 return WValue{ .imm32 = 0xaaaaaaaa };
3149 }
3150
3151 const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod));
3152 switch (res) {
3153 .ok => {},
3154 .fail => |em| {
3155 func.err_msg = em;
3156 return error.CodegenFail;
3157 },
3158 }
3159 const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?;
3160 const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?;
3161 if (is_fn_body) {
3162 return WValue{ .function_index = target_sym_index };
3163 } else if (offset == 0) {
3164 return WValue{ .memory = target_sym_index };
3165 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
3166}
3167
31423168fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
31433169 const mod = func.bin_file.base.options.module.?;
31443170 if (tv.ty.isSlice(mod)) {
......@@ -3306,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
33063332 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
33073333 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),
33083334 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3335 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
33093336 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
33103337 },
33113338 .opt => if (ty.optionalReprIsPayload(mod)) {
src/link/Wasm.zig+94-28
......@@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,
187187/// rather than by the linker.
188188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
189189
190/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
191anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
192
190193pub const Alignment = types.Alignment;
191194
192195pub const Segment = struct {
......@@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {
12911294 }
12921295
12931296 wasm.decls.deinit(gpa);
1297 wasm.anon_decls.deinit(gpa);
12941298 wasm.atom_types.deinit(gpa);
12951299 wasm.symbols.deinit(gpa);
12961300 wasm.symbols_free_list.deinit(gpa);
......@@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
15481552 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
15491553 const decl = mod.declPtr(decl_index);
15501554
1551 // Create and initialize a new local symbol and atom
1552 const atom_index = try wasm.createAtom();
15531555 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1554 const parent_atom = wasm.getAtomPtr(parent_atom_index);
1556 const parent_atom = wasm.getAtom(parent_atom_index);
15551557 const local_index = parent_atom.locals.items.len;
1556 try parent_atom.locals.append(wasm.base.allocator, atom_index);
15571558 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
15581559 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{
15591560 fqn, local_index,
15601561 });
15611562 defer wasm.base.allocator.free(name);
1563
1564 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
1565 .ok => |atom_index| {
1566 try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index);
1567 return wasm.getAtom(atom_index).getSymbolIndex().?;
1568 },
1569 .fail => |em| {
1570 decl.analysis = .codegen_failure;
1571 try mod.failed_decls.put(mod.gpa, decl_index, em);
1572 return error.CodegenFail;
1573 },
1574 }
1575}
1576
1577const LowerConstResult = union(enum) {
1578 ok: Atom.Index,
1579 fail: *Module.ErrorMsg,
1580};
1581
1582fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
1583 const mod = wasm.base.options.module.?;
1584
1585 // Create and initialize a new local symbol and atom
1586 const atom_index = try wasm.createAtom();
15621587 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
15631588 defer value_bytes.deinit();
15641589
......@@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
15761601
15771602 const result = try codegen.generateSymbol(
15781603 &wasm.base,
1579 decl.srcLoc(mod),
1604 src_loc,
15801605 tv,
15811606 &value_bytes,
15821607 .none,
......@@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
15881613 break :code switch (result) {
15891614 .ok => value_bytes.items,
15901615 .fail => |em| {
1591 decl.analysis = .codegen_failure;
1592 try mod.failed_decls.put(mod.gpa, decl_index, em);
1593 return error.CodegenFail;
1616 return .{ .fail = em };
15941617 },
15951618 };
15961619 };
15971620
15981621 const atom = wasm.getAtomPtr(atom_index);
1599 atom.size = @as(u32, @intCast(code.len));
1622 atom.size = @intCast(code.len);
16001623 try atom.code.appendSlice(wasm.base.allocator, code);
1601 return atom.sym_index;
1624 return .{ .ok = atom_index };
16021625}
16031626
16041627/// Returns the symbol index from a symbol of which its flag is set global,
......@@ -1679,27 +1702,61 @@ pub fn getDeclVAddr(
16791702 return target_symbol_index;
16801703}
16811704
1682pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1683 // This is basically the same as lowerUnnamedConst.
1684 // example:
1685 // const ty = mod.intern_pool.typeOf(decl_val).toType();
1686 // const val = decl_val.toValue();
1687 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
1688 // It doesn't have an owner decl because it's just an unnamed constant that might
1689 // be used by more than one function, however, its address is being used so we need
1690 // to put it in some location.
1691 // ...
1692 _ = self;
1693 _ = decl_val;
1694 _ = src_loc;
1695 _ = @panic("TODO: link/Wasm lowerAnonDecl");
1705pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1706 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
1707 if (gop.found_existing) {
1708 return .ok;
1709 }
1710
1711 const mod = wasm.base.options.module.?;
1712 const ty = mod.intern_pool.typeOf(decl_val).toType();
1713 const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };
1714 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)});
1715 defer wasm.base.allocator.free(name);
1716
1717 switch (try wasm.lowerConst(name, tv, src_loc)) {
1718 .ok => |atom_index| {
1719 gop.value_ptr.* = atom_index;
1720 return .ok;
1721 },
1722 .fail => |em| return .{ .fail = em },
1723 }
16961724}
16971725
16981726pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1699 _ = wasm;
1700 _ = decl_val;
1701 _ = reloc_info;
1702 _ = @panic("TODO: link/Wasm getAnonDeclVAddr");
1727 const atom_index = wasm.anon_decls.get(decl_val).?;
1728 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
1729
1730 const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1731 const parent_atom = wasm.getAtomPtr(parent_atom_index);
1732 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
1733 const mod = wasm.base.options.module.?;
1734 const ty = mod.intern_pool.typeOf(decl_val).toType();
1735 if (ty.zigTypeTag(mod) == .Fn) {
1736 assert(reloc_info.addend == 0); // addend not allowed for function relocations
1737 // We found a function pointer, so add it to our table,
1738 // as function pointers are not allowed to be stored inside the data section.
1739 // They are instead stored in a function table which are called by index.
1740 try wasm.addTableFunction(target_symbol_index);
1741 try parent_atom.relocs.append(wasm.base.allocator, .{
1742 .index = target_symbol_index,
1743 .offset = @as(u32, @intCast(reloc_info.offset)),
1744 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1745 });
1746 } else {
1747 try parent_atom.relocs.append(wasm.base.allocator, .{
1748 .index = target_symbol_index,
1749 .offset = @as(u32, @intCast(reloc_info.offset)),
1750 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1751 .addend = @as(i32, @intCast(reloc_info.addend)),
1752 });
1753 }
1754
1755 // we do not know the final address at this point,
1756 // as atom allocation will determine the address and relocations
1757 // will calculate and rewrite this. Therefore, we simply return the symbol index
1758 // that was targeted.
1759 return target_symbol_index;
17031760}
17041761
17051762pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
......@@ -3465,6 +3522,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
34653522 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
34663523 }
34673524 }
3525 // parse anonymous declarations
3526 for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| {
3527 const ty = mod.intern_pool.typeOf(decl_val).toType();
3528 if (ty.zigTypeTag(mod) == .Fn) {
3529 try wasm.parseAtom(atom_index, .function);
3530 } else {
3531 try wasm.parseAtom(atom_index, .{ .data = .read_only });
3532 }
3533 }
34683534
34693535 // also parse any backend-generated functions
34703536 for (wasm.synthetic_functions.items) |atom_index| {