| ... | ... | @@ -1271,60 +1271,73 @@ pub const Context = struct { |
| 1271 | 1271 | } |
| 1272 | 1272 | |
| 1273 | 1273 | fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { |
| 1274 | | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1275 | | const extra = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 1276 | | const cases = self.air.extra[extra.end..][0..extra.data.cases_len]; |
| 1277 | | const else_body = self.air.extra[extra.end + cases.len ..][0..extra.data.else_body_len]; |
| 1278 | | |
| 1279 | | const target = self.resolveInst(pl_op.operand); |
| 1280 | | const target_ty = self.air.typeOf(pl_op.operand); |
| 1281 | | const valtype = try self.typeToValtype(target_ty); |
| 1282 | 1274 | // result type is always 'noreturn' |
| 1283 | 1275 | const blocktype = wasm.block_empty; |
| 1276 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1277 | const target = self.resolveInst(pl_op.operand); |
| 1278 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 1279 | var extra_index: usize = switch_br.end; |
| 1280 | var case_i: u32 = 0; |
| 1281 | |
| 1282 | // a map that maps each value with its index and body |
| 1283 | var map = std.AutoArrayHashMap(u32, struct { index: u32, body: []const Air.Inst.Index }).init(self.gpa); |
| 1284 | defer map.deinit(); |
| 1285 | |
| 1286 | var lowest: u32 = 0; |
| 1287 | var highest: u32 = 0; |
| 1288 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| 1289 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| 1290 | const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); |
| 1291 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 1292 | extra_index = case.end + items.len + case_body.len; |
| 1293 | |
| 1294 | for (items) |ref| { |
| 1295 | const item_val = @intCast(u32, self.air.value(ref).?.toUnsignedInt()); |
| 1296 | if (item_val < lowest) { |
| 1297 | lowest = item_val; |
| 1298 | } |
| 1299 | if (item_val > highest) { |
| 1300 | highest = item_val; |
| 1301 | } |
| 1302 | try map.put(item_val, .{ .index = case_i, .body = case_body }); |
| 1303 | } |
| 1304 | |
| 1305 | try self.startBlock(.block, blocktype, null); |
| 1306 | } |
| 1284 | 1307 | |
| 1285 | | _ = valtype; |
| 1286 | | _ = blocktype; |
| 1287 | | _ = target; |
| 1288 | | _ = else_body; |
| 1289 | | return self.fail("TODO implement wasm codegen for switch", .{}); |
| 1290 | | //const signedness: std.builtin.Signedness = blk: { |
| 1291 | | // // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 1292 | | // if (target_ty.zigTypeTag() != .Int) break :blk .unsigned; |
| 1293 | | |
| 1294 | | // // incase of an actual integer, we emit the correct signedness |
| 1295 | | // break :blk target_ty.intInfo(self.target).signedness; |
| 1296 | | //}; |
| 1297 | | //for (cases) |case_idx| { |
| 1298 | | // const case = self.air.extraData(Air.SwitchBr.Case, case_idx); |
| 1299 | | // const case_body = self.air.extra[case.end..][0..case.data.body_len]; |
| 1300 | | |
| 1301 | | // // create a block for each case, when the condition does not match we break out of it |
| 1302 | | // try self.startBlock(.block, blocktype, null); |
| 1303 | | // try self.emitWValue(target); |
| 1304 | | |
| 1305 | | // const val = self.air.value(case.data.item).?; |
| 1306 | | // try self.emitConstant(val, target_ty); |
| 1307 | | // const opcode = buildOpcode(.{ |
| 1308 | | // .valtype1 = valtype, |
| 1309 | | // .op = .ne, // not equal because we jump out the block if it does not match the condition |
| 1310 | | // .signedness = signedness, |
| 1311 | | // }); |
| 1312 | | // try self.code.append(wasm.opcode(opcode)); |
| 1313 | | // try self.code.append(wasm.opcode(.br_if)); |
| 1314 | | // try leb.writeULEB128(self.code.writer(), @as(u32, 0)); |
| 1315 | | |
| 1316 | | // // emit our block code |
| 1317 | | // try self.genBody(case_body); |
| 1318 | | |
| 1319 | | // // end the block we created earlier |
| 1320 | | // try self.endBlock(); |
| 1321 | | //} |
| 1322 | | |
| 1323 | | //// finally, emit the else case if it exists. Here we will not have to |
| 1324 | | //// check for a condition, so also no need to emit a block. |
| 1325 | | //try self.genBody(else_body); |
| 1326 | | |
| 1327 | | //return .none; |
| 1308 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 1309 | if (else_body.len != 0) { |
| 1310 | try self.startBlock(.block, blocktype, null); |
| 1311 | } |
| 1312 | |
| 1313 | // Generate the jump table 'br_table'. |
| 1314 | // The value 'target' represents the index into the table. |
| 1315 | // Each index in the table represents a label to the branch |
| 1316 | // to jump to. |
| 1317 | try self.startBlock(.block, blocktype, null); |
| 1318 | try self.emitWValue(target); |
| 1319 | try self.code.append(wasm.opcode(.br_table)); |
| 1320 | try leb.writeULEB128(self.code.writer(), highest - lowest + 1); |
| 1321 | while (lowest <= highest) : (lowest += 1) { |
| 1322 | const idx = if (map.get(lowest)) |value| blk: { |
| 1323 | break :blk value.index + 1; |
| 1324 | } else 0; |
| 1325 | try leb.writeULEB128(self.code.writer(), idx); |
| 1326 | } else if (else_body.len != 0) { |
| 1327 | try leb.writeULEB128(self.code.writer(), @as(u32, 0)); // default branch |
| 1328 | } |
| 1329 | try self.endBlock(); |
| 1330 | |
| 1331 | if (else_body.len != 0) { |
| 1332 | try self.genBody(else_body); |
| 1333 | try self.endBlock(); |
| 1334 | } |
| 1335 | |
| 1336 | for (map.values()) |val| { |
| 1337 | try self.genBody(val.body); |
| 1338 | try self.endBlock(); |
| 1339 | } |
| 1340 | return .none; |
| 1328 | 1341 | } |
| 1329 | 1342 | |
| 1330 | 1343 | fn airIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue { |