| ... | ... | @@ -1946,6 +1946,8 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1946 | 1946 | .ret_addr => func.airRetAddr(inst), |
| 1947 | 1947 | .tag_name => func.airTagName(inst), |
| 1948 | 1948 | |
| 1949 | .error_set_has_value => func.airErrorSetHasValue(inst), |
| 1950 | |
| 1949 | 1951 | .mul_sat, |
| 1950 | 1952 | .mod, |
| 1951 | 1953 | .assembly, |
| ... | ... | @@ -1967,7 +1969,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1967 | 1969 | .set_err_return_trace, |
| 1968 | 1970 | .save_err_return_trace_index, |
| 1969 | 1971 | .is_named_enum_value, |
| 1970 | | .error_set_has_value, |
| 1971 | 1972 | .addrspace_cast, |
| 1972 | 1973 | .vector_store_elem, |
| 1973 | 1974 | .c_va_arg, |
| ... | ... | @@ -6514,3 +6515,85 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6514 | 6515 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); |
| 6515 | 6516 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6516 | 6517 | } |
| 6518 | |
| 6519 | fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6520 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6521 | if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 6522 | |
| 6523 | const operand = try func.resolveInst(ty_op.operand); |
| 6524 | const error_set_ty = func.air.getRefType(ty_op.ty); |
| 6525 | const result = try func.allocLocal(Type.bool); |
| 6526 | |
| 6527 | const names = error_set_ty.errorSetNames(); |
| 6528 | var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len); |
| 6529 | defer values.deinit(); |
| 6530 | |
| 6531 | const module = func.bin_file.base.options.module.?; |
| 6532 | var lowest: ?u32 = null; |
| 6533 | var highest: ?u32 = null; |
| 6534 | for (names) |name| { |
| 6535 | const err_int = module.global_error_set.get(name).?; |
| 6536 | if (lowest) |*l| { |
| 6537 | if (err_int < l.*) { |
| 6538 | l.* = err_int; |
| 6539 | } |
| 6540 | } else { |
| 6541 | lowest = err_int; |
| 6542 | } |
| 6543 | if (highest) |*h| { |
| 6544 | if (err_int > h.*) { |
| 6545 | highest = err_int; |
| 6546 | } |
| 6547 | } else { |
| 6548 | highest = err_int; |
| 6549 | } |
| 6550 | |
| 6551 | values.appendAssumeCapacity(err_int); |
| 6552 | } |
| 6553 | |
| 6554 | // start block for 'true' branch |
| 6555 | try func.startBlock(.block, wasm.block_empty); |
| 6556 | // start block for 'false' branch |
| 6557 | try func.startBlock(.block, wasm.block_empty); |
| 6558 | // block for the jump table itself |
| 6559 | try func.startBlock(.block, wasm.block_empty); |
| 6560 | |
| 6561 | // lower operand to determine jump table target |
| 6562 | try func.emitWValue(operand); |
| 6563 | try func.addImm32(@intCast(i32, lowest.?)); |
| 6564 | try func.addTag(.i32_sub); |
| 6565 | |
| 6566 | // Account for default branch so always add '1' |
| 6567 | const depth = @intCast(u32, highest.? - lowest.? + 1); |
| 6568 | const jump_table: Mir.JumpTable = .{ .length = depth }; |
| 6569 | const table_extra_index = try func.addExtra(jump_table); |
| 6570 | try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } }); |
| 6571 | try func.mir_extra.ensureUnusedCapacity(func.gpa, depth); |
| 6572 | |
| 6573 | var value: u32 = lowest.?; |
| 6574 | while (value <= highest.?) : (value += 1) { |
| 6575 | const idx: u32 = blk: { |
| 6576 | for (values.items) |val| { |
| 6577 | if (val == value) break :blk 1; |
| 6578 | } |
| 6579 | break :blk 0; |
| 6580 | }; |
| 6581 | func.mir_extra.appendAssumeCapacity(idx); |
| 6582 | } |
| 6583 | try func.endBlock(); |
| 6584 | |
| 6585 | // 'false' branch (i.e. error set does not have value |
| 6586 | // ensure we set local to 0 in case the local was re-used. |
| 6587 | try func.addImm32(0); |
| 6588 | try func.addLabel(.local_set, result.local.value); |
| 6589 | try func.addLabel(.br, 1); |
| 6590 | try func.endBlock(); |
| 6591 | |
| 6592 | // 'true' branch |
| 6593 | try func.addImm32(1); |
| 6594 | try func.addLabel(.local_set, result.local.value); |
| 6595 | try func.addLabel(.br, 0); |
| 6596 | try func.endBlock(); |
| 6597 | |
| 6598 | return func.finishAir(inst, result, &.{ty_op.operand}); |
| 6599 | } |