tint/hlsl: fix RemoveContinueInSwitch transform to handle nested switch statements
Rework the transform so that it handles a continue within a switch
nested within switches within a loop. Also make the transform only
generate a single bool variable per loop, rather than per continue
statement.
Bug: tint:1080
Change-Id: I626cf4aa35e900ccc8ad08712ff1393c91587f10
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/151041
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.cc b/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.cc
index b091b91..4f1808b 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.cc
@@ -15,7 +15,6 @@
#include "src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.h"
#include <string>
-#include <unordered_map>
#include <utility>
#include "src/tint/lang/wgsl/ast/continue_statement.h"
@@ -25,11 +24,10 @@
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/resolve.h"
#include "src/tint/lang/wgsl/sem/block_statement.h"
-#include "src/tint/lang/wgsl/sem/for_loop_statement.h"
#include "src/tint/lang/wgsl/sem/loop_statement.h"
#include "src/tint/lang/wgsl/sem/switch_statement.h"
-#include "src/tint/lang/wgsl/sem/while_statement.h"
-#include "src/tint/utils/containers/map.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/containers/hashset.h"
TINT_INSTANTIATE_TYPEINFO(tint::hlsl::writer::RemoveContinueInSwitch);
@@ -44,8 +42,7 @@
/// Runs the transform
/// @returns the new program or SkipTransform if the transform is not required
ApplyResult Run() {
- bool made_changes = false;
-
+ // First collect all switch statements within loops that contain a continue statement.
for (auto* node : src->ASTNodes().Objects()) {
auto* cont = node->As<ast::ContinueStatement>();
if (!cont) {
@@ -58,37 +55,71 @@
continue;
}
- made_changes = true;
-
- auto cont_var_name = tint::GetOrCreate(switch_to_cont_var_name, switch_stmt, [&] {
- // Create and insert 'var tint_continue : bool = false;' before the
- // switch.
- auto var_name = b.Symbols().New("tint_continue");
- auto* decl = b.Decl(b.Var(var_name, b.ty.bool_(), b.Expr(false)));
- auto ip = ast::transform::utils::GetInsertionPoint(ctx, switch_stmt);
- ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
-
- // Create and insert 'if (tint_continue) { continue; }' after
- // switch.
- auto* if_stmt = b.If(b.Expr(var_name), b.Block(b.Continue()));
- ctx.InsertAfter(ip.first->Declaration()->statements, ip.second, if_stmt);
-
- // Return the new var name
- return var_name;
+ auto& info = switch_infos.GetOrCreate(switch_stmt, [&] {
+ switch_stmts.Push(switch_stmt);
+ auto* block = sem.Get(switch_stmt)->FindFirstParent<sem::LoopBlockStatement>();
+ return SwitchInfo{/* loop_block */ block, /* continues */ Empty};
});
-
- // Replace 'continue;' with '{ tint_continue = true; break; }'
- auto* new_stmt = b.Block( //
- b.Assign(b.Expr(cont_var_name), true), //
- b.Break());
-
- ctx.Replace(cont, new_stmt);
+ info.continues.Push(cont);
}
- if (!made_changes) {
+ if (switch_stmts.IsEmpty()) {
return SkipTransform;
}
+ // For each switch statement:
+ // 1. Declare a 'tint_continue' var just before the parent loop, and reset it to false at
+ // the top of the loop body.
+ // 2. Replace 'continue' with 'tint_continue = true; break;'
+ // 3. Insert 'if (tint_continue) { break; }' after switch, and all parent switches, except
+ // for the parent-most, for which we insert 'if (tint_continue) { continue; }'
+ for (auto* switch_stmt : switch_stmts) {
+ const auto& info = switch_infos.Get(switch_stmt);
+
+ auto var_name = loop_to_var.GetOrCreate(info->loop_block, [&] {
+ // Create and insert 'var tint_continue : bool;' before loop
+ auto var = b.Symbols().New("tint_continue");
+ auto* decl = b.Decl(b.Var(var, b.ty.bool_()));
+ auto ip = ast::transform::utils::GetInsertionPoint(
+ ctx, info->loop_block->Parent()->Declaration());
+ ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
+
+ // Insert 'tint_continue = false' at top of loop body
+ auto assign_false = b.Assign(var, false);
+ ctx.InsertFront(info->loop_block->Declaration()->statements, assign_false);
+
+ return var;
+ });
+
+ for (auto& c : info->continues) {
+ // Replace 'continue;' with 'tint_continue = true; break;'
+ ctx.Replace(c, b.Assign(b.Expr(var_name), true));
+ ctx.InsertAfter(sem.Get(c)->Block()->Declaration()->statements, c, b.Break());
+ }
+
+ // Insert 'if (tint_continue) { break; }' after switch, and all parent switches,
+ // except for the parent-most, for which we insert 'if (tint_continue) { continue; }'
+ auto* curr_switch = switch_stmt;
+ while (curr_switch) {
+ auto* curr_switch_sem = sem.Get(curr_switch);
+ auto* parent = curr_switch_sem->Parent()->Declaration();
+ auto* next_switch = GetParentSwitchInLoop(sem, parent);
+
+ if (switch_handles_continue.Add(curr_switch)) {
+ const ast::IfStatement* if_stmt = nullptr;
+ if (next_switch) {
+ if_stmt = b.If(b.Expr(var_name), b.Block(b.Break()));
+ } else {
+ if_stmt = b.If(b.Expr(var_name), b.Block(b.Continue()));
+ }
+ ctx.InsertAfter(curr_switch_sem->Block()->Declaration()->statements,
+ curr_switch, if_stmt);
+ }
+
+ curr_switch = next_switch;
+ }
+ }
+
ctx.Clone();
return resolver::Resolve(b);
}
@@ -103,17 +134,38 @@
/// Alias to src->sem
const sem::Info& sem = src->Sem();
- // Map of switch statement to 'tint_continue' variable.
- std::unordered_map<const ast::SwitchStatement*, Symbol> switch_to_cont_var_name;
+ // Vector of switch statements within a loop that contains at least one continue statement.
+ Vector<const ast::SwitchStatement*, 4> switch_stmts;
- // If `cont` is within a switch statement within a loop, returns a pointer to
+ // Info for each switch statement within a loop that contains at least one continue statement.
+ struct SwitchInfo {
+ // Loop block containing this switch
+ const sem::LoopBlockStatement* loop_block;
+ // Continue statements within this switch
+ Vector<const ast::ContinueStatement*, 4> continues;
+ };
+
+ // Map of switch statements to per-switch info for switch statements within a loop that contains
+ // at least one continue statement.
+ Hashmap<const ast::SwitchStatement*, SwitchInfo, 4> switch_infos;
+
+ // Map of loop block statement to the single 'tint_continue' variable used to replace 'continue'
+ // control flow.
+ Hashmap<const sem::LoopBlockStatement*, Symbol, 4> loop_to_var;
+
+ // Set used to avoid duplicating 'if (tint_continue) { break/continue; }' after each switch
+ // within a loop.
+ Hashset<const ast::SwitchStatement*, 4> switch_handles_continue;
+
+ // If `stmt` is within a switch statement within a loop, returns a pointer to
// that switch statement.
static const ast::SwitchStatement* GetParentSwitchInLoop(const sem::Info& sem,
- const ast::ContinueStatement* cont) {
+ const ast::Statement* stmt) {
// Find whether first parent is a switch or a loop
- auto* sem_stmt = sem.Get(cont);
- auto* sem_parent = sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
- sem::ForLoopStatement, sem::WhileStatement>();
+ auto* sem_stmt = sem.Get(stmt);
+ auto* sem_parent =
+ sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement>();
+
if (!sem_parent) {
return nullptr;
}
diff --git a/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch_test.cc b/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch_test.cc
index 60153b1..e03e734 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch_test.cc
@@ -28,7 +28,6 @@
switch(i) {
case 0: {
continue;
- break;
}
default: {
break;
@@ -116,7 +115,6 @@
switch(i) {
case 0: {
continue;
- break;
}
default: {
break;
@@ -135,15 +133,13 @@
auto* expect = R"(
fn f() {
var i = 0;
+ var tint_continue : bool;
loop {
+ tint_continue = false;
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
@@ -178,15 +174,12 @@
switch(i) {
case 0: {
continue;
- break;
}
case 1: {
continue;
- break;
}
case 2: {
continue;
- break;
}
default: {
break;
@@ -205,29 +198,21 @@
auto* expect = R"(
fn f() {
var i = 0;
+ var tint_continue : bool;
loop {
+ tint_continue = false;
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
case 1: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
case 2: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
@@ -262,7 +247,6 @@
switch(i) {
case 0: {
continue;
- break;
}
default: {
break;
@@ -274,7 +258,6 @@
switch(i) {
case 0: {
continue;
- break;
}
default: {
break;
@@ -290,15 +273,13 @@
auto* expect = R"(
fn f() {
var i = 0;
+ var tint_continue : bool;
loop {
+ tint_continue = false;
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
@@ -310,20 +291,16 @@
}
let marker2 = 0;
let marker3 = 0;
- var tint_continue_1 : bool = false;
switch(i) {
case 0: {
- {
- tint_continue_1 = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
break;
}
}
- if (tint_continue_1) {
+ if (tint_continue) {
continue;
}
let marker4 = 0;
@@ -338,87 +315,253 @@
EXPECT_EQ(expect, str(got));
}
-TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitch) {
+TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitchSwitch) {
auto* src = R"(
fn f() {
- var i = 0;
- loop {
- let marker1 = 0;
+ var j = 0;
+ for (var i = 0; i < 2; i += 2) {
switch(i) {
case 0: {
- var j = 0;
- loop {
- let marker3 = 0;
- switch(j) {
- case 0: {
- continue;
- break;
- }
- default: {
- break;
- }
+ switch(j) {
+ case 0: {
+ continue;
}
- let marker4 = 0;
- break;
+ default: {
+ }
}
- continue;
- break;
}
default: {
- break;
}
}
- let marker2 = 0;
- break;
}
}
)";
auto* expect = R"(
fn f() {
- var i = 0;
- loop {
- let marker1 = 0;
- var tint_continue_1 : bool = false;
+ var j = 0;
+ var tint_continue : bool;
+ for(var i = 0; (i < 2); i += 2) {
+ tint_continue = false;
switch(i) {
case 0: {
- var j = 0;
- loop {
- let marker3 = 0;
- var tint_continue : bool = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ }
+ default: {
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+}
+)";
+
+ ast::transform::DataMap data;
+ auto got = Run<RemoveContinueInSwitch>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, NestedLoopLoopSwitch) {
+ auto* src = R"(
+fn f() {
+ for (var i = 0; i < 2; i += 2) {
+ for (var j = 0; j < 2; j += 2) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ for(var i = 0; (i < 2); i += 2) {
+ var tint_continue : bool;
+ for(var j = 0; (j < 2); j += 2) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+}
+)";
+
+ ast::transform::DataMap data;
+ auto got = Run<RemoveContinueInSwitch>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitchLoopSwitch) {
+ auto* src = R"(
+fn f() {
+ for (var i = 0; i < 2; i += 2) {
+ switch(i) {
+ case 0: {
+ for (var j = 0; j < 2; j += 2) {
switch(j) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ continue; // j loop
+ }
+ default: {
+ }
+ }
+ }
+ continue; // i loop
+ }
+ default: {
+ }
+ }
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var tint_continue_1 : bool;
+ for(var i = 0; (i < 2); i += 2) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ var tint_continue : bool;
+ for(var j = 0; (j < 2); j += 2) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
break;
}
default: {
- break;
}
}
if (tint_continue) {
continue;
}
- let marker4 = 0;
- break;
}
- {
- tint_continue_1 = true;
- break;
- }
+ tint_continue_1 = true;
break;
}
default: {
- break;
}
}
if (tint_continue_1) {
continue;
}
- let marker2 = 0;
- break;
+ }
+}
+)";
+
+ ast::transform::DataMap data;
+ auto got = Run<RemoveContinueInSwitch>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitchLoopSwitchSwitch) {
+ auto* src = R"(
+fn f() {
+ var k = 0;
+ for (var i = 0; i < 2; i += 2) {
+ switch(i) {
+ case 0: {
+ for (var j = 0; j < 2; j += 2) {
+ switch(j) {
+ case 0: {
+ continue; // j loop
+ }
+ case 1: {
+ switch (k) {
+ case 0: {
+ continue; // j loop
+ }
+ default: {
+ }
+ }
+ }
+ default: {
+ }
+ }
+ }
+ continue; // i loop
+ }
+ default: {
+ }
+ }
+ }
+}
+)";
+
+ auto* expect = R"(
+fn f() {
+ var k = 0;
+ var tint_continue_1 : bool;
+ for(var i = 0; (i < 2); i += 2) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ var tint_continue : bool;
+ for(var j = 0; (j < 2); j += 2) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ }
+ default: {
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ tint_continue_1 = true;
+ break;
+ }
+ default: {
+ }
+ }
+ if (tint_continue_1) {
+ continue;
+ }
}
}
)";
@@ -469,19 +612,18 @@
var b = true;
var c = true;
var d = true;
+ var tint_continue : bool;
loop {
+ tint_continue = false;
if (a) {
if (b) {
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
if (c) {
if (d) {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
+ break;
}
}
break;
@@ -529,15 +671,14 @@
auto* expect = R"(
fn f() {
+ var tint_continue : bool;
for(var i = 0; (i < 4); i = (i + 1)) {
+ tint_continue = false;
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
+ break;
break;
}
default: {
@@ -583,15 +724,14 @@
auto* expect = R"(
fn f() {
var i = 0;
+ var tint_continue : bool;
while((i < 4)) {
+ tint_continue = false;
let marker1 = 0;
- var tint_continue : bool = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
+ break;
break;
}
default: {
diff --git a/test/tint/loops/continue_in_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/continue_in_switch.wgsl.expected.dxc.hlsl
index ca926df..3ed9dc4 100644
--- a/test/tint/loops/continue_in_switch.wgsl.expected.dxc.hlsl
+++ b/test/tint/loops/continue_in_switch.wgsl.expected.dxc.hlsl
@@ -1,14 +1,12 @@
[numthreads(1, 1, 1)]
void f() {
+ bool tint_continue = false;
{
for(int i = 0; (i < 4); i = (i + 1)) {
- bool tint_continue = false;
+ tint_continue = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
diff --git a/test/tint/loops/continue_in_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/continue_in_switch.wgsl.expected.fxc.hlsl
index ca926df..3ed9dc4 100644
--- a/test/tint/loops/continue_in_switch.wgsl.expected.fxc.hlsl
+++ b/test/tint/loops/continue_in_switch.wgsl.expected.fxc.hlsl
@@ -1,14 +1,12 @@
[numthreads(1, 1, 1)]
void f() {
+ bool tint_continue = false;
{
for(int i = 0; (i < 4); i = (i + 1)) {
- bool tint_continue = false;
+ tint_continue = false;
switch(i) {
case 0: {
- {
- tint_continue = true;
- break;
- }
+ tint_continue = true;
break;
}
default: {
diff --git a/test/tint/loops/multiple_continues.wgsl b/test/tint/loops/multiple_continues.wgsl
new file mode 100644
index 0000000..a57f773
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl
@@ -0,0 +1,18 @@
+@compute @workgroup_size(1)
+fn main() {
+ for (var i = 0; i < 2; i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ case 1: {
+ continue;
+ }
+ case 2: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.dxc.hlsl b/test/tint/loops/multiple_continues.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..21f9f90
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ case 1: {
+ tint_continue = true;
+ break;
+ }
+ case 2: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.fxc.hlsl b/test/tint/loops/multiple_continues.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..21f9f90
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ case 1: {
+ tint_continue = true;
+ break;
+ }
+ case 2: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.glsl b/test/tint/loops/multiple_continues.wgsl.expected.glsl
new file mode 100644
index 0000000..36c86d8
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+#version 310 es
+
+void tint_symbol() {
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ case 1: {
+ continue;
+ break;
+ }
+ case 2: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.msl b/test/tint/loops/multiple_continues.wgsl.expected.msl
new file mode 100644
index 0000000..ed8fcc1
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.msl
@@ -0,0 +1,26 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ case 1: {
+ continue;
+ break;
+ }
+ case 2: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.spvasm b/test/tint/loops/multiple_continues.wgsl.expected.spvasm
new file mode 100644
index 0000000..4d6a668
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.spvasm
@@ -0,0 +1,57 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %6
+ OpStore %i %6
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranch %12
+ %12 = OpLabel
+ %14 = OpLoad %int %i
+ %16 = OpSLessThan %bool %14 %int_2
+ %13 = OpLogicalNot %bool %16
+ OpSelectionMerge %18 None
+ OpBranchConditional %13 %19 %18
+ %19 = OpLabel
+ OpBranch %10
+ %18 = OpLabel
+ %21 = OpLoad %int %i
+ OpSelectionMerge %20 None
+ OpSwitch %21 %22 0 %23 1 %24 2 %25
+ %23 = OpLabel
+ OpBranch %11
+ %24 = OpLabel
+ OpBranch %11
+ %25 = OpLabel
+ OpBranch %11
+ %22 = OpLabel
+ OpBranch %20
+ %20 = OpLabel
+ OpBranch %11
+ %11 = OpLabel
+ %26 = OpLoad %int %i
+ %28 = OpIAdd %int %26 %int_1
+ OpStore %i %28
+ OpBranch %9
+ %10 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/multiple_continues.wgsl.expected.wgsl b/test/tint/loops/multiple_continues.wgsl.expected.wgsl
new file mode 100644
index 0000000..a80bcaf
--- /dev/null
+++ b/test/tint/loops/multiple_continues.wgsl.expected.wgsl
@@ -0,0 +1,18 @@
+@compute @workgroup_size(1)
+fn main() {
+ for(var i = 0; (i < 2); i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ case 1: {
+ continue;
+ }
+ case 2: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/multiple_switch.wgsl b/test/tint/loops/multiple_switch.wgsl
new file mode 100644
index 0000000..b3acc1f
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl
@@ -0,0 +1,21 @@
+@compute @workgroup_size(1)
+fn main() {
+ var i = 0;
+ for (var i = 0; i < 2; i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/multiple_switch.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..b61b6b5
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.dxc.hlsl
@@ -0,0 +1,35 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 0;
+ bool tint_continue = false;
+ {
+ for(int i_1 = 0; (i_1 < 2); i_1 = (i_1 + 1)) {
+ tint_continue = false;
+ switch(i_1) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ switch(i_1) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/multiple_switch.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..b61b6b5
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.fxc.hlsl
@@ -0,0 +1,35 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int i = 0;
+ bool tint_continue = false;
+ {
+ for(int i_1 = 0; (i_1 < 2); i_1 = (i_1 + 1)) {
+ tint_continue = false;
+ switch(i_1) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ switch(i_1) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.glsl b/test/tint/loops/multiple_switch.wgsl.expected.glsl
new file mode 100644
index 0000000..290f1e3
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.glsl
@@ -0,0 +1,33 @@
+#version 310 es
+
+void tint_symbol() {
+ int i = 0;
+ {
+ for(int i_1 = 0; (i_1 < 2); i_1 = (i_1 + 1)) {
+ switch(i_1) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ switch(i_1) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.msl b/test/tint/loops/multiple_switch.wgsl.expected.msl
new file mode 100644
index 0000000..342db50
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.msl
@@ -0,0 +1,28 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int i = 0;
+ for(int i_1 = 0; (i_1 < 2); i_1 = as_type<int>((as_type<uint>(i_1) + as_type<uint>(1)))) {
+ switch(i_1) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ switch(i_1) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.spvasm b/test/tint/loops/multiple_switch.wgsl.expected.spvasm
new file mode 100644
index 0000000..edf7850
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 32
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ OpName %i_1 "i_1"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %6
+ %i_1 = OpVariable %_ptr_Function_int Function %6
+ OpStore %i %6
+ OpStore %i_1 %6
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %11 %12 None
+ OpBranch %13
+ %13 = OpLabel
+ %15 = OpLoad %int %i_1
+ %17 = OpSLessThan %bool %15 %int_2
+ %14 = OpLogicalNot %bool %17
+ OpSelectionMerge %19 None
+ OpBranchConditional %14 %20 %19
+ %20 = OpLabel
+ OpBranch %11
+ %19 = OpLabel
+ %22 = OpLoad %int %i_1
+ OpSelectionMerge %21 None
+ OpSwitch %22 %23 0 %24
+ %24 = OpLabel
+ OpBranch %12
+ %23 = OpLabel
+ OpBranch %21
+ %21 = OpLabel
+ %26 = OpLoad %int %i_1
+ OpSelectionMerge %25 None
+ OpSwitch %26 %27 0 %28
+ %28 = OpLabel
+ OpBranch %12
+ %27 = OpLabel
+ OpBranch %25
+ %25 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ %29 = OpLoad %int %i_1
+ %31 = OpIAdd %int %29 %int_1
+ OpStore %i_1 %31
+ OpBranch %10
+ %11 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/multiple_switch.wgsl.expected.wgsl b/test/tint/loops/multiple_switch.wgsl.expected.wgsl
new file mode 100644
index 0000000..1ef17ce
--- /dev/null
+++ b/test/tint/loops/multiple_switch.wgsl.expected.wgsl
@@ -0,0 +1,20 @@
+@compute @workgroup_size(1)
+fn main() {
+ var i = 0;
+ for(var i = 0; (i < 2); i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl b/test/tint/loops/nested_loop_loop_switch.wgsl
new file mode 100644
index 0000000..f925971
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl
@@ -0,0 +1,14 @@
+@compute @workgroup_size(1)
+fn main() {
+ for (var i = 0; i < 2; i += 2) {
+ for (var j = 0; j < 2; j += 2) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..01759c8
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.dxc.hlsl
@@ -0,0 +1,26 @@
+[numthreads(1, 1, 1)]
+void main() {
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..01759c8
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.fxc.hlsl
@@ -0,0 +1,26 @@
+[numthreads(1, 1, 1)]
+void main() {
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.glsl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.glsl
new file mode 100644
index 0000000..a3ad0a3
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+#version 310 es
+
+void tint_symbol() {
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.msl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.msl
new file mode 100644
index 0000000..a1f0843
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.msl
@@ -0,0 +1,20 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(2)))) {
+ for(int j = 0; (j < 2); j = as_type<int>((as_type<uint>(j) + as_type<uint>(2)))) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.spvasm b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.spvasm
new file mode 100644
index 0000000..16f154d
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.spvasm
@@ -0,0 +1,75 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ OpName %j "j"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %6
+ %j = OpVariable %_ptr_Function_int Function %6
+ OpStore %i %6
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranch %12
+ %12 = OpLabel
+ %14 = OpLoad %int %i
+ %16 = OpSLessThan %bool %14 %int_2
+ %13 = OpLogicalNot %bool %16
+ OpSelectionMerge %18 None
+ OpBranchConditional %13 %19 %18
+ %19 = OpLabel
+ OpBranch %10
+ %18 = OpLabel
+ OpStore %j %6
+ OpBranch %21
+ %21 = OpLabel
+ OpLoopMerge %22 %23 None
+ OpBranch %24
+ %24 = OpLabel
+ %26 = OpLoad %int %j
+ %27 = OpSLessThan %bool %26 %int_2
+ %25 = OpLogicalNot %bool %27
+ OpSelectionMerge %28 None
+ OpBranchConditional %25 %29 %28
+ %29 = OpLabel
+ OpBranch %22
+ %28 = OpLabel
+ %31 = OpLoad %int %i
+ OpSelectionMerge %30 None
+ OpSwitch %31 %32 0 %33
+ %33 = OpLabel
+ OpBranch %23
+ %32 = OpLabel
+ OpBranch %30
+ %30 = OpLabel
+ OpBranch %23
+ %23 = OpLabel
+ %34 = OpLoad %int %j
+ %35 = OpIAdd %int %34 %int_2
+ OpStore %j %35
+ OpBranch %21
+ %22 = OpLabel
+ OpBranch %11
+ %11 = OpLabel
+ %36 = OpLoad %int %i
+ %37 = OpIAdd %int %36 %int_2
+ OpStore %i %37
+ OpBranch %9
+ %10 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/nested_loop_loop_switch.wgsl.expected.wgsl b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.wgsl
new file mode 100644
index 0000000..8026320
--- /dev/null
+++ b/test/tint/loops/nested_loop_loop_switch.wgsl.expected.wgsl
@@ -0,0 +1,14 @@
+@compute @workgroup_size(1)
+fn main() {
+ for(var i = 0; (i < 2); i += 2) {
+ for(var j = 0; (j < 2); j += 2) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl
new file mode 100644
index 0000000..020d6df
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl
@@ -0,0 +1,21 @@
+@compute @workgroup_size(1)
+fn main() {
+ for (var i = 0; i < 2; i += 2) {
+ switch(i) {
+ case 0: {
+ for (var j = 0; j < 2; j += 2) {
+ switch(j) {
+ case 0: {
+ continue; // j loop
+ }
+ default: {
+ }
+ }
+ }
+ continue; // i loop
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..305bfbd
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.dxc.hlsl
@@ -0,0 +1,40 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue_1 = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ tint_continue_1 = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue_1) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..305bfbd
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.fxc.hlsl
@@ -0,0 +1,40 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue_1 = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ tint_continue_1 = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue_1) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.glsl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.glsl
new file mode 100644
index 0000000..1e45661
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.glsl
@@ -0,0 +1,36 @@
+#version 310 es
+
+void tint_symbol() {
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ switch(i) {
+ case 0: {
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.msl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.msl
new file mode 100644
index 0000000..a5e768d
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.msl
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(2)))) {
+ switch(i) {
+ case 0: {
+ for(int j = 0; (j < 2); j = as_type<int>((as_type<uint>(j) + as_type<uint>(2)))) {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.spvasm b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.spvasm
new file mode 100644
index 0000000..9509f0d
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.spvasm
@@ -0,0 +1,83 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 42
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ OpName %j "j"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %6
+ %j = OpVariable %_ptr_Function_int Function %6
+ OpStore %i %6
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranch %12
+ %12 = OpLabel
+ %14 = OpLoad %int %i
+ %16 = OpSLessThan %bool %14 %int_2
+ %13 = OpLogicalNot %bool %16
+ OpSelectionMerge %18 None
+ OpBranchConditional %13 %19 %18
+ %19 = OpLabel
+ OpBranch %10
+ %18 = OpLabel
+ %21 = OpLoad %int %i
+ OpSelectionMerge %20 None
+ OpSwitch %21 %22 0 %23
+ %23 = OpLabel
+ OpStore %j %6
+ OpBranch %25
+ %25 = OpLabel
+ OpLoopMerge %26 %27 None
+ OpBranch %28
+ %28 = OpLabel
+ %30 = OpLoad %int %j
+ %31 = OpSLessThan %bool %30 %int_2
+ %29 = OpLogicalNot %bool %31
+ OpSelectionMerge %32 None
+ OpBranchConditional %29 %33 %32
+ %33 = OpLabel
+ OpBranch %26
+ %32 = OpLabel
+ %35 = OpLoad %int %j
+ OpSelectionMerge %34 None
+ OpSwitch %35 %36 0 %37
+ %37 = OpLabel
+ OpBranch %27
+ %36 = OpLabel
+ OpBranch %34
+ %34 = OpLabel
+ OpBranch %27
+ %27 = OpLabel
+ %38 = OpLoad %int %j
+ %39 = OpIAdd %int %38 %int_2
+ OpStore %j %39
+ OpBranch %25
+ %26 = OpLabel
+ OpBranch %11
+ %22 = OpLabel
+ OpBranch %20
+ %20 = OpLabel
+ OpBranch %11
+ %11 = OpLabel
+ %40 = OpLoad %int %i
+ %41 = OpIAdd %int %40 %int_2
+ OpStore %i %41
+ OpBranch %9
+ %10 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.wgsl b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.wgsl
new file mode 100644
index 0000000..0398609
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch.wgsl.expected.wgsl
@@ -0,0 +1,21 @@
+@compute @workgroup_size(1)
+fn main() {
+ for(var i = 0; (i < 2); i += 2) {
+ switch(i) {
+ case 0: {
+ for(var j = 0; (j < 2); j += 2) {
+ switch(j) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl
new file mode 100644
index 0000000..c152681
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl
@@ -0,0 +1,31 @@
+@compute @workgroup_size(1)
+fn main() {
+ var k = 0;
+ for (var i = 0; i < 2; i += 2) {
+ switch(i) {
+ case 0: {
+ for (var j = 0; j < 2; j += 2) {
+ switch(j) {
+ case 0: {
+ continue; // j loop
+ }
+ case 1: {
+ switch (k) {
+ case 0: {
+ continue; // j loop
+ }
+ default: {
+ }
+ }
+ }
+ default: {
+ }
+ }
+ }
+ continue; // i loop
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..7d646a9
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.dxc.hlsl
@@ -0,0 +1,56 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int k = 0;
+ bool tint_continue_1 = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ tint_continue_1 = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue_1) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7d646a9
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.fxc.hlsl
@@ -0,0 +1,56 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int k = 0;
+ bool tint_continue_1 = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue_1 = false;
+ switch(i) {
+ case 0: {
+ bool tint_continue = false;
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ tint_continue = false;
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ tint_continue_1 = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue_1) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.glsl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.glsl
new file mode 100644
index 0000000..3c59535
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.glsl
@@ -0,0 +1,49 @@
+#version 310 es
+
+void tint_symbol() {
+ int k = 0;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ switch(i) {
+ case 0: {
+ {
+ for(int j = 0; (j < 2); j = (j + 2)) {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.msl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.msl
new file mode 100644
index 0000000..b3a1fd6
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.msl
@@ -0,0 +1,42 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int k = 0;
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(2)))) {
+ switch(i) {
+ case 0: {
+ for(int j = 0; (j < 2); j = as_type<int>((as_type<uint>(j) + as_type<uint>(2)))) {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.spvasm b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.spvasm
new file mode 100644
index 0000000..b32b253
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.spvasm
@@ -0,0 +1,96 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 48
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %k "k"
+ OpName %i "i"
+ OpName %j "j"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %k = OpVariable %_ptr_Function_int Function %6
+ %i = OpVariable %_ptr_Function_int Function %6
+ %j = OpVariable %_ptr_Function_int Function %6
+ OpStore %k %6
+ OpStore %i %6
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %11 %12 None
+ OpBranch %13
+ %13 = OpLabel
+ %15 = OpLoad %int %i
+ %17 = OpSLessThan %bool %15 %int_2
+ %14 = OpLogicalNot %bool %17
+ OpSelectionMerge %19 None
+ OpBranchConditional %14 %20 %19
+ %20 = OpLabel
+ OpBranch %11
+ %19 = OpLabel
+ %22 = OpLoad %int %i
+ OpSelectionMerge %21 None
+ OpSwitch %22 %23 0 %24
+ %24 = OpLabel
+ OpStore %j %6
+ OpBranch %26
+ %26 = OpLabel
+ OpLoopMerge %27 %28 None
+ OpBranch %29
+ %29 = OpLabel
+ %31 = OpLoad %int %j
+ %32 = OpSLessThan %bool %31 %int_2
+ %30 = OpLogicalNot %bool %32
+ OpSelectionMerge %33 None
+ OpBranchConditional %30 %34 %33
+ %34 = OpLabel
+ OpBranch %27
+ %33 = OpLabel
+ %36 = OpLoad %int %j
+ OpSelectionMerge %35 None
+ OpSwitch %36 %37 0 %38 1 %39
+ %38 = OpLabel
+ OpBranch %28
+ %39 = OpLabel
+ %41 = OpLoad %int %k
+ OpSelectionMerge %40 None
+ OpSwitch %41 %42 0 %43
+ %43 = OpLabel
+ OpBranch %28
+ %42 = OpLabel
+ OpBranch %40
+ %40 = OpLabel
+ OpBranch %35
+ %37 = OpLabel
+ OpBranch %35
+ %35 = OpLabel
+ OpBranch %28
+ %28 = OpLabel
+ %44 = OpLoad %int %j
+ %45 = OpIAdd %int %44 %int_2
+ OpStore %j %45
+ OpBranch %26
+ %27 = OpLabel
+ OpBranch %12
+ %23 = OpLabel
+ OpBranch %21
+ %21 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ %46 = OpLoad %int %i
+ %47 = OpIAdd %int %46 %int_2
+ OpStore %i %47
+ OpBranch %10
+ %11 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.wgsl b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.wgsl
new file mode 100644
index 0000000..7c7cdb9
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_loop_switch_switch.wgsl.expected.wgsl
@@ -0,0 +1,31 @@
+@compute @workgroup_size(1)
+fn main() {
+ var k = 0;
+ for(var i = 0; (i < 2); i += 2) {
+ switch(i) {
+ case 0: {
+ for(var j = 0; (j < 2); j += 2) {
+ switch(j) {
+ case 0: {
+ continue;
+ }
+ case 1: {
+ switch(k) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ default: {
+ }
+ }
+ }
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl b/test/tint/loops/nested_loop_switch_switch.wgsl
new file mode 100644
index 0000000..9949f96
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl
@@ -0,0 +1,19 @@
+@compute @workgroup_size(1)
+fn main() {
+ var j = 0;
+ for (var i = 0; i < 2; i += 2) {
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.dxc.hlsl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..160d4d6
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.dxc.hlsl
@@ -0,0 +1,34 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int j = 0;
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.fxc.hlsl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..160d4d6
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+[numthreads(1, 1, 1)]
+void main() {
+ int j = 0;
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.glsl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.glsl
new file mode 100644
index 0000000..ec32b25
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.glsl
@@ -0,0 +1,32 @@
+#version 310 es
+
+void tint_symbol() {
+ int j = 0;
+ {
+ for(int i = 0; (i < 2); i = (i + 2)) {
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.msl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.msl
new file mode 100644
index 0000000..55f4436
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.msl
@@ -0,0 +1,27 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ int j = 0;
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(2)))) {
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.spvasm b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.spvasm
new file mode 100644
index 0000000..f6add1f
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.spvasm
@@ -0,0 +1,63 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 31
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %j "j"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %j = OpVariable %_ptr_Function_int Function %6
+ %i = OpVariable %_ptr_Function_int Function %6
+ OpStore %j %6
+ OpStore %i %6
+ OpBranch %10
+ %10 = OpLabel
+ OpLoopMerge %11 %12 None
+ OpBranch %13
+ %13 = OpLabel
+ %15 = OpLoad %int %i
+ %17 = OpSLessThan %bool %15 %int_2
+ %14 = OpLogicalNot %bool %17
+ OpSelectionMerge %19 None
+ OpBranchConditional %14 %20 %19
+ %20 = OpLabel
+ OpBranch %11
+ %19 = OpLabel
+ %22 = OpLoad %int %i
+ OpSelectionMerge %21 None
+ OpSwitch %22 %23 0 %24
+ %24 = OpLabel
+ %26 = OpLoad %int %j
+ OpSelectionMerge %25 None
+ OpSwitch %26 %27 0 %28
+ %28 = OpLabel
+ OpBranch %12
+ %27 = OpLabel
+ OpBranch %25
+ %25 = OpLabel
+ OpBranch %21
+ %23 = OpLabel
+ OpBranch %21
+ %21 = OpLabel
+ OpBranch %12
+ %12 = OpLabel
+ %29 = OpLoad %int %i
+ %30 = OpIAdd %int %29 %int_2
+ OpStore %i %30
+ OpBranch %10
+ %11 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/nested_loop_switch_switch.wgsl.expected.wgsl b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.wgsl
new file mode 100644
index 0000000..4d8f604
--- /dev/null
+++ b/test/tint/loops/nested_loop_switch_switch.wgsl.expected.wgsl
@@ -0,0 +1,19 @@
+@compute @workgroup_size(1)
+fn main() {
+ var j = 0;
+ for(var i = 0; (i < 2); i += 2) {
+ switch(i) {
+ case 0: {
+ switch(j) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/single_continue.wgsl b/test/tint/loops/single_continue.wgsl
new file mode 100644
index 0000000..d59d2fa
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl
@@ -0,0 +1,12 @@
+@compute @workgroup_size(1)
+fn main() {
+ for (var i = 0; i < 2; i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}
diff --git a/test/tint/loops/single_continue.wgsl.expected.dxc.hlsl b/test/tint/loops/single_continue.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..5955f1e
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.dxc.hlsl
@@ -0,0 +1,22 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/single_continue.wgsl.expected.fxc.hlsl b/test/tint/loops/single_continue.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..5955f1e
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.fxc.hlsl
@@ -0,0 +1,22 @@
+[numthreads(1, 1, 1)]
+void main() {
+ bool tint_continue = false;
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ tint_continue = false;
+ switch(i) {
+ case 0: {
+ tint_continue = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ if (tint_continue) {
+ continue;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/tint/loops/single_continue.wgsl.expected.glsl b/test/tint/loops/single_continue.wgsl.expected.glsl
new file mode 100644
index 0000000..79afd54
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.glsl
@@ -0,0 +1,23 @@
+#version 310 es
+
+void tint_symbol() {
+ {
+ for(int i = 0; (i < 2); i = (i + 1)) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
+}
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+ tint_symbol();
+ return;
+}
diff --git a/test/tint/loops/single_continue.wgsl.expected.msl b/test/tint/loops/single_continue.wgsl.expected.msl
new file mode 100644
index 0000000..3ce3ba5
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.msl
@@ -0,0 +1,18 @@
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+ for(int i = 0; (i < 2); i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
+ switch(i) {
+ case 0: {
+ continue;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/tint/loops/single_continue.wgsl.expected.spvasm b/test/tint/loops/single_continue.wgsl.expected.spvasm
new file mode 100644
index 0000000..7b4bed2
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.spvasm
@@ -0,0 +1,53 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 27
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpName %main "main"
+ OpName %i "i"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %int = OpTypeInt 32 1
+ %6 = OpConstantNull %int
+%_ptr_Function_int = OpTypePointer Function %int
+ %int_2 = OpConstant %int 2
+ %bool = OpTypeBool
+ %int_1 = OpConstant %int 1
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ %i = OpVariable %_ptr_Function_int Function %6
+ OpStore %i %6
+ OpBranch %9
+ %9 = OpLabel
+ OpLoopMerge %10 %11 None
+ OpBranch %12
+ %12 = OpLabel
+ %14 = OpLoad %int %i
+ %16 = OpSLessThan %bool %14 %int_2
+ %13 = OpLogicalNot %bool %16
+ OpSelectionMerge %18 None
+ OpBranchConditional %13 %19 %18
+ %19 = OpLabel
+ OpBranch %10
+ %18 = OpLabel
+ %21 = OpLoad %int %i
+ OpSelectionMerge %20 None
+ OpSwitch %21 %22 0 %23
+ %23 = OpLabel
+ OpBranch %11
+ %22 = OpLabel
+ OpBranch %20
+ %20 = OpLabel
+ OpBranch %11
+ %11 = OpLabel
+ %24 = OpLoad %int %i
+ %26 = OpIAdd %int %24 %int_1
+ OpStore %i %26
+ OpBranch %9
+ %10 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/loops/single_continue.wgsl.expected.wgsl b/test/tint/loops/single_continue.wgsl.expected.wgsl
new file mode 100644
index 0000000..6554849
--- /dev/null
+++ b/test/tint/loops/single_continue.wgsl.expected.wgsl
@@ -0,0 +1,12 @@
+@compute @workgroup_size(1)
+fn main() {
+ for(var i = 0; (i < 2); i += 1) {
+ switch(i) {
+ case 0: {
+ continue;
+ }
+ default: {
+ }
+ }
+ }
+}