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