1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/ast/variable_decl_statement.h"
16 #include "src/writer/glsl/test_helper.h"
17
18 namespace tint {
19 namespace writer {
20 namespace glsl {
21 namespace {
22
23 using GlslGeneratorImplTest_Loop = TestHelper;
24
TEST_F(GlslGeneratorImplTest_Loop,Emit_Loop)25 TEST_F(GlslGeneratorImplTest_Loop, Emit_Loop) {
26 auto* body = Block(create<ast::DiscardStatement>());
27 auto* continuing = Block();
28 auto* l = Loop(body, continuing);
29
30 WrapInFunction(l);
31
32 GeneratorImpl& gen = Build();
33
34 gen.increment_indent();
35
36 ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
37 EXPECT_EQ(gen.result(), R"( while (true) {
38 discard;
39 }
40 )");
41 }
42
TEST_F(GlslGeneratorImplTest_Loop,Emit_LoopWithContinuing)43 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
44 Func("a_statement", {}, ty.void_(), {});
45
46 auto* body = Block(create<ast::DiscardStatement>());
47 auto* continuing = Block(CallStmt(Call("a_statement")));
48 auto* l = Loop(body, continuing);
49
50 WrapInFunction(l);
51
52 GeneratorImpl& gen = Build();
53
54 gen.increment_indent();
55
56 ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
57 EXPECT_EQ(gen.result(), R"( while (true) {
58 discard;
59 {
60 a_statement();
61 }
62 }
63 )");
64 }
65
TEST_F(GlslGeneratorImplTest_Loop,Emit_LoopNestedWithContinuing)66 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
67 Func("a_statement", {}, ty.void_(), {});
68
69 Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
70 Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
71
72 auto* body = Block(create<ast::DiscardStatement>());
73 auto* continuing = Block(CallStmt(Call("a_statement")));
74 auto* inner = Loop(body, continuing);
75
76 body = Block(inner);
77
78 auto* lhs = Expr("lhs");
79 auto* rhs = Expr("rhs");
80
81 continuing = Block(Assign(lhs, rhs));
82
83 auto* outer = Loop(body, continuing);
84 WrapInFunction(outer);
85
86 GeneratorImpl& gen = Build();
87
88 gen.increment_indent();
89
90 ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
91 EXPECT_EQ(gen.result(), R"( while (true) {
92 while (true) {
93 discard;
94 {
95 a_statement();
96 }
97 }
98 {
99 lhs = rhs;
100 }
101 }
102 )");
103 }
104
TEST_F(GlslGeneratorImplTest_Loop,Emit_LoopWithVarUsedInContinuing)105 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithVarUsedInContinuing) {
106 // loop {
107 // var lhs : f32 = 2.4;
108 // var other : f32;
109 // continuing {
110 // lhs = rhs
111 // }
112 // }
113 //
114 // ->
115 // {
116 // float lhs;
117 // float other;
118 // for (;;) {
119 // if (continuing) {
120 // lhs = rhs;
121 // }
122 // lhs = 2.4f;
123 // other = 0.0f;
124 // }
125 // }
126
127 Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
128
129 auto* var = Var("lhs", ty.f32(), ast::StorageClass::kNone, Expr(2.4f));
130
131 auto* body = Block(Decl(var), Decl(Var("other", ty.f32())));
132
133 auto* lhs = Expr("lhs");
134 auto* rhs = Expr("rhs");
135
136 auto* continuing = Block(Assign(lhs, rhs));
137 auto* outer = Loop(body, continuing);
138 WrapInFunction(outer);
139
140 GeneratorImpl& gen = Build();
141
142 gen.increment_indent();
143
144 ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
145 EXPECT_EQ(gen.result(), R"( while (true) {
146 float lhs = 2.400000095f;
147 float other = 0.0f;
148 {
149 lhs = rhs;
150 }
151 }
152 )");
153 }
154
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoop)155 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoop) {
156 // for(; ; ) {
157 // return;
158 // }
159
160 Func("a_statement", {}, ty.void_(), {});
161
162 auto* f =
163 For(nullptr, nullptr, nullptr, Block(CallStmt(Call("a_statement"))));
164 WrapInFunction(f);
165
166 GeneratorImpl& gen = Build();
167
168 gen.increment_indent();
169
170 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
171 EXPECT_EQ(gen.result(), R"( {
172 for(; ; ) {
173 a_statement();
174 }
175 }
176 )");
177 }
178
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithSimpleInit)179 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInit) {
180 // for(var i : i32; ; ) {
181 // return;
182 // }
183
184 Func("a_statement", {}, ty.void_(), {});
185
186 auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,
187 Block(CallStmt(Call("a_statement"))));
188 WrapInFunction(f);
189
190 GeneratorImpl& gen = Build();
191
192 gen.increment_indent();
193
194 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
195 EXPECT_EQ(gen.result(), R"( {
196 for(int i = 0; ; ) {
197 a_statement();
198 }
199 }
200 )");
201 }
202
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithMultiStmtInit)203 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInit) {
204 // for(var b = true && false; ; ) {
205 // return;
206 // }
207 Func("a_statement", {}, ty.void_(), {});
208
209 auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
210 Expr(true), Expr(false));
211 auto* f = For(Decl(Var("b", nullptr, multi_stmt)), nullptr, nullptr,
212 Block(CallStmt(Call("a_statement"))));
213 WrapInFunction(f);
214
215 GeneratorImpl& gen = Build();
216
217 gen.increment_indent();
218
219 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
220 EXPECT_EQ(gen.result(), R"( {
221 bool tint_tmp = true;
222 if (tint_tmp) {
223 tint_tmp = false;
224 }
225 bool b = (tint_tmp);
226 for(; ; ) {
227 a_statement();
228 }
229 }
230 )");
231 }
232
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithSimpleCond)233 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCond) {
234 // for(; true; ) {
235 // return;
236 // }
237
238 Func("a_statement", {}, ty.void_(), {});
239
240 auto* f = For(nullptr, true, nullptr, Block(CallStmt(Call("a_statement"))));
241 WrapInFunction(f);
242
243 GeneratorImpl& gen = Build();
244
245 gen.increment_indent();
246
247 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
248 EXPECT_EQ(gen.result(), R"( {
249 for(; true; ) {
250 a_statement();
251 }
252 }
253 )");
254 }
255
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithMultiStmtCond)256 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCond) {
257 // for(; true && false; ) {
258 // return;
259 // }
260
261 Func("a_statement", {}, ty.void_(), {});
262
263 auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
264 Expr(true), Expr(false));
265 auto* f =
266 For(nullptr, multi_stmt, nullptr, Block(CallStmt(Call("a_statement"))));
267 WrapInFunction(f);
268
269 GeneratorImpl& gen = Build();
270
271 gen.increment_indent();
272
273 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
274 EXPECT_EQ(gen.result(), R"( {
275 while (true) {
276 bool tint_tmp = true;
277 if (tint_tmp) {
278 tint_tmp = false;
279 }
280 if (!((tint_tmp))) { break; }
281 a_statement();
282 }
283 }
284 )");
285 }
286
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithSimpleCont)287 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCont) {
288 // for(; ; i = i + 1) {
289 // return;
290 // }
291
292 Func("a_statement", {}, ty.void_(), {});
293
294 auto* v = Decl(Var("i", ty.i32()));
295 auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)),
296 Block(CallStmt(Call("a_statement"))));
297 WrapInFunction(v, f);
298
299 GeneratorImpl& gen = Build();
300
301 gen.increment_indent();
302
303 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
304 EXPECT_EQ(gen.result(), R"( {
305 for(; ; i = (i + 1)) {
306 a_statement();
307 }
308 }
309 )");
310 }
311
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithMultiStmtCont)312 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCont) {
313 // for(; ; i = true && false) {
314 // return;
315 // }
316
317 Func("a_statement", {}, ty.void_(), {});
318
319 auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
320 Expr(true), Expr(false));
321 auto* v = Decl(Var("i", ty.bool_()));
322 auto* f = For(nullptr, nullptr, Assign("i", multi_stmt),
323 Block(CallStmt(Call("a_statement"))));
324 WrapInFunction(v, f);
325
326 GeneratorImpl& gen = Build();
327
328 gen.increment_indent();
329
330 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
331 EXPECT_EQ(gen.result(), R"( {
332 while (true) {
333 a_statement();
334 bool tint_tmp = true;
335 if (tint_tmp) {
336 tint_tmp = false;
337 }
338 i = (tint_tmp);
339 }
340 }
341 )");
342 }
343
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithSimpleInitCondCont)344 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInitCondCont) {
345 // for(var i : i32; true; i = i + 1) {
346 // return;
347 // }
348
349 Func("a_statement", {}, ty.void_(), {});
350
351 auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
352 Block(CallStmt(Call("a_statement"))));
353 WrapInFunction(f);
354
355 GeneratorImpl& gen = Build();
356
357 gen.increment_indent();
358
359 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
360 EXPECT_EQ(gen.result(), R"( {
361 for(int i = 0; true; i = (i + 1)) {
362 a_statement();
363 }
364 }
365 )");
366 }
367
TEST_F(GlslGeneratorImplTest_Loop,Emit_ForLoopWithMultiStmtInitCondCont)368 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
369 // for(var i = true && false; true && false; i = true && false) {
370 // return;
371 // }
372 Func("a_statement", {}, ty.void_(), {});
373
374 auto* multi_stmt_a = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
375 Expr(true), Expr(false));
376 auto* multi_stmt_b = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
377 Expr(true), Expr(false));
378 auto* multi_stmt_c = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
379 Expr(true), Expr(false));
380
381 auto* f =
382 For(Decl(Var("i", nullptr, multi_stmt_a)), multi_stmt_b,
383 Assign("i", multi_stmt_c), Block(CallStmt(Call("a_statement"))));
384 WrapInFunction(f);
385
386 GeneratorImpl& gen = Build();
387
388 gen.increment_indent();
389
390 ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
391 EXPECT_EQ(gen.result(), R"( {
392 bool tint_tmp = true;
393 if (tint_tmp) {
394 tint_tmp = false;
395 }
396 bool i = (tint_tmp);
397 while (true) {
398 bool tint_tmp_1 = true;
399 if (tint_tmp_1) {
400 tint_tmp_1 = false;
401 }
402 if (!((tint_tmp_1))) { break; }
403 a_statement();
404 bool tint_tmp_2 = true;
405 if (tint_tmp_2) {
406 tint_tmp_2 = false;
407 }
408 i = (tint_tmp_2);
409 }
410 }
411 )");
412 }
413
414 } // namespace
415 } // namespace glsl
416 } // namespace writer
417 } // namespace tint
418