mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 13:30:45 +00:00
wasm: implement lowering anon decls
This commit is contained in:
parent
cbdf4858e8
commit
de78caf9c4
@ -3075,7 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
|
||||
.decl => |decl_index| {
|
||||
return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
|
||||
},
|
||||
.anon_decl => @panic("TODO"),
|
||||
.anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
|
||||
.mut_decl => |mut_decl| {
|
||||
const decl_index = mut_decl.decl;
|
||||
return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
|
||||
@ -3139,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
|
||||
return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
|
||||
}
|
||||
|
||||
fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue {
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
const ty = mod.intern_pool.typeOf(anon_decl).toType();
|
||||
|
||||
const is_fn_body = ty.zigTypeTag(mod) == .Fn;
|
||||
if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) {
|
||||
return WValue{ .imm32 = 0xaaaaaaaa };
|
||||
}
|
||||
|
||||
const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
.fail => |em| {
|
||||
func.err_msg = em;
|
||||
return error.CodegenFail;
|
||||
},
|
||||
}
|
||||
const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?;
|
||||
const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?;
|
||||
if (is_fn_body) {
|
||||
return WValue{ .function_index = target_sym_index };
|
||||
} else if (offset == 0) {
|
||||
return WValue{ .memory = target_sym_index };
|
||||
} else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
|
||||
}
|
||||
|
||||
fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
if (tv.ty.isSlice(mod)) {
|
||||
@ -3306,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||
.mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
|
||||
.int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),
|
||||
.opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
|
||||
.anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
|
||||
else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
|
||||
},
|
||||
.opt => if (ty.optionalReprIsPayload(mod)) {
|
||||
|
||||
@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,
|
||||
/// rather than by the linker.
|
||||
synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
|
||||
/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
|
||||
anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
|
||||
|
||||
pub const Alignment = types.Alignment;
|
||||
|
||||
pub const Segment = struct {
|
||||
@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
}
|
||||
|
||||
wasm.decls.deinit(gpa);
|
||||
wasm.anon_decls.deinit(gpa);
|
||||
wasm.atom_types.deinit(gpa);
|
||||
wasm.symbols.deinit(gpa);
|
||||
wasm.symbols_free_list.deinit(gpa);
|
||||
@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
|
||||
assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
|
||||
const decl = mod.declPtr(decl_index);
|
||||
|
||||
// Create and initialize a new local symbol and atom
|
||||
const atom_index = try wasm.createAtom();
|
||||
const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
|
||||
const parent_atom = wasm.getAtomPtr(parent_atom_index);
|
||||
const parent_atom = wasm.getAtom(parent_atom_index);
|
||||
const local_index = parent_atom.locals.items.len;
|
||||
try parent_atom.locals.append(wasm.base.allocator, atom_index);
|
||||
const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
|
||||
const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{
|
||||
fqn, local_index,
|
||||
});
|
||||
defer wasm.base.allocator.free(name);
|
||||
|
||||
switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
|
||||
.ok => |atom_index| {
|
||||
try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index);
|
||||
return wasm.getAtom(atom_index).getSymbolIndex().?;
|
||||
},
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try mod.failed_decls.put(mod.gpa, decl_index, em);
|
||||
return error.CodegenFail;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const LowerConstResult = union(enum) {
|
||||
ok: Atom.Index,
|
||||
fail: *Module.ErrorMsg,
|
||||
};
|
||||
|
||||
fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
|
||||
const mod = wasm.base.options.module.?;
|
||||
|
||||
// Create and initialize a new local symbol and atom
|
||||
const atom_index = try wasm.createAtom();
|
||||
var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
|
||||
defer value_bytes.deinit();
|
||||
|
||||
@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
|
||||
|
||||
const result = try codegen.generateSymbol(
|
||||
&wasm.base,
|
||||
decl.srcLoc(mod),
|
||||
src_loc,
|
||||
tv,
|
||||
&value_bytes,
|
||||
.none,
|
||||
@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
|
||||
break :code switch (result) {
|
||||
.ok => value_bytes.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try mod.failed_decls.put(mod.gpa, decl_index, em);
|
||||
return error.CodegenFail;
|
||||
return .{ .fail = em };
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
atom.size = @as(u32, @intCast(code.len));
|
||||
atom.size = @intCast(code.len);
|
||||
try atom.code.appendSlice(wasm.base.allocator, code);
|
||||
return atom.sym_index;
|
||||
return .{ .ok = atom_index };
|
||||
}
|
||||
|
||||
/// Returns the symbol index from a symbol of which its flag is set global,
|
||||
@ -1679,27 +1702,61 @@ pub fn getDeclVAddr(
|
||||
return target_symbol_index;
|
||||
}
|
||||
|
||||
pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
|
||||
// This is basically the same as lowerUnnamedConst.
|
||||
// example:
|
||||
// const ty = mod.intern_pool.typeOf(decl_val).toType();
|
||||
// const val = decl_val.toValue();
|
||||
// The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
|
||||
// It doesn't have an owner decl because it's just an unnamed constant that might
|
||||
// be used by more than one function, however, its address is being used so we need
|
||||
// to put it in some location.
|
||||
// ...
|
||||
_ = self;
|
||||
_ = decl_val;
|
||||
_ = src_loc;
|
||||
_ = @panic("TODO: link/Wasm lowerAnonDecl");
|
||||
pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
|
||||
const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
|
||||
if (gop.found_existing) {
|
||||
return .ok;
|
||||
}
|
||||
|
||||
const mod = wasm.base.options.module.?;
|
||||
const ty = mod.intern_pool.typeOf(decl_val).toType();
|
||||
const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };
|
||||
const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)});
|
||||
defer wasm.base.allocator.free(name);
|
||||
|
||||
switch (try wasm.lowerConst(name, tv, src_loc)) {
|
||||
.ok => |atom_index| {
|
||||
gop.value_ptr.* = atom_index;
|
||||
return .ok;
|
||||
},
|
||||
.fail => |em| return .{ .fail = em },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
_ = wasm;
|
||||
_ = decl_val;
|
||||
_ = reloc_info;
|
||||
_ = @panic("TODO: link/Wasm getAnonDeclVAddr");
|
||||
const atom_index = wasm.anon_decls.get(decl_val).?;
|
||||
const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
|
||||
|
||||
const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
|
||||
const parent_atom = wasm.getAtomPtr(parent_atom_index);
|
||||
const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
|
||||
const mod = wasm.base.options.module.?;
|
||||
const ty = mod.intern_pool.typeOf(decl_val).toType();
|
||||
if (ty.zigTypeTag(mod) == .Fn) {
|
||||
assert(reloc_info.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.
|
||||
// They are instead stored in a function table which are called by index.
|
||||
try wasm.addTableFunction(target_symbol_index);
|
||||
try parent_atom.relocs.append(wasm.base.allocator, .{
|
||||
.index = target_symbol_index,
|
||||
.offset = @as(u32, @intCast(reloc_info.offset)),
|
||||
.relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
|
||||
});
|
||||
} else {
|
||||
try parent_atom.relocs.append(wasm.base.allocator, .{
|
||||
.index = target_symbol_index,
|
||||
.offset = @as(u32, @intCast(reloc_info.offset)),
|
||||
.relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
|
||||
.addend = @as(i32, @intCast(reloc_info.addend)),
|
||||
});
|
||||
}
|
||||
|
||||
// we do not know the final address at this point,
|
||||
// as atom allocation will determine the address and relocations
|
||||
// will calculate and rewrite this. Therefore, we simply return the symbol index
|
||||
// that was targeted.
|
||||
return target_symbol_index;
|
||||
}
|
||||
|
||||
pub 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
|
||||
try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
|
||||
}
|
||||
}
|
||||
// parse anonymous declarations
|
||||
for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| {
|
||||
const ty = mod.intern_pool.typeOf(decl_val).toType();
|
||||
if (ty.zigTypeTag(mod) == .Fn) {
|
||||
try wasm.parseAtom(atom_index, .function);
|
||||
} else {
|
||||
try wasm.parseAtom(atom_index, .{ .data = .read_only });
|
||||
}
|
||||
}
|
||||
|
||||
// also parse any backend-generated functions
|
||||
for (wasm.synthetic_functions.items) |atom_index| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user