authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-05-20 14:21:02+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-05-20 14:21:02+02:00
log81d8fe7558cdae829c30cba3c92dfc373336929c
tree5da6bf37ec0afacd3256cd9e5ac272707c4a09f2
parent87a9c6946dd536de562bc86ac4819a33df3442df
signaturelock-open Commit is signed but in an unrecognized format.

stage2 wasm: Support basic switches

- Adds support for single branches - Allows both enums and integers - Supports 'else' branch

1 files changed, 42 insertions(+), 0 deletions(-)

src/codegen/wasm.zig+42
...@@ -746,6 +746,7 @@ pub const Context = struct {...@@ -746,6 +746,7 @@ pub const Context = struct {
746 .store => self.genStore(inst.castTag(.store).?),746 .store => self.genStore(inst.castTag(.store).?),
747 .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),747 .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
748 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),748 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
749 .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
749 .unreach => self.genUnreachable(inst.castTag(.unreach).?),750 .unreach => self.genUnreachable(inst.castTag(.unreach).?),
750 .xor => self.genBinOp(inst.castTag(.xor).?, .xor),751 .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
751 else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}),752 else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}),
...@@ -1130,4 +1131,45 @@ pub const Context = struct {...@@ -1130,4 +1131,45 @@ pub const Context = struct {
11301131
1131 return WValue{ .local = struct_ptr.multi_value + @intCast(u32, inst.field_index) };1132 return WValue{ .local = struct_ptr.multi_value + @intCast(u32, inst.field_index) };
1132 }1133 }
1134
1135 fn genSwitchBr(self: *Context, inst: *Inst.SwitchBr) InnerError!WValue {
1136 const target = self.resolveInst(inst.target);
1137 const target_ty = inst.target.ty;
1138 const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty);
1139 const blocktype = try self.genBlockType(inst.base.src, inst.base.ty);
1140
1141 const signedness: std.builtin.Signedness = blk: {
1142 // by default we tell the operand type is unsigned (i.e. bools and enum values)
1143 if (target_ty.zigTypeTag() != .Int) break :blk .unsigned;
1144
1145 // incase of an actual integer, we emit the correct signedness
1146 break :blk target_ty.intInfo(self.target).signedness;
1147 };
1148 for (inst.cases) |case| {
1149 // create a block for each case, when the condition does not match we break out of it
1150 try self.startBlock(.block, blocktype, null);
1151 try self.emitWValue(target);
1152 try self.emitConstant(.{ .node_offset = 0 }, case.item, target_ty);
1153 const opcode = buildOpcode(.{
1154 .valtype1 = valtype,
1155 .op = .ne, // not equal because we jump out the block if it does not match the condition
1156 .signedness = signedness,
1157 });
1158 try self.code.append(wasm.opcode(opcode));
1159 try self.code.append(wasm.opcode(.br_if));
1160 try leb.writeULEB128(self.code.writer(), @as(u32, 0));
1161
1162 // emit our block code
1163 try self.genBody(case.body);
1164
1165 // end the block we created earlier
1166 try self.endBlock();
1167 }
1168
1169 // finally, emit the else case if it exists. Here we will not have to
1170 // check for a condition, so also no need to emit a block.
1171 try self.genBody(inst.else_body);
1172
1173 return .none;
1174 }
1133};1175};