From 32c9b0950ba79619e6d42f15652b2338fd027290 Mon Sep 17 00:00:00 2001 From: Literally Void Date: Tue, 10 Sep 2024 22:00:23 -0700 Subject: [PATCH] Add langref docs for labeled switch This feature was proposed in #8220, and implemented in #21257. --- doc/langref.html.in | 13 ++++++ doc/langref/test_switch_continue.zig | 22 ++++++++++ doc/langref/test_switch_dispatch_loop.zig | 52 +++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 doc/langref/test_switch_continue.zig create mode 100644 doc/langref/test_switch_dispatch_loop.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index cea86e895541..968a5fb78e8f 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2497,6 +2497,19 @@ or {#header_close#} + {#header_open|Labeled switch#} +

+ When a {#syntax#}switch{#endsyntax#} statement is labeled, it can be referenced from a {#syntax#}continue{#endsyntax#} statement. The executed prong is specified by the value passed to the {#syntax#}continue{#endsyntax#} statement. +

+ {#code|test_switch_continue.zig#} + +

+ The intent is to allow the CPU to create an independent branch-prediction cache for each prong, instead of a single branch prediction cache for the switch's entry point. This can improve performance. +

+ {#code|test_switch_dispatch_loop.zig#} + + {#header_close#} + {#header_open|Inline Switch Prongs#}

Switch prongs can be marked as {#syntax#}inline{#endsyntax#} to generate diff --git a/doc/langref/test_switch_continue.zig b/doc/langref/test_switch_continue.zig new file mode 100644 index 000000000000..baa3ce4580a0 --- /dev/null +++ b/doc/langref/test_switch_continue.zig @@ -0,0 +1,22 @@ +const std = @import("std"); +const expectEqual = std.testing.expectEqual; + +test "switch continue" { + const value: i32 = 54; + const result = sw: switch (value) { + 10...60 => |v| continue :sw v - 10, + 4 => continue :sw 3, + 3 => continue :sw 2, + 2 => continue :sw 1, + + // A switch statement can be targeted by a break, even if the switch and + // the break are unlabeled. + 1 => break -6, + + else => unreachable, + }; + + try expectEqual(-6, result); +} + +// test diff --git a/doc/langref/test_switch_dispatch_loop.zig b/doc/langref/test_switch_dispatch_loop.zig new file mode 100644 index 000000000000..6491bbb100f3 --- /dev/null +++ b/doc/langref/test_switch_dispatch_loop.zig @@ -0,0 +1,52 @@ +const std = @import("std"); +const expectEqual = std.testing.expectEqual; + +const Instruction = enum { + mul, + add, + end, +}; + +test "switch dispatch loop" { + var stack = std.ArrayList(i32).init(std.testing.allocator); + defer stack.deinit(); + + try stack.append(5); + try stack.append(1); + try stack.append(-1); + + const instructions: []const Instruction = &.{ + .mul, .add, .end, + }; + + var ip: usize = 0; + + const result = vm: switch (instructions[ip]) { + // Because this prong always `continue`s, it's not required to produce + // a result. + .add => { + const l = stack.pop(); + const r = stack.pop(); + + try stack.append(l + r); + + ip += 1; + continue :vm instructions[ip]; + }, + .mul => { + const l = stack.pop(); + const r = stack.pop(); + + try stack.append(l * r); + + ip += 1; + continue :vm instructions[ip]; + }, + .end => stack.pop(), + }; + + try expectEqual(4, result); +} + +// test +