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...@@ -3075,7 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
3075 .decl => |decl_index| {3075 .decl => |decl_index| {
3076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
3077 },3077 },
3078 .anon_decl => @panic("TODO"),3078 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
3079 .mut_decl => |mut_decl| {3079 .mut_decl => |mut_decl| {
3080 const decl_index = mut_decl.decl;3080 const decl_index = mut_decl.decl;
3081 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3081 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
...@@ -3139,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In...@@ -3139,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
3139 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);3139 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
3140}3140}
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
3142fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {3168fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
3143 const mod = func.bin_file.base.options.module.?;3169 const mod = func.bin_file.base.options.module.?;
3144 if (tv.ty.isSlice(mod)) {3170 if (tv.ty.isSlice(mod)) {
...@@ -3306,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3306,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3306 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),3332 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
3307 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),3333 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),
3308 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),3334 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3335 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
3309 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),3336 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
3310 },3337 },
3311 .opt => if (ty.optionalReprIsPayload(mod)) {3338 .opt => if (ty.optionalReprIsPayload(mod)) {
src/link/Wasm.zig+94-28
...@@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,...@@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,
187/// rather than by the linker.187/// rather than by the linker.
188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},188synthetic_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
190pub const Alignment = types.Alignment;193pub const Alignment = types.Alignment;
191194
192pub const Segment = struct {195pub const Segment = struct {
...@@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {
1291 }1294 }
12921295
1293 wasm.decls.deinit(gpa);1296 wasm.decls.deinit(gpa);
1297 wasm.anon_decls.deinit(gpa);
1294 wasm.atom_types.deinit(gpa);1298 wasm.atom_types.deinit(gpa);
1295 wasm.symbols.deinit(gpa);1299 wasm.symbols.deinit(gpa);
1296 wasm.symbols_free_list.deinit(gpa);1300 wasm.symbols_free_list.deinit(gpa);
...@@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1548 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions1552 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
1549 const decl = mod.declPtr(decl_index);1553 const decl = mod.declPtr(decl_index);
15501554
1551 // Create and initialize a new local symbol and atom
1552 const atom_index = try wasm.createAtom();
1553 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);1555 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);
1555 const local_index = parent_atom.locals.items.len;1557 const local_index = parent_atom.locals.items.len;
1556 try parent_atom.locals.append(wasm.base.allocator, atom_index);
1557 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1558 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1558 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{1559 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{
1559 fqn, local_index,1560 fqn, local_index,
1560 });1561 });
1561 defer wasm.base.allocator.free(name);1562 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();
1562 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);1587 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
1563 defer value_bytes.deinit();1588 defer value_bytes.deinit();
15641589
...@@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
15761601
1577 const result = try codegen.generateSymbol(1602 const result = try codegen.generateSymbol(
1578 &wasm.base,1603 &wasm.base,
1579 decl.srcLoc(mod),1604 src_loc,
1580 tv,1605 tv,
1581 &value_bytes,1606 &value_bytes,
1582 .none,1607 .none,
...@@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1588 break :code switch (result) {1613 break :code switch (result) {
1589 .ok => value_bytes.items,1614 .ok => value_bytes.items,
1590 .fail => |em| {1615 .fail => |em| {
1591 decl.analysis = .codegen_failure;1616 return .{ .fail = em };
1592 try mod.failed_decls.put(mod.gpa, decl_index, em);
1593 return error.CodegenFail;
1594 },1617 },
1595 };1618 };
1596 };1619 };
15971620
1598 const atom = wasm.getAtomPtr(atom_index);1621 const atom = wasm.getAtomPtr(atom_index);
1599 atom.size = @as(u32, @intCast(code.len));1622 atom.size = @intCast(code.len);
1600 try atom.code.appendSlice(wasm.base.allocator, code);1623 try atom.code.appendSlice(wasm.base.allocator, code);
1601 return atom.sym_index;1624 return .{ .ok = atom_index };
1602}1625}
16031626
1604/// Returns the symbol index from a symbol of which its flag is set global,1627/// Returns the symbol index from a symbol of which its flag is set global,
...@@ -1679,27 +1702,61 @@ pub fn getDeclVAddr(...@@ -1679,27 +1702,61 @@ pub fn getDeclVAddr(
1679 return target_symbol_index;1702 return target_symbol_index;
1680}1703}
16811704
1682pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {1705pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1683 // This is basically the same as lowerUnnamedConst.1706 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
1684 // example:1707 if (gop.found_existing) {
1685 // const ty = mod.intern_pool.typeOf(decl_val).toType();1708 return .ok;
1686 // const val = decl_val.toValue();1709 }
1687 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.1710
1688 // It doesn't have an owner decl because it's just an unnamed constant that might1711 const mod = wasm.base.options.module.?;
1689 // be used by more than one function, however, its address is being used so we need1712 const ty = mod.intern_pool.typeOf(decl_val).toType();
1690 // to put it in some location.1713 const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };
1691 // ...1714 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)});
1692 _ = self;1715 defer wasm.base.allocator.free(name);
1693 _ = decl_val;1716
1694 _ = src_loc;1717 switch (try wasm.lowerConst(name, tv, src_loc)) {
1695 _ = @panic("TODO: link/Wasm lowerAnonDecl");1718 .ok => |atom_index| {
1719 gop.value_ptr.* = atom_index;
1720 return .ok;
1721 },
1722 .fail => |em| return .{ .fail = em },
1723 }
1696}1724}
16971725
1698pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1726pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1699 _ = wasm;1727 const atom_index = wasm.anon_decls.get(decl_val).?;
1700 _ = decl_val;1728 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
1701 _ = reloc_info;1729
1702 _ = @panic("TODO: link/Wasm getAnonDeclVAddr");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;
1703}1760}
17041761
1705pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {1762pub 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...@@ -3465,6 +3522,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3465 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });3522 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
3466 }3523 }
3467 }3524 }
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
3469 // also parse any backend-generated functions3535 // also parse any backend-generated functions
3470 for (wasm.synthetic_functions.items) |atom_index| {3536 for (wasm.synthetic_functions.items) |atom_index| {