diff --git a/src/transform/loop_to_for_loop.cc b/src/transform/loop_to_for_loop.cc index 63c63146b0..85f7a84dd7 100644 --- a/src/transform/loop_to_for_loop.cc +++ b/src/transform/loop_to_for_loop.cc @@ -89,7 +89,8 @@ void LoopToForLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) { 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 @@ void LoopToForLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) { } continuing = loop_cont->statements()[0]; + if (!continuing + ->IsAnyOf()) { + 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 91f2ffd745..402c69ad27 100644 --- a/src/transform/loop_to_for_loop_test.cc +++ b/src/transform/loop_to_for_loop_test.cc @@ -208,6 +208,32 @@ fn f() { 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(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 0000000000..782a564a7d --- /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 0000000000..56911a4b81 --- /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 0000000000..f9c26ccd8c --- /dev/null +++ b/test/bug/tint/1064.wgsl.expected.msl @@ -0,0 +1,19 @@ +#include + +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 0000000000..5ebd236719 --- /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 0000000000..27842dc0d4 --- /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 3f53893923..47412bc214 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; +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 x_GLF_color : vec4; - -[[group(0), binding(0)]] var x_7 : buf0; - -var gl_FragCoord : vec4; - -fn main_1() { - var i : i32; - var i_1 : i32; - var i_2 : i32; - x_GLF_color = vec4(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; - } - - continuing { - let x_70 : i32 = i_2; - i_2 = (x_70 + 1); + { + for(; (i_1 < 1); i_1 = (i_1 + 1)) { + if (x_42) { + i_2 = 0; + { + for(; (i_2 < 1); i_2 = (i_2 + 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 @@ fn main_1() { } struct main_out { - [[location(0)]] - x_GLF_color_1 : vec4; + 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) -> 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 251e7b93de..47412bc214 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; +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 x_GLF_color : vec4; - -[[group(0), binding(0)]] var x_7 : buf0; - -var gl_FragCoord : vec4; - -fn main_1() { - var i : i32; - var i_1 : i32; - var i_2 : i32; - x_GLF_color = vec4(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; - } - - continuing { - let x_70 : i32 = i_2; - i_2 = (x_70 + 1); + { + for(; (i_1 < 1); i_1 = (i_1 + 1)) { + if (x_42) { + i_2 = 0; + { + for(; (i_2 < 1); i_2 = (i_2 + 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 @@ fn main_1() { } struct main_out { - [[location(0)]] - x_GLF_color_1 : vec4; + 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) -> 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; - ^^^^^ -