Add WGSL support for break, continue, and nop statements.

These statements are very straightforward and don't need special
handling. This unlocks a handful of additional tests.

Change-Id: I94fb48979430dd67b483afd0cf2200ec55428cfa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/707420
Reviewed-by: Arman Uguray <armansito@google.com>
Commit-Queue: Arman Uguray <armansito@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 273ebc8..1d76fa5 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -396,10 +396,14 @@
 sksl_wgsl_tests = [
   "runtime/GLSLTypeNames.rts",
   "runtime/GlobalVariables.rts",
+  "runtime/LargeProgram_BlocklessLoops.rts",
   "runtime/LargeProgram_FlatLoop.rts",
+  "runtime/LargeProgram_Functions.rts",
   "runtime/LargeProgram_NestedLoops.rts",
   "runtime/LargeProgram_SplitLoops.rts",
   "runtime/LargeProgram_ZeroIterFor.rts",
+  "runtime/LoopFloat.rts",
+  "runtime/LoopInt.rts",
   "shared/ArrayConstructors.sksl",
   "shared/ArrayFollowedByScalar.sksl",
   "shared/ArrayIndexTypes.sksl",
@@ -408,6 +412,7 @@
   "shared/CommaSideEffects.sksl",
   "shared/ConstArray.sksl",
   "shared/ConstantIf.sksl",
+  "shared/ForLoopMultipleInit.sksl",
   "shared/FunctionAnonymousParameters.sksl",
   "shared/HelloWorld.sksl",
   "shared/InoutParameters.sksl",
@@ -447,8 +452,10 @@
   "shared/TernaryTrueFalseOptimization.sksl",
   "shared/UnaryPositiveNegative.sksl",
   "shared/UniformMatrixResize.sksl",
+  "shared/UnusedVariables.sksl",
   "shared/VectorConstructors.sksl",
   "shared/VertexID.vert",
+  "shared/WhileLoopControlFlow.sksl",
   "wgsl/BuiltinFragmentStageIO.sksl",
   "wgsl/BuiltinVertexStageIO.vert",
   "wgsl/CastMat2x2ToMat3x3.sksl",
diff --git a/resources/sksl/BUILD.bazel b/resources/sksl/BUILD.bazel
index 0015b70..6022d9b 100644
--- a/resources/sksl/BUILD.bazel
+++ b/resources/sksl/BUILD.bazel
@@ -1071,9 +1071,13 @@
         "wgsl/VertexPositionOutputIsAlwaysDeclared.vert",
 
         # Shared tests that are supported so far:
+        "runtime/LoopFloat.rts",
+        "runtime/LoopInt.rts",
         "runtime/GlobalVariables.rts",
         "runtime/GLSLTypeNames.rts",
+        "runtime/LargeProgram_BlocklessLoops.rts",
         "runtime/LargeProgram_FlatLoop.rts",
+        "runtime/LargeProgram_Functions.rts",
         "runtime/LargeProgram_NestedLoops.rts",
         "runtime/LargeProgram_SplitLoops.rts",
         "runtime/LargeProgram_ZeroIterFor.rts",
@@ -1085,6 +1089,7 @@
         "shared/CommaSideEffects.sksl",
         "shared/ConstArray.sksl",
         "shared/ConstantIf.sksl",
+        "shared/ForLoopMultipleInit.sksl",
         "shared/FunctionAnonymousParameters.sksl",
         "shared/HelloWorld.sksl",
         "shared/InoutParameters.sksl",
@@ -1123,8 +1128,10 @@
         "shared/TernaryNesting.sksl",
         "shared/TernaryTrueFalseOptimization.sksl",
         "shared/UnaryPositiveNegative.sksl",
+        "shared/UnusedVariables.sksl",
         "shared/UniformMatrixResize.sksl",
         "shared/VectorConstructors.sksl",
         "shared/VertexID.vert",
+        "shared/WhileLoopControlFlow.sksl",
     ],
 )
diff --git a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
index 3f802d7..9486fdd 100644
--- a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
@@ -901,6 +901,12 @@
         case Statement::Kind::kBlock:
             this->writeBlock(s.as<Block>());
             break;
