• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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/msl/test_helper.h"
17 
18 namespace tint {
19 namespace writer {
20 namespace msl {
21 namespace {
22 
23 using MslGeneratorImplTest = TestHelper;
24 
TEST_F(MslGeneratorImplTest,Emit_Loop)25 TEST_F(MslGeneratorImplTest, Emit_Loop) {
26   auto* body = Block(create<ast::DiscardStatement>());
27   auto* continuing = Block();
28   auto* l = Loop(body, continuing);
29   WrapInFunction(l);
30 
31   GeneratorImpl& gen = Build();
32 
33   gen.increment_indent();
34 
35   ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
36   EXPECT_EQ(gen.result(), R"(  while (true) {
37     discard_fragment();
38   }
39 )");
40 }
41 
TEST_F(MslGeneratorImplTest,Emit_LoopWithContinuing)42 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
43   Func("a_statement", {}, ty.void_(), {});
44 
45   auto* body = Block(create<ast::DiscardStatement>());
46   auto* continuing = Block(CallStmt(Call("a_statement")));
47   auto* l = Loop(body, continuing);
48   WrapInFunction(l);
49 
50   GeneratorImpl& gen = Build();
51 
52   gen.increment_indent();
53 
54   ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
55   EXPECT_EQ(gen.result(), R"(  while (true) {
56     discard_fragment();
57     {
58       a_statement();
59     }
60   }
61 )");
62 }
63 
TEST_F(MslGeneratorImplTest,Emit_LoopNestedWithContinuing)64 TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
65   Func("a_statement", {}, ty.void_(), {});
66 
67   Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
68   Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
69 
70   auto* body = Block(create<ast::DiscardStatement>());
71   auto* continuing = Block(CallStmt(Call("a_statement")));
72   auto* inner = Loop(body, continuing);
73 
74   body = Block(inner);
75 
76   continuing = Block(Assign("lhs", "rhs"));
77 
78   auto* outer = Loop(body, continuing);
79   WrapInFunction(outer);
80 
81   GeneratorImpl& gen = Build();
82 
83   gen.increment_indent();
84 
85   ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
86   EXPECT_EQ(gen.result(), R"(  while (true) {
87     while (true) {
88       discard_fragment();
89       {
90         a_statement();
91       }
92     }
93     {
94       lhs = rhs;
95     }
96   }
97 )");
98 }
99 
TEST_F(MslGeneratorImplTest,Emit_LoopWithVarUsedInContinuing)100 TEST_F(MslGeneratorImplTest, Emit_LoopWithVarUsedInContinuing) {
101   // loop {
102   //   var lhs : f32 = 2.4;
103   //   var other : f32;
104   //   continuing {
105   //     lhs = rhs
106   //   }
107   // }
108   //
109   // ->
110   // {
111   //   float lhs;
112   //   float other;
113   //   for (;;) {
114   //     if (continuing) {
115   //       lhs = rhs;
116   //     }
117   //     lhs = 2.4f;
118   //     other = 0.0f;
119   //   }
120   // }
121 
122   Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
123 
124   auto* var = Var("lhs", ty.f32(), ast::StorageClass::kNone, Expr(2.4f));
125 
126   auto* body = Block(Decl(var), Decl(Var("other", ty.f32())));
127 
128   auto* continuing = Block(Assign("lhs", "rhs"));
129 
130   auto* outer = Loop(body, continuing);
131   WrapInFunction(outer);
132 
133   GeneratorImpl& gen = Build();
134 
135   gen.increment_indent();
136 
137   ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
138   EXPECT_EQ(gen.result(), R"(  while (true) {
139     float lhs = 2.400000095f;
140     float other = 0.0f;
141     {
142       lhs = rhs;
143     }
144   }
145 )");
146 }
147 
TEST_F(MslGeneratorImplTest,Emit_ForLoop)148 TEST_F(MslGeneratorImplTest, Emit_ForLoop) {
149   // for(; ; ) {
150   //   return;
151   // }
152 
153   Func("a_statement", {}, ty.void_(), {});
154 
155   auto* f =
156       For(nullptr, nullptr, nullptr, Block(CallStmt(Call("a_statement"))));
157   WrapInFunction(f);
158 
159   GeneratorImpl& gen = Build();
160 
161   gen.increment_indent();
162 
163   ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
164   EXPECT_EQ(gen.result(), R"(  for(; ; ) {
165     a_statement();
166   }
167 )");
168 }
169 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithSimpleInit)170 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleInit) {
171   // for(var i : i32; ; ) {
172   //   return;
173   // }
174 
175   Func("a_statement", {}, ty.void_(), {});
176 
177   auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,
178                 Block(CallStmt(Call("a_statement"))));
179   WrapInFunction(f);
180 
181   GeneratorImpl& gen = Build();
182 
183   gen.increment_indent();
184 
185   ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
186   EXPECT_EQ(gen.result(), R"(  for(int i = 0; ; ) {
187     a_statement();
188   }
189 )");
190 }
191 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithMultiStmtInit)192 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInit) {
193   // fn f(i : i32) {}
194   //
195   // var<workgroup> a : atomic<i32>;
196   // for({f(1); f(2);}; ; ) {
197   //   return;
198   // }
199 
200   Func("f", {Param("i", ty.i32())}, ty.void_(), {});
201   auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
202 
203   Func("a_statement", {}, ty.void_(), {});
204 
205   Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
206   auto* multi_stmt = Block(f(1), f(2));
207   auto* loop =
208       For(multi_stmt, nullptr, nullptr, Block(CallStmt(Call("a_statement"))));
209   WrapInFunction(loop);
210 
211   GeneratorImpl& gen = Build();
212 
213   gen.increment_indent();
214 
215   ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
216   EXPECT_EQ(gen.result(), R"(  {
217     {
218       f(1);
219       f(2);
220     }
221     for(; ; ) {
222       a_statement();
223     }
224   }
225 )");
226 }
227 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithSimpleCond)228 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleCond) {
229   // for(; true; ) {
230   //   return;
231   // }
232 
233   Func("a_statement", {}, ty.void_(), {});
234 
235   auto* f = For(nullptr, true, nullptr, Block(CallStmt(Call("a_statement"))));
236   WrapInFunction(f);
237 
238   GeneratorImpl& gen = Build();
239 
240   gen.increment_indent();
241 
242   ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
243   EXPECT_EQ(gen.result(), R"(  for(; true; ) {
244     a_statement();
245   }
246 )");
247 }
248 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithSimpleCont)249 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleCont) {
250   // for(; ; i = i + 1) {
251   //   return;
252   // }
253 
254   Func("a_statement", {}, ty.void_(), {});
255 
256   auto* v = Decl(Var("i", ty.i32()));
257   auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)),
258                 Block(CallStmt(Call("a_statement"))));
259   WrapInFunction(v, f);
260 
261   GeneratorImpl& gen = Build();
262 
263   gen.increment_indent();
264 
265   ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
266   EXPECT_EQ(
267       gen.result(),
268       R"(  for(; ; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
269     a_statement();
270   }
271 )");
272 }
273 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithMultiStmtCont)274 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtCont) {
275   // fn f(i : i32) {}
276   //
277   // var<workgroup> a : atomic<i32>;
278   // for(; ; { f(1); f(2); }) {
279   //   return;
280   // }
281 
282   Func("f", {Param("i", ty.i32())}, ty.void_(), {});
283   auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
284 
285   Func("a_statement", {}, ty.void_(), {});
286 
287   Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
288   auto* multi_stmt = Block(f(1), f(2));
289   auto* loop =
290       For(nullptr, nullptr, multi_stmt, Block(CallStmt(Call("a_statement"))));
291   WrapInFunction(loop);
292 
293   GeneratorImpl& gen = Build();
294 
295   gen.increment_indent();
296 
297   ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
298   EXPECT_EQ(gen.result(), R"(  while (true) {
299     a_statement();
300     {
301       f(1);
302       f(2);
303     }
304   }
305 )");
306 }
307 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithSimpleInitCondCont)308 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleInitCondCont) {
309   // for(var i : i32; true; i = i + 1) {
310   //   return;
311   // }
312 
313   Func("a_statement", {}, ty.void_(), {});
314 
315   auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
316                 Block(CallStmt(Call("a_statement"))));
317   WrapInFunction(f);
318 
319   GeneratorImpl& gen = Build();
320 
321   gen.increment_indent();
322 
323   ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
324   EXPECT_EQ(
325       gen.result(),
326       R"(  for(int i = 0; true; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
327     a_statement();
328   }
329 )");
330 }
331 
TEST_F(MslGeneratorImplTest,Emit_ForLoopWithMultiStmtInitCondCont)332 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
333   // fn f(i : i32) {}
334   //
335   // var<workgroup> a : atomic<i32>;
336   // for({ f(1); f(2); }; true; { f(3); f(4); }) {
337   //   return;
338   // }
339 
340   Func("f", {Param("i", ty.i32())}, ty.void_(), {});
341   auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
342 
343   Func("a_statement", {}, ty.void_(), {});
344 
345   Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
346   auto* multi_stmt_a = Block(f(1), f(2));
347   auto* multi_stmt_b = Block(f(3), f(4));
348   auto* loop = For(multi_stmt_a, Expr(true), multi_stmt_b,
349                    Block(CallStmt(Call("a_statement"))));
350   WrapInFunction(loop);
351 
352   GeneratorImpl& gen = Build();
353 
354   gen.increment_indent();
355 
356   ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
357   EXPECT_EQ(gen.result(), R"(  {
358     {
359       f(1);
360       f(2);
361     }
362     while (true) {
363       if (!(true)) { break; }
364       a_statement();
365       {
366         f(3);
367         f(4);
368       }
369     }
370   }
371 )");
372 }
373 
374 }  // namespace
375 }  // namespace msl
376 }  // namespace writer
377 }  // namespace tint
378