Fix wasm-related compile errors:

- Update `fail()` to not require a `srcLoc`.
This brings it in line with other backends, and we were always passing 'node_offset = 0', anyway.
- Fix unused local due to change of architecture wrt function/decl generation.
- Replace all old instructions to indexes within the function signatures.
This commit is contained in:
Luuk de Gram 2021-07-16 14:48:51 +02:00 committed by Andrew Kelley
parent 8082660118
commit 424f260f85
2 changed files with 118 additions and 120 deletions

View File

@ -25,7 +25,7 @@ const WValue = union(enum) {
/// Index of the local variable
local: u32,
/// Instruction holding a constant `Value`
constant: *Inst,
constant: Air.Inst.Index,
/// Offset position in the list of bytecode instructions
code_offset: usize,
/// Used for variables that create multiple locals on the stack when allocated
@ -484,7 +484,7 @@ pub const Result = union(enum) {
};
/// Hashmap to store generated `WValue` for each `Inst`
pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);
pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
/// Code represents the `Code` section of wasm that
/// belongs to a function
@ -497,8 +497,8 @@ pub const Context = struct {
gpa: *mem.Allocator,
/// Table to save `WValue`'s generated by an `Inst`
values: ValueTable,
/// Mapping from *Inst.Block to block ids
blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{},
/// Mapping from Air.Inst.Index to block ids
blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{},
/// `bytes` contains the wasm bytecode belonging to the 'code' section.
code: ArrayList(u8),
/// Contains the generated function type bytecode for the current function
@ -538,7 +538,8 @@ pub const Context = struct {
}
/// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig
fn fail(self: *Context, src: LazySrcLoc, comptime fmt: []const u8, args: anytype) InnerError {
fn fail(self: *Context, comptime fmt: []const u8, args: anytype) InnerError {
const src: LazySrcLoc = .{ .node_offset = 0 };
const src_loc = src.toSrcLocWithDecl(self.decl);
self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
return error.CodegenFail;
@ -546,7 +547,7 @@ pub const Context = struct {
/// Resolves the `WValue` for the given instruction `inst`
/// When the given instruction has a `Value`, it returns a constant instead
fn resolveInst(self: Context, inst: *Inst) WValue {
fn resolveInst(self: Context, inst: Air.Inst) Index {
if (!inst.ty.hasCodeGenBits()) return .none;
if (inst.value()) |_| {
@ -557,48 +558,45 @@ pub const Context = struct {
}
/// Using a given `Type`, returns the corresponding wasm Valtype
fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
fn typeToValtype(self: *Context, ty: Type) InnerError!wasm.Valtype {
return switch (ty.zigTypeTag()) {
.Float => blk: {
const bits = ty.floatBits(self.target);
if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
if (bits == 64) break :blk wasm.Valtype.f64;
return self.fail(src, "Float bit size not supported by wasm: '{d}'", .{bits});
return self.fail("Float bit size not supported by wasm: '{d}'", .{bits});
},
.Int => blk: {
const info = ty.intInfo(self.target);
if (info.bits <= 32) break :blk wasm.Valtype.i32;
if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
return self.fail(src, "Integer bit size not supported by wasm: '{d}'", .{info.bits});
return self.fail("Integer bit size not supported by wasm: '{d}'", .{info.bits});
},
.Enum => switch (ty.tag()) {
.enum_simple => wasm.Valtype.i32,
else => self.typeToValtype(
src,
ty.cast(Type.Payload.EnumFull).?.data.tag_ty,
),
else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty),
},
.Bool,
.Pointer,
.ErrorSet,
=> wasm.Valtype.i32,
.Struct, .ErrorUnion => unreachable, // Multi typed, must be handled individually.
else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),
else => self.fail("TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),
};
}
/// Using a given `Type`, returns the byte representation of its wasm value type
fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
return wasm.valtype(try self.typeToValtype(src, ty));
fn genValtype(self: *Context, ty: Type) InnerError!u8 {
return wasm.valtype(try self.typeToValtype(ty));
}
/// Using a given `Type`, returns the corresponding wasm value type
/// Differently from `genValtype` this also allows `void` to create a block
/// with no return type
fn genBlockType(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
fn genBlockType(self: *Context, ty: Type) InnerError!u8 {
return switch (ty.tag()) {
.void, .noreturn => wasm.block_empty,
else => self.genValtype(src, ty),
else => self.genValtype(ty),
};
}
@ -612,7 +610,7 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.local_get));
try leb.writeULEB128(writer, idx);
},
.constant => |inst| try self.emitConstant(inst.src, inst.value().?, inst.ty), // creates a new constant onto the stack
.constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack
}
}
@ -682,7 +680,7 @@ pub const Context = struct {
ty.fnParamTypes(params);
for (params) |param_type| {
// Can we maybe get the source index of each param?
const val_type = try self.genValtype(.{ .node_offset = 0 }, param_type);
const val_type = try self.genValtype(param_type);
try writer.writeByte(val_type);
}
}
@ -691,13 +689,10 @@ pub const Context = struct {
const return_type = ty.fnReturnType();
switch (return_type.zigTypeTag()) {
.Void, .NoReturn => try leb.writeULEB128(writer, @as(u32, 0)),
.Struct => return self.fail(.{ .node_offset = 0 }, "TODO: Implement struct as return type for wasm", .{}),
.Optional => return self.fail(.{ .node_offset = 0 }, "TODO: Implement optionals as return type for wasm", .{}),
.Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}),
.Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}),
.ErrorUnion => {
const val_type = try self.genValtype(
.{ .node_offset = 0 },
return_type.errorUnionChild(),
);
const val_type = try self.genValtype(return_type.errorUnionChild());
// write down the amount of return values
try leb.writeULEB128(writer, @as(u32, 2));
@ -707,22 +702,21 @@ pub const Context = struct {
else => {
try leb.writeULEB128(writer, @as(u32, 1));
// Can we maybe get the source index of the return type?
const val_type = try self.genValtype(.{ .node_offset = 0 }, return_type);
const val_type = try self.genValtype(return_type);
try writer.writeByte(val_type);
},
}
}
pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
_ = func;
try self.genFunctype();
// Write instructions
// TODO: check for and handle death of instructions
// Reserve space to write the size after generating the code as well as space for locals count
try self.code.resize(10);
try self.genBody(func.body);
try self.genBody(self.air.getMainBody());
// finally, write our local types at the 'offset' position
{
@ -753,7 +747,7 @@ pub const Context = struct {
return Result.appended;
}
/// Generates the wasm bytecode for the function declaration belonging to `Context`
/// Generates the wasm bytecode for the declaration belonging to `Context`
pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
switch (typed_value.ty.zigTypeTag()) {
.Fn => {
@ -793,58 +787,59 @@ pub const Context = struct {
}
}
fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
return switch (inst.tag) {
.add => self.genBinOp(inst.castTag(.add).?, .add),
.alloc => self.genAlloc(inst.castTag(.alloc).?),
.arg => self.genArg(inst.castTag(.arg).?),
.bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
.bitcast => self.genBitcast(inst.castTag(.bitcast).?),
.bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
.block => self.genBlock(inst.castTag(.block).?),
.bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
.bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
.breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
.br => self.genBr(inst.castTag(.br).?),
.call => self.genCall(inst.castTag(.call).?),
.cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
.cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
.cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
.cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),
.cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),
.cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),
.condbr => self.genCondBr(inst.castTag(.condbr).?),
.constant => unreachable,
.dbg_stmt => WValue.none,
.div => self.genBinOp(inst.castTag(.div).?, .div),
.is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
.is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
.load => self.genLoad(inst.castTag(.load).?),
.loop => self.genLoop(inst.castTag(.loop).?),
.mul => self.genBinOp(inst.castTag(.mul).?, .mul),
.not => self.genNot(inst.castTag(.not).?),
.ret => self.genRet(inst.castTag(.ret).?),
.retvoid => WValue.none,
.store => self.genStore(inst.castTag(.store).?),
.struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
.sub => self.genBinOp(inst.castTag(.sub).?, .sub),
.switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
.unreach => self.genUnreachable(inst.castTag(.unreach).?),
.unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),
.wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
.xor => self.genBinOp(inst.castTag(.xor).?, .xor),
else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}),
fn genInst(self: *Context, inst: Air.Inst.Index) !WValue {
const air_tags = self.air.instructions.items(.tag);
return switch (air_tags[inst]) {
// .add => self.genBinOp(inst.castTag(.add).?, .add),
// .alloc => self.genAlloc(inst.castTag(.alloc).?),
// .arg => self.genArg(inst.castTag(.arg).?),
// .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
// .bitcast => self.genBitcast(inst.castTag(.bitcast).?),
// .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
// .block => self.genBlock(inst.castTag(.block).?),
// .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
// .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
// .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
// .br => self.genBr(inst.castTag(.br).?),
// .call => self.genCall(inst.castTag(.call).?),
// .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
// .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
// .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
// .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),
// .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),
// .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),
// .condbr => self.genCondBr(inst.castTag(.condbr).?),
// .constant => unreachable,
// .dbg_stmt => WValue.none,
// .div => self.genBinOp(inst.castTag(.div).?, .div),
// .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
// .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
// .load => self.genLoad(inst.castTag(.load).?),
// .loop => self.genLoop(inst.castTag(.loop).?),
// .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
// .not => self.genNot(inst.castTag(.not).?),
// .ret => self.genRet(inst.castTag(.ret).?),
// .retvoid => WValue.none,
// .store => self.genStore(inst.castTag(.store).?),
// .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
// .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
// .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
// .unreach => self.genUnreachable(inst.castTag(.unreach).?),
// .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),
// .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
// .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
};
}
fn genBody(self: *Context, body: ir.Body) InnerError!void {
for (body.instructions) |inst| {
fn genBody(self: *Context, body: []const Air.Inst.Index) InnerError!void {
for (body) |inst| {
const result = try self.genInst(inst);
try self.values.putNoClobber(self.gpa, inst, result);
}
}
fn genRet(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
// TODO: Implement tail calls
const operand = self.resolveInst(inst.operand);
try self.emitWValue(operand);
@ -852,7 +847,7 @@ pub const Context = struct {
return .none;
}
fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const func_val = inst.func.value().?;
const target: *Decl = blk: {
@ -861,7 +856,7 @@ pub const Context = struct {
} else if (func_val.castTag(.extern_fn)) |ext_fn| {
break :blk ext_fn.data;
}
return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()});
return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});
};
for (inst.args) |arg| {
@ -881,12 +876,12 @@ pub const Context = struct {
return .none;
}
fn genAlloc(self: *Context, inst: *Inst.NoOp) InnerError!WValue {
fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const elem_type = inst.base.ty.elemType();
return self.allocLocal(elem_type);
}
fn genStore(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const writer = self.code.writer();
const lhs = self.resolveInst(inst.lhs);
@ -924,18 +919,18 @@ pub const Context = struct {
return .none;
}
fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
return self.resolveInst(inst.operand);
}
fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue {
fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
_ = inst;
// arguments share the index with locals
defer self.local_index += 1;
return WValue{ .local = self.local_index };
}
fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue {
const lhs = self.resolveInst(inst.lhs);
const rhs = self.resolveInst(inst.rhs);
@ -952,21 +947,21 @@ pub const Context = struct {
const opcode: wasm.Opcode = buildOpcode(.{
.op = op,
.valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
.valtype1 = try self.typeToValtype(inst.base.ty),
.signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
});
try self.code.append(wasm.opcode(opcode));
return WValue{ .code_offset = offset };
}
fn emitConstant(self: *Context, src: LazySrcLoc, value: Value, ty: Type) InnerError!void {
fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {
const writer = self.code.writer();
switch (ty.zigTypeTag()) {
.Int => {
// write opcode
const opcode: wasm.Opcode = buildOpcode(.{
.op = .@"const",
.valtype1 = try self.typeToValtype(src, ty),
.valtype1 = try self.typeToValtype(ty),
});
try writer.writeByte(wasm.opcode(opcode));
// write constant
@ -985,14 +980,14 @@ pub const Context = struct {
// write opcode
const opcode: wasm.Opcode = buildOpcode(.{
.op = .@"const",
.valtype1 = try self.typeToValtype(src, ty),
.valtype1 = try self.typeToValtype(ty),
});
try writer.writeByte(wasm.opcode(opcode));
// write constant
switch (ty.floatBits(self.target)) {
0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),
64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),
else => |bits| return self.fail(src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),
else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
}
},
.Pointer => {
@ -1009,7 +1004,7 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.i32_load));
try leb.writeULEB128(writer, @as(u32, 0));
try leb.writeULEB128(writer, @as(u32, 0));
} else return self.fail(src, "Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
} else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
},
.Void => {},
.Enum => {
@ -1023,7 +1018,7 @@ pub const Context = struct {
const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
if (enum_full.values.count() != 0) {
const tag_val = enum_full.values.keys()[field_index.data];
try self.emitConstant(src, tag_val, enum_full.tag_ty);
try self.emitConstant(tag_val, enum_full.tag_ty);
} else {
try writer.writeByte(wasm.opcode(.i32_const));
try leb.writeULEB128(writer, field_index.data);
@ -1034,7 +1029,7 @@ pub const Context = struct {
} else {
var int_tag_buffer: Type.Payload.Bits = undefined;
const int_tag_ty = ty.intTagType(&int_tag_buffer);
try self.emitConstant(src, value, int_tag_ty);
try self.emitConstant(value, int_tag_ty);
}
},
.ErrorSet => {
@ -1048,12 +1043,12 @@ pub const Context = struct {
const payload_type = ty.errorUnionChild();
if (value.getError()) |_| {
// write the error value
try self.emitConstant(src, data, error_type);
try self.emitConstant(data, error_type);
// no payload, so write a '0' const
const opcode: wasm.Opcode = buildOpcode(.{
.op = .@"const",
.valtype1 = try self.typeToValtype(src, payload_type),
.valtype1 = try self.typeToValtype(payload_type),
});
try writer.writeByte(wasm.opcode(opcode));
try leb.writeULEB128(writer, @as(u32, 0));
@ -1062,15 +1057,15 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.i32_const));
try leb.writeULEB128(writer, @as(u32, 0));
// after the error code, we emit the payload
try self.emitConstant(src, data, payload_type);
try self.emitConstant(data, payload_type);
}
},
else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
}
}
fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue {
const block_ty = try self.genBlockType(block.base.src, block.base.ty);
fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue {
const block_ty = try self.genBlockType(block.base.ty);
try self.startBlock(.block, block_ty, null);
// Here we set the current block idx, so breaks know the depth to jump
@ -1100,8 +1095,8 @@ pub const Context = struct {
self.block_depth -= 1;
}
fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue {
const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty);
fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue {
const loop_ty = try self.genBlockType(loop.base.ty);
try self.startBlock(.loop, loop_ty, null);
try self.genBody(loop.body);
@ -1115,7 +1110,7 @@ pub const Context = struct {
return .none;
}
fn genCondBr(self: *Context, condbr: *Inst.CondBr) InnerError!WValue {
fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue {
const condition = self.resolveInst(condbr.condition);
const writer = self.code.writer();
@ -1131,7 +1126,7 @@ pub const Context = struct {
break :blk offset;
},
};
const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty);
const block_ty = try self.genBlockType(condbr.base.ty);
try self.startBlock(.block, block_ty, offset);
// we inserted the block in front of the condition
@ -1149,7 +1144,7 @@ pub const Context = struct {
return .none;
}
fn genCmp(self: *Context, inst: *Inst.BinOp, op: std.math.CompareOperator) InnerError!WValue {
fn genCmp(self: *Context, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {
// save offset, so potential conditions can insert blocks in front of
// the comparison that we can later jump back to
const offset = self.code.items.len;
@ -1168,7 +1163,7 @@ pub const Context = struct {
break :blk inst.lhs.ty.intInfo(self.target).signedness;
};
const opcode: wasm.Opcode = buildOpcode(.{
.valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
.valtype1 = try self.typeToValtype(inst.lhs.ty),
.op = switch (op) {
.lt => .lt,
.lte => .le,
@ -1183,7 +1178,7 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue {
// if operand has codegen bits we should break with a value
if (br.operand.ty.hasCodeGenBits()) {
const operand = self.resolveInst(br.operand);
@ -1200,7 +1195,7 @@ pub const Context = struct {
return .none;
}
fn genNot(self: *Context, not: *Inst.UnOp) InnerError!WValue {
fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue {
const offset = self.code.items.len;
const operand = self.resolveInst(not.operand);
@ -1217,7 +1212,7 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
fn genBreakpoint(self: *Context, breakpoint: *Inst.NoOp) InnerError!WValue {
fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue {
_ = self;
_ = breakpoint;
// unsupported by wasm itself. Can be implemented once we support DWARF
@ -1225,27 +1220,27 @@ pub const Context = struct {
return .none;
}
fn genUnreachable(self: *Context, unreach: *Inst.NoOp) InnerError!WValue {
fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue {
_ = unreach;
try self.code.append(wasm.opcode(.@"unreachable"));
return .none;
}
fn genBitcast(self: *Context, bitcast: *Inst.UnOp) InnerError!WValue {
fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue {
return self.resolveInst(bitcast.operand);
}
fn genStructFieldPtr(self: *Context, inst: *Inst.StructFieldPtr) InnerError!WValue {
fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const struct_ptr = self.resolveInst(inst.struct_ptr);
return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) };
}
fn genSwitchBr(self: *Context, inst: *Inst.SwitchBr) InnerError!WValue {
fn genSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const target = self.resolveInst(inst.target);
const target_ty = inst.target.ty;
const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty);
const blocktype = try self.genBlockType(inst.base.src, inst.base.ty);
const blocktype = try self.genBlockType(inst.base.ty);
const signedness: std.builtin.Signedness = blk: {
// by default we tell the operand type is unsigned (i.e. bools and enum values)
@ -1282,7 +1277,7 @@ pub const Context = struct {
return .none;
}
fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {
fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
const operand = self.resolveInst(inst.operand);
const offset = self.code.items.len;
const writer = self.code.writer();
@ -1298,7 +1293,7 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
const operand = self.resolveInst(inst.operand);
// The index of multi_value contains the error code. To get the initial index of the payload we get
// the following index. Next, convert it to a `WValue.local`
@ -1307,7 +1302,7 @@ pub const Context = struct {
return WValue{ .local = operand.multi_value.index + 1 };
}
fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
return self.resolveInst(inst.operand);
}
};

View File

@ -228,7 +228,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
},
else => |e| return e,
};
return self.finishUpdateDecl(decl, result);
return self.finishUpdateDecl(decl, result, &context);
}
// Generate code for the Decl, storing it in memory to be later written to
@ -270,18 +270,21 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
},
else => |e| return e,
};
return self.finishUpdateDecl(decl, result);
return self.finishUpdateDecl(decl, result, &context);
}
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {
const code: []const u8 = switch (result) {
.appended => @as([]const u8, context.code.items),
.externally_managed => |payload| payload,
};
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result, context: *codegen.Context) !void {
const fn_data: *FnData = &decl.fn_link.wasm;
fn_data.code = context.code.toUnmanaged();
fn_data.functype = context.func_type_data.toUnmanaged();
const code: []const u8 = switch (result) {
.appended => @as([]const u8, fn_data.code.items),
.externally_managed => |payload| payload,
};
const block = &decl.link.wasm;
if (decl.ty.zigTypeTag() == .Fn) {
// as locals are patched afterwards, the offsets of funcidx's are off,