+        case Statement::Kind::kBreak:
+            this->writeLine("break;");
+            break;
+        case Statement::Kind::kContinue:
+            this->writeLine("continue;");
+            break;
         case Statement::Kind::kExpression:
             this->writeExpressionStatement(*s.as<ExpressionStatement>().expression());
             break;
@@ -910,6 +916,9 @@
         case Statement::Kind::kIf:
             this->writeIfStatement(s.as<IfStatement>());
             break;
+        case Statement::Kind::kNop:
+            this->writeLine(";");
+            break;
         case Statement::Kind::kReturn:
             this->writeReturnStatement(s.as<ReturnStatement>());
             break;
diff --git a/tests/sksl/runtime/LargeProgram_BlocklessLoops.wgsl b/tests/sksl/runtime/LargeProgram_BlocklessLoops.wgsl
new file mode 100644
index 0000000..a954676
--- /dev/null
+++ b/tests/sksl/runtime/LargeProgram_BlocklessLoops.wgsl
@@ -0,0 +1,56 @@
+fn main(xy: vec2<f32>) -> vec4<f32> {
+    var i: i32;
+    {
+        var a: i32 = 0;
+        loop {
+            if a < 10 {
+                {
+                    var b: i32 = 0;
+                    loop {
+                        if b < 10 {
+                            {
+                                var c: i32 = 0;
+                                loop {
+                                    if c < 10 {
+                                        {
+                                            var d: i32 = 0;
+                                            loop {
+                                                if d < 10 {
+                                                    i = i + i32(1);
+                                                } else {
+                                                    break;
+                                                }
+                                                continuing {
+                                                    d = d + i32(1);
+                                                }
+                                            }
+                                        }
+                                    } else {
+                                        break;
+                                    }
+                                    continuing {
+                                        c = c + i32(1);
+                                    }
+                                }
+                            }
+                        } else {
+                            break;
+                        }
+                        continuing {
+                            b = b + i32(1);
+                        }
+                    }
+                }
+            } else {
+                break;
+            }
+            continuing {
+                a = a + i32(1);
+            }
+        }
+    }
+    return vec4<f32>(0.0);
+}
+@fragment fn runtimeShaderMain(@location(0) _coords: vec2<f32>) -> @location(0) vec4<f32> {
+    return main(_coords);
+}
diff --git a/tests/sksl/runtime/LargeProgram_Functions.wgsl b/tests/sksl/runtime/LargeProgram_Functions.wgsl
new file mode 100644
index 0000000..8bc7f4c
--- /dev/null
+++ b/tests/sksl/runtime/LargeProgram_Functions.wgsl
@@ -0,0 +1,211 @@
+fn _outParamHelper_0_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_1_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_2_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_3_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_4_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_5_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_6_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_7_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_8_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_9_d_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    d_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_10_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_11_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_12_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_13_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_14_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_15_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_16_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_17_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_18_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_19_c_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    c_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_20_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_21_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_22_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_23_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_24_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_25_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_26_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_27_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_28_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_29_b_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    b_vi(&_var0);
+    (*i) = _var0;
+}
+fn _outParamHelper_30_a_vi(i: ptr<function, i32>) {
+    var _var0: i32 = (*i);
+    a_vi(&_var0);
+    (*i) = _var0;
+}
+fn d_vi(i: ptr<function, i32>) {
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+    (*i) = (*i) + i32(1);
+}
+fn c_vi(i: ptr<function, i32>) {
+    _outParamHelper_0_d_vi(&(*i));
+    _outParamHelper_1_d_vi(&(*i));
+    _outParamHelper_2_d_vi(&(*i));
+    _outParamHelper_3_d_vi(&(*i));
+    _outParamHelper_4_d_vi(&(*i));
+    _outParamHelper_5_d_vi(&(*i));
+    _outParamHelper_6_d_vi(&(*i));
+    _outParamHelper_7_d_vi(&(*i));
+    _outParamHelper_8_d_vi(&(*i));
+    _outParamHelper_9_d_vi(&(*i));
+}
+fn b_vi(i: ptr<function, i32>) {
+    _outParamHelper_10_c_vi(&(*i));
+    _outParamHelper_11_c_vi(&(*i));
+    _outParamHelper_12_c_vi(&(*i));
+    _outParamHelper_13_c_vi(&(*i));
+    _outParamHelper_14_c_vi(&(*i));
+    _outParamHelper_15_c_vi(&(*i));
+    _outParamHelper_16_c_vi(&(*i));
+    _outParamHelper_17_c_vi(&(*i));
+    _outParamHelper_18_c_vi(&(*i));
+    _outParamHelper_19_c_vi(&(*i));
+}
+fn a_vi(i: ptr<function, i32>) {
+    _outParamHelper_20_b_vi(&(*i));
+    _outParamHelper_21_b_vi(&(*i));
+    _outParamHelper_22_b_vi(&(*i));
+    _outParamHelper_23_b_vi(&(*i));
+    _outParamHelper_24_b_vi(&(*i));
+    _outParamHelper_25_b_vi(&(*i));
+    _outParamHelper_26_b_vi(&(*i));
+    _outParamHelper_27_b_vi(&(*i));
+    _outParamHelper_28_b_vi(&(*i));
+    _outParamHelper_29_b_vi(&(*i));
+}
+fn main(xy: vec2<f32>) -> vec4<f32> {
+    var i: i32 = 0;
+    _outParamHelper_30_a_vi(&i);
+    return vec4<f32>(0.0);
+}
+@fragment fn runtimeShaderMain(@location(0) _coords: vec2<f32>) -> @location(0) vec4<f32> {
+    return main(_coords);
+}
diff --git a/tests/sksl/runtime/LoopFloat.wgsl b/tests/sksl/runtime/LoopFloat.wgsl
new file mode 100644
index 0000000..908189c
--- /dev/null
+++ b/tests/sksl/runtime/LoopFloat.wgsl
@@ -0,0 +1,290 @@
+struct _GlobalUniforms {
+    colorRed: vec4<f32>,
+    colorGreen: vec4<f32>,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+const kZero: f32 = 0.0;
+fn return_loop_ff(five: f32) -> f32 {
+    {
+        var i: f32 = kZero;
+        loop {
+            if i < 10.0 {
+                {
+                    if (i == five) {
+                        {
+                            return i;
+                        }
+                    }
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return 0.0;
+}
+const kTen: f32 = 10.0;
+fn continue_loop_ff(five: f32) -> f32 {
+    var sum: f32 = 0.0;
+    {
+        var i: f32 = 0.0;
+        loop {
+            if i < kTen {
+                {
+                    if (i < five) {
+                        {
+                            continue;
+                        }
+                    }
+                    sum = sum + i;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return sum;
+}
+fn break_loop_ff(five: f32) -> f32 {
+    var sum: f32 = 0.0;
+    let kOne: f32 = 1.0;
+    {
+        var i: f32 = 0.0;
+        loop {
+            if i < 10.0 {
+                {
+                    if (i > five) {
+                        {
+                            break;
+                        }
+                    }
+                    sum = sum + i;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + kOne;
+            }
+        }
+    }
+    return sum;
+}
+fn float_loop_f() -> f32 {
+    var sum: f32 = 0.0;
+    {
+        var i: f32 = 0.123;
+        loop {
+            if i < 0.6 {
+                {
+                    sum = sum + i;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + 0.111;
+            }
+        }
+    }
+    return sum - 1.725;
+}
+fn loop_operator_le_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 1.0;
+        loop {
+            if i <= 3.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 1.0, 2.0, 3.0));
+}
+fn loop_operator_lt_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 1.0;
+        loop {
+            if i < 4.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 1.0, 2.0, 3.0));
+}
+fn loop_operator_ge_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 3.0;
+        loop {
+            if i >= 1.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i - f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 3.0, 2.0, 1.0));
+}
+fn loop_operator_gt_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 3.0;
+        loop {
+            if i > 0.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i - f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 3.0, 2.0, 1.0));
+}
+fn loop_operator_ne_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 1.0;
+        loop {
+            if i < 4.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 1.0, 2.0, 3.0));
+}
+fn loop_operator_eq_b() -> bool {
+    var result: vec4<f32> = vec4<f32>(9.0);
+    {
+        var i: f32 = 1.0;
+        loop {
+            if i == 1.0 {
+                {
+                    result = vec4<f32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + f32(1);
+            }
+        }
+    }
+    return all(result == vec4<f32>(9.0, 9.0, 9.0, 1.0));
+}
+fn main(pos: vec2<f32>) -> vec4<f32> {
+    let _skTemp0 = clamp(pos.x, f32(_globalUniforms.colorGreen.y), f32(_globalUniforms.colorGreen.w));
+    var five: f32 = _skTemp0 * 5.0;
+    var _skTemp1: vec4<f32>;
+    var _skTemp2: bool;
+    var _skTemp3: bool;
+    var _skTemp4: bool;
+    var _skTemp5: bool;
+    var _skTemp6: bool;
+    var _skTemp7: bool;
+    var _skTemp8: bool;
+    var _skTemp9: bool;
+    var _skTemp10: bool;
+    let _skTemp11 = return_loop_ff(five);
+    if _skTemp11 == 5.0 {
+        let _skTemp12 = continue_loop_ff(five);
+        _skTemp10 = _skTemp12 == 35.0;
+    } else {
+        _skTemp10 = false;
+    }
+    if _skTemp10 {
+        let _skTemp13 = break_loop_ff(five);
+        _skTemp9 = _skTemp13 == 15.0;
+    } else {
+        _skTemp9 = false;
+    }
+    if _skTemp9 {
+        let _skTemp14 = float_loop_f();
+        let _skTemp15 = abs(_skTemp14);
+        _skTemp8 = _skTemp15 < 0.025;
+    } else {
+        _skTemp8 = false;
+    }
+    if _skTemp8 {
+        let _skTemp16 = loop_operator_le_b();
+        _skTemp7 = _skTemp16;
+    } else {
+        _skTemp7 = false;
+    }
+    if _skTemp7 {
+        let _skTemp17 = loop_operator_lt_b();
+        _skTemp6 = _skTemp17;
+    } else {
+        _skTemp6 = false;
+    }
+    if _skTemp6 {
+        let _skTemp18 = loop_operator_ge_b();
+        _skTemp5 = _skTemp18;
+    } else {
+        _skTemp5 = false;
+    }
+    if _skTemp5 {
+        let _skTemp19 = loop_operator_gt_b();
+        _skTemp4 = _skTemp19;
+    } else {
+        _skTemp4 = false;
+    }
+    if _skTemp4 {
+        let _skTemp20 = loop_operator_eq_b();
+        _skTemp3 = _skTemp20;
+    } else {
+        _skTemp3 = false;
+    }
+    if _skTemp3 {
+        let _skTemp21 = loop_operator_ne_b();
+        _skTemp2 = _skTemp21;
+    } else {
+        _skTemp2 = false;
+    }
+    if _skTemp2 {
+        _skTemp1 = _globalUniforms.colorGreen;
+    } else {
+        _skTemp1 = _globalUniforms.colorRed;
+    }
+    return _skTemp1;
+}
+@fragment fn runtimeShaderMain(@location(0) _coords: vec2<f32>) -> @location(0) vec4<f32> {
+    return main(_coords);
+}
diff --git a/tests/sksl/runtime/LoopInt.wgsl b/tests/sksl/runtime/LoopInt.wgsl
new file mode 100644
index 0000000..067412a
--- /dev/null
+++ b/tests/sksl/runtime/LoopInt.wgsl
@@ -0,0 +1,263 @@
+struct _GlobalUniforms {
+    colorRed: vec4<f32>,
+    colorGreen: vec4<f32>,
+};
+@binding(0) @group(0) var<uniform> _globalUniforms: _GlobalUniforms;
+const kZero: i32 = 0;
+fn return_loop_ii(five: i32) -> i32 {
+    {
+        var i: i32 = kZero;
+        loop {
+            if i < 10 {
+                {
+                    if (i == five) {
+                        {
+                            return i;
+                        }
+                    }
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return 0;
+}
+const kTen: i32 = 10;
+fn continue_loop_ii(five: i32) -> i32 {
+    var sum: i32 = 0;
+    {
+        var i: i32 = 0;
+        loop {
+            if i < kTen {
+                {
+                    if (i < five) {
+                        {
+                            continue;
+                        }
+                    }
+                    sum = sum + i;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return sum;
+}
+fn break_loop_ii(five: i32) -> i32 {
+    var sum: i32 = 0;
+    let kOne: i32 = 1;
+    {
+        var i: i32 = 0;
+        loop {
+            if i < 10 {
+                {
+                    if (i > five) {
+                        {
+                            break;
+                        }
+                    }
+                    sum = sum + i;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + kOne;
+            }
+        }
+    }
+    return sum;
+}
+fn loop_operator_le_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 1;
+        loop {
+            if i <= 3 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 1, 2, 3));
+}
+fn loop_operator_lt_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 1;
+        loop {
+            if i < 4 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 1, 2, 3));
+}
+fn loop_operator_ge_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 3;
+        loop {
+            if i >= 1 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i - i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 3, 2, 1));
+}
+fn loop_operator_gt_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 3;
+        loop {
+            if i > 0 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i - i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 3, 2, 1));
+}
+fn loop_operator_ne_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 1;
+        loop {
+            if i != 4 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 1, 2, 3));
+}
+fn loop_operator_eq_b() -> bool {
+    var result: vec4<i32> = vec4<i32>(9);
+    {
+        var i: i32 = 1;
+        loop {
+            if i == 1 {
+                {
+                    result = vec4<i32>(result.yzw, i);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                i = i + i32(1);
+            }
+        }
+    }
+    return all(result == vec4<i32>(9, 9, 9, 1));
+}
+fn main(pos: vec2<f32>) -> vec4<f32> {
+    let _skTemp0 = clamp(pos.x, f32(_globalUniforms.colorGreen.y), f32(_globalUniforms.colorGreen.w));
+    var five: i32 = i32(_skTemp0) * 5;
+    var _skTemp1: vec4<f32>;
+    var _skTemp2: bool;
+    var _skTemp3: bool;
+    var _skTemp4: bool;
+    var _skTemp5: bool;
+    var _skTemp6: bool;
+    var _skTemp7: bool;
+    var _skTemp8: bool;
+    var _skTemp9: bool;
+    let _skTemp10 = return_loop_ii(five);
+    if _skTemp10 == 5 {
+        let _skTemp11 = continue_loop_ii(five);
+        _skTemp9 = _skTemp11 == 35;
+    } else {
+        _skTemp9 = false;
+    }
+    if _skTemp9 {
+        let _skTemp12 = break_loop_ii(5);
+        _skTemp8 = _skTemp12 == 15;
+    } else {
+        _skTemp8 = false;
+    }
+    if _skTemp8 {
+        let _skTemp13 = loop_operator_le_b();
+        _skTemp7 = _skTemp13;
+    } else {
+        _skTemp7 = false;
+    }
+    if _skTemp7 {
+        let _skTemp14 = loop_operator_lt_b();
+        _skTemp6 = _skTemp14;
+    } else {
+        _skTemp6 = false;
+    }
+    if _skTemp6 {
+        let _skTemp15 = loop_operator_ge_b();
+        _skTemp5 = _skTemp15;
+    } else {
+        _skTemp5 = false;
+    }
+    if _skTemp5 {
+        let _skTemp16 = loop_operator_gt_b();
+        _skTemp4 = _skTemp16;
+    } else {
+        _skTemp4 = false;
+    }
+    if _skTemp4 {
+        let _skTemp17 = loop_operator_eq_b();
+        _skTemp3 = _skTemp17;
+    } else {
+        _skTemp3 = false;
+    }
+    if _skTemp3 {
+        let _skTemp18 = loop_operator_ne_b();
+        _skTemp2 = _skTemp18;
+    } else {
+        _skTemp2 = false;
+    }
+    if _skTemp2 {
+        _skTemp1 = _globalUniforms.colorGreen;
+    } else {
+        _skTemp1 = _globalUniforms.colorRed;
+    }
+    return _skTemp1;
+}
+@fragment fn runtimeShaderMain(@location(0) _coords: vec2<f32>) -> @location(0) vec4<f32> {
+    return main(_coords);
+}
diff --git a/tests/sksl/shared/ForLoopMultipleInit.wgsl b/tests/sksl/shared/ForLoopMultipleInit.wgsl
new file mode 100644
index 0000000..e991de6
--- /dev/null
+++ b/tests/sksl/shared/ForLoopMultipleInit.wgsl
@@ -0,0 +1,78 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var result: vec4<f32> = vec4<f32>(0.0);
+    {
+        var a: f32 = 0.0;
+        var b: f32 = 0.0;
+        loop {
+            if a < 10.0 && b < 10.0 {
+                {
+                    result.x = result.x + a;
+                    result.y = result.y + b;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                a = a + f32(1);
+                b = b + f32(1);
+            }
+        }
+    }
+    {
+        var c: i32 = 0;
+        loop {
+            if c < 10 {
+                {
+                    result.z = result.z + 1.0;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                c = c + i32(1);
+            }
+        }
+    }
+    {
+        var d: array<f32, 2> = array<f32, 2>(0.0, 10.0);
+        var e: array<f32, 4> = array<f32, 4>(1.0, 2.0, 3.0, 4.0);
+        var f: f32 = 9.0;
+        loop {
+            if d[0] < d[1] {
+                {
+                    result.w = f32(e[0] * f);
+                }
+            } else {
+                break;
+            }
+            continuing {
+                d[0] = d[0] + f32(1);
+            }
+        }
+    }
+    {
+        loop {
+            break;
+        }
+    }
+    {
+        ;
+
+        loop {
+            break;
+        }
+    }
+    return result;
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}
diff --git a/tests/sksl/shared/UnusedVariables.wgsl b/tests/sksl/shared/UnusedVariables.wgsl
new file mode 100644
index 0000000..7ebfcb3
--- /dev/null
+++ b/tests/sksl/shared/UnusedVariables.wgsl
@@ -0,0 +1,48 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+fn userfunc_ff(v: f32) -> f32 {
+    return v + 1.0;
+}
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var b: f32 = 2.0;
+    var c: f32 = 3.0;
+    b = 2.0;
+    b = c + 77.0;
+    let _skTemp0 = sin(c + 77.0);
+    b = _skTemp0;
+    let _skTemp1 = userfunc_ff(c + 77.0);
+    let _skTemp2 = userfunc_ff(c + 77.0);
+    b = _skTemp2;
+    let _skTemp3 = cos(c);
+    b = _skTemp3;
+    b = b;
+    {
+        var x: i32 = 0;
+        loop {
+            if x < 1 {
+                {
+                    continue;
+                }
+            } else {
+                break;
+            }
+            continuing {
+                x = x + i32(1);
+            }
+        }
+    }
+    var d: f32 = c;
+    b = 3.0;
+    d = d + f32(1);
+    return vec4<f32>(f32(b == 2.0), f32(b == 3.0), f32(d == 5.0), f32(d == 4.0));
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}
diff --git a/tests/sksl/shared/WhileLoopControlFlow.wgsl b/tests/sksl/shared/WhileLoopControlFlow.wgsl
new file mode 100644
index 0000000..e7792c6
--- /dev/null
+++ b/tests/sksl/shared/WhileLoopControlFlow.wgsl
@@ -0,0 +1,41 @@
+struct FSIn {
+    @builtin(front_facing) sk_Clockwise: bool,
+    @builtin(position) sk_FragCoord: vec4<f32>,
+};
+struct FSOut {
+    @location(0) sk_FragColor: vec4<f32>,
+};
+fn main(coords: vec2<f32>) -> vec4<f32> {
+    var x: vec4<f32> = vec4<f32>(1.0);
+    loop {
+        if x.w == 1.0 {
+            {
+                x.x = x.x - 0.25;
+                if (x.x <= 0.0) {
+                    break;
+                }
+            }
+        } else {
+            break;
+        }
+    }
+    loop {
+        if x.z > 0.0 {
+            {
+                x.z = x.z - 0.25;
+                if (x.w == 1.0) {
+                    continue;
+                }
+                x.y = 0.0;
+            }
+        } else {
+            break;
+        }
+    }
+    return x;
+}
+@fragment fn fragmentMain(_stageIn: FSIn) -> FSOut {
+    var _stageOut: FSOut;
+    _stageOut.sk_FragColor = main(_stageIn.sk_FragCoord.xy);
+    return _stageOut;
+}