| ... | @@ -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 { |
| 1130 | | 1131 | |
| 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 | }; |