aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2021-07-16 22:43:06 +0200
committerAndrew Kelley <andrew@ziglang.org>2021-07-20 12:19:16 -0700
commit2438f61f1c37aefa16852130370df44b3fabf785 (patch)
tree831f7d890c87cf50119f5f639a2818e9a7b1c8ba /src/codegen
parent424f260f850cb22637888bbfdf5bfaf9c08a4dae (diff)
downloadzig-2438f61f1c37aefa16852130370df44b3fabf785.tar.gz
zig-2438f61f1c37aefa16852130370df44b3fabf785.zip
Refactor entire wasm-backend to use new AIR memory layout
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/wasm.zig275
1 files changed, 160 insertions, 115 deletions
diff --git a/src/codegen/wasm.zig b/src/codegen/wasm.zig
index 33ab07faf3..5cf3fb15fd 100644
--- a/src/codegen/wasm.zig
+++ b/src/codegen/wasm.zig
@@ -483,8 +483,8 @@ pub const Result = union(enum) {
externally_managed: []const u8,
};
-/// Hashmap to store generated `WValue` for each `Inst`
-pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
+/// Hashmap to store generated `WValue` for each `Air.Inst.Ref`
+pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Ref, WValue);
/// Code represents the `Code` section of wasm that
/// belongs to a function
@@ -495,7 +495,7 @@ pub const Context = struct {
air: Air,
liveness: Liveness,
gpa: *mem.Allocator,
- /// Table to save `WValue`'s generated by an `Inst`
+ /// Table to save `WValue`'s generated by an `Air.Inst`
values: ValueTable,
/// Mapping from Air.Inst.Index to block ids
blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{},
@@ -547,14 +547,15 @@ 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: Air.Inst) Index {
- if (!inst.ty.hasCodeGenBits()) return .none;
+ fn resolveInst(self: Context, ref: Air.Inst.Ref) WValue {
+ const ref_type = self.air.getRefType(ref);
+ if (ref_type.hasCodeGenBits()) return .none;
- if (inst.value()) |_| {
- return WValue{ .constant = inst };
+ if (self.air.instructions.items(.tag)[@enumToInt(ref)] == .constant) {
+ return WValue{ .constant = @enumToInt(ref) };
}
- return self.values.get(inst).?; // Instruction does not dominate all uses!
+ return self.values.get(ref).?; // Instruction does not dominate all uses!
}
/// Using a given `Type`, returns the corresponding wasm Valtype
@@ -610,7 +611,12 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.local_get));
try leb.writeULEB128(writer, idx);
},
- .constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack
+ .constant => |index| {
+ const ty_pl = self.air.instructions.items(.data)[index].ty_pl;
+ const value = self.air.values[ty_pl.payload];
+ // create a new constant onto the stack
+ try self.emitConstant(value, self.air.getRefType(ty_pl.ty));
+ },
}
}
@@ -626,10 +632,7 @@ pub const Context = struct {
const fields_len = @intCast(u32, struct_data.fields.count());
try self.locals.ensureCapacity(self.gpa, self.locals.items.len + fields_len);
for (struct_data.fields.values()) |*value| {
- const val_type = try self.genValtype(
- .{ .node_offset = struct_data.node_offset },
- value.ty,
- );
+ const val_type = try self.genValtype(value.ty);
self.locals.appendAssumeCapacity(val_type);
self.local_index += 1;
}
@@ -640,7 +643,7 @@ pub const Context = struct {
},
.ErrorUnion => {
const payload_type = ty.errorUnionChild();
- const val_type = try self.genValtype(.{ .node_offset = 0 }, payload_type);
+ const val_type = try self.genValtype(payload_type);
// we emit the error value as the first local, and the payload as the following.
// The first local is also used to find the index of the error and payload.
@@ -657,7 +660,7 @@ pub const Context = struct {
} };
},
else => {
- const valtype = try self.genValtype(.{ .node_offset = 0 }, ty);
+ const valtype = try self.genValtype(ty);
try self.locals.append(self.gpa, valtype);
self.local_index += 1;
return WValue{ .local = initial_index };
@@ -708,8 +711,7 @@ pub const Context = struct {
}
}
- pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
- _ = func;
+ pub fn genFunc(self: *Context) InnerError!Result {
try self.genFunctype();
// TODO: check for and handle death of instructions
@@ -790,44 +792,43 @@ pub const Context = struct {
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),
+ .add => self.genBinOp(inst, .add),
+ .alloc => self.genAlloc(inst),
+ .arg => self.genArg(inst),
+ .bit_and => self.genBinOp(inst, .@"and"),
+ .bitcast => self.genBitcast(inst),
+ .bit_or => self.genBinOp(inst, .@"or"),
+ .block => self.genBlock(inst),
+ .bool_and => self.genBinOp(inst, .@"and"),
+ .bool_or => self.genBinOp(inst, .@"or"),
+ .breakpoint => self.genBreakpoint(inst),
+ .br => self.genBr(inst),
+ .call => self.genCall(inst),
+ .cmp_eq => self.genCmp(inst, .eq),
+ .cmp_gte => self.genCmp(inst, .gte),
+ .cmp_gt => self.genCmp(inst, .gt),
+ .cmp_lte => self.genCmp(inst, .lte),
+ .cmp_lt => self.genCmp(inst, .lt),
+ .cmp_neq => self.genCmp(inst, .neq),
+ .cond_br => self.genCondBr(inst),
+ .constant => unreachable,
+ .dbg_stmt => WValue.none,
+ .div => self.genBinOp(inst, .div),
+ .is_err => self.genIsErr(inst, .i32_ne),
+ .is_non_err => self.genIsErr(inst, .i32_eq),
+ .load => self.genLoad(inst),
+ .loop => self.genLoop(inst),
+ .mul => self.genBinOp(inst, .mul),
+ .not => self.genNot(inst),
+ .ret => self.genRet(inst),
+ .store => self.genStore(inst),
+ .struct_field_ptr => self.genStructFieldPtr(inst),
+ .sub => self.genBinOp(inst, .sub),
+ .switch_br => self.genSwitchBr(inst),
+ .unreach => self.genUnreachable(inst),
+ .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst),
+ .wrap_errunion_payload => self.genWrapErrUnionPayload(inst),
+ .xor => self.genBinOp(inst, .xor),
else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
};
}
@@ -835,22 +836,27 @@ pub const Context = struct {
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);
+ try self.values.putNoClobber(self.gpa, @intToEnum(Air.Inst.Ref, inst), result);
}
}
fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- // TODO: Implement tail calls
- const operand = self.resolveInst(inst.operand);
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = self.resolveInst(un_op);
try self.emitWValue(operand);
try self.code.append(wasm.opcode(.@"return"));
return .none;
}
fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- const func_val = inst.func.value().?;
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.Call, pl_op.payload);
+ const args = self.air.extra[extra.end..][0..extra.data.args_len];
const target: *Decl = blk: {
+ const ty_pl = self.air.instructions.items(.data)[@enumToInt(pl_op.operand)].ty_pl;
+ const func_val = self.air.values[ty_pl.payload];
+
if (func_val.castTag(.function)) |func| {
break :blk func.data.owner_decl;
} else if (func_val.castTag(.extern_fn)) |ext_fn| {
@@ -859,8 +865,8 @@ pub const Context = struct {
return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});
};
- for (inst.args) |arg| {
- const arg_val = self.resolveInst(arg);
+ for (args) |arg| {
+ const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg));
try self.emitWValue(arg_val);
}
@@ -877,15 +883,16 @@ pub const Context = struct {
}
fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- const elem_type = inst.base.ty.elemType();
+ const elem_type = self.air.getType(inst).elemType();
return self.allocLocal(elem_type);
}
fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const writer = self.code.writer();
- const lhs = self.resolveInst(inst.lhs);
- const rhs = self.resolveInst(inst.rhs);
+ const lhs = self.resolveInst(bin_op.lhs);
+ const rhs = self.resolveInst(bin_op.rhs);
switch (lhs) {
.multi_value => |multi_value| switch (rhs) {
@@ -893,7 +900,7 @@ pub const Context = struct {
// we simply assign the local_index to the rhs one.
// This allows us to update struct fields without having to individually
// set each local as each field's index will be calculated off the struct's base index
- .multi_value => self.values.put(self.gpa, inst.lhs, rhs) catch unreachable, // Instruction does not dominate all uses!
+ .multi_value => self.values.put(self.gpa, bin_op.lhs, rhs) catch unreachable, // Instruction does not dominate all uses!
.constant, .none => {
// emit all values onto the stack if constant
try self.emitWValue(rhs);
@@ -920,7 +927,8 @@ pub const Context = struct {
}
fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- return self.resolveInst(inst.operand);
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ return self.resolveInst(ty_op.operand);
}
fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
@@ -931,8 +939,9 @@ pub const Context = struct {
}
fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue {
- const lhs = self.resolveInst(inst.lhs);
- const rhs = self.resolveInst(inst.rhs);
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs = self.resolveInst(bin_op.lhs);
+ const rhs = self.resolveInst(bin_op.rhs);
// it's possible for both lhs and/or rhs to return an offset as well,
// in which case we return the first offset occurance we find.
@@ -945,10 +954,11 @@ pub const Context = struct {
try self.emitWValue(lhs);
try self.emitWValue(rhs);
+ const bin_ty = self.air.getRefType(bin_op.lhs);
const opcode: wasm.Opcode = buildOpcode(.{
.op = op,
- .valtype1 = try self.typeToValtype(inst.base.ty),
- .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
+ .valtype1 = try self.typeToValtype(bin_ty),
+ .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned,
});
try self.code.append(wasm.opcode(opcode));
return WValue{ .code_offset = offset };
@@ -1064,14 +1074,17 @@ pub const Context = struct {
}
}
- fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue {
- const block_ty = try self.genBlockType(block.base.ty);
+ fn genBlock(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty));
+ const extra = self.air.extraData(Air.Block, ty_pl.payload);
+ const body = self.air.extra[extra.end..][0..extra.data.body_len];
try self.startBlock(.block, block_ty, null);
// Here we set the current block idx, so breaks know the depth to jump
// to when breaking out.
- try self.blocks.putNoClobber(self.gpa, block, self.block_depth);
- try self.genBody(block.body);
+ try self.blocks.putNoClobber(self.gpa, inst, self.block_depth);
+ try self.genBody(body);
try self.endBlock();
return .none;
@@ -1095,11 +1108,15 @@ pub const Context = struct {
self.block_depth -= 1;
}
- fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue {
- const loop_ty = try self.genBlockType(loop.base.ty);
+ fn genLoop(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const loop = self.air.extraData(Air.Block, ty_pl.payload);
+ const body = self.air.extra[loop.end..][0..loop.data.body_len];
- try self.startBlock(.loop, loop_ty, null);
- try self.genBody(loop.body);
+ // result type of loop is always 'noreturn', meaning we can always
+ // emit the wasm type 'block_empty'.
+ try self.startBlock(.loop, wasm.block_empty, null);
+ try self.genBody(body);
// breaking to the index of a loop block will continue the loop instead
try self.code.append(wasm.opcode(.br));
@@ -1110,8 +1127,12 @@ pub const Context = struct {
return .none;
}
- fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue {
- const condition = self.resolveInst(condbr.condition);
+ fn genCondBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const condition = self.resolveInst(pl_op.operand);
+ const extra = self.air.extraData(Air.CondBr, pl_op.payload);
+ const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
+ const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
const writer = self.code.writer();
// TODO: Handle death instructions for then and else body
@@ -1126,8 +1147,9 @@ pub const Context = struct {
break :blk offset;
},
};
- const block_ty = try self.genBlockType(condbr.base.ty);
- try self.startBlock(.block, block_ty, offset);
+
+ // result type is always noreturn, so use `block_empty` as type.
+ try self.startBlock(.block, wasm.block_empty, offset);
// we inserted the block in front of the condition
// so now check if condition matches. If not, break outside this block
@@ -1135,11 +1157,11 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.br_if));
try leb.writeULEB128(writer, @as(u32, 0));
- try self.genBody(condbr.else_body);
+ try self.genBody(else_body);
try self.endBlock();
// Outer block that matches the condition
- try self.genBody(condbr.then_body);
+ try self.genBody(then_body);
return .none;
}
@@ -1149,21 +1171,23 @@ pub const Context = struct {
// the comparison that we can later jump back to
const offset = self.code.items.len;
- const lhs = self.resolveInst(inst.lhs);
- const rhs = self.resolveInst(inst.rhs);
+ const data: Air.Inst.Data = self.air.instructions.items(.data)[inst];
+ const lhs = self.resolveInst(data.bin_op.lhs);
+ const rhs = self.resolveInst(data.bin_op.rhs);
+ const lhs_ty = self.air.getRefType(data.bin_op.lhs);
try self.emitWValue(lhs);
try self.emitWValue(rhs);
const signedness: std.builtin.Signedness = blk: {
// by default we tell the operand type is unsigned (i.e. bools and enum values)
- if (inst.lhs.ty.zigTypeTag() != .Int) break :blk .unsigned;
+ if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned;
// incase of an actual integer, we emit the correct signedness
- break :blk inst.lhs.ty.intInfo(self.target).signedness;
+ break :blk lhs_ty.intInfo(self.target).signedness;
};
const opcode: wasm.Opcode = buildOpcode(.{
- .valtype1 = try self.typeToValtype(inst.lhs.ty),
+ .valtype1 = try self.typeToValtype(lhs_ty),
.op = switch (op) {
.lt => .lt,
.lte => .le,
@@ -1178,16 +1202,17 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
- fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue {
+ fn genBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const br = self.air.instructions.items(.data)[inst].br;
+
// if operand has codegen bits we should break with a value
- if (br.operand.ty.hasCodeGenBits()) {
- const operand = self.resolveInst(br.operand);
- try self.emitWValue(operand);
+ if (self.air.getRefType(br.operand).hasCodeGenBits()) {
+ try self.emitWValue(self.resolveInst(br.operand));
}
// We map every block to its block index.
// We then determine how far we have to jump to it by substracting it from current block depth
- const idx: u32 = self.block_depth - self.blocks.get(br.block).?;
+ const idx: u32 = self.block_depth - self.blocks.get(br.block_inst).?;
const writer = self.code.writer();
try writer.writeByte(wasm.opcode(.br));
try leb.writeULEB128(writer, idx);
@@ -1195,10 +1220,11 @@ pub const Context = struct {
return .none;
}
- fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue {
+ fn genNot(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const offset = self.code.items.len;
- const operand = self.resolveInst(not.operand);
+ const operand = self.resolveInst(ty_op.operand);
try self.emitWValue(operand);
// wasm does not have booleans nor the `not` instruction, therefore compare with 0
@@ -1212,35 +1238,44 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
- fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue {
+ fn genBreakpoint(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
_ = self;
- _ = breakpoint;
+ _ = inst;
// unsupported by wasm itself. Can be implemented once we support DWARF
// for wasm
return .none;
}
- fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue {
- _ = unreach;
+ fn genUnreachable(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ _ = inst;
try self.code.append(wasm.opcode(.@"unreachable"));
return .none;
}
- fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue {
- return self.resolveInst(bitcast.operand);
+ fn genBitcast(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ return self.resolveInst(ty_op.operand);
}
fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- const struct_ptr = self.resolveInst(inst.struct_ptr);
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.StructField, ty_pl.payload);
+ const struct_ptr = self.resolveInst(extra.data.struct_ptr);
- return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) };
+ return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };
}
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.ty);
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.SwitchBr, pl_op.payload);
+ const cases = self.air.extra[extra.end..][0..extra.data.cases_len];
+ const else_body = self.air.extra[extra.end + cases.len ..][0..extra.data.else_body_len];
+
+ const target = self.resolveInst(pl_op.operand);
+ const target_ty = self.air.getRefType(pl_op.operand);
+ const valtype = try self.typeToValtype(target_ty);
+ // result type is always 'noreturn'
+ const blocktype = wasm.block_empty;
const signedness: std.builtin.Signedness = blk: {
// by default we tell the operand type is unsigned (i.e. bools and enum values)
@@ -1249,11 +1284,18 @@ pub const Context = struct {
// incase of an actual integer, we emit the correct signedness
break :blk target_ty.intInfo(self.target).signedness;
};
- for (inst.cases) |case| {
+ for (cases) |case_idx| {
+ const case = self.air.extraData(Air.SwitchBr.Case, case_idx);
+ const case_body = self.air.extra[case.end..][0..case.data.body_len];
+
// create a block for each case, when the condition does not match we break out of it
try self.startBlock(.block, blocktype, null);
try self.emitWValue(target);
- try self.emitConstant(.{ .node_offset = 0 }, case.item, target_ty);
+
+ // cases must represent a constant of which its type is in the `typed_value_map`
+ // Therefore we can simply retrieve it.
+ const ty_val = Air.Inst.Ref.typed_value_map[@enumToInt(case.data.item)];
+ try self.emitConstant(ty_val.val, target_ty);
const opcode = buildOpcode(.{
.valtype1 = valtype,
.op = .ne, // not equal because we jump out the block if it does not match the condition
@@ -1264,7 +1306,7 @@ pub const Context = struct {
try leb.writeULEB128(self.code.writer(), @as(u32, 0));
// emit our block code
- try self.genBody(case.body);
+ try self.genBody(case_body);
// end the block we created earlier
try self.endBlock();
@@ -1272,13 +1314,14 @@ pub const Context = struct {
// finally, emit the else case if it exists. Here we will not have to
// check for a condition, so also no need to emit a block.
- try self.genBody(inst.else_body);
+ try self.genBody(else_body);
return .none;
}
fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
- const operand = self.resolveInst(inst.operand);
+ const un_op = self.air.instructions.items(.data)[inst].un_op;
+ const operand = self.resolveInst(un_op);
const offset = self.code.items.len;
const writer = self.code.writer();
@@ -1294,7 +1337,8 @@ pub const Context = struct {
}
fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- const operand = self.resolveInst(inst.operand);
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = self.resolveInst(ty_op.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`
//
@@ -1303,6 +1347,7 @@ pub const Context = struct {
}
fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
- return self.resolveInst(inst.operand);
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ return self.resolveInst(ty_op.operand);
}
};