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.
This commit is contained in:
Luuk de Gram 2022-02-23 22:45:51 +01:00
parent 27eb42c15e
commit f4adb53bcf
3 changed files with 55 additions and 45 deletions

View File

@ -645,31 +645,8 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
// In the other cases, we will simply lower the constant to a value that fits
// into a single local (such as a pointer, integer, bool, etc).
const result = if (isByRef(ty, self.target)) blk: {
var value_bytes = std.ArrayList(u8).init(self.gpa);
defer value_bytes.deinit();
var decl_gen: DeclGen = .{
.bin_file = self.bin_file,
.decl = self.decl,
.err_msg = undefined,
.gpa = self.gpa,
.module = self.module,
.code = &value_bytes,
.symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty),
};
const result = decl_gen.genTypedValue(ty, val) catch |err| {
// When a codegen error occured, take ownership of the error message
if (err == error.CodegenFail) {
self.err_msg = decl_gen.err_msg;
}
return err;
};
const code = switch (result) {
.appended => value_bytes.items,
.externally_managed => |data| data,
};
try self.bin_file.updateLocalSymbolCode(self.decl, decl_gen.symbol_index, code);
break :blk WValue{ .memory = decl_gen.symbol_index };
const sym_index = try self.bin_file.lowerUnnamedConst(self.decl, .{ .ty = ty, .val = val });
break :blk WValue{ .memory = sym_index };
} else try self.lowerConstant(val, ty);
gop.value_ptr.* = result;
@ -986,7 +963,7 @@ pub const DeclGen = struct {
}
/// Generates the wasm bytecode for the declaration belonging to `Context`
fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
pub fn genTypedValue(self: *DeclGen, ty: Type, val: Value) InnerError!Result {
log.debug("genTypedValue: ty = {}, val = {}", .{ ty, val });
const writer = self.code.writer();
@ -1324,10 +1301,9 @@ pub const DeclGen = struct {
try writer.writeIntLittle(u32, 0);
} else {
try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(
self.decl, // The decl containing the source symbol index
decl.ty, // type we generate the address of
self.decl, // parent decl that owns the atom of the symbol
self.symbol_index, // source symbol index
decl.link.wasm.sym_index, // target symbol index
decl, // target decl that contains the target symbol
@intCast(u32, self.code.items.len), // offset
@intCast(u32, offset), // addend
));

View File

@ -21,6 +21,7 @@ const build_options = @import("build_options");
const wasi_libc = @import("../wasi_libc.zig");
const Cache = @import("../Cache.zig");
const Type = @import("../type.zig").Type;
const TypedValue = @import("../TypedValue.zig");
const LlvmObject = @import("../codegen/llvm.zig").Object;
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
@ -497,10 +498,13 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
try atom.code.appendSlice(self.base.allocator, code);
}
/// Creates a new local symbol for a given type (and its bytes it's represented by)
/// and then append it as a 'contained' atom onto the Decl.
pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
/// Lowers a constant typed value to a local symbol and atom.
/// Returns the symbol index of the local
/// The given `decl` is the parent decl whom owns the constant.
pub fn lowerUnnamedConst(self: *Wasm, decl: *Module.Decl, tv: TypedValue) !u32 {
assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
// Create and initialize a new local symbol and atom
const local_index = decl.link.wasm.locals.items.len;
const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
var symbol: Symbol = .{
@ -510,10 +514,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
.index = undefined,
};
symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
var atom = Atom.empty;
atom.alignment = ty.abiAlignment(self.base.options.target);
const atom = try decl.link.wasm.locals.addOne(self.base.allocator);
atom.* = Atom.empty;
atom.alignment = tv.ty.abiAlignment(self.base.options.target);
try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
if (self.symbols_free_list.popOrNull()) |index| {
@ -528,14 +532,36 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
.index = atom.sym_index,
}, {});
try decl.link.wasm.locals.append(self.base.allocator, atom);
return atom.sym_index;
}
var value_bytes = std.ArrayList(u8).init(self.base.allocator);
defer value_bytes.deinit();
const module = self.base.options.module.?;
var decl_gen: CodeGen.DeclGen = .{
.bin_file = self,
.decl = decl,
.err_msg = undefined,
.gpa = self.base.allocator,
.module = module,
.code = &value_bytes,
.symbol_index = atom.sym_index,
};
const result = decl_gen.genTypedValue(tv.ty, tv.val) catch |err| switch (err) {
error.CodegenFail => {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, decl_gen.err_msg);
return error.AnalysisFail;
},
else => |e| return e,
};
const code = switch (result) {
.appended => value_bytes.items,
.externally_managed => |data| data,
};
pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32, code: []const u8) !void {
const atom = decl.link.wasm.symbolAtom(symbol_index);
atom.size = @intCast(u32, code.len);
try atom.code.appendSlice(self.base.allocator, code);
return atom.sym_index;
}
/// 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,
pub fn getDeclVAddr(
self: *Wasm,
decl: *Module.Decl,
ty: Type,
symbol_index: u32,
target_symbol_index: u32,
target_decl: *Module.Decl,
offset: u32,
addend: u32,
) !u32 {
const target_symbol_index = target_decl.link.wasm.sym_index;
assert(target_symbol_index != 0);
assert(symbol_index != 0);
const atom = decl.link.wasm.symbolAtom(symbol_index);
const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
if (ty.zigTypeTag() == .Fn) {
if (target_decl.ty.zigTypeTag() == .Fn) {
assert(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.
@ -1192,6 +1220,11 @@ fn resetState(self: *Wasm) void {
const atom = &decl.*.link.wasm;
atom.next = null;
atom.prev = null;
for (atom.locals.items) |*local_atom| {
local_atom.next = null;
local_atom.prev = null;
}
}
self.functions.clearRetainingCapacity();
self.exports.clearRetainingCapacity();

View File

@ -170,9 +170,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
.R_WASM_MEMORY_ADDR_SLEB,
.R_WASM_MEMORY_ADDR_SLEB64,
=> {
if (symbol.isUndefined() and (symbol.tag == .data or symbol.isWeak())) {
if (symbol.isUndefined() and symbol.isWeak()) {
return 0;
}
std.debug.assert(symbol.tag == .data);
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
const atom_index = wasm_bin.data_segments.get(segment_name).?;