let's make wasm codegen emit MIR

which is then lowered to wasm code during linking, with optimal function
indexes etc, or relocations are emitted if outputting an object.
This commit is contained in:
Andrew Kelley 2024-11-12 00:27:39 -08:00
parent c4b2bdb12c
commit 12467ec721
3 changed files with 25 additions and 42 deletions

View File

@ -54,22 +54,19 @@ const WValue = union(enum) {
float32: f32,
/// A constant 64bit float value
float64: f64,
/// A value that represents a pointer to the data section
/// Note: The value contains the symbol index, rather than the actual address
/// as we use this to perform the relocation.
memory: u32,
/// A value that represents a pointer to the data section.
memory: InternPool.Index,
/// A value that represents a parent pointer and an offset
/// from that pointer. i.e. when slicing with constant values.
memory_offset: struct {
/// The symbol of the parent pointer
pointer: u32,
pointer: InternPool.Index,
/// Offset will be set as addend when relocating
offset: u32,
},
/// Represents a function pointer
/// In wasm function pointers are indexes into a function table,
/// rather than an address in the data section.
function_index: u32,
function_index: InternPool.Index,
/// Offset from the bottom of the virtual stack, with the offset
/// pointing to where the value lives.
stack_offset: struct {
@ -775,13 +772,7 @@ fn resolveInst(func: *CodeGen, 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: WValue = if (isByRef(ty, pt, func.target.*))
switch (try func.bin_file.lowerUav(pt, val.toIntern(), .none, func.src_loc)) {
.mcv => |mcv| .{ .memory = mcv.load_symbol },
.fail => |err_msg| {
func.err_msg = err_msg;
return error.CodegenFail;
},
}
.{ .memory = val.toIntern() }
else
try func.lowerConstant(val, ty);
@ -3164,20 +3155,14 @@ fn lowerUavRef(
return .{ .imm32 = 0xaaaaaaaa };
}
const decl_align = zcu.intern_pool.indexToKey(uav.orig_ty).ptr_type.flags.alignment;
const res = try func.bin_file.lowerUav(pt, uav.val, decl_align, func.src_loc);
const target_sym_index = switch (res) {
.mcv => |mcv| mcv.load_symbol,
.fail => |err_msg| {
func.err_msg = err_msg;
return error.CodegenFail;
},
};
if (is_fn_body) {
return .{ .function_index = target_sym_index };
} else if (offset == 0) {
return .{ .memory = target_sym_index };
} else return .{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
return if (is_fn_body) .{
.function_index = uav.val,
} else if (offset == 0) .{
.memory = uav.val,
} else .{ .memory_offset = .{
.pointer = uav.val,
.offset = offset,
} };
}
fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) InnerError!WValue {
@ -3309,13 +3294,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.f64 => |f64_val| return .{ .float64 = f64_val },
else => unreachable,
},
.slice => switch (try func.bin_file.lowerUav(pt, val.toIntern(), .none, func.src_loc)) {
.mcv => |mcv| return .{ .memory = mcv.load_symbol },
.fail => |err_msg| {
func.err_msg = err_msg;
return error.CodegenFail;
},
},
.slice => return .{ .memory = val.toIntern() },
.ptr => return func.lowerPtr(val.toIntern(), 0),
.opt => if (ty.optionalReprIsPayload(zcu)) {
const pl_ty = ty.optionalChild(zcu);

View File

@ -1348,18 +1348,14 @@ pub fn flush(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: st
return wasm.flushModule(arena, tid, prog_node);
}
pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) anyerror!void {
pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
const sub_prog_node = prog_node.start("Wasm Prelink", 0);
defer sub_prog_node.end();
if (wasm.object_init_funcs.items.len > 0) {
// Zig has no constructors so these are only for object file inputs.
mem.sortUnstable(InitFunc, wasm.object_init_funcs.items, {}, InitFunc.lessThan);
try wasm.initializeCallCtorsFunction();
}
_ = wasm;
}
pub fn flushModule(
@ -1379,7 +1375,7 @@ pub fn flushModule(
if (comp.verbose_link) Compilation.dump_argv(wasm.dump_argv_list.items);
if (wasm.base.zcu_object_sub_path) |path| {
const module_obj_path = .{
const module_obj_path: Path = .{
.root_dir = wasm.base.emit.root_dir,
.sub_path = if (fs.path.dirname(wasm.base.emit.sub_path)) |dirname|
try fs.path.join(arena, &.{ dirname, path })

View File

@ -173,6 +173,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id) a
}
if (diags.hasErrors()) return error.LinkFailure;
// TODO only include init functions for objects with must_link=true or
// which have any alive functions inside them.
if (wasm.object_init_funcs.items.len > 0) {
// Zig has no constructors so these are only for object file inputs.
mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);
try f.functions.put(gpa, .__wasm_call_ctors, {});
}
var any_passive_inits = false;
// Merge and order the data segments. Depends on garbage collection so that