Commit 424f260f85
src/codegen/wasm.zig
@@ -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);
}
};
src/link/Wasm.zig
@@ -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,