Fixup continue support in while loops.

The generators were not setting `emit_continuing_` when emitting while
loops. This caused a crash when a `continue` was encountered. This CL
adds the `emit_continuing_` setup to the while emission. It also guards
the `emit_continuing_` usage with making sure the function is setup.

Bug: tint:1490
Change-Id: Ia89c49e567acda71a1f851a582103723cff71d49
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/93960
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2022-06-16 15:27:38 +00:00 committed by Dawn LUCI CQ
parent b4b82f55af
commit 4b88dbcf8e
13 changed files with 195 additions and 3 deletions

View File

@ -1753,7 +1753,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
} }
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) { bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
if (!emit_continuing_()) { if (!emit_continuing_ || !emit_continuing_()) {
return false; return false;
} }
line() << "continue;"; line() << "continue;";
@ -2534,6 +2534,9 @@ bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
} }
} }
auto emit_continuing = [&]() { return true; };
TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
// If the whilehas a multi-statement conditional, then we cannot emit this // If the whilehas a multi-statement conditional, then we cannot emit this
// as a regular while in GLSL. Instead we need to generate a `while(true)` loop. // as a regular while in GLSL. Instead we need to generate a `while(true)` loop.
bool emit_as_loop = cond_pre.lines.size() > 0; bool emit_as_loop = cond_pre.lines.size() > 0;

View File

@ -400,6 +400,25 @@ TEST_F(GlslGeneratorImplTest_Loop, Emit_While) {
)"); )");
} }
TEST_F(GlslGeneratorImplTest_Loop, Emit_While_WithContinue) {
// while(true) {
// continue;
// }
auto* f = While(Expr(true), Block(Continue()));
WrapInFunction(f);
GeneratorImpl& gen = Build();
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
EXPECT_EQ(gen.result(), R"( while(true) {
continue;
}
)");
}
TEST_F(GlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) { TEST_F(GlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) {
// while(true && false) { // while(true && false) {
// return; // return;

View File

@ -2634,7 +2634,7 @@ bool GeneratorImpl::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
} }
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) { bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
if (!emit_continuing_()) { if (!emit_continuing_ || !emit_continuing_()) {
return false; return false;
} }
line() << "continue;"; line() << "continue;";
@ -3492,6 +3492,9 @@ bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
} }
} }
auto emit_continuing = [&]() { return true; };
TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
// If the while has a multi-statement conditional, then we cannot emit this // If the while has a multi-statement conditional, then we cannot emit this
// as a regular while in HLSL. Instead we need to generate a `while(true)` loop. // as a regular while in HLSL. Instead we need to generate a `while(true)` loop.
bool emit_as_loop = cond_pre.lines.size() > 0; bool emit_as_loop = cond_pre.lines.size() > 0;

View File

@ -392,6 +392,25 @@ TEST_F(HlslGeneratorImplTest_Loop, Emit_While) {
)"); )");
} }
TEST_F(HlslGeneratorImplTest_Loop, Emit_While_WithContinue) {
// while(true) {
// continue;
// }
auto* f = While(Expr(true), Block(Continue()));
WrapInFunction(f);
GeneratorImpl& gen = Build();
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
EXPECT_EQ(gen.result(), R"( [loop] while(true) {
continue;
}
)");
}
TEST_F(HlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) { TEST_F(HlslGeneratorImplTest_Loop, Emit_WhileWithMultiStmtCond) {
// while(true && false) { // while(true && false) {
// return; // return;

View File

@ -1521,7 +1521,7 @@ bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
} }
bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) { bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
if (!emit_continuing_()) { if (!emit_continuing_ || !emit_continuing_()) {
return false; return false;
} }
@ -2136,6 +2136,9 @@ bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
} }
} }
auto emit_continuing = [&]() { return true; };
TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
// If the while has a multi-statement conditional, then we cannot emit this // If the while has a multi-statement conditional, then we cannot emit this
// as a regular while in MSL. Instead we need to generate a `while(true)` loop. // as a regular while in MSL. Instead we need to generate a `while(true)` loop.
bool emit_as_loop = cond_pre.lines.size() > 0; bool emit_as_loop = cond_pre.lines.size() > 0;

