authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-18 20:57:04+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-18 20:57:04+01:00
logce1f7136ae6db5809d077ccc52639befd73f50c0
tree74b9a0a3515e5164b1a8eec265d54a344c33ef4b
parent820308b3d44ed7ca2cabd07a11b2099992ed4e6b
parentc10089d060e7c11a01e1bcc382235a24f8c48efa

Merge pull request 'cbe: fix `switch` statements on large types' (#31557) from justusk/zig:cbe-switch-128 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31557

4 files changed, 260 insertions(+), 66 deletions(-)

lib/zig.h+14
...@@ -1981,6 +1981,20 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) {...@@ -1981,6 +1981,20 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) {
1981 return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits));1981 return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits));
1982}1982}
19831983
1984#if zig_has_int128
1985#define zig_switch_int128(operand) switch (operand)
1986#define zig_switch_prong_begin_int128()
1987#define zig_switch_case_int128(Type, operand, value) case value:
1988#define zig_switch_prong_end_int128()
1989#define zig_switch_default_int128() default:
1990#else // zig_has_int128
1991#define zig_switch_int128(operand)
1992#define zig_switch_prong_begin_int128() if (0
1993#define zig_switch_case_int128(Type, operand, value) || (zig_cmp_##Type(operand, value) == 0)
1994#define zig_switch_prong_end_int128() )
1995#define zig_switch_default_int128()
1996#endif // zig_has_int128
1997
1984/* ========================== Big Integer Support =========================== */1998/* ========================== Big Integer Support =========================== */
19851999
1986static inline uint16_t zig_int_bytes(uint16_t bits) {2000static inline uint16_t zig_int_bytes(uint16_t bits) {
src/codegen/c.zig+182-62
...@@ -4453,14 +4453,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -4453,14 +4453,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
4453 const switch_br = f.air.unwrapSwitch(inst);4453 const switch_br = f.air.unwrapSwitch(inst);
4454 const init_condition = try f.resolveInst(switch_br.operand);4454 const init_condition = try f.resolveInst(switch_br.operand);
4455 try reap(f, inst, &.{switch_br.operand});4455 try reap(f, inst, &.{switch_br.operand});
4456 const condition_ty = f.typeOf(switch_br.operand);4456 const cond_ty = f.typeOf(switch_br.operand);
4457 const w = &f.code.writer;4457 const w = &f.code.writer;
44584458
4459 // For dispatches, we will create a local alloc to contain the condition value.4459 // For dispatches, we will create a local alloc to contain the condition value.
4460 // This may not result in optimal codegen for switch loops, but it minimizes the4460 // This may not result in optimal codegen for switch loops, but it minimizes the
4461 // amount of C code we generate, which is probably more desirable here (and is simpler).4461 // amount of C code we generate, which is probably more desirable here (and is simpler).
4462 const condition = if (is_dispatch_loop) cond: {4462 const cond_val = if (is_dispatch_loop) cond: {
4463 const new_local = try f.allocLocal(inst, condition_ty);4463 const new_local = try f.allocLocal(inst, cond_ty);
4464 try f.copyCValue(new_local, init_condition);4464 try f.copyCValue(new_local, init_condition);
4465 try w.print("zig_switch_{d}_loop:", .{@intFromEnum(inst)});4465 try w.print("zig_switch_{d}_loop:", .{@intFromEnum(inst)});
4466 try f.newline();4466 try f.newline();
...@@ -4472,26 +4472,38 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -4472,26 +4472,38 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
4472 assert(f.loop_switch_conds.remove(inst));4472 assert(f.loop_switch_conds.remove(inst));
4473 };4473 };
44744474
4475 try w.writeAll("switch (");4475 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1);
4476 defer gpa.free(liveness.deaths);
44764477
4477 const lowered_condition_ty: Type = if (condition_ty.toIntern() == .bool_type)4478 const lowered_cond_ty: Type = switch (cond_ty.zigTypeTag(zcu)) {
4478 .u14479 .@"enum", .error_set, .int, .@"struct", .@"union" => cond_ty,
4479 else if (condition_ty.isPtrAtRuntime(zcu))4480 .bool => .u1,
4480 .usize4481 .pointer => .usize,
4481 else4482 .void => unreachable, // OPV type, always lowered to block/loop
4482 condition_ty;4483 .comptime_int, .enum_literal, .@"fn", .type => unreachable, // comptime-only
4483 if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) {4484 else => unreachable, // not supported by switch statement
4485 };
4486 const cond_cint = switch (CType.classifyInt(lowered_cond_ty, zcu)) {
4487 .void => unreachable, // OPV type, always lowered to block/loop
4488 .small => |small| small,
4489 .big => {
4490 return lowerSwitchToConditions(f, inst, cond_val, lowered_cond_ty, switch_br, liveness, is_dispatch_loop, false);
4491 },
4492 };
4493
4494 switch (cond_cint) {
4495 .zig_u128, .zig_i128 => try w.writeAll("zig_switch_int128("),
4496 else => try w.writeAll("switch ("),
4497 }
4498 if (cond_ty.toIntern() != lowered_cond_ty.toIntern()) {
4484 try w.writeByte('(');4499 try w.writeByte('(');
4485 try f.renderType(w, lowered_condition_ty);4500 try f.renderType(w, lowered_cond_ty);
4486 try w.writeByte(')');4501 try w.writeByte(')');
4487 }4502 }
4488 try f.writeCValue(w, condition, .other);4503 try f.writeCValue(w, cond_val, .other);
4489 try w.writeAll(") {");4504 try w.writeAll(") {");
4490 f.indent();4505 f.indent();
44914506
4492 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1);
4493 defer gpa.free(liveness.deaths);
4494
4495 var any_range_cases = false;4507 var any_range_cases = false;
4496 var it = switch_br.iterateCases();4508 var it = switch_br.iterateCases();
4497 while (it.next()) |case| {4509 while (it.next()) |case| {
...@@ -4499,28 +4511,63 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -4499,28 +4511,63 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
4499 any_range_cases = true;4511 any_range_cases = true;
4500 continue;4512 continue;
4501 }4513 }
4514
4515 switch (cond_cint) {
4516 .zig_u128, .zig_i128 => {
4517 try f.newline();
4518 try w.writeAll("zig_switch_prong_begin_int128()");
4519 },
4520 else => {},
4521 }
4522
4502 for (case.items) |item| {4523 for (case.items) |item| {
4503 try f.newline();4524 try f.newline();
4504 try w.writeAll("case ");4525 case: {
4526 switch (cond_cint) {
4527 .zig_u128 => try w.writeAll(" zig_switch_case_int128(u128, "),
4528 .zig_i128 => try w.writeAll(" zig_switch_case_int128(i128, "),
4529 else => {
4530 try w.writeAll("case ");
4531 break :case;
4532 },
4533 }
4534 if (cond_ty.toIntern() != lowered_cond_ty.toIntern()) {
4535 try w.writeByte('(');
4536 try f.renderType(w, lowered_cond_ty);
4537 try w.writeByte(')');
4538 }
4539 try f.writeCValue(w, cond_val, .other);
4540 try w.writeAll(", ");
4541 }
4505 const item_value = try f.air.value(item, pt);4542 const item_value = try f.air.value(item, pt);
4506 // If `item_value` is a pointer with a known integer address, print the address4543 // If `item_value` is a pointer with a known integer address, print the address
4507 // with no cast to avoid a warning.4544 // with no cast to avoid a warning.
4508 write_val: {4545 write_val: {
4509 if (condition_ty.isPtrAtRuntime(zcu)) {4546 if (cond_ty.zigTypeTag(zcu) == .pointer) {
4510 if (item_value.?.getUnsignedInt(zcu)) |item_int| {4547 if (item_value.?.getUnsignedInt(zcu)) |item_int| {
4511 try w.print("{f}", .{try f.fmtIntLiteralDec(try pt.intValue(lowered_condition_ty, item_int))});4548 try w.print("{f}", .{try f.fmtIntLiteralDec(try pt.intValue(lowered_cond_ty, item_int))});
4512 break :write_val;4549 break :write_val;
4513 }4550 }
4514 }
4515 if (condition_ty.isPtrAtRuntime(zcu)) {
4516 try w.writeByte('(');4551 try w.writeByte('(');
4517 try f.renderType(w, .usize);4552 try f.renderType(w, .usize);
4518 try w.writeByte(')');4553 try w.writeByte(')');
4519 }4554 }
4520 try f.dg.renderValue(w, (try f.air.value(item, pt)).?, .other);4555 try f.dg.renderValue(w, (try f.air.value(item, pt)).?, .other);
4521 }4556 }
4522 try w.writeByte(':');4557 switch (cond_cint) {
4558 .zig_u128, .zig_i128 => try w.writeByte(')'),
4559 else => try w.writeByte(':'),
4560 }
4523 }4561 }
4562
4563 switch (cond_cint) {
4564 .zig_u128, .zig_i128 => {
4565 try f.newline();
4566 try w.writeAll("zig_switch_prong_end_int128()");
4567 },
4568 else => {},
4569 }
4570
4524 try w.writeAll(" {");4571 try w.writeAll(" {");
4525 f.indent();4572 f.indent();
4526 try f.newline();4573 try f.newline();
...@@ -4537,56 +4584,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -4537,56 +4584,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
4537 // The case body must be noreturn so we don't need to insert a break.4584 // The case body must be noreturn so we don't need to insert a break.
4538 }4585 }
45394586
4540 const else_body = it.elseBody();
4541 try f.newline();4587 try f.newline();
45424588
4543 try w.writeAll("default: ");4589 switch (cond_cint) {
4590 .zig_u128, .zig_i128 => try w.writeAll("zig_switch_default_int128() "),
4591 else => try w.writeAll("default: "),
4592 }
4544 if (any_range_cases) {4593 if (any_range_cases) {
4545 // We will iterate the cases again to handle those with ranges, and generate4594 // We will iterate the cases again to handle those with ranges, and generate
4546 // code using conditions rather than switch cases for such cases.4595 // code using conditions rather than switch cases for such cases.
4547 it = switch_br.iterateCases();4596 try lowerSwitchToConditions(f, inst, cond_val, lowered_cond_ty, switch_br, liveness, is_dispatch_loop, true);
4548 while (it.next()) |case| {
4549 if (case.ranges.len == 0) continue; // handled above
4550
4551 try w.writeAll("if (");
4552 for (case.items, 0..) |item, item_i| {
4553 if (item_i != 0) try w.writeAll(" || ");
4554 try f.writeCValue(w, condition, .other);
4555 try w.writeAll(" == ");
4556 try f.dg.renderValue(w, (try f.air.value(item, pt)).?, .other);
4557 }
4558 for (case.ranges, 0..) |range, range_i| {
4559 if (case.items.len != 0 or range_i != 0) try w.writeAll(" || ");
4560 // "(x >= lower && x <= upper)"
4561 try w.writeByte('(');
4562 try f.writeCValue(w, condition, .other);
4563 try w.writeAll(" >= ");
4564 try f.dg.renderValue(w, (try f.air.value(range[0], pt)).?, .other);
4565 try w.writeAll(" && ");
4566 try f.writeCValue(w, condition, .other);
4567 try w.writeAll(" <= ");
4568 try f.dg.renderValue(w, (try f.air.value(range[1], pt)).?, .other);
4569 try w.writeByte(')');
4570 }
4571 try w.writeAll(") {");
4572 f.indent();
4573 try f.newline();
4574 if (is_dispatch_loop) {
4575 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
4576 }
4577 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
4578 try f.outdent();
4579 try w.writeByte('}');
4580 if (f.dg.expected_block) |_|
4581 return f.fail("runtime code not allowed in naked function", .{});
4582 }
4583 }4597 }
4584 if (is_dispatch_loop) {4598 if (is_dispatch_loop) {
4585 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len });4599 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len });
4586 }4600 }
4601 const else_body = it.elseBody();
4587 if (else_body.len > 0) {4602 if (else_body.len > 0) {
4588 // Note that this must be the last case, so we do not need to use `genBodyResolveState` since4603 // Note that this must be the last case, so we do not need to use `genBodyResolveState`
4589 // the parent block will do it (because the case body is noreturn).4604 // since the parent block will do it (because the case body is noreturn).
4590 for (liveness.deaths[liveness.deaths.len - 1]) |death| {4605 for (liveness.deaths[liveness.deaths.len - 1]) |death| {
4591 try die(f, inst, death.toRef());4606 try die(f, inst, death.toRef());
4592 }4607 }
...@@ -4598,6 +4613,111 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void...@@ -4598,6 +4613,111 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
4598 try f.outdent();4613 try f.outdent();
4599 try w.writeAll("}\n");4614 try w.writeAll("}\n");
4600}4615}
4616fn lowerSwitchToConditions(
4617 f: *Function,
4618 inst: Air.Inst.Index,
4619 cond_val: CValue,
4620 cond_ty: Type,
4621 switch_br: Air.UnwrappedSwitch,
4622 liveness: Air.Liveness.SwitchBrTable,
4623 is_dispatch_loop: bool,
4624 only_ranges: bool,
4625) !void {
4626 const w = &f.code.writer;
4627
4628 var it = switch_br.iterateCases();
4629 while (it.next()) |case| {
4630 if (case.ranges.len == 0 and only_ranges) continue;
4631
4632 try w.writeAll("if (");
4633 for (case.items, 0..) |item, item_i| {
4634 if (item_i != 0) {
4635 try f.newline();
4636 try w.writeAll(" || ");
4637 }
4638 try lowerSwitchCmp(f, cond_val, .eq, item, cond_ty);
4639 }
4640 for (case.ranges, 0..) |range, range_i| {
4641 if (case.items.len != 0 or range_i != 0) {
4642 try f.newline();
4643 try w.writeAll(" || ");
4644 }
4645 // "(x >= lower && x <= upper)"
4646 try w.writeByte('(');
4647 try lowerSwitchCmp(f, cond_val, .gte, range[0], cond_ty);
4648 try w.writeAll(" && ");
4649 try lowerSwitchCmp(f, cond_val, .lte, range[1], cond_ty);
4650 try w.writeByte(')');
4651 }
4652 try w.writeAll(") {");
4653 f.indent();
4654 try f.newline();
4655 if (is_dispatch_loop) {
4656 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
4657 }
4658 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
4659 try f.outdent();
4660 try w.writeByte('}');
4661 try f.newline();
4662 if (f.dg.expected_block) |_|
4663 return f.fail("runtime code not allowed in naked function", .{});
4664 }
4665
4666 if (!only_ranges) {
4667 if (is_dispatch_loop) {
4668 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len });
4669 }
4670 const else_body = it.elseBody();
4671 if (else_body.len > 0) {
4672 // Note that this must be the last case, so we do not need to use `genBodyResolveState`
4673 // since the parent block will do it (because the case body is noreturn).
4674 for (liveness.deaths[liveness.deaths.len - 1]) |death| {
4675 try die(f, inst, death.toRef());
4676 }
4677 try genBody(f, else_body);
4678 if (f.dg.expected_block) |_|
4679 return f.fail("runtime code not allowed in naked function", .{});
4680 } else try airUnreach(f);
4681 try f.newline();
4682 }
4683}
4684fn lowerSwitchCmp(
4685 f: *Function,
4686 cond_val: CValue,
4687 operator: std.math.CompareOperator,
4688 case_inst: Air.Inst.Ref,
4689 ty: Type,
4690) !void {
4691 const pt = f.dg.pt;
4692 const zcu = pt.zcu;
4693 const w = &f.code.writer;
4694
4695 const class = CType.classifyInt(ty, zcu);
4696 const use_builtin = switch (class) {
4697 .void => unreachable, // assertion failure
4698 .small => |small| switch (small) {
4699 .zig_u128, .zig_i128 => true,
4700 else => false,
4701 },
4702 .big => true,
4703 };
4704 if (use_builtin) {
4705 try w.writeAll("zig_cmp_");
4706 try f.dg.renderTypeForBuiltinFnName(w, ty);
4707 try w.writeByte('(');
4708 }
4709 if (class == .big) try w.writeByte('&');
4710 try f.writeCValue(w, cond_val, .other);
4711 try w.writeAll(if (use_builtin) ", " else compareOperatorC(operator));
4712 if (class == .big) try w.writeByte('&');
4713 try f.dg.renderValue(w, (try f.air.value(case_inst, pt)).?, .other);
4714 if (use_builtin) {
4715 try f.dg.renderBuiltinInfo(w, ty, if (class == .big) .bits else .none);
4716 try w.writeByte(')');
4717 try w.writeAll(compareOperatorC(operator));
4718 try w.writeByte('0');
4719 }
4720}
46014721
4602fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {4722fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
4603 const dg = f.dg;4723 const dg = f.dg;
test/behavior/switch.zig+32-4
...@@ -49,8 +49,6 @@ test "switch arbitrary int size" {...@@ -49,8 +49,6 @@ test "switch arbitrary int size" {
49 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
5151
52 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO
53
54 try expect(testSwitchArbInt(u64, 0) == 0);52 try expect(testSwitchArbInt(u64, 0) == 0);
55 try expect(testSwitchArbInt(u64, 12) == 1);53 try expect(testSwitchArbInt(u64, 12) == 1);
56 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);54 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);
...@@ -1406,8 +1404,6 @@ test "switch on packed union" {...@@ -1406,8 +1404,6 @@ test "switch on packed union" {
1406}1404}
14071405
1408test "switch on nested packed containers" {1406test "switch on nested packed containers" {
1409 if (builtin.object_format == .c) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/31467
1410
1411 const P = packed struct {1407 const P = packed struct {
1412 iu: u17,1408 iu: u17,
1413 is: i31,1409 is: i31,
...@@ -1459,3 +1455,35 @@ test "switch on nested packed containers" {...@@ -1459,3 +1455,35 @@ test "switch on nested packed containers" {
1459 .p = .{ .a = 2, .b = 17 },1455 .p = .{ .a = 2, .b = 17 },
1460 });1456 });
1461}1457}
1458
1459test "switch on large types" {
1460 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1461
1462 const S = struct {
1463 fn doTheTest(a: u128, b: i500) !void {
1464 switch (a) {
1465 0x0,
1466 0x3...0xFFFF_FFFF_FFFF_FFFF_FFFF_ABCD,
1467 0xFFFF_FFFF_FFFF_FFFF_FFFF_EF00,
1468 => return error.TestFailed,
1469 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000...0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFF0,
1470 => |val| {
1471 try expect(val == 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_1234);
1472 },
1473 else => return error.TestFailed,
1474 }
1475 switch (b) {
1476 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000...0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_1234,
1477 => return error.TestFailed,
1478 0xFFFF_1234,
1479 0xFFFF_FFFF_FFFF_FFFF_FFFF_0123...0xFFFF_FFFF_FFFF_FFFF_FFFF_4567,
1480 => |val| {
1481 try expect(val == 0xFFFF_1234);
1482 },
1483 else => return error.TestFailed,
1484 }
1485 }
1486 };
1487 try S.doTheTest(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_1234, 0xFFFF_1234);
1488 try comptime S.doTheTest(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_1234, 0xFFFF_1234);
1489}
test/behavior/switch_loop.zig+32
...@@ -564,3 +564,35 @@ test "switch loop with packed unions with OPV" {...@@ -564,3 +564,35 @@ test "switch loop with packed unions with OPV" {
564 try P.doTheTest(.{ .a = 0 });564 try P.doTheTest(.{ .a = 0 });
565 try comptime P.doTheTest(.{ .a = 0 });565 try comptime P.doTheTest(.{ .a = 0 });
566}566}
567
568test "switch loop on large types" {
569 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
570
571 const S = struct {
572 fn doTheTest(a: u128, b: i500) !void {
573 label: switch (a) {
574 0x0,
575 0x3...0xFFFF_FFFF_FFFF_FFFF_FFFF_ABCD,
576 0xFFFF_FFFF_FFFF_FFFF_FFFF_EF00,
577 => return error.TestFailed,
578 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000...0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFF0,
579 => |val| {
580 continue :label val + 1;
581 },
582 else => {},
583 }
584 label: switch (b) {
585 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_0000...0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_1234,
586 => return error.TestFailed,
587 0xFFFF_1234,
588 0xFFFF_FFFF_FFFF_FFFF_FFFF_0123...0xFFFF_FFFF_FFFF_FFFF_FFFF_4567,
589 => |val| {
590 continue :label val + 1;
591 },
592 else => {},
593 }
594 }
595 };
596 try S.doTheTest(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FF00, 0xFFFF_FFFF_FFFF_FFFF_FFFF_4550);
597 try comptime S.doTheTest(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FF00, 0xFFFF_FFFF_FFFF_FFFF_FFFF_4550);
598}