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;
+}