View File

@ -363,6 +363,25 @@ TEST_F(MslGeneratorImplTest, Emit_While) {
)"); )");
} }
TEST_F(MslGeneratorImplTest, Emit_While_WithContinue) {
// while(true) {
// continue;
// }
auto* f = While(Expr(true), Block(Continue()));
WrapInFunction(f);
GeneratorImpl& gen = Build();
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
EXPECT_EQ(gen.result(), R"( while(true) {
continue;
}
)");
}
TEST_F(MslGeneratorImplTest, Emit_WhileWithMultiCond) { TEST_F(MslGeneratorImplTest, Emit_WhileWithMultiCond) {
// while(true && false) { // while(true && false) {
// return; // return;

View File

@ -217,6 +217,25 @@ TEST_F(WgslGeneratorImplTest, Emit_While) {
)"); )");
} }
TEST_F(WgslGeneratorImplTest, Emit_While_WithContinue) {
// while(true) {
// continue;
// }
auto* f = While(Expr(true), Block(Continue()));
WrapInFunction(f);
GeneratorImpl& gen = Build();
gen.increment_indent();
ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
EXPECT_EQ(gen.result(), R"( while(true) {
continue;
}
)");
}
TEST_F(WgslGeneratorImplTest, Emit_WhileMultiCond) { TEST_F(WgslGeneratorImplTest, Emit_WhileMultiCond) {
// while(true && false) { // while(true && false) {
// return; // return;

View File

@ -0,0 +1,8 @@
fn f() -> i32 {
var i : i32;
while (i < 4) {
i = i + 1;
continue;
}
return i;
}

View File

@ -0,0 +1,15 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void unused_entry_point() {
return;
}
int f() {
int i = 0;
while((i < 4)) {
i = (i + 1);
continue;
}
return i;
}

View File

@ -0,0 +1,13 @@
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
int f() {
int i = 0;
[loop] while((i < 4)) {
i = (i + 1);
continue;
}
return i;
}

View File

@ -0,0 +1,12 @@
#include <metal_stdlib>
using namespace metal;
int f() {
int i = 0;
while((i < 4)) {
i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)));
continue;
}
return i;
}

View File

@ -0,0 +1,51 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 27
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
OpExecutionMode %unused_entry_point LocalSize 1 1 1
OpName %unused_entry_point "unused_entry_point"
OpName %f "f"
OpName %i "i"
%void = OpTypeVoid
%1 = OpTypeFunction %void
%int = OpTypeInt 32 1
%5 = OpTypeFunction %int
%_ptr_Function_int = OpTypePointer Function %int
%11 = OpConstantNull %int
%int_4 = OpConstant %int 4
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%unused_entry_point = OpFunction %void None %1
%4 = OpLabel
OpReturn
OpFunctionEnd
%f = OpFunction %int None %5
%8 = OpLabel
%i = OpVariable %_ptr_Function_int Function %11
OpBranch %12
%12 = OpLabel
OpLoopMerge %13 %14 None
OpBranch %15
%15 = OpLabel
%17 = OpLoad %int %i
%19 = OpSLessThan %bool %17 %int_4
%16 = OpLogicalNot %bool %19
OpSelectionMerge %21 None
OpBranchConditional %16 %22 %21
%22 = OpLabel
OpBranch %13
%21 = OpLabel
%23 = OpLoad %int %i
%25 = OpIAdd %int %23 %int_1
OpStore %i %25
OpBranch %14
%14 = OpLabel
OpBranch %12
%13 = OpLabel
%26 = OpLoad %int %i
OpReturnValue %26
OpFunctionEnd

View File

@ -0,0 +1,8 @@
fn f() -> i32 {
var i : i32;
while((i < 4)) {
i = (i + 1);
continue;
}
return i;
}