mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
wasm codegen: fix some compilation errors
This commit is contained in:
parent
e521879e47
commit
bffa148600
11
src/Zcu.zig
11
src/Zcu.zig
@ -4120,3 +4120,14 @@ pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg)
|
||||
zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg);
|
||||
return error.CodegenFail;
|
||||
}
|
||||
|
||||
/// Check if nav is an alias to a function, in which case we want to lower the
|
||||
/// actual nav, rather than the alias itself.
|
||||
pub fn chaseNav(zcu: *const Zcu, nav: InternPool.Nav.Index) InternPool.Nav.Index {
|
||||
return switch (zcu.intern_pool.indexToKey(zcu.navValue(nav).toIntern())) {
|
||||
.func => |f| f.owner_nav,
|
||||
.variable => |variable| variable.owner_nav,
|
||||
.@"extern" => |@"extern"| @"extern".owner_nav,
|
||||
else => nav,
|
||||
};
|
||||
}
|
||||
|
||||
@ -146,19 +146,14 @@ const WValue = union(enum) {
|
||||
float32: f32,
|
||||
/// A constant 64bit float value
|
||||
float64: f64,
|
||||
/// 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 {
|
||||
pointer: InternPool.Index,
|
||||
/// Offset will be set as addend when relocating
|
||||
offset: u32,
|
||||
nav_ref: struct {
|
||||
nav_index: InternPool.Nav.Index,
|
||||
offset: i32 = 0,
|
||||
},
|
||||
uav_ref: struct {
|
||||
ip_index: InternPool.Index,
|
||||
offset: i32 = 0,
|
||||
},
|
||||
/// Represents a function pointer
|
||||
/// In wasm function pointers are indexes into a function table,
|
||||
/// rather than an address in the data section.
|
||||
function_index: InternPool.Index,
|
||||
/// Offset from the bottom of the virtual stack, with the offset
|
||||
/// pointing to where the value lives.
|
||||
stack_offset: struct {
|
||||
@ -752,7 +747,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
|
||||
const ty = func.typeOf(ref);
|
||||
if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {
|
||||
gop.value_ptr.* = .none;
|
||||
return gop.value_ptr.*;
|
||||
return .none;
|
||||
}
|
||||
|
||||
// When we need to pass the value by reference (such as a struct), we will
|
||||
@ -762,7 +757,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))
|
||||
.{ .memory = val.toIntern() }
|
||||
.{ .uav_ref = .{ .ip_index = val.toIntern() } }
|
||||
else
|
||||
try func.lowerConstant(val, ty);
|
||||
|
||||
@ -956,6 +951,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32
|
||||
u32 => @field(extra, field.name),
|
||||
i32 => @bitCast(@field(extra, field.name)),
|
||||
InternPool.Index => @intFromEnum(@field(extra, field.name)),
|
||||
InternPool.Nav.Index => @intFromEnum(@field(extra, field.name)),
|
||||
else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)),
|
||||
});
|
||||
}
|
||||
@ -1028,17 +1024,36 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
|
||||
.imm128 => |val| try func.addImm128(val),
|
||||
.float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
|
||||
.float64 => |val| try func.addFloat64(val),
|
||||
.memory => |ptr| try func.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = ptr } }),
|
||||
.memory_offset => |mo| try func.addInst(.{
|
||||
.tag = .uav_ref_off,
|
||||
.data = .{
|
||||
.payload = try func.addExtra(Mir.UavRefOff{
|
||||
.ip_index = mo.pointer,
|
||||
.offset = @intCast(mo.offset), // TODO should not be an assert
|
||||
}),
|
||||
},
|
||||
}),
|
||||
.function_index => |index| try func.addIpIndex(.function_index, index),
|
||||
.nav_ref => |nav_ref| {
|
||||
if (nav_ref.offset == 0) {
|
||||
try func.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } });
|
||||
} else {
|
||||
try func.addInst(.{
|
||||
.tag = .nav_ref_off,
|
||||
.data = .{
|
||||
.payload = try func.addExtra(Mir.NavRefOff{
|
||||
.nav_index = nav_ref.nav_index,
|
||||
.offset = nav_ref.offset,
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
.uav_ref => |uav| {
|
||||
if (uav.offset == 0) {
|
||||
try func.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = uav.ip_index } });
|
||||
} else {
|
||||
try func.addInst(.{
|
||||
.tag = .uav_ref_off,
|
||||
.data = .{
|
||||
.payload = try func.addExtra(Mir.UavRefOff{
|
||||
.ip_index = uav.ip_index,
|
||||
.offset = uav.offset,
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
.stack_offset => try func.addLabel(.local_get, func.bottom_stack_value.local.value), // caller must ensure to address the offset
|
||||
}
|
||||
}
|
||||
@ -1466,10 +1481,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value:
|
||||
assert(ty_classes[0] == .direct);
|
||||
const scalar_type = abi.scalarType(ty, zcu);
|
||||
switch (value) {
|
||||
.memory,
|
||||
.memory_offset,
|
||||
.stack_offset,
|
||||
=> _ = try func.load(value, scalar_type, 0),
|
||||
.nav_ref, .stack_offset => _ = try func.load(value, scalar_type, 0),
|
||||
.dead => unreachable,
|
||||
else => try func.emitWValue(value),
|
||||
}
|
||||
@ -3117,8 +3129,8 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr
|
||||
const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
|
||||
const offset: u64 = prev_offset + ptr.byte_offset;
|
||||
return switch (ptr.base_addr) {
|
||||
.nav => |nav| return func.lowerNavRef(nav, @intCast(offset)),
|
||||
.uav => |uav| return func.lowerUavRef(uav, @intCast(offset)),
|
||||
.nav => |nav| return .{ .nav_ref = .{ .nav_index = zcu.chaseNav(nav), .offset = @intCast(offset) } },
|
||||
.uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset) } },
|
||||
.int => return func.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
|
||||
.eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}),
|
||||
.opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset),
|
||||
@ -3162,51 +3174,6 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerUavRef(
|
||||
func: *CodeGen,
|
||||
uav: InternPool.Key.Ptr.BaseAddr.Uav,
|
||||
offset: u32,
|
||||
) InnerError!WValue {
|
||||
const pt = func.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ty = Type.fromInterned(zcu.intern_pool.typeOf(uav.val));
|
||||
|
||||
const is_fn_body = ty.zigTypeTag(zcu) == .@"fn";
|
||||
if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(zcu)) {
|
||||
return .{ .imm32 = 0xaaaaaaaa };
|
||||
}
|
||||
|
||||
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 {
|
||||
const pt = func.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const nav_ty = ip.getNav(nav_index).typeOf(ip);
|
||||
if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) {
|
||||
return .{ .imm32 = 0xaaaaaaaa };
|
||||
}
|
||||
|
||||
const atom_index = try func.wasm.getOrCreateAtomForNav(pt, nav_index);
|
||||
const atom = func.wasm.getAtom(atom_index);
|
||||
|
||||
const target_sym_index = @intFromEnum(atom.sym_index);
|
||||
if (ip.isFunctionType(nav_ty)) {
|
||||
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 } };
|
||||
}
|
||||
|
||||
/// Asserts that `isByRef` returns `false` for `ty`.
|
||||
fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
|
||||
const pt = func.pt;
|
||||
@ -3307,7 +3274,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
|
||||
.f64 => |f64_val| return .{ .float64 = f64_val },
|
||||
else => unreachable,
|
||||
},
|
||||
.slice => return .{ .memory = val.toIntern() },
|
||||
.slice => unreachable, // isByRef == true
|
||||
.ptr => return func.lowerPtr(val.toIntern(), 0),
|
||||
.opt => if (ty.optionalReprIsPayload(zcu)) {
|
||||
const pl_ty = ty.optionalChild(zcu);
|
||||
|
||||
@ -33,6 +33,9 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
var inst: u32 = 0;
|
||||
|
||||
loop: switch (tags[inst]) {
|
||||
.dbg_epilogue_begin => {
|
||||
return;
|
||||
},
|
||||
.block, .loop => {
|
||||
const block_type = datas[inst].block_type;
|
||||
try code.ensureUnusedCapacity(gpa, 2);
|
||||
@ -42,16 +45,23 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
|
||||
.uav_ref => {
|
||||
try uavRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 });
|
||||
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
.uav_ref_off => {
|
||||
try uavRefOff(wasm, code, mir.extraData(Mir.UavRefOff, datas[inst].payload).data);
|
||||
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
.nav_ref => {
|
||||
try navRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 });
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
.nav_ref_off => {
|
||||
try navRefOff(wasm, code, mir.extraData(Mir.NavRefOff, datas[inst].payload).data);
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
@ -60,10 +70,6 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
inst += 1;
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
.dbg_epilogue_begin => {
|
||||
return;
|
||||
},
|
||||
|
||||
.br_if, .br, .memory_grow, .memory_size => {
|
||||
try code.ensureUnusedCapacity(gpa, 11);
|
||||
code.appendAssumeCapacity(@intFromEnum(tags[inst]));
|
||||
@ -431,7 +437,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
|
||||
_ => unreachable,
|
||||
}
|
||||
unreachable;
|
||||
comptime unreachable;
|
||||
},
|
||||
.simd_prefix => {
|
||||
try code.ensureUnusedCapacity(gpa, 6 + 20);
|
||||
@ -487,7 +493,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
},
|
||||
_ => unreachable,
|
||||
}
|
||||
unreachable;
|
||||
comptime unreachable;
|
||||
},
|
||||
.atomics_prefix => {
|
||||
try code.ensureUnusedCapacity(gpa, 6 + 20);
|
||||
@ -576,13 +582,13 @@ pub fn lowerToCode(emit: *Emit) Error!void {
|
||||
continue :loop tags[inst];
|
||||
},
|
||||
}
|
||||
unreachable;
|
||||
comptime unreachable;
|
||||
},
|
||||
}
|
||||
unreachable;
|
||||
comptime unreachable;
|
||||
}
|
||||
|
||||
/// Assert 20 unused capacity.
|
||||
/// Asserts 20 unused capacity.
|
||||
fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void {
|
||||
assert(code.unusedCapacitySlice().len >= 20);
|
||||
// Wasm encodes alignment as power of 2, rather than natural alignment.
|
||||
@ -619,3 +625,48 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir
|
||||
const addr: i64 = try wasm.uavAddr(data.ip_index);
|
||||
leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
|
||||
}
|
||||
|
||||
fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff) !void {
|
||||
const comp = wasm.base.comp;
|
||||
const zcu = comp.zcu.?;
|
||||
const ip = &zcu.intern_pool;
|
||||
const gpa = comp.gpa;
|
||||
const is_obj = comp.config.output_mode == .Obj;
|
||||
const target = &comp.root_mod.resolved_target.result;
|
||||
const nav_ty = ip.getNav(data.nav_index).typeOf(ip);
|
||||
|
||||
try code.ensureUnusedCapacity(gpa, 11);
|
||||
|
||||
if (ip.isFunctionType(nav_ty)) {
|
||||
code.appendAssumeCapacity(std.wasm.Opcode.i32_const);
|
||||
assert(data.offset == 0);
|
||||
if (is_obj) {
|
||||
try wasm.out_relocs.append(gpa, .{
|
||||
.offset = @intCast(code.items.len),
|
||||
.index = try wasm.navSymbolIndex(data.nav_index),
|
||||
.tag = .TABLE_INDEX_SLEB,
|
||||
.addend = data.offset,
|
||||
});
|
||||
code.appendNTimesAssumeCapacity(0, 5);
|
||||
} else {
|
||||
const addr: i64 = try wasm.navAddr(data.nav_index);
|
||||
leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
|
||||
}
|
||||
} else {
|
||||
const is_wasm32 = target.cpu.arch == .wasm32;
|
||||
const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
|
||||
code.appendAssumeCapacity(@intFromEnum(opcode));
|
||||
if (is_obj) {
|
||||
try wasm.out_relocs.append(gpa, .{
|
||||
.offset = @intCast(code.items.len),
|
||||
.index = try wasm.navSymbolIndex(data.nav_index),
|
||||
.tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
|
||||
.addend = data.offset,
|
||||
});
|
||||
code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
|
||||
} else {
|
||||
const addr: i64 = try wasm.navAddr(data.nav_index);
|
||||
leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,8 +32,12 @@ pub const Inst = struct {
|
||||
|
||||
/// Some tags match wasm opcode values to facilitate trivial lowering.
|
||||
pub const Tag = enum(u8) {
|
||||
/// Uses `nop`
|
||||
/// Uses `tag`.
|
||||
@"unreachable" = 0x00,
|
||||
/// Emits epilogue begin debug information. Marks the end of the function.
|
||||
///
|
||||
/// Uses `tag` (no additional data).
|
||||
dbg_epilogue_begin,
|
||||
/// Creates a new block that can be jump from.
|
||||
///
|
||||
/// Type of the block is given in data `block_type`
|
||||
@ -46,34 +50,51 @@ pub const Inst = struct {
|
||||
/// memory address of an unnamed constant. When emitting an object
|
||||
/// file, this adds a relocation.
|
||||
///
|
||||
/// Data is `ip_index`.
|
||||
/// This may not refer to a function.
|
||||
///
|
||||
/// Uses `ip_index`.
|
||||
uav_ref,
|
||||
/// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
|
||||
/// memory address of an unnamed constant, offset by an integer value.
|
||||
/// When emitting an object file, this adds a relocation.
|
||||
///
|
||||
/// Data is `payload` pointing to a `UavRefOff`.
|
||||
/// This may not refer to a function.
|
||||
///
|
||||
/// Uses `payload` pointing to a `UavRefOff`.
|
||||
uav_ref_off,
|
||||
/// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
|
||||
/// memory address of a named constant.
|
||||
///
|
||||
/// When this refers to a function, this always lowers to an i32_const
|
||||
/// which is the function index. When emitting an object file, this
|
||||
/// adds a `Wasm.Relocation.Tag.TABLE_INDEX_SLEB` relocation.
|
||||
///
|
||||
/// Uses `nav_index`.
|
||||
nav_ref,
|
||||
/// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
|
||||
/// memory address of named constant, offset by an integer value.
|
||||
/// When emitting an object file, this adds a relocation.
|
||||
///
|
||||
/// This may not refer to a function.
|
||||
///
|
||||
/// Uses `payload` pointing to a `NavRefOff`.
|
||||
nav_ref_off,
|
||||
/// Inserts debug information about the current line and column
|
||||
/// of the source code
|
||||
///
|
||||
/// Uses `payload` of which the payload type is `DbgLineColumn`
|
||||
dbg_line = 0x06,
|
||||
/// Emits epilogue begin debug information. Marks the end of the function.
|
||||
///
|
||||
/// Uses `nop`
|
||||
dbg_epilogue_begin = 0x07,
|
||||
dbg_line,
|
||||
/// Represents the end of a function body or an initialization expression
|
||||
///
|
||||
/// Payload is `nop`
|
||||
/// Uses `tag` (no additional data).
|
||||
end = 0x0B,
|
||||
/// Breaks from the current block to a label
|
||||
///
|
||||
/// Data is `label` where index represents the label to jump to
|
||||
/// Uses `label` where index represents the label to jump to
|
||||
br = 0x0C,
|
||||
/// Breaks from the current block if the stack value is non-zero
|
||||
///
|
||||
/// Data is `label` where index represents the label to jump to
|
||||
/// Uses `label` where index represents the label to jump to
|
||||
br_if = 0x0D,
|
||||
/// Jump table that takes the stack value as an index where each value
|
||||
/// represents the label to jump to.
|
||||
@ -82,7 +103,7 @@ pub const Inst = struct {
|
||||
br_table = 0x0E,
|
||||
/// Returns from the function
|
||||
///
|
||||
/// Uses `nop`
|
||||
/// Uses `tag`.
|
||||
@"return" = 0x0F,
|
||||
/// Calls a function using `nav_index`.
|
||||
call_nav,
|
||||
@ -98,10 +119,6 @@ pub const Inst = struct {
|
||||
/// The function is the auto-generated tag name function for the type
|
||||
/// provided in `ip_index`.
|
||||
call_tag_name,
|
||||
/// Lowers to an i32_const containing the index of a function.
|
||||
/// When emitting an object file, this adds a relocation.
|
||||
/// Uses `ip_index`.
|
||||
function_index,
|
||||
|
||||
/// Pops three values from the stack and pushes
|
||||
/// the first or second value dependent on the third value.
|
||||
@ -663,6 +680,11 @@ pub const UavRefOff = struct {
|
||||
offset: i32,
|
||||
};
|
||||
|
||||
pub const NavRefOff = struct {
|
||||
nav_index: InternPool.Nav.Index,
|
||||
offset: i32,
|
||||
};
|
||||
|
||||
/// Maps a source line with wasm bytecode
|
||||
pub const DbgLineColumn = struct {
|
||||
line: u32,
|
||||
|
||||
@ -1508,6 +1508,10 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
|
||||
|
||||
dev.check(.wasm_backend);
|
||||
|
||||
// This converts AIR to MIR but does not yet lower to wasm code.
|
||||
// That lowering happens during `flush`, after garbage collection, which
|
||||
// can affect function and global indexes, which affects the LEB integer
|
||||
// encoding, which affects the output binary size.
|
||||
try wasm.zcu_funcs.put(pt.zcu.gpa, func_index, .{
|
||||
.function = try CodeGen.function(wasm, pt, func_index, air, liveness),
|
||||
});
|
||||
@ -1729,7 +1733,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
|
||||
continue;
|
||||
}
|
||||
}
|
||||
wasm.functions_len = @intCast(wasm.functions.items.len);
|
||||
wasm.functions_len = @intCast(wasm.functions.entries.len);
|
||||
wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys());
|
||||
wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.vals());
|
||||
wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user