transform: LoopToForLoop - fix bad emission
For loops only support assignments or function calls for the continuing statement.
Fixed: tint:1064
Change-Id: I07065b2119e7b9f97ca7e46b1464fd72333ca429
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/60212
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/transform/loop_to_for_loop.cc b/src/transform/loop_to_for_loop.cc
index 63c6314..85f7a84 100644
--- a/src/transform/loop_to_for_loop.cc
+++ b/src/transform/loop_to_for_loop.cc
@@ -89,7 +89,8 @@
return nullptr;
}
- // The continuing block must be empty or contain a single statement
+ // The continuing block must be empty or contain a single, assignment or
+ // function call statement.
ast::Statement* continuing = nullptr;
if (auto* loop_cont = loop->continuing()) {
if (loop_cont->statements().size() != 1) {
@@ -97,6 +98,10 @@
}
continuing = loop_cont->statements()[0];
+ if (!continuing
+ ->IsAnyOf<ast::AssignmentStatement, ast::CallStatement>()) {
+ return nullptr;
+ }
// And the continuing statement must not use any of the variables declared
// in the loop body.
diff --git a/src/transform/loop_to_for_loop_test.cc b/src/transform/loop_to_for_loop_test.cc
index 91f2ffd..402c69a 100644
--- a/src/transform/loop_to_for_loop_test.cc
+++ b/src/transform/loop_to_for_loop_test.cc
@@ -208,6 +208,32 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(LoopToForLoopTest, NoTransform_ContinuingIsCompound) {
+ auto* src = R"(
+fn f() {
+ var i : i32;
+ i = 0;
+ loop {
+ if ((i < 15)) {
+ break;
+ }
+ ignore(123);
+
+ continuing {
+ if (false) {
+ }
+ }
+ }
+}
+)";
+
+ auto* expect = src;
+
+ auto got = Run<LoopToForLoop>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(LoopToForLoopTest, NoTransform_ContinuingMultipleStmts) {
auto* src = R"(
fn f() {
diff --git a/test/bug/tint/1064.wgsl b/test/bug/tint/1064.wgsl
new file mode 100644
index 0000000..782a564
--- /dev/null
+++ b/test/bug/tint/1064.wgsl
@@ -0,0 +1,16 @@
+[[stage(fragment)]]
+fn main() {
+ loop {
+ if (false) {
+ } else {
+ break;
+ }
+
+ continuing {
+ if (true) {
+ } else {
+ break;
+ }
+ }
+ }
+}
diff --git a/test/bug/tint/1064.wgsl.expected.hlsl b/test/bug/tint/1064.wgsl.expected.hlsl
new file mode 100644
index 0000000..56911a4
--- /dev/null
+++ b/test/bug/tint/1064.wgsl.expected.hlsl
@@ -0,0 +1,15 @@
+void main() {
+ while (true) {
+ if (false) {
+ } else {
+ break;
+ }
+ {
+ if (true) {
+ } else {
+ break;
+ }
+ }
+ }
+ return;
+}
diff --git a/test/bug/tint/1064.wgsl.expected.msl b/test/bug/tint/1064.wgsl.expected.msl
new file mode 100644
index 0000000..f9c26cc
--- /dev/null
+++ b/test/bug/tint/1064.wgsl.expected.msl
@@ -0,0 +1,19 @@
+#include <metal_stdlib>
+
+using namespace metal;
+fragment void tint_symbol() {
+ while (true) {
+ if (false) {
+ } else {
+ break;
+ }
+ {
+ if (true) {
+ } else {
+ break;
+ }
+ }
+ }
+ return;
+}
+
diff --git a/test/bug/tint/1064.wgsl.expected.spvasm b/test/bug/tint/1064.wgsl.expected.spvasm
new file mode 100644
index 0000000..5ebd236
--- /dev/null
+++ b/test/bug/tint/1064.wgsl.expected.spvasm
@@ -0,0 +1,35 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpName %main "main"
+ %void = OpTypeVoid
+ %1 = OpTypeFunction %void
+ %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+ %true = OpConstantTrue %bool
+ %main = OpFunction %void None %1
+ %4 = OpLabel
+ OpBranch %5
+ %5 = OpLabel
+ OpLoopMerge %6 %7 None
+ OpBranch %8
+ %8 = OpLabel
+ OpSelectionMerge %11 None
+ OpBranchConditional %false %12 %13
+ %12 = OpLabel
+ OpBranch %11
+ %13 = OpLabel
+ OpBranch %6
+ %11 = OpLabel
+ OpBranch %7
+ %7 = OpLabel
+ OpBranchConditional %true %5 %6
+ %6 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/bug/tint/1064.wgsl.expected.wgsl b/test/bug/tint/1064.wgsl.expected.wgsl
new file mode 100644
index 0000000..27842dc
--- /dev/null
+++ b/test/bug/tint/1064.wgsl.expected.wgsl
@@ -0,0 +1,16 @@
+[[stage(fragment)]]
+fn main() {
+ loop {
+ if (false) {
+ } else {
+ break;
+ }
+
+ continuing {
+ if (true) {
+ } else {
+ break;
+ }
+ }
+ }
+}
diff --git a/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.spvasm.expected.hlsl b/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.spvasm.expected.hlsl
index 3f53893..47412bc 100644
--- a/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.spvasm.expected.hlsl
+++ b/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.spvasm.expected.hlsl
@@ -1,77 +1,50 @@
-SKIP: FAILED
-
-
-[[block]]
-struct buf0 {
- injectionSwitch : vec2<f32>;
+static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
+cbuffer cbuffer_x_7 : register(b0, space0) {
+ uint4 x_7[1];
};
+static float4 gl_FragCoord = float4(0.0f, 0.0f, 0.0f, 0.0f);
-var<private> x_GLF_color : vec4<f32>;
-
-[[group(0), binding(0)]] var<uniform> x_7 : buf0;
-
-var<private> gl_FragCoord : vec4<f32>;
-
-fn main_1() {
- var i : i32;
- var i_1 : i32;
- var i_2 : i32;
- x_GLF_color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+void main_1() {
+ int i = 0;
+ int i_1 = 0;
+ int i_2 = 0;
+ x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
i = 0;
- let x_35 : f32 = x_7.injectionSwitch.y;
- if ((x_35 < 0.0)) {
+ const float x_35 = asfloat(x_7[0].y);
+ if ((x_35 < 0.0f)) {
} else {
- var x_42 : bool;
- let x_41 : f32 = gl_FragCoord.y;
- x_42 = (x_41 < -1.0);
+ bool x_42 = false;
+ const float x_41 = gl_FragCoord.y;
+ x_42 = (x_41 < -1.0f);
if (x_42) {
} else {
- loop {
- let x_50 : i32 = i;
- if ((x_50 >= 256)) {
+ while (true) {
+ if ((i >= 256)) {
break;
}
- loop {
+ while (true) {
i_1 = 0;
- loop {
- let x_58 : i32 = i_1;
- if ((x_58 < 1)) {
- } else {
- break;
- }
- if (x_42) {
- i_2 = 0;
- loop {
- let x_66 : i32 = i_2;
- if ((x_66 < 1)) {
- } else {
- break;
+ {
+ for(; (i_1 < 1); i_1 = (i_1 + 1)) {
+ if (x_42) {
+ i_2 = 0;
+ {
+ for(; (i_2 < 1); i_2 = (i_2 + 1)) {
+ }
}
-
- continuing {
- let x_70 : i32 = i_2;
- i_2 = (x_70 + 1);
- }
+ continue;
}
- continue;
- }
- return;
-
- continuing {
- let x_72 : i32 = i_1;
- i_1 = (x_72 + 1);
+ return;
}
}
-
- continuing {
+ {
if (false) {
} else {
break;
}
}
}
-
- continuing {
+ {
if (false) {
} else {
break;
@@ -84,15 +57,20 @@
}
struct main_out {
- [[location(0)]]
- x_GLF_color_1 : vec4<f32>;
+ float4 x_GLF_color_1;
+};
+struct tint_symbol_1 {
+ float4 gl_FragCoord_param : SV_Position;
+};
+struct tint_symbol_2 {
+ float4 x_GLF_color_1 : SV_Target0;
};
-[[stage(fragment)]]
-fn main([[builtin(position)]] gl_FragCoord_param : vec4<f32>) -> main_out {
+tint_symbol_2 main(tint_symbol_1 tint_symbol) {
+ const float4 gl_FragCoord_param = tint_symbol.gl_FragCoord_param;
gl_FragCoord = gl_FragCoord_param;
main_1();
- return main_out(x_GLF_color);
+ const main_out tint_symbol_3 = {x_GLF_color};
+ const tint_symbol_2 tint_symbol_5 = {tint_symbol_3.x_GLF_color_1};
+ return tint_symbol_5;
}
-
-Failed to generate: error: break statement must be in a loop or switch case
diff --git a/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.wgsl.expected.hlsl b/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.wgsl.expected.hlsl
index 251e7b9..47412bc 100644
--- a/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.wgsl.expected.hlsl
+++ b/test/vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.wgsl.expected.hlsl
@@ -1,77 +1,50 @@
-SKIP: FAILED
-
-
-[[block]]
-struct buf0 {
- injectionSwitch : vec2<f32>;
+static float4 x_GLF_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
+cbuffer cbuffer_x_7 : register(b0, space0) {
+ uint4 x_7[1];
};
+static float4 gl_FragCoord = float4(0.0f, 0.0f, 0.0f, 0.0f);
-var<private> x_GLF_color : vec4<f32>;
-
-[[group(0), binding(0)]] var<uniform> x_7 : buf0;
-
-var<private> gl_FragCoord : vec4<f32>;
-
-fn main_1() {
- var i : i32;
- var i_1 : i32;
- var i_2 : i32;
- x_GLF_color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+void main_1() {
+ int i = 0;
+ int i_1 = 0;
+ int i_2 = 0;
+ x_GLF_color = float4(1.0f, 0.0f, 0.0f, 1.0f);
i = 0;
- let x_35 : f32 = x_7.injectionSwitch.y;
- if ((x_35 < 0.0)) {
+ const float x_35 = asfloat(x_7[0].y);
+ if ((x_35 < 0.0f)) {
} else {
- var x_42 : bool;
- let x_41 : f32 = gl_FragCoord.y;
- x_42 = (x_41 < -1.0);
+ bool x_42 = false;
+ const float x_41 = gl_FragCoord.y;
+ x_42 = (x_41 < -1.0f);
if (x_42) {
} else {
- loop {
- let x_50 : i32 = i;
- if ((x_50 >= 256)) {
+ while (true) {
+ if ((i >= 256)) {
break;
}
- loop {
+ while (true) {
i_1 = 0;
- loop {
- let x_58 : i32 = i_1;
- if ((x_58 < 1)) {
- } else {
- break;
- }
- if (x_42) {
- i_2 = 0;
- loop {
- let x_66 : i32 = i_2;
- if ((x_66 < 1)) {
- } else {
- break;
+ {
+ for(; (i_1 < 1); i_1 = (i_1 + 1)) {
+ if (x_42) {
+ i_2 = 0;
+ {
+ for(; (i_2 < 1); i_2 = (i_2 + 1)) {
+ }
}
-
- continuing {
- let x_70 : i32 = i_2;
- i_2 = (x_70 + 1);
- }
+ continue;
}
- continue;
- }
- return;
-
- continuing {
- let x_72 : i32 = i_1;
- i_1 = (x_72 + 1);
+ return;
}
}
-
- continuing {
+ {
if (false) {
} else {
break;
}
}
}
-
- continuing {
+ {
if (false) {
} else {
break;
@@ -84,18 +57,20 @@
}
struct main_out {
- [[location(0)]]
- x_GLF_color_1 : vec4<f32>;
+ float4 x_GLF_color_1;
+};
+struct tint_symbol_1 {
+ float4 gl_FragCoord_param : SV_Position;
+};
+struct tint_symbol_2 {
+ float4 x_GLF_color_1 : SV_Target0;
};
-[[stage(fragment)]]
-fn main([[builtin(position)]] gl_FragCoord_param : vec4<f32>) -> main_out {
+tint_symbol_2 main(tint_symbol_1 tint_symbol) {
+ const float4 gl_FragCoord_param = tint_symbol.gl_FragCoord_param;
gl_FragCoord = gl_FragCoord_param;
main_1();
- return main_out(x_GLF_color);
+ const main_out tint_symbol_3 = {x_GLF_color};
+ const tint_symbol_2 tint_symbol_5 = {tint_symbol_3.x_GLF_color_1};
+ return tint_symbol_5;
}
-
-Failed to generate: vk-gl-cts/graphicsfuzz/two-nested-do-whiles/0-opt.wgsl:74:13 error: break statement must be in a loop or switch case
- break;
- ^^^^^
-