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>
This commit is contained in:
Ben Clayton 2021-07-29 18:05:19 +00:00
parent a52324fde1
commit ed60a9905c
9 changed files with 213 additions and 128 deletions

View File

@ -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<ast::AssignmentStatement, ast::CallStatement>()) {
return nullptr;
}
// And the continuing statement must not use any of the variables declared
// in the loop body.

View File

@ -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<LoopToForLoop>(src);
EXPECT_EQ(expect, str(got));
}
TEST_F(LoopToForLoopTest, NoTransform_ContinuingMultipleStmts) {
auto* src = R"(
fn f() {

16
test/bug/tint/1064.wgsl Normal file
View File

@ -0,0 +1,16 @@
[[stage(fragment)]]
fn main() {
loop {
if (false) {
} else {
break;
}
continuing {
if (true) {
} else {
break;
}
}
}
}

View File

@ -0,0 +1,15 @@
void main() {
while (true) {
if (false) {
} else {
break;
}
{
if (true) {
} else {
break;
}
}
}
return;
}

View File

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

View File

@ -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

View File

@ -0,0 +1,16 @@
[[stage(fragment)]]
fn main() {
loop {
if (false) {
} else {
break;
}
continuing {
if (true) {
} else {
break;
}
}
}
}

View File

@ -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;
}
{
for(; (i_1 < 1); i_1 = (i_1 + 1)) {
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_2 < 1); i_2 = (i_2 + 1)) {
}
}
continue;
}
return;
continuing {
let x_72 : i32 = i_1;
i_1 = (x_72 + 1);
}
}
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<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

View File

@ -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;
}
{
for(; (i_1 < 1); i_1 = (i_1 + 1)) {
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_2 < 1); i_2 = (i_2 + 1)) {
}
}
continue;
}
return;
continuing {
let x_72 : i32 = i_1;
i_1 = (x_72 + 1);
}
}
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<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;
^^^^^