1 // Copyright (c) 2018 Google LLC.
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 <memory>
16 #include <vector>
17
18 #include "gmock/gmock.h"
19 #include "source/opt/loop_unroller.h"
20 #include "source/opt/loop_utils.h"
21 #include "source/opt/pass.h"
22 #include "test/opt/assembly_builder.h"
23 #include "test/opt/function_utils.h"
24 #include "test/opt/pass_fixture.h"
25 #include "test/opt/pass_utils.h"
26
27 namespace spvtools {
28 namespace opt {
29 namespace {
30
31 using ::testing::UnorderedElementsAre;
32 using PassClassTest = PassTest<::testing::Test>;
33
34 /*
35 Generated from the following GLSL
36 #version 330 core
37 layout(location = 0) out vec4 c;
38 void main() {
39 float x[4];
40 for (int i = 0; i < 4; ++i) {
41 x[i] = 1.0f;
42 }
43 }
44 */
TEST_F(PassClassTest,SimpleFullyUnrollTest)45 TEST_F(PassClassTest, SimpleFullyUnrollTest) {
46 // With LocalMultiStoreElimPass
47 const std::string text = R"(
48 OpCapability Shader
49 %1 = OpExtInstImport "GLSL.std.450"
50 OpMemoryModel Logical GLSL450
51 OpEntryPoint Fragment %2 "main" %3
52 OpExecutionMode %2 OriginUpperLeft
53 OpSource GLSL 330
54 OpName %2 "main"
55 OpName %5 "x"
56 OpName %3 "c"
57 OpDecorate %3 Location 0
58 %6 = OpTypeVoid
59 %7 = OpTypeFunction %6
60 %8 = OpTypeInt 32 1
61 %9 = OpTypePointer Function %8
62 %10 = OpConstant %8 0
63 %11 = OpConstant %8 4
64 %12 = OpTypeBool
65 %13 = OpTypeFloat 32
66 %14 = OpTypeInt 32 0
67 %15 = OpConstant %14 4
68 %16 = OpTypeArray %13 %15
69 %17 = OpTypePointer Function %16
70 %18 = OpConstant %13 1
71 %19 = OpTypePointer Function %13
72 %20 = OpConstant %8 1
73 %21 = OpTypeVector %13 4
74 %22 = OpTypePointer Output %21
75 %3 = OpVariable %22 Output
76 %2 = OpFunction %6 None %7
77 %23 = OpLabel
78 %5 = OpVariable %17 Function
79 OpBranch %24
80 %24 = OpLabel
81 %35 = OpPhi %8 %10 %23 %34 %26
82 OpLoopMerge %25 %26 Unroll
83 OpBranch %27
84 %27 = OpLabel
85 %29 = OpSLessThan %12 %35 %11
86 OpBranchConditional %29 %30 %25
87 %30 = OpLabel
88 %32 = OpAccessChain %19 %5 %35
89 OpStore %32 %18
90 OpBranch %26
91 %26 = OpLabel
92 %34 = OpIAdd %8 %35 %20
93 OpBranch %24
94 %25 = OpLabel
95 OpReturn
96 OpFunctionEnd
97 )";
98
99 const std::string output = R"(OpCapability Shader
100 %1 = OpExtInstImport "GLSL.std.450"
101 OpMemoryModel Logical GLSL450
102 OpEntryPoint Fragment %2 "main" %3
103 OpExecutionMode %2 OriginUpperLeft
104 OpSource GLSL 330
105 OpName %2 "main"
106 OpName %4 "x"
107 OpName %3 "c"
108 OpDecorate %3 Location 0
109 %5 = OpTypeVoid
110 %6 = OpTypeFunction %5
111 %7 = OpTypeInt 32 1
112 %8 = OpTypePointer Function %7
113 %9 = OpConstant %7 0
114 %10 = OpConstant %7 4
115 %11 = OpTypeBool
116 %12 = OpTypeFloat 32
117 %13 = OpTypeInt 32 0
118 %14 = OpConstant %13 4
119 %15 = OpTypeArray %12 %14
120 %16 = OpTypePointer Function %15
121 %17 = OpConstant %12 1
122 %18 = OpTypePointer Function %12
123 %19 = OpConstant %7 1
124 %20 = OpTypeVector %12 4
125 %21 = OpTypePointer Output %20
126 %3 = OpVariable %21 Output
127 %2 = OpFunction %5 None %6
128 %22 = OpLabel
129 %4 = OpVariable %16 Function
130 OpBranch %23
131 %23 = OpLabel
132 OpBranch %28
133 %28 = OpLabel
134 %29 = OpSLessThan %11 %9 %10
135 OpBranch %30
136 %30 = OpLabel
137 %31 = OpAccessChain %18 %4 %9
138 OpStore %31 %17
139 OpBranch %26
140 %26 = OpLabel
141 %25 = OpIAdd %7 %9 %19
142 OpBranch %32
143 %32 = OpLabel
144 OpBranch %34
145 %34 = OpLabel
146 %35 = OpSLessThan %11 %25 %10
147 OpBranch %36
148 %36 = OpLabel
149 %37 = OpAccessChain %18 %4 %25
150 OpStore %37 %17
151 OpBranch %38
152 %38 = OpLabel
153 %39 = OpIAdd %7 %25 %19
154 OpBranch %40
155 %40 = OpLabel
156 OpBranch %42
157 %42 = OpLabel
158 %43 = OpSLessThan %11 %39 %10
159 OpBranch %44
160 %44 = OpLabel
161 %45 = OpAccessChain %18 %4 %39
162 OpStore %45 %17
163 OpBranch %46
164 %46 = OpLabel
165 %47 = OpIAdd %7 %39 %19
166 OpBranch %48
167 %48 = OpLabel
168 OpBranch %50
169 %50 = OpLabel
170 %51 = OpSLessThan %11 %47 %10
171 OpBranch %52
172 %52 = OpLabel
173 %53 = OpAccessChain %18 %4 %47
174 OpStore %53 %17
175 OpBranch %54
176 %54 = OpLabel
177 %55 = OpIAdd %7 %47 %19
178 OpBranch %27
179 %27 = OpLabel
180 OpReturn
181 OpFunctionEnd
182 )";
183
184 std::unique_ptr<IRContext> context =
185 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
186 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
187 Module* module = context->module();
188 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
189 << text << std::endl;
190
191 LoopUnroller loop_unroller;
192 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
193 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
194 }
195
196 /*
197 Generated from the following GLSL
198 #version 330 core
199 layout(location = 0) out vec4 c;
200 void main() {
201 float x[4];
202 for (int i = 0; i < 4; ++i) {
203 x[i] = 1.0f;
204 }
205 }
206 */
TEST_F(PassClassTest,SimpleFullyUnrollWithDebugInstructions)207 TEST_F(PassClassTest, SimpleFullyUnrollWithDebugInstructions) {
208 // We must preserve the debug information including OpenCL.DebugInfo.100
209 // instructions and OpLine instructions. Only the first block has
210 // DebugDeclare and DebugValue used for the declaration (i.e., DebugValue
211 // with Deref). Other blocks unrolled from the loop must not contain them.
212 const std::string text = R"(
213 OpCapability Shader
214 %1 = OpExtInstImport "GLSL.std.450"
215 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
216 OpMemoryModel Logical GLSL450
217 OpEntryPoint Fragment %2 "main" %3
218 OpExecutionMode %2 OriginUpperLeft
219 OpSource GLSL 330
220 %file_name = OpString "test"
221 %float_name = OpString "float"
222 %main_name = OpString "main"
223 %f_name = OpString "f"
224 %i_name = OpString "i"
225 OpName %2 "main"
226 OpName %5 "x"
227 OpName %3 "c"
228 OpDecorate %3 Location 0
229 %6 = OpTypeVoid
230 %7 = OpTypeFunction %6
231 %8 = OpTypeInt 32 1
232 %9 = OpTypePointer Function %8
233 %10 = OpConstant %8 0
234 %11 = OpConstant %8 4
235 %12 = OpTypeBool
236 %13 = OpTypeFloat 32
237 %14 = OpTypeInt 32 0
238 %uint_32 = OpConstant %14 32
239 %15 = OpConstant %14 4
240 %16 = OpTypeArray %13 %15
241 %17 = OpTypePointer Function %16
242 %18 = OpConstant %13 1
243 %19 = OpTypePointer Function %13
244 %20 = OpConstant %8 1
245 %21 = OpTypeVector %13 4
246 %22 = OpTypePointer Output %21
247 %3 = OpVariable %22 Output
248 %null_expr = OpExtInst %6 %ext DebugExpression
249 %deref = OpExtInst %6 %ext DebugOperation Deref
250 %deref_expr = OpExtInst %6 %ext DebugExpression %deref
251 %src = OpExtInst %6 %ext DebugSource %file_name
252 %cu = OpExtInst %6 %ext DebugCompilationUnit 1 4 %src HLSL
253 %dbg_tf = OpExtInst %6 %ext DebugTypeBasic %float_name %uint_32 Float
254 %dbg_v4f = OpExtInst %6 %ext DebugTypeVector %dbg_tf 4
255 %main_ty = OpExtInst %6 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
256 %dbg_main = OpExtInst %6 %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %2
257 %bb = OpExtInst %6 %ext DebugLexicalBlock %src 0 0 %dbg_main
258 %dbg_f = OpExtInst %6 %ext DebugLocalVariable %f_name %dbg_v4f %src 0 0 %dbg_main FlagIsLocal
259 %dbg_i = OpExtInst %6 %ext DebugLocalVariable %i_name %dbg_v4f %src 1 0 %bb FlagIsLocal
260
261 ; CHECK: [[f:%\w+]] = OpString "f"
262 ; CHECK: [[i:%\w+]] = OpString "i"
263 ; CHECK: [[int_0:%\w+]] = OpConstant {{%\w+}} 0
264
265 ; CHECK: [[null_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression
266 ; CHECK: [[deref:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugOperation Deref
267 ; CHECK: [[deref_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression [[deref]]
268 ; CHECK: [[dbg_fn:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugFunction
269 ; CHECK: [[dbg_bb:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLexicalBlock
270 ; CHECK: [[dbg_f:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[f]] {{%\w+}} {{%\w+}} 0 0 [[dbg_fn]]
271 ; CHECK: [[dbg_i:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[i]] {{%\w+}} {{%\w+}} 1 0 [[dbg_bb]]
272
273 %2 = OpFunction %6 None %7
274 %23 = OpLabel
275
276 ; The first block has DebugDeclare and DebugValue with Deref
277 ;
278 ; CHECK: OpLabel
279 ; CHECK: DebugScope [[dbg_fn]]
280 ; CHECK: [[x:%\w+]] = OpVariable {{%\w+}} Function
281 ; CHECK: OpLine {{%\w+}} 0 0
282 ; CHECK: OpBranch
283 ; CHECK: OpLabel
284 ; CHECK: DebugScope [[dbg_fn]]
285 ; CHECK: DebugValue [[dbg_f]] [[int_0]] [[null_expr]]
286 ; CHECK: OpBranch
287 ; CHECK: DebugScope [[dbg_fn]]
288 ; CHECK: OpLine {{%\w+}} 1 1
289 ; CHECK: OpSLessThan
290 ; CHECK: OpLine {{%\w+}} 2 0
291 ; CHECK: OpBranch
292 ; CHECK: OpLabel
293 ; CHECK: DebugScope [[dbg_bb]]
294 ; CHECK: DebugDeclare [[dbg_f]] [[x]] [[null_expr]]
295 ; CHECK: DebugValue [[dbg_i]] [[x]] [[deref_expr]]
296 ; CHECK: OpLine {{%\w+}} 3 0
297 ;
298 ; CHECK: OpLine {{%\w+}} 6 0
299 ; CHECK: [[add:%\w+]] = OpIAdd
300 ; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]]
301 ; CHECK: OpLine {{%\w+}} 7 0
302
303 ; Other blocks do not have DebugDeclare and DebugValue with Deref
304 ;
305 ; CHECK: DebugScope [[dbg_fn]]
306 ; CHECK: OpLine {{%\w+}} 1 1
307 ; CHECK: OpSLessThan
308 ; CHECK: OpLine {{%\w+}} 2 0
309 ; CHECK: OpBranch
310 ; CHECK: OpLabel
311 ;
312 ; CHECK: DebugScope [[dbg_bb]]
313 ; CHECK-NOT: DebugDeclare [[dbg_f]] [[x]] [[null_expr]]
314 ; CHECK-NOT: DebugValue [[dbg_i]] [[x]] [[deref_expr]]
315 ; CHECK: OpLine {{%\w+}} 3 0
316 ;
317 ; CHECK: OpLine {{%\w+}} 6 0
318 ; CHECK: [[add:%\w+]] = OpIAdd
319 ; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]]
320 ; CHECK: OpLine {{%\w+}} 7 0
321 ;
322 ; CHECK-NOT: DebugDeclare [[dbg_f]] [[x]] [[null_expr]]
323 ; CHECK-NOT: DebugValue [[dbg_i]] [[x]] [[deref_expr]]
324 ; CHECK: DebugScope [[dbg_fn]]
325 ; CHECK: OpLine {{%\w+}} 8 0
326 ; CHECK: OpReturn
327
328 %s0 = OpExtInst %6 %ext DebugScope %dbg_main
329 %5 = OpVariable %17 Function
330 OpLine %file_name 0 0
331 OpBranch %24
332 %24 = OpLabel
333 %s1 = OpExtInst %6 %ext DebugScope %dbg_main
334 %35 = OpPhi %8 %10 %23 %34 %26
335 %value0 = OpExtInst %6 %ext DebugValue %dbg_f %35 %null_expr
336 OpLine %file_name 1 0
337 OpLoopMerge %25 %26 Unroll
338 OpBranch %27
339 %27 = OpLabel
340 %s2 = OpExtInst %6 %ext DebugScope %dbg_main
341 OpLine %file_name 1 1
342 %29 = OpSLessThan %12 %35 %11
343 OpLine %file_name 2 0
344 OpBranchConditional %29 %30 %25
345 %30 = OpLabel
346 %s3 = OpExtInst %6 %ext DebugScope %bb
347 %decl0 = OpExtInst %6 %ext DebugDeclare %dbg_f %5 %null_expr
348 %decl1 = OpExtInst %6 %ext DebugValue %dbg_i %5 %deref_expr
349 OpLine %file_name 3 0
350 %32 = OpAccessChain %19 %5 %35
351 OpLine %file_name 4 0
352 OpStore %32 %18
353 OpLine %file_name 5 0
354 OpBranch %26
355 %26 = OpLabel
356 %s4 = OpExtInst %6 %ext DebugScope %dbg_main
357 OpLine %file_name 6 0
358 %34 = OpIAdd %8 %35 %20
359 %value1 = OpExtInst %6 %ext DebugValue %dbg_f %34 %null_expr
360 OpLine %file_name 7 0
361 OpBranch %24
362 %25 = OpLabel
363 %s5 = OpExtInst %6 %ext DebugScope %dbg_main
364 OpLine %file_name 8 0
365 OpReturn
366 OpFunctionEnd)";
367
368 std::unique_ptr<IRContext> context =
369 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
370 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
371 Module* module = context->module();
372 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
373 << text << std::endl;
374
375 LoopUnroller loop_unroller;
376 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
377 SinglePassRunAndMatch<LoopUnroller>(text, true);
378 }
379
TEST_F(PassClassTest,SimpleFullyUnrollWithShaderDebugInstructions)380 TEST_F(PassClassTest, SimpleFullyUnrollWithShaderDebugInstructions) {
381 // We must preserve the debug information including
382 // NonSemantic.Shader.DebugInfo.100 instructions and DebugLine instructions.
383 const std::string text = R"(
384 OpCapability Shader
385 OpExtension "SPV_KHR_non_semantic_info"
386 %1 = OpExtInstImport "GLSL.std.450"
387 %ext = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
388 OpMemoryModel Logical GLSL450
389 OpEntryPoint Fragment %2 "main" %3
390 OpExecutionMode %2 OriginUpperLeft
391 OpSource GLSL 330
392 %file_name = OpString "test"
393 %float_name = OpString "float"
394 %main_name = OpString "main"
395 %f_name = OpString "f"
396 %i_name = OpString "i"
397 OpName %2 "main"
398 OpName %5 "x"
399 OpName %3 "c"
400 OpDecorate %3 Location 0
401 %6 = OpTypeVoid
402 %7 = OpTypeFunction %6
403 %8 = OpTypeInt 32 1
404 %9 = OpTypePointer Function %8
405 %10 = OpConstant %8 0
406 %11 = OpConstant %8 4
407 %12 = OpTypeBool
408 %13 = OpTypeFloat 32
409 %14 = OpTypeInt 32 0
410 %uint_0 = OpConstant %14 0
411 %uint_1 = OpConstant %14 1
412 %uint_2 = OpConstant %14 2
413 %uint_3 = OpConstant %14 3
414 %uint_4 = OpConstant %14 4
415 %uint_5 = OpConstant %14 5
416 %uint_6 = OpConstant %14 6
417 %uint_7 = OpConstant %14 7
418 %uint_8 = OpConstant %14 8
419 %uint_10 = OpConstant %14 10
420 %uint_32 = OpConstant %14 32
421 %15 = OpConstant %14 4
422 %16 = OpTypeArray %13 %15
423 %17 = OpTypePointer Function %16
424 %18 = OpConstant %13 1
425 %19 = OpTypePointer Function %13
426 %20 = OpConstant %8 1
427 %21 = OpTypeVector %13 4
428 %22 = OpTypePointer Output %21
429 %3 = OpVariable %22 Output
430 %null_expr = OpExtInst %6 %ext DebugExpression
431 %deref = OpExtInst %6 %ext DebugOperation %uint_0
432 %deref_expr = OpExtInst %6 %ext DebugExpression %deref
433 %src = OpExtInst %6 %ext DebugSource %file_name
434 %cu = OpExtInst %6 %ext DebugCompilationUnit %uint_1 %uint_4 %src %uint_5
435 %dbg_tf = OpExtInst %6 %ext DebugTypeBasic %float_name %uint_32 %uint_3 %uint_0
436 %dbg_v4f = OpExtInst %6 %ext DebugTypeVector %dbg_tf %uint_4
437 %main_ty = OpExtInst %6 %ext DebugTypeFunction %uint_3 %dbg_v4f %dbg_v4f
438 %dbg_main = OpExtInst %6 %ext DebugFunction %main_name %main_ty %src %uint_0 %uint_0 %cu %main_name %uint_3 %uint_10
439 %bb = OpExtInst %6 %ext DebugLexicalBlock %src %uint_0 %uint_0 %dbg_main
440 %dbg_f = OpExtInst %6 %ext DebugLocalVariable %f_name %dbg_v4f %src %uint_0 %uint_0 %dbg_main %uint_4
441 %dbg_i = OpExtInst %6 %ext DebugLocalVariable %i_name %dbg_v4f %src %uint_1 %uint_0 %bb %uint_4
442
443 ; CHECK: [[f:%\w+]] = OpString "f"
444 ; CHECK: [[i:%\w+]] = OpString "i"
445 ; CHECK: [[int_0:%\w+]] = OpConstant {{%\w+}} 0
446
447 ; CHECK: [[null_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression
448 ; CHECK: [[deref:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugOperation %uint_0
449 ; CHECK: [[deref_expr:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugExpression [[deref]]
450 ; CHECK: [[dbg_fn:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugFunction
451 ; CHECK: [[dbg_bb:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLexicalBlock
452 ; CHECK: [[dbg_f:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[f]] {{%\w+}} {{%\w+}} %uint_0 %uint_0 [[dbg_fn]]
453 ; CHECK: [[dbg_i:%\w+]] = OpExtInst {{%\w+}} {{%\w+}} DebugLocalVariable [[i]] {{%\w+}} {{%\w+}} %uint_1 %uint_0 [[dbg_bb]]
454
455 %2 = OpFunction %6 None %7
456 %23 = OpLabel
457
458 ; The first block has DebugDeclare and DebugValue with Deref
459 ;
460 ; CHECK: OpLabel
461 ; CHECK: %x = OpVariable %_ptr_Function__arr_float_uint_4_0 Function
462 ; CHECK: OpBranch
463 ; CHECK: OpLabel
464 ; CHECK: DebugScope [[dbg_fn]]
465 ; CHECK: DebugValue [[dbg_f]] [[int_0]] [[null_expr]]
466 ; CHECK: OpBranch
467 ; CHECK: DebugScope [[dbg_fn]]
468 ; CHECK: DebugLine {{%\w+}} %uint_1 %uint_1 %uint_1 %uint_1
469 ; CHECK: OpSLessThan
470 ; CHECK: DebugLine {{%\w+}} %uint_2 %uint_2 %uint_0 %uint_0
471 ; CHECK: OpBranch
472 ; CHECK: OpLabel
473 ; CHECK: DebugScope [[dbg_bb]]
474 ; CHECK: DebugDeclare [[dbg_f]] %x [[null_expr]]
475 ; CHECK: DebugValue [[dbg_i]] %x [[deref_expr]]
476 ; CHECK: DebugLine {{%\w+}} %uint_3 %uint_3 %uint_0 %uint_0
477 ;
478 ; CHECK: DebugLine {{%\w+}} %uint_6 %uint_6 %uint_0 %uint_0
479 ; CHECK: [[add:%\w+]] = OpIAdd
480 ; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]]
481 ; CHECK: DebugLine {{%\w+}} %uint_7 %uint_7 %uint_0 %uint_0
482
483 ; Other blocks do not have DebugDeclare and DebugValue with Deref
484 ;
485 ; CHECK: DebugScope [[dbg_fn]]
486 ; CHECK: DebugLine {{%\w+}} %uint_1 %uint_1 %uint_1 %uint_1
487 ; CHECK: OpSLessThan
488 ; CHECK: DebugLine {{%\w+}} %uint_2 %uint_2 %uint_0 %uint_0
489 ; CHECK: OpBranch
490 ; CHECK: OpLabel
491 ;
492 ; CHECK: DebugScope [[dbg_bb]]
493 ; CHECK-NOT: DebugDeclare [[dbg_f]] %x [[null_expr]]
494 ; CHECK-NOT: DebugValue [[dbg_i]] %x [[deref_expr]]
495 ; CHECK: DebugLine {{%\w+}} %uint_3 %uint_3 %uint_0 %uint_0
496 ;
497 ; CHECK: DebugLine {{%\w+}} %uint_6 %uint_6 %uint_0 %uint_0
498 ; CHECK: [[add:%\w+]] = OpIAdd
499 ; CHECK: DebugValue [[dbg_f]] [[add]] [[null_expr]]
500 ; CHECK: DebugLine {{%\w+}} %uint_7 %uint_7 %uint_0 %uint_0
501 ;
502 ; CHECK-NOT: DebugDeclare [[dbg_f]] %x [[null_expr]]
503 ; CHECK-NOT: DebugValue [[dbg_i]] %x [[deref_expr]]
504 ; CHECK: DebugScope [[dbg_fn]]
505 ; CHECK: DebugLine {{%\w+}} %uint_8 %uint_8 %uint_0 %uint_0
506 ; CHECK: OpReturn
507
508 %5 = OpVariable %17 Function
509 OpBranch %24
510 %24 = OpLabel
511 %35 = OpPhi %8 %10 %23 %34 %26
512 %s1 = OpExtInst %6 %ext DebugScope %dbg_main
513 %d10 = OpExtInst %6 %ext DebugLine %file_name %uint_1 %uint_1 %uint_0 %uint_0
514 %value0 = OpExtInst %6 %ext DebugValue %dbg_f %35 %null_expr
515 OpLoopMerge %25 %26 Unroll
516 OpBranch %27
517 %27 = OpLabel
518 %s2 = OpExtInst %6 %ext DebugScope %dbg_main
519 %d1 = OpExtInst %6 %ext DebugLine %file_name %uint_1 %uint_1 %uint_1 %uint_1
520 %29 = OpSLessThan %12 %35 %11
521 %d2 = OpExtInst %6 %ext DebugLine %file_name %uint_2 %uint_2 %uint_0 %uint_0
522 OpBranchConditional %29 %30 %25
523 %30 = OpLabel
524 %s3 = OpExtInst %6 %ext DebugScope %bb
525 %decl0 = OpExtInst %6 %ext DebugDeclare %dbg_f %5 %null_expr
526 %decl1 = OpExtInst %6 %ext DebugValue %dbg_i %5 %deref_expr
527 %d3 = OpExtInst %6 %ext DebugLine %file_name %uint_3 %uint_3 %uint_0 %uint_0
528 %32 = OpAccessChain %19 %5 %35
529 %d4 = OpExtInst %6 %ext DebugLine %file_name %uint_4 %uint_4 %uint_0 %uint_0
530 OpStore %32 %18
531 %d5 = OpExtInst %6 %ext DebugLine %file_name %uint_5 %uint_5 %uint_0 %uint_0
532 OpBranch %26
533 %26 = OpLabel
534 %s4 = OpExtInst %6 %ext DebugScope %dbg_main
535 %d6 = OpExtInst %6 %ext DebugLine %file_name %uint_6 %uint_6 %uint_0 %uint_0
536 %34 = OpIAdd %8 %35 %20
537 %value1 = OpExtInst %6 %ext DebugValue %dbg_f %34 %null_expr
538 %d7 = OpExtInst %6 %ext DebugLine %file_name %uint_7 %uint_7 %uint_0 %uint_0
539 OpBranch %24
540 %25 = OpLabel
541 %s5 = OpExtInst %6 %ext DebugScope %dbg_main
542 %d8 = OpExtInst %6 %ext DebugLine %file_name %uint_8 %uint_8 %uint_0 %uint_0
543 OpReturn
544 OpFunctionEnd)";
545
546 std::unique_ptr<IRContext> context =
547 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
548 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
549 Module* module = context->module();
550 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
551 << text << std::endl;
552
553 LoopUnroller loop_unroller;
554 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
555 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
556 SinglePassRunAndMatch<LoopUnroller>(text, true);
557 }
558
559 template <int factor>
560 class PartialUnrollerTestPass : public Pass {
561 public:
PartialUnrollerTestPass()562 PartialUnrollerTestPass() : Pass() {}
563
name() const564 const char* name() const override { return "Loop unroller"; }
565
Process()566 Status Process() override {
567 for (Function& f : *context()->module()) {
568 LoopDescriptor& loop_descriptor = *context()->GetLoopDescriptor(&f);
569 for (auto& loop : loop_descriptor) {
570 LoopUtils loop_utils{context(), &loop};
571 loop_utils.PartiallyUnroll(factor);
572 }
573 }
574
575 return Pass::Status::SuccessWithChange;
576 }
577 };
578
579 /*
580 Generated from the following GLSL
581 #version 330 core
582 layout(location = 0) out vec4 c;
583 void main() {
584 float x[10];
585 for (int i = 0; i < 10; ++i) {
586 x[i] = 1.0f;
587 }
588 }
589 */
TEST_F(PassClassTest,SimplePartialUnroll)590 TEST_F(PassClassTest, SimplePartialUnroll) {
591 // With LocalMultiStoreElimPass
592 const std::string text = R"(
593 OpCapability Shader
594 %1 = OpExtInstImport "GLSL.std.450"
595 OpMemoryModel Logical GLSL450
596 OpEntryPoint Fragment %2 "main" %3
597 OpExecutionMode %2 OriginUpperLeft
598 OpSource GLSL 330
599 OpName %2 "main"
600 OpName %5 "x"
601 OpName %3 "c"
602 OpDecorate %3 Location 0
603 %6 = OpTypeVoid
604 %7 = OpTypeFunction %6
605 %8 = OpTypeInt 32 1
606 %9 = OpTypePointer Function %8
607 %10 = OpConstant %8 0
608 %11 = OpConstant %8 10
609 %12 = OpTypeBool
610 %13 = OpTypeFloat 32
611 %14 = OpTypeInt 32 0
612 %15 = OpConstant %14 10
613 %16 = OpTypeArray %13 %15
614 %17 = OpTypePointer Function %16
615 %18 = OpConstant %13 1
616 %19 = OpTypePointer Function %13
617 %20 = OpConstant %8 1
618 %21 = OpTypeVector %13 4
619 %22 = OpTypePointer Output %21
620 %3 = OpVariable %22 Output
621 %2 = OpFunction %6 None %7
622 %23 = OpLabel
623 %5 = OpVariable %17 Function
624 OpBranch %24
625 %24 = OpLabel
626 %35 = OpPhi %8 %10 %23 %34 %26
627 OpLoopMerge %25 %26 Unroll
628 OpBranch %27
629 %27 = OpLabel
630 %29 = OpSLessThan %12 %35 %11
631 OpBranchConditional %29 %30 %25
632 %30 = OpLabel
633 %32 = OpAccessChain %19 %5 %35
634 OpStore %32 %18
635 OpBranch %26
636 %26 = OpLabel
637 %34 = OpIAdd %8 %35 %20
638 OpBranch %24
639 %25 = OpLabel
640 OpReturn
641 OpFunctionEnd
642 )";
643
644 const std::string output = R"(OpCapability Shader
645 %1 = OpExtInstImport "GLSL.std.450"
646 OpMemoryModel Logical GLSL450
647 OpEntryPoint Fragment %2 "main" %3
648 OpExecutionMode %2 OriginUpperLeft
649 OpSource GLSL 330
650 OpName %2 "main"
651 OpName %4 "x"
652 OpName %3 "c"
653 OpDecorate %3 Location 0
654 %5 = OpTypeVoid
655 %6 = OpTypeFunction %5
656 %7 = OpTypeInt 32 1
657 %8 = OpTypePointer Function %7
658 %9 = OpConstant %7 0
659 %10 = OpConstant %7 10
660 %11 = OpTypeBool
661 %12 = OpTypeFloat 32
662 %13 = OpTypeInt 32 0
663 %14 = OpConstant %13 10
664 %15 = OpTypeArray %12 %14
665 %16 = OpTypePointer Function %15
666 %17 = OpConstant %12 1
667 %18 = OpTypePointer Function %12
668 %19 = OpConstant %7 1
669 %20 = OpTypeVector %12 4
670 %21 = OpTypePointer Output %20
671 %3 = OpVariable %21 Output
672 %2 = OpFunction %5 None %6
673 %22 = OpLabel
674 %4 = OpVariable %16 Function
675 OpBranch %23
676 %23 = OpLabel
677 %24 = OpPhi %7 %9 %22 %39 %38
678 OpLoopMerge %27 %38 DontUnroll
679 OpBranch %28
680 %28 = OpLabel
681 %29 = OpSLessThan %11 %24 %10
682 OpBranchConditional %29 %30 %27
683 %30 = OpLabel
684 %31 = OpAccessChain %18 %4 %24
685 OpStore %31 %17
686 OpBranch %26
687 %26 = OpLabel
688 %25 = OpIAdd %7 %24 %19
689 OpBranch %32
690 %32 = OpLabel
691 OpBranch %34
692 %34 = OpLabel
693 %35 = OpSLessThan %11 %25 %10
694 OpBranch %36
695 %36 = OpLabel
696 %37 = OpAccessChain %18 %4 %25
697 OpStore %37 %17
698 OpBranch %38
699 %38 = OpLabel
700 %39 = OpIAdd %7 %25 %19
701 OpBranch %23
702 %27 = OpLabel
703 OpReturn
704 OpFunctionEnd
705 )";
706
707 std::unique_ptr<IRContext> context =
708 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
709 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
710 Module* module = context->module();
711 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
712 << text << std::endl;
713
714 LoopUnroller loop_unroller;
715 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
716 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, output, false);
717 }
718
719 /*
720 Generated from the following GLSL
721 #version 330 core
722 layout(location = 0) out vec4 c;
723 void main() {
724 float x[10];
725 for (int i = 0; i < 10; ++i) {
726 x[i] = 1.0f;
727 }
728 }
729 */
TEST_F(PassClassTest,SimpleUnevenPartialUnroll)730 TEST_F(PassClassTest, SimpleUnevenPartialUnroll) {
731 // With LocalMultiStoreElimPass
732 const std::string text = R"(
733 OpCapability Shader
734 %1 = OpExtInstImport "GLSL.std.450"
735 OpMemoryModel Logical GLSL450
736 OpEntryPoint Fragment %2 "main" %3
737 OpExecutionMode %2 OriginUpperLeft
738 OpSource GLSL 330
739 OpName %2 "main"
740 OpName %5 "x"
741 OpName %3 "c"
742 OpDecorate %3 Location 0
743 %6 = OpTypeVoid
744 %7 = OpTypeFunction %6
745 %8 = OpTypeInt 32 1
746 %9 = OpTypePointer Function %8
747 %10 = OpConstant %8 0
748 %11 = OpConstant %8 10
749 %12 = OpTypeBool
750 %13 = OpTypeFloat 32
751 %14 = OpTypeInt 32 0
752 %15 = OpConstant %14 10
753 %16 = OpTypeArray %13 %15
754 %17 = OpTypePointer Function %16
755 %18 = OpConstant %13 1
756 %19 = OpTypePointer Function %13
757 %20 = OpConstant %8 1
758 %21 = OpTypeVector %13 4
759 %22 = OpTypePointer Output %21
760 %3 = OpVariable %22 Output
761 %2 = OpFunction %6 None %7
762 %23 = OpLabel
763 %5 = OpVariable %17 Function
764 OpBranch %24
765 %24 = OpLabel
766 %35 = OpPhi %8 %10 %23 %34 %26
767 OpLoopMerge %25 %26 Unroll
768 OpBranch %27
769 %27 = OpLabel
770 %29 = OpSLessThan %12 %35 %11
771 OpBranchConditional %29 %30 %25
772 %30 = OpLabel
773 %32 = OpAccessChain %19 %5 %35
774 OpStore %32 %18
775 OpBranch %26
776 %26 = OpLabel
777 %34 = OpIAdd %8 %35 %20
778 OpBranch %24
779 %25 = OpLabel
780 OpReturn
781 OpFunctionEnd
782 )";
783
784 const std::string output = R"(OpCapability Shader
785 %1 = OpExtInstImport "GLSL.std.450"
786 OpMemoryModel Logical GLSL450
787 OpEntryPoint Fragment %2 "main" %3
788 OpExecutionMode %2 OriginUpperLeft
789 OpSource GLSL 330
790 OpName %2 "main"
791 OpName %4 "x"
792 OpName %3 "c"
793 OpDecorate %3 Location 0
794 %5 = OpTypeVoid
795 %6 = OpTypeFunction %5
796 %7 = OpTypeInt 32 1
797 %8 = OpTypePointer Function %7
798 %9 = OpConstant %7 0
799 %10 = OpConstant %7 10
800 %11 = OpTypeBool
801 %12 = OpTypeFloat 32
802 %13 = OpTypeInt 32 0
803 %14 = OpConstant %13 10
804 %15 = OpTypeArray %12 %14
805 %16 = OpTypePointer Function %15
806 %17 = OpConstant %12 1
807 %18 = OpTypePointer Function %12
808 %19 = OpConstant %7 1
809 %20 = OpTypeVector %12 4
810 %21 = OpTypePointer Output %20
811 %3 = OpVariable %21 Output
812 %58 = OpConstant %13 1
813 %2 = OpFunction %5 None %6
814 %22 = OpLabel
815 %4 = OpVariable %16 Function
816 OpBranch %23
817 %23 = OpLabel
818 %24 = OpPhi %7 %9 %22 %25 %26
819 OpLoopMerge %32 %26 Unroll
820 OpBranch %28
821 %28 = OpLabel
822 %29 = OpSLessThan %11 %24 %58
823 OpBranchConditional %29 %30 %32
824 %30 = OpLabel
825 %31 = OpAccessChain %18 %4 %24
826 OpStore %31 %17
827 OpBranch %26
828 %26 = OpLabel
829 %25 = OpIAdd %7 %24 %19
830 OpBranch %23
831 %32 = OpLabel
832 OpBranch %33
833 %33 = OpLabel
834 %34 = OpPhi %7 %24 %32 %57 %56
835 OpLoopMerge %41 %56 DontUnroll
836 OpBranch %35
837 %35 = OpLabel
838 %36 = OpSLessThan %11 %34 %10
839 OpBranchConditional %36 %37 %41
840 %37 = OpLabel
841 %38 = OpAccessChain %18 %4 %34
842 OpStore %38 %17
843 OpBranch %39
844 %39 = OpLabel
845 %40 = OpIAdd %7 %34 %19
846 OpBranch %42
847 %42 = OpLabel
848 OpBranch %44
849 %44 = OpLabel
850 %45 = OpSLessThan %11 %40 %10
851 OpBranch %46
852 %46 = OpLabel
853 %47 = OpAccessChain %18 %4 %40
854 OpStore %47 %17
855 OpBranch %48
856 %48 = OpLabel
857 %49 = OpIAdd %7 %40 %19
858 OpBranch %50
859 %50 = OpLabel
860 OpBranch %52
861 %52 = OpLabel
862 %53 = OpSLessThan %11 %49 %10
863 OpBranch %54
864 %54 = OpLabel
865 %55 = OpAccessChain %18 %4 %49
866 OpStore %55 %17
867 OpBranch %56
868 %56 = OpLabel
869 %57 = OpIAdd %7 %49 %19
870 OpBranch %33
871 %41 = OpLabel
872 OpReturn
873 %27 = OpLabel
874 OpReturn
875 OpFunctionEnd
876 )";
877
878 std::unique_ptr<IRContext> context =
879 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
880 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
881 Module* module = context->module();
882 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
883 << text << std::endl;
884
885 LoopUnroller loop_unroller;
886 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
887 // By unrolling by a factor that doesn't divide evenly into the number of loop
888 // iterations we perform an additional transform when partially unrolling to
889 // account for the remainder.
890 SinglePassRunAndCheck<PartialUnrollerTestPass<3>>(text, output, false);
891 }
892
893 /* Generated from
894 #version 410 core
895 layout(location=0) flat in int upper_bound;
896 void main() {
897 float x[10];
898 for (int i = 2; i < 8; i+=2) {
899 x[i] = i;
900 }
901 }
902 */
TEST_F(PassClassTest,SimpleLoopIterationsCheck)903 TEST_F(PassClassTest, SimpleLoopIterationsCheck) {
904 // With LocalMultiStoreElimPass
905 const std::string text = R"(
906 OpCapability Shader
907 %1 = OpExtInstImport "GLSL.std.450"
908 OpMemoryModel Logical GLSL450
909 OpEntryPoint Fragment %2 "main" %3
910 OpExecutionMode %2 OriginUpperLeft
911 OpSource GLSL 410
912 OpName %2 "main"
913 OpName %5 "x"
914 OpName %3 "upper_bound"
915 OpDecorate %3 Flat
916 OpDecorate %3 Location 0
917 %6 = OpTypeVoid
918 %7 = OpTypeFunction %6
919 %8 = OpTypeInt 32 1
920 %9 = OpTypePointer Function %8
921 %10 = OpConstant %8 2
922 %11 = OpConstant %8 8
923 %12 = OpTypeBool
924 %13 = OpTypeFloat 32
925 %14 = OpTypeInt 32 0
926 %15 = OpConstant %14 10
927 %16 = OpTypeArray %13 %15
928 %17 = OpTypePointer Function %16
929 %18 = OpTypePointer Function %13
930 %19 = OpTypePointer Input %8
931 %3 = OpVariable %19 Input
932 %2 = OpFunction %6 None %7
933 %20 = OpLabel
934 %5 = OpVariable %17 Function
935 OpBranch %21
936 %21 = OpLabel
937 %34 = OpPhi %8 %10 %20 %33 %23
938 OpLoopMerge %22 %23 Unroll
939 OpBranch %24
940 %24 = OpLabel
941 %26 = OpSLessThan %12 %34 %11
942 OpBranchConditional %26 %27 %22
943 %27 = OpLabel
944 %30 = OpConvertSToF %13 %34
945 %31 = OpAccessChain %18 %5 %34
946 OpStore %31 %30
947 OpBranch %23
948 %23 = OpLabel
949 %33 = OpIAdd %8 %34 %10
950 OpBranch %21
951 %22 = OpLabel
952 OpReturn
953 OpFunctionEnd
954 )";
955
956 std::unique_ptr<IRContext> context =
957 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
958 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
959 Module* module = context->module();
960 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
961 << text << std::endl;
962
963 Function* f = spvtest::GetFunction(module, 2);
964
965 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
966 EXPECT_EQ(loop_descriptor.NumLoops(), 1u);
967
968 Loop& loop = loop_descriptor.GetLoopByIndex(0);
969
970 EXPECT_TRUE(loop.HasUnrollLoopControl());
971
972 BasicBlock* condition = loop.FindConditionBlock();
973 EXPECT_EQ(condition->id(), 24u);
974
975 Instruction* induction = loop.FindConditionVariable(condition);
976 EXPECT_EQ(induction->result_id(), 34u);
977
978 LoopUtils loop_utils{context.get(), &loop};
979 EXPECT_TRUE(loop_utils.CanPerformUnroll());
980
981 size_t iterations = 0;
982 EXPECT_TRUE(loop.FindNumberOfIterations(induction, &*condition->ctail(),
983 &iterations));
984 EXPECT_EQ(iterations, 3u);
985 }
986
987 /* Generated from
988 #version 410 core
989 void main() {
990 float x[10];
991 for (int i = -1; i < 6; i+=3) {
992 x[i] = i;
993 }
994 }
995 */
TEST_F(PassClassTest,SimpleLoopIterationsCheckSignedInit)996 TEST_F(PassClassTest, SimpleLoopIterationsCheckSignedInit) {
997 // With LocalMultiStoreElimPass
998 const std::string text = R"(
999 OpCapability Shader
1000 %1 = OpExtInstImport "GLSL.std.450"
1001 OpMemoryModel Logical GLSL450
1002 OpEntryPoint Fragment %2 "main" %3
1003 OpExecutionMode %2 OriginUpperLeft
1004 OpSource GLSL 410
1005 OpName %2 "main"
1006 OpName %5 "x"
1007 OpName %3 "upper_bound"
1008 OpDecorate %3 Flat
1009 OpDecorate %3 Location 0
1010 %6 = OpTypeVoid
1011 %7 = OpTypeFunction %6
1012 %8 = OpTypeInt 32 1
1013 %9 = OpTypePointer Function %8
1014 %10 = OpConstant %8 -1
1015 %11 = OpConstant %8 6
1016 %12 = OpTypeBool
1017 %13 = OpTypeFloat 32
1018 %14 = OpTypeInt 32 0
1019 %15 = OpConstant %14 10
1020 %16 = OpTypeArray %13 %15
1021 %17 = OpTypePointer Function %16
1022 %18 = OpTypePointer Function %13
1023 %19 = OpConstant %8 3
1024 %20 = OpTypePointer Input %8
1025 %3 = OpVariable %20 Input
1026 %2 = OpFunction %6 None %7
1027 %21 = OpLabel
1028 %5 = OpVariable %17 Function
1029 OpBranch %22
1030 %22 = OpLabel
1031 %35 = OpPhi %8 %10 %21 %34 %24
1032 OpLoopMerge %23 %24 None
1033 OpBranch %25
1034 %25 = OpLabel
1035 %27 = OpSLessThan %12 %35 %11
1036 OpBranchConditional %27 %28 %23
1037 %28 = OpLabel
1038 %31 = OpConvertSToF %13 %35
1039 %32 = OpAccessChain %18 %5 %35
1040 OpStore %32 %31
1041 OpBranch %24
1042 %24 = OpLabel
1043 %34 = OpIAdd %8 %35 %19
1044 OpBranch %22
1045 %23 = OpLabel
1046 OpReturn
1047 OpFunctionEnd
1048 )";
1049
1050 std::unique_ptr<IRContext> context =
1051 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1052 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1053 Module* module = context->module();
1054 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1055 << text << std::endl;
1056
1057 Function* f = spvtest::GetFunction(module, 2);
1058
1059 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
1060
1061 EXPECT_EQ(loop_descriptor.NumLoops(), 1u);
1062
1063 Loop& loop = loop_descriptor.GetLoopByIndex(0);
1064
1065 EXPECT_FALSE(loop.HasUnrollLoopControl());
1066
1067 BasicBlock* condition = loop.FindConditionBlock();
1068 EXPECT_EQ(condition->id(), 25u);
1069
1070 Instruction* induction = loop.FindConditionVariable(condition);
1071 EXPECT_EQ(induction->result_id(), 35u);
1072
1073 LoopUtils loop_utils{context.get(), &loop};
1074 EXPECT_TRUE(loop_utils.CanPerformUnroll());
1075
1076 size_t iterations = 0;
1077 EXPECT_TRUE(loop.FindNumberOfIterations(induction, &*condition->ctail(),
1078 &iterations));
1079 EXPECT_EQ(iterations, 3u);
1080 }
1081
1082 /*
1083 Generated from the following GLSL
1084 #version 410 core
1085 void main() {
1086 float out_array[6];
1087 for (uint i = 0; i < 2; i++) {
1088 for (int x = 0; x < 3; ++x) {
1089 out_array[x + i*3] = i;
1090 }
1091 }
1092 }
1093 */
TEST_F(PassClassTest,UnrollNestedLoops)1094 TEST_F(PassClassTest, UnrollNestedLoops) {
1095 // With LocalMultiStoreElimPass
1096 const std::string text = R"(
1097 OpCapability Shader
1098 %1 = OpExtInstImport "GLSL.std.450"
1099 OpMemoryModel Logical GLSL450
1100 OpEntryPoint Fragment %4 "main"
1101 OpExecutionMode %4 OriginUpperLeft
1102 OpSource GLSL 410
1103 OpName %4 "main"
1104 OpName %35 "out_array"
1105 %2 = OpTypeVoid
1106 %3 = OpTypeFunction %2
1107 %6 = OpTypeInt 32 0
1108 %7 = OpTypePointer Function %6
1109 %9 = OpConstant %6 0
1110 %16 = OpConstant %6 2
1111 %17 = OpTypeBool
1112 %19 = OpTypeInt 32 1
1113 %20 = OpTypePointer Function %19
1114 %22 = OpConstant %19 0
1115 %29 = OpConstant %19 3
1116 %31 = OpTypeFloat 32
1117 %32 = OpConstant %6 6
1118 %33 = OpTypeArray %31 %32
1119 %34 = OpTypePointer Function %33
1120 %39 = OpConstant %6 3
1121 %44 = OpTypePointer Function %31
1122 %47 = OpConstant %19 1
1123 %4 = OpFunction %2 None %3
1124 %5 = OpLabel
1125 %35 = OpVariable %34 Function
1126 OpBranch %10
1127 %10 = OpLabel
1128 %51 = OpPhi %6 %9 %5 %50 %13
1129 OpLoopMerge %12 %13 Unroll
1130 OpBranch %14
1131 %14 = OpLabel
1132 %18 = OpULessThan %17 %51 %16
1133 OpBranchConditional %18 %11 %12
1134 %11 = OpLabel
1135 OpBranch %23
1136 %23 = OpLabel
1137 %54 = OpPhi %19 %22 %11 %48 %26
1138 OpLoopMerge %25 %26 Unroll
1139 OpBranch %27
1140 %27 = OpLabel
1141 %30 = OpSLessThan %17 %54 %29
1142 OpBranchConditional %30 %24 %25
1143 %24 = OpLabel
1144 %37 = OpBitcast %6 %54
1145 %40 = OpIMul %6 %51 %39
1146 %41 = OpIAdd %6 %37 %40
1147 %43 = OpConvertUToF %31 %51
1148 %45 = OpAccessChain %44 %35 %41
1149 OpStore %45 %43
1150 OpBranch %26
1151 %26 = OpLabel
1152 %48 = OpIAdd %19 %54 %47
1153 OpBranch %23
1154 %25 = OpLabel
1155 OpBranch %13
1156 %13 = OpLabel
1157 %50 = OpIAdd %6 %51 %47
1158 OpBranch %10
1159 %12 = OpLabel
1160 OpReturn
1161 OpFunctionEnd
1162 )";
1163
1164 const std::string output = R"(OpCapability Shader
1165 %1 = OpExtInstImport "GLSL.std.450"
1166 OpMemoryModel Logical GLSL450
1167 OpEntryPoint Fragment %2 "main"
1168 OpExecutionMode %2 OriginUpperLeft
1169 OpSource GLSL 410
1170 OpName %2 "main"
1171 OpName %3 "out_array"
1172 %4 = OpTypeVoid
1173 %5 = OpTypeFunction %4
1174 %6 = OpTypeInt 32 0
1175 %7 = OpTypePointer Function %6
1176 %8 = OpConstant %6 0
1177 %9 = OpConstant %6 2
1178 %10 = OpTypeBool
1179 %11 = OpTypeInt 32 1
1180 %12 = OpTypePointer Function %11
1181 %13 = OpConstant %11 0
1182 %14 = OpConstant %11 3
1183 %15 = OpTypeFloat 32
1184 %16 = OpConstant %6 6
1185 %17 = OpTypeArray %15 %16
1186 %18 = OpTypePointer Function %17
1187 %19 = OpConstant %6 3
1188 %20 = OpTypePointer Function %15
1189 %21 = OpConstant %11 1
1190 %2 = OpFunction %4 None %5
1191 %22 = OpLabel
1192 %3 = OpVariable %18 Function
1193 OpBranch %23
1194 %23 = OpLabel
1195 OpBranch %28
1196 %28 = OpLabel
1197 %29 = OpULessThan %10 %8 %9
1198 OpBranch %30
1199 %30 = OpLabel
1200 OpBranch %31
1201 %31 = OpLabel
1202 OpBranch %36
1203 %36 = OpLabel
1204 %37 = OpSLessThan %10 %13 %14
1205 OpBranch %38
1206 %38 = OpLabel
1207 %39 = OpBitcast %6 %13
1208 %40 = OpIMul %6 %8 %19
1209 %41 = OpIAdd %6 %39 %40
1210 %42 = OpConvertUToF %15 %8
1211 %43 = OpAccessChain %20 %3 %41
1212 OpStore %43 %42
1213 OpBranch %34
1214 %34 = OpLabel
1215 %33 = OpIAdd %11 %13 %21
1216 OpBranch %44
1217 %44 = OpLabel
1218 OpBranch %46
1219 %46 = OpLabel
1220 %47 = OpSLessThan %10 %33 %14
1221 OpBranch %48
1222 %48 = OpLabel
1223 %49 = OpBitcast %6 %33
1224 %50 = OpIMul %6 %8 %19
1225 %51 = OpIAdd %6 %49 %50
1226 %52 = OpConvertUToF %15 %8
1227 %53 = OpAccessChain %20 %3 %51
1228 OpStore %53 %52
1229 OpBranch %54
1230 %54 = OpLabel
1231 %55 = OpIAdd %11 %33 %21
1232 OpBranch %56
1233 %56 = OpLabel
1234 OpBranch %58
1235 %58 = OpLabel
1236 %59 = OpSLessThan %10 %55 %14
1237 OpBranch %60
1238 %60 = OpLabel
1239 %61 = OpBitcast %6 %55
1240 %62 = OpIMul %6 %8 %19
1241 %63 = OpIAdd %6 %61 %62
1242 %64 = OpConvertUToF %15 %8
1243 %65 = OpAccessChain %20 %3 %63
1244 OpStore %65 %64
1245 OpBranch %66
1246 %66 = OpLabel
1247 %67 = OpIAdd %11 %55 %21
1248 OpBranch %35
1249 %35 = OpLabel
1250 OpBranch %26
1251 %26 = OpLabel
1252 %25 = OpIAdd %6 %8 %21
1253 OpBranch %68
1254 %68 = OpLabel
1255 OpBranch %70
1256 %70 = OpLabel
1257 %71 = OpULessThan %10 %25 %9
1258 OpBranch %72
1259 %72 = OpLabel
1260 OpBranch %73
1261 %73 = OpLabel
1262 OpBranch %74
1263 %74 = OpLabel
1264 %75 = OpSLessThan %10 %13 %14
1265 OpBranch %76
1266 %76 = OpLabel
1267 %77 = OpBitcast %6 %13
1268 %78 = OpIMul %6 %25 %19
1269 %79 = OpIAdd %6 %77 %78
1270 %80 = OpConvertUToF %15 %25
1271 %81 = OpAccessChain %20 %3 %79
1272 OpStore %81 %80
1273 OpBranch %82
1274 %82 = OpLabel
1275 %83 = OpIAdd %11 %13 %21
1276 OpBranch %84
1277 %84 = OpLabel
1278 OpBranch %85
1279 %85 = OpLabel
1280 %86 = OpSLessThan %10 %83 %14
1281 OpBranch %87
1282 %87 = OpLabel
1283 %88 = OpBitcast %6 %83
1284 %89 = OpIMul %6 %25 %19
1285 %90 = OpIAdd %6 %88 %89
1286 %91 = OpConvertUToF %15 %25
1287 %92 = OpAccessChain %20 %3 %90
1288 OpStore %92 %91
1289 OpBranch %93
1290 %93 = OpLabel
1291 %94 = OpIAdd %11 %83 %21
1292 OpBranch %95
1293 %95 = OpLabel
1294 OpBranch %96
1295 %96 = OpLabel
1296 %97 = OpSLessThan %10 %94 %14
1297 OpBranch %98
1298 %98 = OpLabel
1299 %99 = OpBitcast %6 %94
1300 %100 = OpIMul %6 %25 %19
1301 %101 = OpIAdd %6 %99 %100
1302 %102 = OpConvertUToF %15 %25
1303 %103 = OpAccessChain %20 %3 %101
1304 OpStore %103 %102
1305 OpBranch %104
1306 %104 = OpLabel
1307 %105 = OpIAdd %11 %94 %21
1308 OpBranch %106
1309 %106 = OpLabel
1310 OpBranch %107
1311 %107 = OpLabel
1312 %108 = OpIAdd %6 %25 %21
1313 OpBranch %27
1314 %27 = OpLabel
1315 OpReturn
1316 OpFunctionEnd
1317 )";
1318
1319 std::unique_ptr<IRContext> context =
1320 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1321 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1322 Module* module = context->module();
1323 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1324 << text << std::endl;
1325 LoopUnroller loop_unroller;
1326 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1327 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
1328 }
1329
1330 /*
1331 Generated from the following GLSL
1332 #version 410 core
1333 void main() {
1334 float out_array[2];
1335 for (int i = -3; i < -1; i++) {
1336 out_array[3 + i] = i;
1337 }
1338 }
1339 */
TEST_F(PassClassTest,NegativeConditionAndInit)1340 TEST_F(PassClassTest, NegativeConditionAndInit) {
1341 // With LocalMultiStoreElimPass
1342 const std::string text = R"(
1343 OpCapability Shader
1344 %1 = OpExtInstImport "GLSL.std.450"
1345 OpMemoryModel Logical GLSL450
1346 OpEntryPoint Fragment %4 "main"
1347 OpExecutionMode %4 OriginUpperLeft
1348 OpSource GLSL 410
1349 OpName %4 "main"
1350 OpName %23 "out_array"
1351 %2 = OpTypeVoid
1352 %3 = OpTypeFunction %2
1353 %6 = OpTypeInt 32 1
1354 %7 = OpTypePointer Function %6
1355 %9 = OpConstant %6 -3
1356 %16 = OpConstant %6 -1
1357 %17 = OpTypeBool
1358 %19 = OpTypeInt 32 0
1359 %20 = OpConstant %19 2
1360 %21 = OpTypeArray %6 %20
1361 %22 = OpTypePointer Function %21
1362 %25 = OpConstant %6 3
1363 %30 = OpConstant %6 1
1364 %4 = OpFunction %2 None %3
1365 %5 = OpLabel
1366 %23 = OpVariable %22 Function
1367 OpBranch %10
1368 %10 = OpLabel
1369 %32 = OpPhi %6 %9 %5 %31 %13
1370 OpLoopMerge %12 %13 Unroll
1371 OpBranch %14
1372 %14 = OpLabel
1373 %18 = OpSLessThan %17 %32 %16
1374 OpBranchConditional %18 %11 %12
1375 %11 = OpLabel
1376 %26 = OpIAdd %6 %32 %25
1377 %28 = OpAccessChain %7 %23 %26
1378 OpStore %28 %32
1379 OpBranch %13
1380 %13 = OpLabel
1381 %31 = OpIAdd %6 %32 %30
1382 OpBranch %10
1383 %12 = OpLabel
1384 OpReturn
1385 OpFunctionEnd
1386 )";
1387
1388 const std::string expected = R"(OpCapability Shader
1389 %1 = OpExtInstImport "GLSL.std.450"
1390 OpMemoryModel Logical GLSL450
1391 OpEntryPoint Fragment %2 "main"
1392 OpExecutionMode %2 OriginUpperLeft
1393 OpSource GLSL 410
1394 OpName %2 "main"
1395 OpName %3 "out_array"
1396 %4 = OpTypeVoid
1397 %5 = OpTypeFunction %4
1398 %6 = OpTypeInt 32 1
1399 %7 = OpTypePointer Function %6
1400 %8 = OpConstant %6 -3
1401 %9 = OpConstant %6 -1
1402 %10 = OpTypeBool
1403 %11 = OpTypeInt 32 0
1404 %12 = OpConstant %11 2
1405 %13 = OpTypeArray %6 %12
1406 %14 = OpTypePointer Function %13
1407 %15 = OpConstant %6 3
1408 %16 = OpConstant %6 1
1409 %2 = OpFunction %4 None %5
1410 %17 = OpLabel
1411 %3 = OpVariable %14 Function
1412 OpBranch %18
1413 %18 = OpLabel
1414 OpBranch %23
1415 %23 = OpLabel
1416 %24 = OpSLessThan %10 %8 %9
1417 OpBranch %25
1418 %25 = OpLabel
1419 %26 = OpIAdd %6 %8 %15
1420 %27 = OpAccessChain %7 %3 %26
1421 OpStore %27 %8
1422 OpBranch %21
1423 %21 = OpLabel
1424 %20 = OpIAdd %6 %8 %16
1425 OpBranch %28
1426 %28 = OpLabel
1427 OpBranch %30
1428 %30 = OpLabel
1429 %31 = OpSLessThan %10 %20 %9
1430 OpBranch %32
1431 %32 = OpLabel
1432 %33 = OpIAdd %6 %20 %15
1433 %34 = OpAccessChain %7 %3 %33
1434 OpStore %34 %20
1435 OpBranch %35
1436 %35 = OpLabel
1437 %36 = OpIAdd %6 %20 %16
1438 OpBranch %22
1439 %22 = OpLabel
1440 OpReturn
1441 OpFunctionEnd
1442 )";
1443
1444 std::unique_ptr<IRContext> context =
1445 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1446 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1447 Module* module = context->module();
1448 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1449 << text << std::endl;
1450
1451 LoopUnroller loop_unroller;
1452 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1453 // SinglePassRunAndCheck<LoopUnroller>(text, expected, false);
1454
1455 Function* f = spvtest::GetFunction(module, 4);
1456
1457 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
1458 EXPECT_EQ(loop_descriptor.NumLoops(), 1u);
1459
1460 Loop& loop = loop_descriptor.GetLoopByIndex(0);
1461
1462 EXPECT_TRUE(loop.HasUnrollLoopControl());
1463
1464 BasicBlock* condition = loop.FindConditionBlock();
1465 EXPECT_EQ(condition->id(), 14u);
1466
1467 Instruction* induction = loop.FindConditionVariable(condition);
1468 EXPECT_EQ(induction->result_id(), 32u);
1469
1470 LoopUtils loop_utils{context.get(), &loop};
1471 EXPECT_TRUE(loop_utils.CanPerformUnroll());
1472
1473 size_t iterations = 0;
1474 EXPECT_TRUE(loop.FindNumberOfIterations(induction, &*condition->ctail(),
1475 &iterations));
1476 EXPECT_EQ(iterations, 2u);
1477 SinglePassRunAndCheck<LoopUnroller>(text, expected, false);
1478 }
1479
1480 /*
1481 Generated from the following GLSL
1482 #version 410 core
1483 void main() {
1484 float out_array[9];
1485 for (int i = -10; i < -1; i++) {
1486 out_array[i] = i;
1487 }
1488 }
1489 */
TEST_F(PassClassTest,NegativeConditionAndInitResidualUnroll)1490 TEST_F(PassClassTest, NegativeConditionAndInitResidualUnroll) {
1491 // With LocalMultiStoreElimPass
1492 const std::string text = R"(
1493 OpCapability Shader
1494 %1 = OpExtInstImport "GLSL.std.450"
1495 OpMemoryModel Logical GLSL450
1496 OpEntryPoint Fragment %4 "main"
1497 OpExecutionMode %4 OriginUpperLeft
1498 OpSource GLSL 410
1499 OpName %4 "main"
1500 OpName %23 "out_array"
1501 %2 = OpTypeVoid
1502 %3 = OpTypeFunction %2
1503 %6 = OpTypeInt 32 1
1504 %7 = OpTypePointer Function %6
1505 %9 = OpConstant %6 -10
1506 %16 = OpConstant %6 -1
1507 %17 = OpTypeBool
1508 %19 = OpTypeInt 32 0
1509 %20 = OpConstant %19 9
1510 %21 = OpTypeArray %6 %20
1511 %22 = OpTypePointer Function %21
1512 %25 = OpConstant %6 10
1513 %30 = OpConstant %6 1
1514 %4 = OpFunction %2 None %3
1515 %5 = OpLabel
1516 %23 = OpVariable %22 Function
1517 OpBranch %10
1518 %10 = OpLabel
1519 %32 = OpPhi %6 %9 %5 %31 %13
1520 OpLoopMerge %12 %13 Unroll
1521 OpBranch %14
1522 %14 = OpLabel
1523 %18 = OpSLessThan %17 %32 %16
1524 OpBranchConditional %18 %11 %12
1525 %11 = OpLabel
1526 %26 = OpIAdd %6 %32 %25
1527 %28 = OpAccessChain %7 %23 %26
1528 OpStore %28 %32
1529 OpBranch %13
1530 %13 = OpLabel
1531 %31 = OpIAdd %6 %32 %30
1532 OpBranch %10
1533 %12 = OpLabel
1534 OpReturn
1535 OpFunctionEnd
1536 )";
1537
1538 const std::string expected = R"(OpCapability Shader
1539 %1 = OpExtInstImport "GLSL.std.450"
1540 OpMemoryModel Logical GLSL450
1541 OpEntryPoint Fragment %2 "main"
1542 OpExecutionMode %2 OriginUpperLeft
1543 OpSource GLSL 410
1544 OpName %2 "main"
1545 OpName %3 "out_array"
1546 %4 = OpTypeVoid
1547 %5 = OpTypeFunction %4
1548 %6 = OpTypeInt 32 1
1549 %7 = OpTypePointer Function %6
1550 %8 = OpConstant %6 -10
1551 %9 = OpConstant %6 -1
1552 %10 = OpTypeBool
1553 %11 = OpTypeInt 32 0
1554 %12 = OpConstant %11 9
1555 %13 = OpTypeArray %6 %12
1556 %14 = OpTypePointer Function %13
1557 %15 = OpConstant %6 10
1558 %16 = OpConstant %6 1
1559 %48 = OpConstant %6 -9
1560 %2 = OpFunction %4 None %5
1561 %17 = OpLabel
1562 %3 = OpVariable %14 Function
1563 OpBranch %18
1564 %18 = OpLabel
1565 %19 = OpPhi %6 %8 %17 %20 %21
1566 OpLoopMerge %28 %21 Unroll
1567 OpBranch %23
1568 %23 = OpLabel
1569 %24 = OpSLessThan %10 %19 %48
1570 OpBranchConditional %24 %25 %28
1571 %25 = OpLabel
1572 %26 = OpIAdd %6 %19 %15
1573 %27 = OpAccessChain %7 %3 %26
1574 OpStore %27 %19
1575 OpBranch %21
1576 %21 = OpLabel
1577 %20 = OpIAdd %6 %19 %16
1578 OpBranch %18
1579 %28 = OpLabel
1580 OpBranch %29
1581 %29 = OpLabel
1582 %30 = OpPhi %6 %19 %28 %47 %46
1583 OpLoopMerge %38 %46 DontUnroll
1584 OpBranch %31
1585 %31 = OpLabel
1586 %32 = OpSLessThan %10 %30 %9
1587 OpBranchConditional %32 %33 %38
1588 %33 = OpLabel
1589 %34 = OpIAdd %6 %30 %15
1590 %35 = OpAccessChain %7 %3 %34
1591 OpStore %35 %30
1592 OpBranch %36
1593 %36 = OpLabel
1594 %37 = OpIAdd %6 %30 %16
1595 OpBranch %39
1596 %39 = OpLabel
1597 OpBranch %41
1598 %41 = OpLabel
1599 %42 = OpSLessThan %10 %37 %9
1600 OpBranch %43
1601 %43 = OpLabel
1602 %44 = OpIAdd %6 %37 %15
1603 %45 = OpAccessChain %7 %3 %44
1604 OpStore %45 %37
1605 OpBranch %46
1606 %46 = OpLabel
1607 %47 = OpIAdd %6 %37 %16
1608 OpBranch %29
1609 %38 = OpLabel
1610 OpReturn
1611 %22 = OpLabel
1612 OpReturn
1613 OpFunctionEnd
1614 )";
1615
1616 std::unique_ptr<IRContext> context =
1617 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1618 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1619 Module* module = context->module();
1620 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1621 << text << std::endl;
1622
1623 LoopUnroller loop_unroller;
1624 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1625
1626 Function* f = spvtest::GetFunction(module, 4);
1627
1628 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
1629 EXPECT_EQ(loop_descriptor.NumLoops(), 1u);
1630
1631 Loop& loop = loop_descriptor.GetLoopByIndex(0);
1632
1633 EXPECT_TRUE(loop.HasUnrollLoopControl());
1634
1635 BasicBlock* condition = loop.FindConditionBlock();
1636 EXPECT_EQ(condition->id(), 14u);
1637
1638 Instruction* induction = loop.FindConditionVariable(condition);
1639 EXPECT_EQ(induction->result_id(), 32u);
1640
1641 LoopUtils loop_utils{context.get(), &loop};
1642 EXPECT_TRUE(loop_utils.CanPerformUnroll());
1643
1644 size_t iterations = 0;
1645 EXPECT_TRUE(loop.FindNumberOfIterations(induction, &*condition->ctail(),
1646 &iterations));
1647 EXPECT_EQ(iterations, 9u);
1648 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, expected, false);
1649 }
1650
1651 /*
1652 Generated from the following GLSL
1653 #version 410 core
1654 void main() {
1655 float out_array[10];
1656 for (uint i = 0; i < 2; i++) {
1657 for (int x = 0; x < 5; ++x) {
1658 out_array[x + i*5] = i;
1659 }
1660 }
1661 }
1662 */
TEST_F(PassClassTest,UnrollNestedLoopsValidateDescriptor)1663 TEST_F(PassClassTest, UnrollNestedLoopsValidateDescriptor) {
1664 // With LocalMultiStoreElimPass
1665 const std::string text = R"(
1666 OpCapability Shader
1667 %1 = OpExtInstImport "GLSL.std.450"
1668 OpMemoryModel Logical GLSL450
1669 OpEntryPoint Fragment %4 "main"
1670 OpExecutionMode %4 OriginUpperLeft
1671 OpSource GLSL 410
1672 OpName %4 "main"
1673 OpName %35 "out_array"
1674 %2 = OpTypeVoid
1675 %3 = OpTypeFunction %2
1676 %6 = OpTypeInt 32 0
1677 %7 = OpTypePointer Function %6
1678 %9 = OpConstant %6 0
1679 %16 = OpConstant %6 2
1680 %17 = OpTypeBool
1681 %19 = OpTypeInt 32 1
1682 %20 = OpTypePointer Function %19
1683 %22 = OpConstant %19 0
1684 %29 = OpConstant %19 5
1685 %31 = OpTypeFloat 32
1686 %32 = OpConstant %6 10
1687 %33 = OpTypeArray %31 %32
1688 %34 = OpTypePointer Function %33
1689 %39 = OpConstant %6 5
1690 %44 = OpTypePointer Function %31
1691 %47 = OpConstant %19 1
1692 %4 = OpFunction %2 None %3
1693 %5 = OpLabel
1694 %35 = OpVariable %34 Function
1695 OpBranch %10
1696 %10 = OpLabel
1697 %51 = OpPhi %6 %9 %5 %50 %13
1698 OpLoopMerge %12 %13 Unroll
1699 OpBranch %14
1700 %14 = OpLabel
1701 %18 = OpULessThan %17 %51 %16
1702 OpBranchConditional %18 %11 %12
1703 %11 = OpLabel
1704 OpBranch %23
1705 %23 = OpLabel
1706 %54 = OpPhi %19 %22 %11 %48 %26
1707 OpLoopMerge %25 %26 Unroll
1708 OpBranch %27
1709 %27 = OpLabel
1710 %30 = OpSLessThan %17 %54 %29
1711 OpBranchConditional %30 %24 %25
1712 %24 = OpLabel
1713 %37 = OpBitcast %6 %54
1714 %40 = OpIMul %6 %51 %39
1715 %41 = OpIAdd %6 %37 %40
1716 %43 = OpConvertUToF %31 %51
1717 %45 = OpAccessChain %44 %35 %41
1718 OpStore %45 %43
1719 OpBranch %26
1720 %26 = OpLabel
1721 %48 = OpIAdd %19 %54 %47
1722 OpBranch %23
1723 %25 = OpLabel
1724 OpBranch %13
1725 %13 = OpLabel
1726 %50 = OpIAdd %6 %51 %47
1727 OpBranch %10
1728 %12 = OpLabel
1729 OpReturn
1730 OpFunctionEnd
1731 )";
1732
1733 { // Test fully unroll
1734 std::unique_ptr<IRContext> context =
1735 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1736 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1737 Module* module = context->module();
1738 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1739 << text << std::endl;
1740 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1741
1742 Function* f = spvtest::GetFunction(module, 4);
1743 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
1744 EXPECT_EQ(loop_descriptor.NumLoops(), 2u);
1745
1746 Loop& outer_loop = loop_descriptor.GetLoopByIndex(1);
1747
1748 EXPECT_TRUE(outer_loop.HasUnrollLoopControl());
1749
1750 Loop& inner_loop = loop_descriptor.GetLoopByIndex(0);
1751
1752 EXPECT_TRUE(inner_loop.HasUnrollLoopControl());
1753
1754 EXPECT_EQ(outer_loop.GetBlocks().size(), 9u);
1755
1756 EXPECT_EQ(inner_loop.GetBlocks().size(), 4u);
1757 EXPECT_EQ(outer_loop.NumImmediateChildren(), 1u);
1758 EXPECT_EQ(inner_loop.NumImmediateChildren(), 0u);
1759
1760 {
1761 LoopUtils loop_utils{context.get(), &inner_loop};
1762 loop_utils.FullyUnroll();
1763 loop_utils.Finalize();
1764 }
1765
1766 EXPECT_EQ(loop_descriptor.NumLoops(), 1u);
1767 EXPECT_EQ(outer_loop.GetBlocks().size(), 25u);
1768 EXPECT_EQ(outer_loop.NumImmediateChildren(), 0u);
1769 {
1770 LoopUtils loop_utils{context.get(), &outer_loop};
1771 loop_utils.FullyUnroll();
1772 loop_utils.Finalize();
1773 }
1774 EXPECT_EQ(loop_descriptor.NumLoops(), 0u);
1775 }
1776
1777 { // Test partially unroll
1778 std::unique_ptr<IRContext> context =
1779 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1780 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1781 Module* module = context->module();
1782 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1783 << text << std::endl;
1784 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1785
1786 Function* f = spvtest::GetFunction(module, 4);
1787 LoopDescriptor& loop_descriptor = *context->GetLoopDescriptor(f);
1788 EXPECT_EQ(loop_descriptor.NumLoops(), 2u);
1789
1790 Loop& outer_loop = loop_descriptor.GetLoopByIndex(1);
1791
1792 EXPECT_TRUE(outer_loop.HasUnrollLoopControl());
1793
1794 Loop& inner_loop = loop_descriptor.GetLoopByIndex(0);
1795
1796 EXPECT_TRUE(inner_loop.HasUnrollLoopControl());
1797
1798 EXPECT_EQ(outer_loop.GetBlocks().size(), 9u);
1799
1800 EXPECT_EQ(inner_loop.GetBlocks().size(), 4u);
1801
1802 EXPECT_EQ(outer_loop.NumImmediateChildren(), 1u);
1803 EXPECT_EQ(inner_loop.NumImmediateChildren(), 0u);
1804
1805 LoopUtils loop_utils{context.get(), &inner_loop};
1806 loop_utils.PartiallyUnroll(2);
1807 loop_utils.Finalize();
1808
1809 // The number of loops should actually grow.
1810 EXPECT_EQ(loop_descriptor.NumLoops(), 3u);
1811 EXPECT_EQ(outer_loop.GetBlocks().size(), 18u);
1812 EXPECT_EQ(outer_loop.NumImmediateChildren(), 2u);
1813 }
1814 }
1815
1816 /*
1817 Generated from the following GLSL
1818 #version 410 core
1819 void main() {
1820 float out_array[3];
1821 for (int i = 3; i > 0; --i) {
1822 out_array[i] = i;
1823 }
1824 }
1825 */
TEST_F(PassClassTest,FullyUnrollNegativeStepLoopTest)1826 TEST_F(PassClassTest, FullyUnrollNegativeStepLoopTest) {
1827 // With LocalMultiStoreElimPass
1828 const std::string text = R"(
1829 OpCapability Shader
1830 %1 = OpExtInstImport "GLSL.std.450"
1831 OpMemoryModel Logical GLSL450
1832 OpEntryPoint Fragment %4 "main"
1833 OpExecutionMode %4 OriginUpperLeft
1834 OpSource GLSL 410
1835 OpName %4 "main"
1836 OpName %24 "out_array"
1837 %2 = OpTypeVoid
1838 %3 = OpTypeFunction %2
1839 %6 = OpTypeInt 32 1
1840 %7 = OpTypePointer Function %6
1841 %9 = OpConstant %6 3
1842 %16 = OpConstant %6 0
1843 %17 = OpTypeBool
1844 %19 = OpTypeFloat 32
1845 %20 = OpTypeInt 32 0
1846 %21 = OpConstant %20 3
1847 %22 = OpTypeArray %19 %21
1848 %23 = OpTypePointer Function %22
1849 %28 = OpTypePointer Function %19
1850 %31 = OpConstant %6 1
1851 %4 = OpFunction %2 None %3
1852 %5 = OpLabel
1853 %24 = OpVariable %23 Function
1854 OpBranch %10
1855 %10 = OpLabel
1856 %33 = OpPhi %6 %9 %5 %32 %13
1857 OpLoopMerge %12 %13 Unroll
1858 OpBranch %14
1859 %14 = OpLabel
1860 %18 = OpSGreaterThan %17 %33 %16
1861 OpBranchConditional %18 %11 %12
1862 %11 = OpLabel
1863 %27 = OpConvertSToF %19 %33
1864 %29 = OpAccessChain %28 %24 %33
1865 OpStore %29 %27
1866 OpBranch %13
1867 %13 = OpLabel
1868 %32 = OpISub %6 %33 %31
1869 OpBranch %10
1870 %12 = OpLabel
1871 OpReturn
1872 OpFunctionEnd
1873 )";
1874
1875 const std::string output = R"(OpCapability Shader
1876 %1 = OpExtInstImport "GLSL.std.450"
1877 OpMemoryModel Logical GLSL450
1878 OpEntryPoint Fragment %2 "main"
1879 OpExecutionMode %2 OriginUpperLeft
1880 OpSource GLSL 410
1881 OpName %2 "main"
1882 OpName %3 "out_array"
1883 %4 = OpTypeVoid
1884 %5 = OpTypeFunction %4
1885 %6 = OpTypeInt 32 1
1886 %7 = OpTypePointer Function %6
1887 %8 = OpConstant %6 3
1888 %9 = OpConstant %6 0
1889 %10 = OpTypeBool
1890 %11 = OpTypeFloat 32
1891 %12 = OpTypeInt 32 0
1892 %13 = OpConstant %12 3
1893 %14 = OpTypeArray %11 %13
1894 %15 = OpTypePointer Function %14
1895 %16 = OpTypePointer Function %11
1896 %17 = OpConstant %6 1
1897 %2 = OpFunction %4 None %5
1898 %18 = OpLabel
1899 %3 = OpVariable %15 Function
1900 OpBranch %19
1901 %19 = OpLabel
1902 OpBranch %24
1903 %24 = OpLabel
1904 %25 = OpSGreaterThan %10 %8 %9
1905 OpBranch %26
1906 %26 = OpLabel
1907 %27 = OpConvertSToF %11 %8
1908 %28 = OpAccessChain %16 %3 %8
1909 OpStore %28 %27
1910 OpBranch %22
1911 %22 = OpLabel
1912 %21 = OpISub %6 %8 %17
1913 OpBranch %29
1914 %29 = OpLabel
1915 OpBranch %31
1916 %31 = OpLabel
1917 %32 = OpSGreaterThan %10 %21 %9
1918 OpBranch %33
1919 %33 = OpLabel
1920 %34 = OpConvertSToF %11 %21
1921 %35 = OpAccessChain %16 %3 %21
1922 OpStore %35 %34
1923 OpBranch %36
1924 %36 = OpLabel
1925 %37 = OpISub %6 %21 %17
1926 OpBranch %38
1927 %38 = OpLabel
1928 OpBranch %40
1929 %40 = OpLabel
1930 %41 = OpSGreaterThan %10 %37 %9
1931 OpBranch %42
1932 %42 = OpLabel
1933 %43 = OpConvertSToF %11 %37
1934 %44 = OpAccessChain %16 %3 %37
1935 OpStore %44 %43
1936 OpBranch %45
1937 %45 = OpLabel
1938 %46 = OpISub %6 %37 %17
1939 OpBranch %23
1940 %23 = OpLabel
1941 OpReturn
1942 OpFunctionEnd
1943 )";
1944
1945 std::unique_ptr<IRContext> context =
1946 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1947 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1948 Module* module = context->module();
1949 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
1950 << text << std::endl;
1951
1952 LoopUnroller loop_unroller;
1953 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1954 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
1955 }
1956
1957 /*
1958 Generated from the following GLSL
1959 #version 410 core
1960 void main() {
1961 float out_array[3];
1962 for (int i = 9; i > 0; i-=3) {
1963 out_array[i] = i;
1964 }
1965 }
1966 */
TEST_F(PassClassTest,FullyUnrollNegativeNonOneStepLoop)1967 TEST_F(PassClassTest, FullyUnrollNegativeNonOneStepLoop) {
1968 // With LocalMultiStoreElimPass
1969 const std::string text = R"(
1970 OpCapability Shader
1971 %1 = OpExtInstImport "GLSL.std.450"
1972 OpMemoryModel Logical GLSL450
1973 OpEntryPoint Fragment %4 "main"
1974 OpExecutionMode %4 OriginUpperLeft
1975 OpSource GLSL 410
1976 OpName %4 "main"
1977 OpName %24 "out_array"
1978 %2 = OpTypeVoid
1979 %3 = OpTypeFunction %2
1980 %6 = OpTypeInt 32 1
1981 %7 = OpTypePointer Function %6
1982 %9 = OpConstant %6 9
1983 %16 = OpConstant %6 0
1984 %17 = OpTypeBool
1985 %19 = OpTypeFloat 32
1986 %20 = OpTypeInt 32 0
1987 %21 = OpConstant %20 3
1988 %22 = OpTypeArray %19 %21
1989 %23 = OpTypePointer Function %22
1990 %28 = OpTypePointer Function %19
1991 %30 = OpConstant %6 3
1992 %4 = OpFunction %2 None %3
1993 %5 = OpLabel
1994 %24 = OpVariable %23 Function
1995 OpBranch %10
1996 %10 = OpLabel
1997 %33 = OpPhi %6 %9 %5 %32 %13
1998 OpLoopMerge %12 %13 Unroll
1999 OpBranch %14
2000 %14 = OpLabel
2001 %18 = OpSGreaterThan %17 %33 %16
2002 OpBranchConditional %18 %11 %12
2003 %11 = OpLabel
2004 %27 = OpConvertSToF %19 %33
2005 %29 = OpAccessChain %28 %24 %33
2006 OpStore %29 %27
2007 OpBranch %13
2008 %13 = OpLabel
2009 %32 = OpISub %6 %33 %30
2010 OpBranch %10
2011 %12 = OpLabel
2012 OpReturn
2013 OpFunctionEnd
2014 )";
2015
2016 const std::string output = R"(OpCapability Shader
2017 %1 = OpExtInstImport "GLSL.std.450"
2018 OpMemoryModel Logical GLSL450
2019 OpEntryPoint Fragment %2 "main"
2020 OpExecutionMode %2 OriginUpperLeft
2021 OpSource GLSL 410
2022 OpName %2 "main"
2023 OpName %3 "out_array"
2024 %4 = OpTypeVoid
2025 %5 = OpTypeFunction %4
2026 %6 = OpTypeInt 32 1
2027 %7 = OpTypePointer Function %6
2028 %8 = OpConstant %6 9
2029 %9 = OpConstant %6 0
2030 %10 = OpTypeBool
2031 %11 = OpTypeFloat 32
2032 %12 = OpTypeInt 32 0
2033 %13 = OpConstant %12 3
2034 %14 = OpTypeArray %11 %13
2035 %15 = OpTypePointer Function %14
2036 %16 = OpTypePointer Function %11
2037 %17 = OpConstant %6 3
2038 %2 = OpFunction %4 None %5
2039 %18 = OpLabel
2040 %3 = OpVariable %15 Function
2041 OpBranch %19
2042 %19 = OpLabel
2043 OpBranch %24
2044 %24 = OpLabel
2045 %25 = OpSGreaterThan %10 %8 %9
2046 OpBranch %26
2047 %26 = OpLabel
2048 %27 = OpConvertSToF %11 %8
2049 %28 = OpAccessChain %16 %3 %8
2050 OpStore %28 %27
2051 OpBranch %22
2052 %22 = OpLabel
2053 %21 = OpISub %6 %8 %17
2054 OpBranch %29
2055 %29 = OpLabel
2056 OpBranch %31
2057 %31 = OpLabel
2058 %32 = OpSGreaterThan %10 %21 %9
2059 OpBranch %33
2060 %33 = OpLabel
2061 %34 = OpConvertSToF %11 %21
2062 %35 = OpAccessChain %16 %3 %21
2063 OpStore %35 %34
2064 OpBranch %36
2065 %36 = OpLabel
2066 %37 = OpISub %6 %21 %17
2067 OpBranch %38
2068 %38 = OpLabel
2069 OpBranch %40
2070 %40 = OpLabel
2071 %41 = OpSGreaterThan %10 %37 %9
2072 OpBranch %42
2073 %42 = OpLabel
2074 %43 = OpConvertSToF %11 %37
2075 %44 = OpAccessChain %16 %3 %37
2076 OpStore %44 %43
2077 OpBranch %45
2078 %45 = OpLabel
2079 %46 = OpISub %6 %37 %17
2080 OpBranch %23
2081 %23 = OpLabel
2082 OpReturn
2083 OpFunctionEnd
2084 )";
2085
2086 std::unique_ptr<IRContext> context =
2087 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
2088 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2089 Module* module = context->module();
2090 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2091 << text << std::endl;
2092
2093 LoopUnroller loop_unroller;
2094 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2095 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
2096 }
2097
2098 /*
2099 Generated from the following GLSL
2100 #version 410 core
2101 void main() {
2102 float out_array[3];
2103 for (int i = 0; i < 7; i+=3) {
2104 out_array[i] = i;
2105 }
2106 }
2107 */
TEST_F(PassClassTest,FullyUnrollNonDivisibleStepLoop)2108 TEST_F(PassClassTest, FullyUnrollNonDivisibleStepLoop) {
2109 // With LocalMultiStoreElimPass
2110 const std::string text = R"(OpCapability Shader
2111 %1 = OpExtInstImport "GLSL.std.450"
2112 OpMemoryModel Logical GLSL450
2113 OpEntryPoint Fragment %4 "main"
2114 OpExecutionMode %4 OriginUpperLeft
2115 OpSource GLSL 410
2116 OpName %4 "main"
2117 OpName %24 "out_array"
2118 %2 = OpTypeVoid
2119 %3 = OpTypeFunction %2
2120 %6 = OpTypeInt 32 1
2121 %7 = OpTypePointer Function %6
2122 %9 = OpConstant %6 0
2123 %16 = OpConstant %6 7
2124 %17 = OpTypeBool
2125 %19 = OpTypeFloat 32
2126 %20 = OpTypeInt 32 0
2127 %21 = OpConstant %20 3
2128 %22 = OpTypeArray %19 %21
2129 %23 = OpTypePointer Function %22
2130 %28 = OpTypePointer Function %19
2131 %30 = OpConstant %6 3
2132 %4 = OpFunction %2 None %3
2133 %5 = OpLabel
2134 %24 = OpVariable %23 Function
2135 OpBranch %10
2136 %10 = OpLabel
2137 %33 = OpPhi %6 %9 %5 %32 %13
2138 OpLoopMerge %12 %13 Unroll
2139 OpBranch %14
2140 %14 = OpLabel
2141 %18 = OpSLessThan %17 %33 %16
2142 OpBranchConditional %18 %11 %12
2143 %11 = OpLabel
2144 %27 = OpConvertSToF %19 %33
2145 %29 = OpAccessChain %28 %24 %33
2146 OpStore %29 %27
2147 OpBranch %13
2148 %13 = OpLabel
2149 %32 = OpIAdd %6 %33 %30
2150 OpBranch %10
2151 %12 = OpLabel
2152 OpReturn
2153 OpFunctionEnd
2154 )";
2155
2156 const std::string output = R"(OpCapability Shader
2157 %1 = OpExtInstImport "GLSL.std.450"
2158 OpMemoryModel Logical GLSL450
2159 OpEntryPoint Fragment %2 "main"
2160 OpExecutionMode %2 OriginUpperLeft
2161 OpSource GLSL 410
2162 OpName %2 "main"
2163 OpName %3 "out_array"
2164 %4 = OpTypeVoid
2165 %5 = OpTypeFunction %4
2166 %6 = OpTypeInt 32 1
2167 %7 = OpTypePointer Function %6
2168 %8 = OpConstant %6 0
2169 %9 = OpConstant %6 7
2170 %10 = OpTypeBool
2171 %11 = OpTypeFloat 32
2172 %12 = OpTypeInt 32 0
2173 %13 = OpConstant %12 3
2174 %14 = OpTypeArray %11 %13
2175 %15 = OpTypePointer Function %14
2176 %16 = OpTypePointer Function %11
2177 %17 = OpConstant %6 3
2178 %2 = OpFunction %4 None %5
2179 %18 = OpLabel
2180 %3 = OpVariable %15 Function
2181 OpBranch %19
2182 %19 = OpLabel
2183 OpBranch %24
2184 %24 = OpLabel
2185 %25 = OpSLessThan %10 %8 %9
2186 OpBranch %26
2187 %26 = OpLabel
2188 %27 = OpConvertSToF %11 %8
2189 %28 = OpAccessChain %16 %3 %8
2190 OpStore %28 %27
2191 OpBranch %22
2192 %22 = OpLabel
2193 %21 = OpIAdd %6 %8 %17
2194 OpBranch %29
2195 %29 = OpLabel
2196 OpBranch %31
2197 %31 = OpLabel
2198 %32 = OpSLessThan %10 %21 %9
2199 OpBranch %33
2200 %33 = OpLabel
2201 %34 = OpConvertSToF %11 %21
2202 %35 = OpAccessChain %16 %3 %21
2203 OpStore %35 %34
2204 OpBranch %36
2205 %36 = OpLabel
2206 %37 = OpIAdd %6 %21 %17
2207 OpBranch %38
2208 %38 = OpLabel
2209 OpBranch %40
2210 %40 = OpLabel
2211 %41 = OpSLessThan %10 %37 %9
2212 OpBranch %42
2213 %42 = OpLabel
2214 %43 = OpConvertSToF %11 %37
2215 %44 = OpAccessChain %16 %3 %37
2216 OpStore %44 %43
2217 OpBranch %45
2218 %45 = OpLabel
2219 %46 = OpIAdd %6 %37 %17
2220 OpBranch %23
2221 %23 = OpLabel
2222 OpReturn
2223 OpFunctionEnd
2224 )";
2225
2226 std::unique_ptr<IRContext> context =
2227 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
2228 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2229 Module* module = context->module();
2230 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2231 << text << std::endl;
2232
2233 LoopUnroller loop_unroller;
2234 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2235 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
2236 }
2237
2238 /*
2239 Generated from the following GLSL
2240 #version 410 core
2241 void main() {
2242 float out_array[4];
2243 for (int i = 11; i > 0; i-=3) {
2244 out_array[i] = i;
2245 }
2246 }
2247 */
TEST_F(PassClassTest,FullyUnrollNegativeNonDivisibleStepLoop)2248 TEST_F(PassClassTest, FullyUnrollNegativeNonDivisibleStepLoop) {
2249 // With LocalMultiStoreElimPass
2250 const std::string text = R"(OpCapability Shader
2251 %1 = OpExtInstImport "GLSL.std.450"
2252 OpMemoryModel Logical GLSL450
2253 OpEntryPoint Fragment %4 "main"
2254 OpExecutionMode %4 OriginUpperLeft
2255 OpSource GLSL 410
2256 OpName %4 "main"
2257 OpName %24 "out_array"
2258 %2 = OpTypeVoid
2259 %3 = OpTypeFunction %2
2260 %6 = OpTypeInt 32 1
2261 %7 = OpTypePointer Function %6
2262 %9 = OpConstant %6 11
2263 %16 = OpConstant %6 0
2264 %17 = OpTypeBool
2265 %19 = OpTypeFloat 32
2266 %20 = OpTypeInt 32 0
2267 %21 = OpConstant %20 4
2268 %22 = OpTypeArray %19 %21
2269 %23 = OpTypePointer Function %22
2270 %28 = OpTypePointer Function %19
2271 %30 = OpConstant %6 3
2272 %4 = OpFunction %2 None %3
2273 %5 = OpLabel
2274 %24 = OpVariable %23 Function
2275 OpBranch %10
2276 %10 = OpLabel
2277 %33 = OpPhi %6 %9 %5 %32 %13
2278 OpLoopMerge %12 %13 Unroll
2279 OpBranch %14
2280 %14 = OpLabel
2281 %18 = OpSGreaterThan %17 %33 %16
2282 OpBranchConditional %18 %11 %12
2283 %11 = OpLabel
2284 %27 = OpConvertSToF %19 %33
2285 %29 = OpAccessChain %28 %24 %33
2286 OpStore %29 %27
2287 OpBranch %13
2288 %13 = OpLabel
2289 %32 = OpISub %6 %33 %30
2290 OpBranch %10
2291 %12 = OpLabel
2292 OpReturn
2293 OpFunctionEnd
2294 )";
2295
2296 const std::string output = R"(OpCapability Shader
2297 %1 = OpExtInstImport "GLSL.std.450"
2298 OpMemoryModel Logical GLSL450
2299 OpEntryPoint Fragment %2 "main"
2300 OpExecutionMode %2 OriginUpperLeft
2301 OpSource GLSL 410
2302 OpName %2 "main"
2303 OpName %3 "out_array"
2304 %4 = OpTypeVoid
2305 %5 = OpTypeFunction %4
2306 %6 = OpTypeInt 32 1
2307 %7 = OpTypePointer Function %6
2308 %8 = OpConstant %6 11
2309 %9 = OpConstant %6 0
2310 %10 = OpTypeBool
2311 %11 = OpTypeFloat 32
2312 %12 = OpTypeInt 32 0
2313 %13 = OpConstant %12 4
2314 %14 = OpTypeArray %11 %13
2315 %15 = OpTypePointer Function %14
2316 %16 = OpTypePointer Function %11
2317 %17 = OpConstant %6 3
2318 %2 = OpFunction %4 None %5
2319 %18 = OpLabel
2320 %3 = OpVariable %15 Function
2321 OpBranch %19
2322 %19 = OpLabel
2323 OpBranch %24
2324 %24 = OpLabel
2325 %25 = OpSGreaterThan %10 %8 %9
2326 OpBranch %26
2327 %26 = OpLabel
2328 %27 = OpConvertSToF %11 %8
2329 %28 = OpAccessChain %16 %3 %8
2330 OpStore %28 %27
2331 OpBranch %22
2332 %22 = OpLabel
2333 %21 = OpISub %6 %8 %17
2334 OpBranch %29
2335 %29 = OpLabel
2336 OpBranch %31
2337 %31 = OpLabel
2338 %32 = OpSGreaterThan %10 %21 %9
2339 OpBranch %33
2340 %33 = OpLabel
2341 %34 = OpConvertSToF %11 %21
2342 %35 = OpAccessChain %16 %3 %21
2343 OpStore %35 %34
2344 OpBranch %36
2345 %36 = OpLabel
2346 %37 = OpISub %6 %21 %17
2347 OpBranch %38
2348 %38 = OpLabel
2349 OpBranch %40
2350 %40 = OpLabel
2351 %41 = OpSGreaterThan %10 %37 %9
2352 OpBranch %42
2353 %42 = OpLabel
2354 %43 = OpConvertSToF %11 %37
2355 %44 = OpAccessChain %16 %3 %37
2356 OpStore %44 %43
2357 OpBranch %45
2358 %45 = OpLabel
2359 %46 = OpISub %6 %37 %17
2360 OpBranch %47
2361 %47 = OpLabel
2362 OpBranch %49
2363 %49 = OpLabel
2364 %50 = OpSGreaterThan %10 %46 %9
2365 OpBranch %51
2366 %51 = OpLabel
2367 %52 = OpConvertSToF %11 %46
2368 %53 = OpAccessChain %16 %3 %46
2369 OpStore %53 %52
2370 OpBranch %54
2371 %54 = OpLabel
2372 %55 = OpISub %6 %46 %17
2373 OpBranch %23
2374 %23 = OpLabel
2375 OpReturn
2376 OpFunctionEnd
2377 )";
2378
2379 std::unique_ptr<IRContext> context =
2380 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
2381 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2382 Module* module = context->module();
2383 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2384 << text << std::endl;
2385
2386 LoopUnroller loop_unroller;
2387 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2388 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
2389 }
2390
2391 // With LocalMultiStoreElimPass
2392 static const std::string multiple_phi_shader = R"(
2393 OpCapability Shader
2394 %1 = OpExtInstImport "GLSL.std.450"
2395 OpMemoryModel Logical GLSL450
2396 OpEntryPoint Fragment %4 "main"
2397 OpExecutionMode %4 OriginUpperLeft
2398 OpSource GLSL 410
2399 OpName %4 "main"
2400 OpName %8 "foo("
2401 %2 = OpTypeVoid
2402 %3 = OpTypeFunction %2
2403 %6 = OpTypeInt 32 1
2404 %7 = OpTypeFunction %6
2405 %10 = OpTypePointer Function %6
2406 %12 = OpConstant %6 0
2407 %14 = OpConstant %6 3
2408 %22 = OpConstant %6 6
2409 %23 = OpTypeBool
2410 %31 = OpConstant %6 1
2411 %4 = OpFunction %2 None %3
2412 %5 = OpLabel
2413 %40 = OpFunctionCall %6 %8
2414 OpReturn
2415 OpFunctionEnd
2416 %8 = OpFunction %6 None %7
2417 %9 = OpLabel
2418 OpBranch %16
2419 %16 = OpLabel
2420 %41 = OpPhi %6 %12 %9 %34 %19
2421 %42 = OpPhi %6 %14 %9 %29 %19
2422 %43 = OpPhi %6 %12 %9 %32 %19
2423 OpLoopMerge %18 %19 Unroll
2424 OpBranch %20
2425 %20 = OpLabel
2426 %24 = OpSLessThan %23 %43 %22
2427 OpBranchConditional %24 %17 %18
2428 %17 = OpLabel
2429 %27 = OpIMul %6 %43 %41
2430 %29 = OpIAdd %6 %42 %27
2431 OpBranch %19
2432 %19 = OpLabel
2433 %32 = OpIAdd %6 %43 %31
2434 %34 = OpISub %6 %41 %31
2435 OpBranch %16
2436 %18 = OpLabel
2437 %37 = OpIAdd %6 %42 %41
2438 OpReturnValue %37
2439 OpFunctionEnd
2440 )";
2441
TEST_F(PassClassTest,PartiallyUnrollResidualMultipleInductionVariables)2442 TEST_F(PassClassTest, PartiallyUnrollResidualMultipleInductionVariables) {
2443 const std::string output = R"(OpCapability Shader
2444 %1 = OpExtInstImport "GLSL.std.450"
2445 OpMemoryModel Logical GLSL450
2446 OpEntryPoint Fragment %2 "main"
2447 OpExecutionMode %2 OriginUpperLeft
2448 OpSource GLSL 410
2449 OpName %2 "main"
2450 OpName %3 "foo("
2451 %4 = OpTypeVoid
2452 %5 = OpTypeFunction %4
2453 %6 = OpTypeInt 32 1
2454 %7 = OpTypeFunction %6
2455 %8 = OpTypePointer Function %6
2456 %9 = OpConstant %6 0
2457 %10 = OpConstant %6 3
2458 %11 = OpConstant %6 6
2459 %12 = OpTypeBool
2460 %13 = OpConstant %6 1
2461 %82 = OpTypeInt 32 0
2462 %83 = OpConstant %82 2
2463 %2 = OpFunction %4 None %5
2464 %14 = OpLabel
2465 %15 = OpFunctionCall %6 %3
2466 OpReturn
2467 OpFunctionEnd
2468 %3 = OpFunction %6 None %7
2469 %16 = OpLabel
2470 OpBranch %17
2471 %17 = OpLabel
2472 %18 = OpPhi %6 %9 %16 %19 %20
2473 %21 = OpPhi %6 %10 %16 %22 %20
2474 %23 = OpPhi %6 %9 %16 %24 %20
2475 OpLoopMerge %31 %20 Unroll
2476 OpBranch %26
2477 %26 = OpLabel
2478 %27 = OpSLessThan %12 %23 %83
2479 OpBranchConditional %27 %28 %31
2480 %28 = OpLabel
2481 %29 = OpIMul %6 %23 %18
2482 %22 = OpIAdd %6 %21 %29
2483 OpBranch %20
2484 %20 = OpLabel
2485 %24 = OpIAdd %6 %23 %13
2486 %19 = OpISub %6 %18 %13
2487 OpBranch %17
2488 %31 = OpLabel
2489 OpBranch %32
2490 %32 = OpLabel
2491 %33 = OpPhi %6 %18 %31 %81 %79
2492 %34 = OpPhi %6 %21 %31 %78 %79
2493 %35 = OpPhi %6 %23 %31 %80 %79
2494 OpLoopMerge %44 %79 DontUnroll
2495 OpBranch %36
2496 %36 = OpLabel
2497 %37 = OpSLessThan %12 %35 %11
2498 OpBranchConditional %37 %38 %44
2499 %38 = OpLabel
2500 %39 = OpIMul %6 %35 %33
2501 %40 = OpIAdd %6 %34 %39
2502 OpBranch %41
2503 %41 = OpLabel
2504 %42 = OpIAdd %6 %35 %13
2505 %43 = OpISub %6 %33 %13
2506 OpBranch %46
2507 %46 = OpLabel
2508 OpBranch %50
2509 %50 = OpLabel
2510 %51 = OpSLessThan %12 %42 %11
2511 OpBranch %52
2512 %52 = OpLabel
2513 %53 = OpIMul %6 %42 %43
2514 %54 = OpIAdd %6 %40 %53
2515 OpBranch %55
2516 %55 = OpLabel
2517 %56 = OpIAdd %6 %42 %13
2518 %57 = OpISub %6 %43 %13
2519 OpBranch %58
2520 %58 = OpLabel
2521 OpBranch %62
2522 %62 = OpLabel
2523 %63 = OpSLessThan %12 %56 %11
2524 OpBranch %64
2525 %64 = OpLabel
2526 %65 = OpIMul %6 %56 %57
2527 %66 = OpIAdd %6 %54 %65
2528 OpBranch %67
2529 %67 = OpLabel
2530 %68 = OpIAdd %6 %56 %13
2531 %69 = OpISub %6 %57 %13
2532 OpBranch %70
2533 %70 = OpLabel
2534 OpBranch %74
2535 %74 = OpLabel
2536 %75 = OpSLessThan %12 %68 %11
2537 OpBranch %76
2538 %76 = OpLabel
2539 %77 = OpIMul %6 %68 %69
2540 %78 = OpIAdd %6 %66 %77
2541 OpBranch %79
2542 %79 = OpLabel
2543 %80 = OpIAdd %6 %68 %13
2544 %81 = OpISub %6 %69 %13
2545 OpBranch %32
2546 %44 = OpLabel
2547 %45 = OpIAdd %6 %34 %33
2548 OpReturnValue %45
2549 %25 = OpLabel
2550 %30 = OpIAdd %6 %34 %33
2551 OpReturnValue %30
2552 OpFunctionEnd
2553 )";
2554
2555 std::unique_ptr<IRContext> context =
2556 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, multiple_phi_shader,
2557 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2558 Module* module = context->module();
2559 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2560 << multiple_phi_shader << std::endl;
2561
2562 LoopUnroller loop_unroller;
2563 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2564 SinglePassRunAndCheck<PartialUnrollerTestPass<4>>(multiple_phi_shader, output,
2565 false);
2566 }
2567
TEST_F(PassClassTest,PartiallyUnrollMultipleInductionVariables)2568 TEST_F(PassClassTest, PartiallyUnrollMultipleInductionVariables) {
2569 const std::string output = R"(OpCapability Shader
2570 %1 = OpExtInstImport "GLSL.std.450"
2571 OpMemoryModel Logical GLSL450
2572 OpEntryPoint Fragment %2 "main"
2573 OpExecutionMode %2 OriginUpperLeft
2574 OpSource GLSL 410
2575 OpName %2 "main"
2576 OpName %3 "foo("
2577 %4 = OpTypeVoid
2578 %5 = OpTypeFunction %4
2579 %6 = OpTypeInt 32 1
2580 %7 = OpTypeFunction %6
2581 %8 = OpTypePointer Function %6
2582 %9 = OpConstant %6 0
2583 %10 = OpConstant %6 3
2584 %11 = OpConstant %6 6
2585 %12 = OpTypeBool
2586 %13 = OpConstant %6 1
2587 %2 = OpFunction %4 None %5
2588 %14 = OpLabel
2589 %15 = OpFunctionCall %6 %3
2590 OpReturn
2591 OpFunctionEnd
2592 %3 = OpFunction %6 None %7
2593 %16 = OpLabel
2594 OpBranch %17
2595 %17 = OpLabel
2596 %18 = OpPhi %6 %9 %16 %42 %40
2597 %21 = OpPhi %6 %10 %16 %39 %40
2598 %23 = OpPhi %6 %9 %16 %41 %40
2599 OpLoopMerge %25 %40 DontUnroll
2600 OpBranch %26
2601 %26 = OpLabel
2602 %27 = OpSLessThan %12 %23 %11
2603 OpBranchConditional %27 %28 %25
2604 %28 = OpLabel
2605 %29 = OpIMul %6 %23 %18
2606 %22 = OpIAdd %6 %21 %29
2607 OpBranch %20
2608 %20 = OpLabel
2609 %24 = OpIAdd %6 %23 %13
2610 %19 = OpISub %6 %18 %13
2611 OpBranch %31
2612 %31 = OpLabel
2613 OpBranch %35
2614 %35 = OpLabel
2615 %36 = OpSLessThan %12 %24 %11
2616 OpBranch %37
2617 %37 = OpLabel
2618 %38 = OpIMul %6 %24 %19
2619 %39 = OpIAdd %6 %22 %38
2620 OpBranch %40
2621 %40 = OpLabel
2622 %41 = OpIAdd %6 %24 %13
2623 %42 = OpISub %6 %19 %13
2624 OpBranch %17
2625 %25 = OpLabel
2626 %30 = OpIAdd %6 %21 %18
2627 OpReturnValue %30
2628 OpFunctionEnd
2629 )";
2630
2631 std::unique_ptr<IRContext> context =
2632 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, multiple_phi_shader,
2633 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2634 Module* module = context->module();
2635 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2636 << multiple_phi_shader << std::endl;
2637
2638 LoopUnroller loop_unroller;
2639 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2640 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(multiple_phi_shader, output,
2641 false);
2642 }
2643
TEST_F(PassClassTest,FullyUnrollMultipleInductionVariables)2644 TEST_F(PassClassTest, FullyUnrollMultipleInductionVariables) {
2645 const std::string output = R"(OpCapability Shader
2646 %1 = OpExtInstImport "GLSL.std.450"
2647 OpMemoryModel Logical GLSL450
2648 OpEntryPoint Fragment %2 "main"
2649 OpExecutionMode %2 OriginUpperLeft
2650 OpSource GLSL 410
2651 OpName %2 "main"
2652 OpName %3 "foo("
2653 %4 = OpTypeVoid
2654 %5 = OpTypeFunction %4
2655 %6 = OpTypeInt 32 1
2656 %7 = OpTypeFunction %6
2657 %8 = OpTypePointer Function %6
2658 %9 = OpConstant %6 0
2659 %10 = OpConstant %6 3
2660 %11 = OpConstant %6 6
2661 %12 = OpTypeBool
2662 %13 = OpConstant %6 1
2663 %2 = OpFunction %4 None %5
2664 %14 = OpLabel
2665 %15 = OpFunctionCall %6 %3
2666 OpReturn
2667 OpFunctionEnd
2668 %3 = OpFunction %6 None %7
2669 %16 = OpLabel
2670 OpBranch %17
2671 %17 = OpLabel
2672 OpBranch %26
2673 %26 = OpLabel
2674 %27 = OpSLessThan %12 %9 %11
2675 OpBranch %28
2676 %28 = OpLabel
2677 %29 = OpIMul %6 %9 %9
2678 %22 = OpIAdd %6 %10 %29
2679 OpBranch %20
2680 %20 = OpLabel
2681 %24 = OpIAdd %6 %9 %13
2682 %19 = OpISub %6 %9 %13
2683 OpBranch %31
2684 %31 = OpLabel
2685 OpBranch %35
2686 %35 = OpLabel
2687 %36 = OpSLessThan %12 %24 %11
2688 OpBranch %37
2689 %37 = OpLabel
2690 %38 = OpIMul %6 %24 %19
2691 %39 = OpIAdd %6 %22 %38
2692 OpBranch %40
2693 %40 = OpLabel
2694 %41 = OpIAdd %6 %24 %13
2695 %42 = OpISub %6 %19 %13
2696 OpBranch %43
2697 %43 = OpLabel
2698 OpBranch %47
2699 %47 = OpLabel
2700 %48 = OpSLessThan %12 %41 %11
2701 OpBranch %49
2702 %49 = OpLabel
2703 %50 = OpIMul %6 %41 %42
2704 %51 = OpIAdd %6 %39 %50
2705 OpBranch %52
2706 %52 = OpLabel
2707 %53 = OpIAdd %6 %41 %13
2708 %54 = OpISub %6 %42 %13
2709 OpBranch %55
2710 %55 = OpLabel
2711 OpBranch %59
2712 %59 = OpLabel
2713 %60 = OpSLessThan %12 %53 %11
2714 OpBranch %61
2715 %61 = OpLabel
2716 %62 = OpIMul %6 %53 %54
2717 %63 = OpIAdd %6 %51 %62
2718 OpBranch %64
2719 %64 = OpLabel
2720 %65 = OpIAdd %6 %53 %13
2721 %66 = OpISub %6 %54 %13
2722 OpBranch %67
2723 %67 = OpLabel
2724 OpBranch %71
2725 %71 = OpLabel
2726 %72 = OpSLessThan %12 %65 %11
2727 OpBranch %73
2728 %73 = OpLabel
2729 %74 = OpIMul %6 %65 %66
2730 %75 = OpIAdd %6 %63 %74
2731 OpBranch %76
2732 %76 = OpLabel
2733 %77 = OpIAdd %6 %65 %13
2734 %78 = OpISub %6 %66 %13
2735 OpBranch %79
2736 %79 = OpLabel
2737 OpBranch %83
2738 %83 = OpLabel
2739 %84 = OpSLessThan %12 %77 %11
2740 OpBranch %85
2741 %85 = OpLabel
2742 %86 = OpIMul %6 %77 %78
2743 %87 = OpIAdd %6 %75 %86
2744 OpBranch %88
2745 %88 = OpLabel
2746 %89 = OpIAdd %6 %77 %13
2747 %90 = OpISub %6 %78 %13
2748 OpBranch %25
2749 %25 = OpLabel
2750 %30 = OpIAdd %6 %87 %90
2751 OpReturnValue %30
2752 OpFunctionEnd
2753 )";
2754
2755 std::unique_ptr<IRContext> context =
2756 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, multiple_phi_shader,
2757 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2758 Module* module = context->module();
2759 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2760 << multiple_phi_shader << std::endl;
2761
2762 LoopUnroller loop_unroller;
2763 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2764 SinglePassRunAndCheck<LoopUnroller>(multiple_phi_shader, output, false);
2765 }
2766
2767 /*
2768 Generated from the following GLSL
2769 #version 440 core
2770 void main()
2771 {
2772 int j = 0;
2773 for (int i = 0; i <= 2; ++i)
2774 ++j;
2775
2776 for (int i = 1; i >= 0; --i)
2777 ++j;
2778 }
2779 */
TEST_F(PassClassTest,FullyUnrollEqualToOperations)2780 TEST_F(PassClassTest, FullyUnrollEqualToOperations) {
2781 // With LocalMultiStoreElimPass
2782 const std::string text = R"(
2783 OpCapability Shader
2784 %1 = OpExtInstImport "GLSL.std.450"
2785 OpMemoryModel Logical GLSL450
2786 OpEntryPoint Fragment %4 "main"
2787 OpExecutionMode %4 OriginUpperLeft
2788 OpSource GLSL 440
2789 OpName %4 "main"
2790 %2 = OpTypeVoid
2791 %3 = OpTypeFunction %2
2792 %6 = OpTypeInt 32 1
2793 %7 = OpTypePointer Function %6
2794 %9 = OpConstant %6 0
2795 %17 = OpConstant %6 2
2796 %18 = OpTypeBool
2797 %21 = OpConstant %6 1
2798 %4 = OpFunction %2 None %3
2799 %5 = OpLabel
2800 OpBranch %11
2801 %11 = OpLabel
2802 %37 = OpPhi %6 %9 %5 %22 %14
2803 %38 = OpPhi %6 %9 %5 %24 %14
2804 OpLoopMerge %13 %14 Unroll
2805 OpBranch %15
2806 %15 = OpLabel
2807 %19 = OpSLessThanEqual %18 %38 %17
2808 OpBranchConditional %19 %12 %13
2809 %12 = OpLabel
2810 %22 = OpIAdd %6 %37 %21
2811 OpBranch %14
2812 %14 = OpLabel
2813 %24 = OpIAdd %6 %38 %21
2814 OpBranch %11
2815 %13 = OpLabel
2816 OpBranch %26
2817 %26 = OpLabel
2818 %39 = OpPhi %6 %37 %13 %34 %29
2819 %40 = OpPhi %6 %21 %13 %36 %29
2820 OpLoopMerge %28 %29 Unroll
2821 OpBranch %30
2822 %30 = OpLabel
2823 %32 = OpSGreaterThanEqual %18 %40 %9
2824 OpBranchConditional %32 %27 %28
2825 %27 = OpLabel
2826 %34 = OpIAdd %6 %39 %21
2827 OpBranch %29
2828 %29 = OpLabel
2829 %36 = OpISub %6 %40 %21
2830 OpBranch %26
2831 %28 = OpLabel
2832 OpReturn
2833 OpFunctionEnd
2834 )";
2835
2836 const std::string output = R"(OpCapability Shader
2837 %1 = OpExtInstImport "GLSL.std.450"
2838 OpMemoryModel Logical GLSL450
2839 OpEntryPoint Fragment %2 "main"
2840 OpExecutionMode %2 OriginUpperLeft
2841 OpSource GLSL 440
2842 OpName %2 "main"
2843 %3 = OpTypeVoid
2844 %4 = OpTypeFunction %3
2845 %5 = OpTypeInt 32 1
2846 %6 = OpTypePointer Function %5
2847 %7 = OpConstant %5 0
2848 %8 = OpConstant %5 2
2849 %9 = OpTypeBool
2850 %10 = OpConstant %5 1
2851 %2 = OpFunction %3 None %4
2852 %11 = OpLabel
2853 OpBranch %12
2854 %12 = OpLabel
2855 OpBranch %19
2856 %19 = OpLabel
2857 %20 = OpSLessThanEqual %9 %7 %8
2858 OpBranch %21
2859 %21 = OpLabel
2860 %14 = OpIAdd %5 %7 %10
2861 OpBranch %15
2862 %15 = OpLabel
2863 %17 = OpIAdd %5 %7 %10
2864 OpBranch %41
2865 %41 = OpLabel
2866 OpBranch %44
2867 %44 = OpLabel
2868 %45 = OpSLessThanEqual %9 %17 %8
2869 OpBranch %46
2870 %46 = OpLabel
2871 %47 = OpIAdd %5 %14 %10
2872 OpBranch %48
2873 %48 = OpLabel
2874 %49 = OpIAdd %5 %17 %10
2875 OpBranch %50
2876 %50 = OpLabel
2877 OpBranch %53
2878 %53 = OpLabel
2879 %54 = OpSLessThanEqual %9 %49 %8
2880 OpBranch %55
2881 %55 = OpLabel
2882 %56 = OpIAdd %5 %47 %10
2883 OpBranch %57
2884 %57 = OpLabel
2885 %58 = OpIAdd %5 %49 %10
2886 OpBranch %18
2887 %18 = OpLabel
2888 OpBranch %22
2889 %22 = OpLabel
2890 OpBranch %29
2891 %29 = OpLabel
2892 %30 = OpSGreaterThanEqual %9 %10 %7
2893 OpBranch %31
2894 %31 = OpLabel
2895 %24 = OpIAdd %5 %56 %10
2896 OpBranch %25
2897 %25 = OpLabel
2898 %27 = OpISub %5 %10 %10
2899 OpBranch %32
2900 %32 = OpLabel
2901 OpBranch %35
2902 %35 = OpLabel
2903 %36 = OpSGreaterThanEqual %9 %27 %7
2904 OpBranch %37
2905 %37 = OpLabel
2906 %38 = OpIAdd %5 %24 %10
2907 OpBranch %39
2908 %39 = OpLabel
2909 %40 = OpISub %5 %27 %10
2910 OpBranch %28
2911 %28 = OpLabel
2912 OpReturn
2913 OpFunctionEnd
2914 )";
2915
2916 std::unique_ptr<IRContext> context =
2917 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
2918 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2919 Module* module = context->module();
2920 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
2921 << text << std::endl;
2922
2923 LoopUnroller loop_unroller;
2924 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
2925 SinglePassRunAndCheck<LoopUnroller>(text, output, false);
2926 }
2927
2928 // With LocalMultiStoreElimPass
2929 const std::string condition_in_header = R"(
2930 OpCapability Shader
2931 OpMemoryModel Logical GLSL450
2932 OpEntryPoint Fragment %main "main" %o
2933 OpExecutionMode %main OriginUpperLeft
2934 OpSource GLSL 430
2935 OpDecorate %o Location 0
2936 %void = OpTypeVoid
2937 %6 = OpTypeFunction %void
2938 %int = OpTypeInt 32 1
2939 %int_n2 = OpConstant %int -2
2940 %int_2 = OpConstant %int 2
2941 %bool = OpTypeBool
2942 %float = OpTypeFloat 32
2943 %_ptr_Output_float = OpTypePointer Output %float
2944 %o = OpVariable %_ptr_Output_float Output
2945 %float_1 = OpConstant %float 1
2946 %main = OpFunction %void None %6
2947 %15 = OpLabel
2948 OpBranch %16
2949 %16 = OpLabel
2950 %27 = OpPhi %int %int_n2 %15 %26 %18
2951 %21 = OpSLessThanEqual %bool %27 %int_2
2952 OpLoopMerge %17 %18 Unroll
2953 OpBranchConditional %21 %22 %17
2954 %22 = OpLabel
2955 %23 = OpLoad %float %o
2956 %24 = OpFAdd %float %23 %float_1
2957 OpStore %o %24
2958 OpBranch %18
2959 %18 = OpLabel
2960 %26 = OpIAdd %int %27 %int_2
2961 OpBranch %16
2962 %17 = OpLabel
2963 OpReturn
2964 OpFunctionEnd
2965 )";
2966
TEST_F(PassClassTest,FullyUnrollConditionIsInHeaderBlock)2967 TEST_F(PassClassTest, FullyUnrollConditionIsInHeaderBlock) {
2968 const std::string output = R"(OpCapability Shader
2969 OpMemoryModel Logical GLSL450
2970 OpEntryPoint Fragment %1 "main" %2
2971 OpExecutionMode %1 OriginUpperLeft
2972 OpSource GLSL 430
2973 OpDecorate %2 Location 0
2974 %3 = OpTypeVoid
2975 %4 = OpTypeFunction %3
2976 %5 = OpTypeInt 32 1
2977 %6 = OpConstant %5 -2
2978 %7 = OpConstant %5 2
2979 %8 = OpTypeBool
2980 %9 = OpTypeFloat 32
2981 %10 = OpTypePointer Output %9
2982 %2 = OpVariable %10 Output
2983 %11 = OpConstant %9 1
2984 %1 = OpFunction %3 None %4
2985 %12 = OpLabel
2986 OpBranch %13
2987 %13 = OpLabel
2988 %17 = OpSLessThanEqual %8 %6 %7
2989 OpBranch %19
2990 %19 = OpLabel
2991 %20 = OpLoad %9 %2
2992 %21 = OpFAdd %9 %20 %11
2993 OpStore %2 %21
2994 OpBranch %16
2995 %16 = OpLabel
2996 %15 = OpIAdd %5 %6 %7
2997 OpBranch %22
2998 %22 = OpLabel
2999 %24 = OpSLessThanEqual %8 %15 %7
3000 OpBranch %25
3001 %25 = OpLabel
3002 %26 = OpLoad %9 %2
3003 %27 = OpFAdd %9 %26 %11
3004 OpStore %2 %27
3005 OpBranch %28
3006 %28 = OpLabel
3007 %29 = OpIAdd %5 %15 %7
3008 OpBranch %30
3009 %30 = OpLabel
3010 %32 = OpSLessThanEqual %8 %29 %7
3011 OpBranch %33
3012 %33 = OpLabel
3013 %34 = OpLoad %9 %2
3014 %35 = OpFAdd %9 %34 %11
3015 OpStore %2 %35
3016 OpBranch %36
3017 %36 = OpLabel
3018 %37 = OpIAdd %5 %29 %7
3019 OpBranch %18
3020 %18 = OpLabel
3021 OpReturn
3022 OpFunctionEnd
3023 )";
3024
3025 std::unique_ptr<IRContext> context =
3026 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, condition_in_header,
3027 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3028 Module* module = context->module();
3029 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
3030 << condition_in_header << std::endl;
3031
3032 LoopUnroller loop_unroller;
3033 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3034 SinglePassRunAndCheck<LoopUnroller>(condition_in_header, output, false);
3035 }
3036
TEST_F(PassClassTest,PartiallyUnrollResidualConditionIsInHeaderBlock)3037 TEST_F(PassClassTest, PartiallyUnrollResidualConditionIsInHeaderBlock) {
3038 const std::string output = R"(OpCapability Shader
3039 OpMemoryModel Logical GLSL450
3040 OpEntryPoint Fragment %1 "main" %2
3041 OpExecutionMode %1 OriginUpperLeft
3042 OpSource GLSL 430
3043 OpDecorate %2 Location 0
3044 %3 = OpTypeVoid
3045 %4 = OpTypeFunction %3
3046 %5 = OpTypeInt 32 1
3047 %6 = OpConstant %5 -2
3048 %7 = OpConstant %5 2
3049 %8 = OpTypeBool
3050 %9 = OpTypeFloat 32
3051 %10 = OpTypePointer Output %9
3052 %2 = OpVariable %10 Output
3053 %11 = OpConstant %9 1
3054 %40 = OpTypeInt 32 0
3055 %41 = OpConstant %40 1
3056 %1 = OpFunction %3 None %4
3057 %12 = OpLabel
3058 OpBranch %13
3059 %13 = OpLabel
3060 %14 = OpPhi %5 %6 %12 %15 %16
3061 %17 = OpSLessThanEqual %8 %14 %41
3062 OpLoopMerge %22 %16 Unroll
3063 OpBranchConditional %17 %19 %22
3064 %19 = OpLabel
3065 %20 = OpLoad %9 %2
3066 %21 = OpFAdd %9 %20 %11
3067 OpStore %2 %21
3068 OpBranch %16
3069 %16 = OpLabel
3070 %15 = OpIAdd %5 %14 %7
3071 OpBranch %13
3072 %22 = OpLabel
3073 OpBranch %23
3074 %23 = OpLabel
3075 %24 = OpPhi %5 %14 %22 %39 %38
3076 %25 = OpSLessThanEqual %8 %24 %7
3077 OpLoopMerge %31 %38 DontUnroll
3078 OpBranchConditional %25 %26 %31
3079 %26 = OpLabel
3080 %27 = OpLoad %9 %2
3081 %28 = OpFAdd %9 %27 %11
3082 OpStore %2 %28
3083 OpBranch %29
3084 %29 = OpLabel
3085 %30 = OpIAdd %5 %24 %7
3086 OpBranch %32
3087 %32 = OpLabel
3088 %34 = OpSLessThanEqual %8 %30 %7
3089 OpBranch %35
3090 %35 = OpLabel
3091 %36 = OpLoad %9 %2
3092 %37 = OpFAdd %9 %36 %11
3093 OpStore %2 %37
3094 OpBranch %38
3095 %38 = OpLabel
3096 %39 = OpIAdd %5 %30 %7
3097 OpBranch %23
3098 %31 = OpLabel
3099 OpReturn
3100 %18 = OpLabel
3101 OpReturn
3102 OpFunctionEnd
3103 )";
3104
3105 std::unique_ptr<IRContext> context =
3106 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, condition_in_header,
3107 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3108 Module* module = context->module();
3109 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
3110 << condition_in_header << std::endl;
3111
3112 LoopUnroller loop_unroller;
3113 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3114 SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(condition_in_header, output,
3115 false);
3116 }
3117
3118 /*
3119 Generated from following GLSL with latch block artificially inserted to be
3120 separate from continue.
3121 #version 430
3122 void main(void) {
3123 float x[10];
3124 for (int i = 0; i < 10; ++i) {
3125 x[i] = i;
3126 }
3127 }
3128 */
TEST_F(PassClassTest,PartiallyUnrollLatchNotContinue)3129 TEST_F(PassClassTest, PartiallyUnrollLatchNotContinue) {
3130 const std::string text = R"(OpCapability Shader
3131 %1 = OpExtInstImport "GLSL.std.450"
3132 OpMemoryModel Logical GLSL450
3133 OpEntryPoint Fragment %2 "main"
3134 OpExecutionMode %2 OriginUpperLeft
3135 OpSource GLSL 430
3136 OpName %2 "main"
3137 OpName %3 "i"
3138 OpName %4 "x"
3139 %5 = OpTypeVoid
3140 %6 = OpTypeFunction %5
3141 %7 = OpTypeInt 32 1
3142 %8 = OpTypePointer Function %7
3143 %9 = OpConstant %7 0
3144 %10 = OpConstant %7 10
3145 %11 = OpTypeBool
3146 %12 = OpTypeFloat 32
3147 %13 = OpTypeInt 32 0
3148 %14 = OpConstant %13 10
3149 %15 = OpTypeArray %12 %14
3150 %16 = OpTypePointer Function %15
3151 %17 = OpTypePointer Function %12
3152 %18 = OpConstant %7 1
3153 %2 = OpFunction %5 None %6
3154 %19 = OpLabel
3155 %3 = OpVariable %8 Function
3156 %4 = OpVariable %16 Function
3157 OpStore %3 %9
3158 OpBranch %20
3159 %20 = OpLabel
3160 %21 = OpPhi %7 %9 %19 %22 %30
3161 OpLoopMerge %24 %23 Unroll
3162 OpBranch %25
3163 %25 = OpLabel
3164 %26 = OpSLessThan %11 %21 %10
3165 OpBranchConditional %26 %27 %24
3166 %27 = OpLabel
3167 %28 = OpConvertSToF %12 %21
3168 %29 = OpAccessChain %17 %4 %21
3169 OpStore %29 %28
3170 OpBranch %23
3171 %23 = OpLabel
3172 %22 = OpIAdd %7 %21 %18
3173 OpStore %3 %22
3174 OpBranch %30
3175 %30 = OpLabel
3176 OpBranch %20
3177 %24 = OpLabel
3178 OpReturn
3179 OpFunctionEnd
3180 )";
3181
3182 const std::string expected = R"(OpCapability Shader
3183 %1 = OpExtInstImport "GLSL.std.450"
3184 OpMemoryModel Logical GLSL450
3185 OpEntryPoint Fragment %2 "main"
3186 OpExecutionMode %2 OriginUpperLeft
3187 OpSource GLSL 430
3188 OpName %2 "main"
3189 OpName %3 "i"
3190 OpName %4 "x"
3191 %5 = OpTypeVoid
3192 %6 = OpTypeFunction %5
3193 %7 = OpTypeInt 32 1
3194 %8 = OpTypePointer Function %7
3195 %9 = OpConstant %7 0
3196 %10 = OpConstant %7 10
3197 %11 = OpTypeBool
3198 %12 = OpTypeFloat 32
3199 %13 = OpTypeInt 32 0
3200 %14 = OpConstant %13 10
3201 %15 = OpTypeArray %12 %14
3202 %16 = OpTypePointer Function %15
3203 %17 = OpTypePointer Function %12
3204 %18 = OpConstant %7 1
3205 %63 = OpConstant %13 1
3206 %2 = OpFunction %5 None %6
3207 %19 = OpLabel
3208 %3 = OpVariable %8 Function
3209 %4 = OpVariable %16 Function
3210 OpStore %3 %9
3211 OpBranch %20
3212 %20 = OpLabel
3213 %21 = OpPhi %7 %9 %19 %22 %23
3214 OpLoopMerge %31 %25 Unroll
3215 OpBranch %26
3216 %26 = OpLabel
3217 %27 = OpSLessThan %11 %21 %63
3218 OpBranchConditional %27 %28 %31
3219 %28 = OpLabel
3220 %29 = OpConvertSToF %12 %21
3221 %30 = OpAccessChain %17 %4 %21
3222 OpStore %30 %29
3223 OpBranch %25
3224 %25 = OpLabel
3225 %22 = OpIAdd %7 %21 %18
3226 OpStore %3 %22
3227 OpBranch %23
3228 %23 = OpLabel
3229 OpBranch %20
3230 %31 = OpLabel
3231 OpBranch %32
3232 %32 = OpLabel
3233 %33 = OpPhi %7 %21 %31 %61 %62
3234 OpLoopMerge %42 %60 DontUnroll
3235 OpBranch %34
3236 %34 = OpLabel
3237 %35 = OpSLessThan %11 %33 %10
3238 OpBranchConditional %35 %36 %42
3239 %36 = OpLabel
3240 %37 = OpConvertSToF %12 %33
3241 %38 = OpAccessChain %17 %4 %33
3242 OpStore %38 %37
3243 OpBranch %39
3244 %39 = OpLabel
3245 %40 = OpIAdd %7 %33 %18
3246 OpStore %3 %40
3247 OpBranch %41
3248 %41 = OpLabel
3249 OpBranch %43
3250 %43 = OpLabel
3251 OpBranch %45
3252 %45 = OpLabel
3253 %46 = OpSLessThan %11 %40 %10
3254 OpBranch %47
3255 %47 = OpLabel
3256 %48 = OpConvertSToF %12 %40
3257 %49 = OpAccessChain %17 %4 %40
3258 OpStore %49 %48
3259 OpBranch %50
3260 %50 = OpLabel
3261 %51 = OpIAdd %7 %40 %18
3262 OpStore %3 %51
3263 OpBranch %52
3264 %52 = OpLabel
3265 OpBranch %53
3266 %53 = OpLabel
3267 OpBranch %55
3268 %55 = OpLabel
3269 %56 = OpSLessThan %11 %51 %10
3270 OpBranch %57
3271 %57 = OpLabel
3272 %58 = OpConvertSToF %12 %51
3273 %59 = OpAccessChain %17 %4 %51
3274 OpStore %59 %58
3275 OpBranch %60
3276 %60 = OpLabel
3277 %61 = OpIAdd %7 %51 %18
3278 OpStore %3 %61
3279 OpBranch %62
3280 %62 = OpLabel
3281 OpBranch %32
3282 %42 = OpLabel
3283 OpReturn
3284 %24 = OpLabel
3285 OpReturn
3286 OpFunctionEnd
3287 )";
3288
3289 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3290 SinglePassRunAndCheck<PartialUnrollerTestPass<3>>(text, expected, true);
3291
3292 // Make sure the latch block information is preserved and propagated correctly
3293 // by the pass.
3294 std::unique_ptr<IRContext> context =
3295 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
3296 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3297
3298 PartialUnrollerTestPass<3> unroller;
3299 unroller.SetContextForTesting(context.get());
3300 unroller.Process();
3301
3302 Module* module = context->module();
3303 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3304 << text << std::endl;
3305 const Function* f = spvtest::GetFunction(module, 2);
3306 LoopDescriptor ld{context.get(), f};
3307
3308 EXPECT_EQ(ld.NumLoops(), 2u);
3309
3310 Loop& loop_1 = ld.GetLoopByIndex(0u);
3311 EXPECT_NE(loop_1.GetLatchBlock(), loop_1.GetContinueBlock());
3312
3313 Loop& loop_2 = ld.GetLoopByIndex(1u);
3314 EXPECT_NE(loop_2.GetLatchBlock(), loop_2.GetContinueBlock());
3315 }
3316
3317 // Test that a loop with a self-referencing OpPhi instruction is handled
3318 // correctly.
TEST_F(PassClassTest,OpPhiSelfReference)3319 TEST_F(PassClassTest, OpPhiSelfReference) {
3320 const std::string text = R"(
3321 ; Find the two adds from the unrolled loop
3322 ; CHECK: OpIAdd
3323 ; CHECK: OpIAdd
3324 ; CHECK: OpIAdd %uint %uint_0 %uint_1
3325 ; CHECK-NEXT: OpReturn
3326 OpCapability Shader
3327 %1 = OpExtInstImport "GLSL.std.450"
3328 OpMemoryModel Logical GLSL450
3329 OpEntryPoint GLCompute %2 "main"
3330 OpExecutionMode %2 LocalSize 8 8 1
3331 OpSource HLSL 600
3332 %uint = OpTypeInt 32 0
3333 %void = OpTypeVoid
3334 %5 = OpTypeFunction %void
3335 %uint_0 = OpConstant %uint 0
3336 %uint_1 = OpConstant %uint 1
3337 %bool = OpTypeBool
3338 %true = OpConstantTrue %bool
3339 %2 = OpFunction %void None %5
3340 %10 = OpLabel
3341 OpBranch %19
3342 %19 = OpLabel
3343 %20 = OpPhi %uint %uint_0 %10 %20 %21
3344 %22 = OpPhi %uint %uint_0 %10 %23 %21
3345 %24 = OpULessThanEqual %bool %22 %uint_1
3346 OpLoopMerge %25 %21 Unroll
3347 OpBranchConditional %24 %21 %25
3348 %21 = OpLabel
3349 %23 = OpIAdd %uint %22 %uint_1
3350 OpBranch %19
3351 %25 = OpLabel
3352 %14 = OpIAdd %uint %20 %uint_1
3353 OpReturn
3354 OpFunctionEnd
3355 )";
3356
3357 const bool kFullyUnroll = true;
3358 const uint32_t kUnrollFactor = 0;
3359 SinglePassRunAndMatch<opt::LoopUnroller>(text, true, kFullyUnroll,
3360 kUnrollFactor);
3361 }
3362
3363 // Test that a loop containing an unreachable merge block can still be unrolled
3364 // correctly.
TEST_F(PassClassTest,UnreachableMerge)3365 TEST_F(PassClassTest, UnreachableMerge) {
3366 const std::string text = R"(
3367 ; Identify the first iteration of the unrolled loop, and make sure it contains
3368 ; the unreachable merge block.
3369 ; The first SelectionMerge corresponds to the original loop merge.
3370 ; The second is the branch in the loop.
3371 ; CHECK: OpSelectionMerge {{%\w+}} None
3372 ; CHECK: OpSelectionMerge [[unrch1:%\w+]] None
3373 ; CHECK: [[unrch1]] = OpLabel
3374 ; CHECK-NEXT: OpUnreachable
3375 ; Identify the second iteration of the unrolled loop, and make sure it contains
3376 ; the unreachable merge block.
3377 ; The first SelectionMerge corresponds to the original loop merge
3378 ; The second is the branch in the loop.
3379 ; CHECK: OpSelectionMerge {{%\w+}} None
3380 ; CHECK: OpSelectionMerge [[unrch2:%\w+]] None
3381 ; CHECK: [[unrch2]] = OpLabel
3382 ; CHECK-NEXT: OpUnreachable
3383
3384 OpCapability Shader
3385 OpMemoryModel Logical GLSL450
3386 OpEntryPoint GLCompute %main "main"
3387 OpExecutionMode %main LocalSize 64 1 1
3388 OpSource HLSL 600
3389 OpName %main "main"
3390 %uint = OpTypeInt 32 0
3391 %uint_0 = OpConstant %uint 0
3392 %uint_2 = OpConstant %uint 2
3393 %uint_1 = OpConstant %uint 1
3394 %bool = OpTypeBool
3395 %void = OpTypeVoid
3396 %18 = OpTypeFunction %void
3397 %main = OpFunction %void None %18
3398 %23 = OpLabel
3399 OpBranch %24
3400 %24 = OpLabel
3401 %28 = OpPhi %uint %uint_0 %23 %29 %27
3402 %30 = OpULessThan %bool %28 %uint_2
3403 OpLoopMerge %31 %27 Unroll
3404 OpBranchConditional %30 %32 %31
3405 %32 = OpLabel
3406 OpSelectionMerge %33 None
3407 OpSwitch %uint_0 %34
3408 %34 = OpLabel
3409 %35 = OpUndef %bool
3410 OpSelectionMerge %36 None
3411 OpBranchConditional %35 %37 %38
3412 %38 = OpLabel
3413 OpBranch %33
3414 %37 = OpLabel
3415 OpBranch %33
3416 %36 = OpLabel
3417 OpUnreachable
3418 %33 = OpLabel
3419 OpBranch %27
3420 %27 = OpLabel
3421 %29 = OpIAdd %uint %28 %uint_1
3422 OpBranch %24
3423 %31 = OpLabel
3424 OpReturn
3425 OpFunctionEnd
3426 )";
3427
3428 const bool kFullyUnroll = true;
3429 const uint32_t kUnrollFactor = 0;
3430 SinglePassRunAndMatch<opt::LoopUnroller>(text, true, kFullyUnroll,
3431 kUnrollFactor);
3432 }
3433
TEST_F(PassClassTest,InitValueIsConstantNull)3434 TEST_F(PassClassTest, InitValueIsConstantNull) {
3435 const std::string shader = R"(
3436 OpCapability Shader
3437 %1 = OpExtInstImport "GLSL.std.450"
3438 OpMemoryModel Logical GLSL450
3439 OpEntryPoint Fragment %4 "main"
3440 OpExecutionMode %4 OriginUpperLeft
3441 OpSource ESSL 320
3442 %2 = OpTypeVoid
3443 %3 = OpTypeFunction %2
3444 %6 = OpTypeInt 32 1
3445 %7 = OpConstantNull %6
3446 %13 = OpConstant %6 1
3447 %21 = OpConstant %6 1
3448 %10 = OpTypeBool
3449 %17 = OpTypePointer Function %6
3450 %4 = OpFunction %2 None %3
3451 %11 = OpLabel
3452 OpBranch %5
3453 %5 = OpLabel
3454 %23 = OpPhi %6 %7 %11 %20 %15
3455 OpLoopMerge %8 %15 Unroll
3456 OpBranch %14
3457 %14 = OpLabel
3458 %9 = OpSLessThan %10 %23 %13
3459 OpBranchConditional %9 %15 %8
3460 %15 = OpLabel
3461 %20 = OpIAdd %6 %23 %21
3462 OpBranch %5
3463 %8 = OpLabel
3464 OpReturn
3465 OpFunctionEnd
3466 )";
3467
3468 const std::string output = R"(OpCapability Shader
3469 %1 = OpExtInstImport "GLSL.std.450"
3470 OpMemoryModel Logical GLSL450
3471 OpEntryPoint Fragment %2 "main"
3472 OpExecutionMode %2 OriginUpperLeft
3473 OpSource ESSL 320
3474 %3 = OpTypeVoid
3475 %4 = OpTypeFunction %3
3476 %5 = OpTypeInt 32 1
3477 %6 = OpConstantNull %5
3478 %7 = OpConstant %5 1
3479 %8 = OpConstant %5 1
3480 %9 = OpTypeBool
3481 %10 = OpTypePointer Function %5
3482 %2 = OpFunction %3 None %4
3483 %11 = OpLabel
3484 OpBranch %12
3485 %12 = OpLabel
3486 OpBranch %17
3487 %17 = OpLabel
3488 %18 = OpSLessThan %9 %6 %7
3489 OpBranch %15
3490 %15 = OpLabel
3491 %14 = OpIAdd %5 %6 %8
3492 OpBranch %16
3493 %16 = OpLabel
3494 OpReturn
3495 OpFunctionEnd
3496 )";
3497
3498 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, shader,
3499 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3500 Module* module = context->module();
3501 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3502 << shader << std::endl;
3503
3504 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3505 SinglePassRunAndCheck<LoopUnroller>(shader, output, false);
3506 }
3507
TEST_F(PassClassTest,ConditionValueIsConstantNull)3508 TEST_F(PassClassTest, ConditionValueIsConstantNull) {
3509 const std::string shader = R"(
3510 OpCapability Shader
3511 %1 = OpExtInstImport "GLSL.std.450"
3512 OpMemoryModel Logical GLSL450
3513 OpEntryPoint Fragment %4 "main"
3514 OpExecutionMode %4 OriginUpperLeft
3515 OpSource ESSL 320
3516 %2 = OpTypeVoid
3517 %3 = OpTypeFunction %2
3518 %6 = OpTypeInt 32 1
3519 %7 = OpConstantNull %6
3520 %13 = OpConstant %6 1
3521 %21 = OpConstant %6 1
3522 %10 = OpTypeBool
3523 %17 = OpTypePointer Function %6
3524 %4 = OpFunction %2 None %3
3525 %11 = OpLabel
3526 OpBranch %5
3527 %5 = OpLabel
3528 %23 = OpPhi %6 %13 %11 %20 %15
3529 OpLoopMerge %8 %15 Unroll
3530 OpBranch %14
3531 %14 = OpLabel
3532 %9 = OpSGreaterThan %10 %23 %7
3533 OpBranchConditional %9 %15 %8
3534 %15 = OpLabel
3535 %20 = OpISub %6 %23 %21
3536 OpBranch %5
3537 %8 = OpLabel
3538 OpReturn
3539 OpFunctionEnd
3540 )";
3541
3542 const std::string output = R"(OpCapability Shader
3543 %1 = OpExtInstImport "GLSL.std.450"
3544 OpMemoryModel Logical GLSL450
3545 OpEntryPoint Fragment %2 "main"
3546 OpExecutionMode %2 OriginUpperLeft
3547 OpSource ESSL 320
3548 %3 = OpTypeVoid
3549 %4 = OpTypeFunction %3
3550 %5 = OpTypeInt 32 1
3551 %6 = OpConstantNull %5
3552 %7 = OpConstant %5 1
3553 %8 = OpConstant %5 1
3554 %9 = OpTypeBool
3555 %10 = OpTypePointer Function %5
3556 %2 = OpFunction %3 None %4
3557 %11 = OpLabel
3558 OpBranch %12
3559 %12 = OpLabel
3560 OpBranch %17
3561 %17 = OpLabel
3562 %18 = OpSGreaterThan %9 %7 %6
3563 OpBranch %15
3564 %15 = OpLabel
3565 %14 = OpISub %5 %7 %8
3566 OpBranch %16
3567 %16 = OpLabel
3568 OpReturn
3569 OpFunctionEnd
3570 )";
3571
3572 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, shader,
3573 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3574 Module* module = context->module();
3575 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
3576 << shader << std::endl;
3577
3578 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3579 SinglePassRunAndCheck<LoopUnroller>(shader, output, false);
3580 }
3581
TEST_F(PassClassTest,UnrollWithPhiReferencesPhi)3582 TEST_F(PassClassTest, UnrollWithPhiReferencesPhi) {
3583 const std::string text = R"(
3584 OpCapability Shader
3585 %1 = OpExtInstImport "GLSL.std.450"
3586 OpMemoryModel Logical GLSL450
3587 OpEntryPoint Fragment %main "main" %color
3588 OpExecutionMode %main OriginUpperLeft
3589 OpSource HLSL 600
3590 OpName %main "main"
3591 OpName %color "color"
3592 OpDecorate %color Location 0
3593 %uint = OpTypeInt 32 0
3594 %float = OpTypeFloat 32
3595 %float_0 = OpConstant %float 0
3596 %float_1 = OpConstant %float 1
3597 %uint_1 = OpConstant %uint 1
3598 %uint_3 = OpConstant %uint 3
3599 %void = OpTypeVoid
3600 %11 = OpTypeFunction %void
3601 %bool = OpTypeBool
3602 %v4float = OpTypeVector %float 4
3603 %_ptr_Output_v4float = OpTypePointer Output %v4float
3604 %color = OpVariable %_ptr_Output_v4float Output
3605 %main = OpFunction %void None %11
3606 %15 = OpLabel
3607 OpBranch %16
3608 %16 = OpLabel
3609 %17 = OpPhi %float %float_0 %15 %18 %19
3610 %18 = OpPhi %float %float_1 %15 %20 %19
3611 %21 = OpPhi %uint %uint_1 %15 %22 %19
3612 %23 = OpULessThanEqual %bool %21 %uint_3
3613 OpLoopMerge %24 %19 Unroll
3614 OpBranchConditional %23 %25 %24
3615 %25 = OpLabel
3616
3617 ; First loop iteration
3618 ; CHECK: [[next_phi1_0:%\w+]] = OpFSub %float %float_1 %float_0
3619
3620 ; Second loop iteration
3621 ; CHECK: [[next_phi1_1:%\w+]] = OpFSub %float [[next_phi1_0]] %float_1
3622
3623 ; Third loop iteration
3624 ; CHECK: OpFSub %float [[next_phi1_1]] [[next_phi1_0]]
3625
3626 %20 = OpFSub %float %18 %17
3627 OpBranch %19
3628 %19 = OpLabel
3629 %22 = OpIAdd %uint %21 %uint_1
3630 OpBranch %16
3631 %24 = OpLabel
3632 OpReturn
3633 OpFunctionEnd
3634 )";
3635
3636 std::unique_ptr<IRContext> context =
3637 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
3638 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3639 Module* module = context->module();
3640 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
3641 << text << std::endl;
3642
3643 LoopUnroller loop_unroller;
3644 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
3645 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
3646 SinglePassRunAndMatch<LoopUnroller>(text, true);
3647 }
3648
TEST_F(PassClassTest,UnrollWithDoublePhiReferencesPhi)3649 TEST_F(PassClassTest, UnrollWithDoublePhiReferencesPhi) {
3650 const std::string text = R"(
3651 OpCapability Shader
3652 %1 = OpExtInstImport "GLSL.std.450"
3653 OpMemoryModel Logical GLSL450
3654 OpEntryPoint Fragment %main "main" %color
3655 OpExecutionMode %main OriginUpperLeft
3656 OpSource HLSL 600
3657 OpName %main "main"
3658 OpName %color "color"
3659 OpDecorate %color Location 0
3660 %uint = OpTypeInt 32 0
3661 %float = OpTypeFloat 32
3662 %float_0 = OpConstant %float 0
3663 %float_1 = OpConstant %float 1
3664 %uint_1 = OpConstant %uint 1
3665 %uint_3 = OpConstant %uint 3
3666 %void = OpTypeVoid
3667 %11 = OpTypeFunction %void
3668 %bool = OpTypeBool
3669 %v4float = OpTypeVector %float 4
3670 %_ptr_Output_v4float = OpTypePointer Output %v4float
3671 %color = OpVariable %_ptr_Output_v4float Output
3672 %main = OpFunction %void None %11
3673 %15 = OpLabel
3674 OpBranch %16
3675 %16 = OpLabel
3676 %17 = OpPhi %float %float_1 %15 %18 %19
3677 %18 = OpPhi %float %float_0 %15 %20 %19
3678 %20 = OpPhi %float %float_1 %15 %21 %19
3679 %22 = OpPhi %uint %uint_1 %15 %23 %19
3680 %24 = OpULessThanEqual %bool %22 %uint_3
3681 OpLoopMerge %25 %19 Unroll
3682 OpBranchConditional %24 %26 %25
3683 %26 = OpLabel
3684
3685 ; First loop iteration
3686 ; CHECK: [[next_phi1_0:%\w+]] = OpFSub %float %float_1 %float_0
3687 ; CHECK: OpFMul %float %float_1
3688
3689 ; Second loop iteration
3690 ; CHECK: [[next_phi1_1:%\w+]] = OpFSub %float [[next_phi1_0]] %float_1
3691 ; CHECK: OpFMul %float %float_0
3692
3693 ; Third loop iteration
3694 ; CHECK: OpFSub %float [[next_phi1_1]] [[next_phi1_0]]
3695 ; CHECK: OpFMul %float %float_1
3696
3697 %21 = OpFSub %float %20 %18
3698 %27 = OpFMul %float %17 %21
3699 OpBranch %19
3700 %19 = OpLabel
3701 %23 = OpIAdd %uint %22 %uint_1
3702 OpBranch %16
3703 %25 = OpLabel
3704 OpReturn
3705 OpFunctionEnd
3706 )";
3707
3708 std::unique_ptr<IRContext> context =
3709 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
3710 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3711 Module* module = context->module();
3712 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
3713 << text << std::endl;
3714
3715 LoopUnroller loop_unroller;
3716 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
3717 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
3718 SinglePassRunAndMatch<LoopUnroller>(text, true);
3719 }
3720
TEST_F(PassClassTest,PartialUnrollWithPhiReferencesPhi)3721 TEST_F(PassClassTest, PartialUnrollWithPhiReferencesPhi) {
3722 // With LocalMultiStoreElimPass
3723 const std::string text = R"(
3724 OpCapability Shader
3725 %1 = OpExtInstImport "GLSL.std.450"
3726 OpMemoryModel Logical GLSL450
3727 OpEntryPoint Fragment %main "main" %color
3728 OpExecutionMode %main OriginUpperLeft
3729 OpSource HLSL 600
3730 OpName %main "main"
3731 OpName %color "color"
3732 OpDecorate %color Location 0
3733 %uint = OpTypeInt 32 0
3734 %float = OpTypeFloat 32
3735 %float_0 = OpConstant %float 0
3736 %float_1 = OpConstant %float 1
3737 %uint_1 = OpConstant %uint 1
3738 %uint_3 = OpConstant %uint 3
3739 %void = OpTypeVoid
3740 %11 = OpTypeFunction %void
3741 %bool = OpTypeBool
3742 %v4float = OpTypeVector %float 4
3743 %_ptr_Output_v4float = OpTypePointer Output %v4float
3744 %color = OpVariable %_ptr_Output_v4float Output
3745 %main = OpFunction %void None %11
3746 %15 = OpLabel
3747 OpBranch %16
3748 %16 = OpLabel
3749 %17 = OpPhi %float %float_0 %15 %18 %19
3750 %18 = OpPhi %float %float_1 %15 %20 %19
3751 %21 = OpPhi %uint %uint_1 %15 %22 %19
3752 %23 = OpULessThanEqual %bool %21 %uint_3
3753 OpLoopMerge %24 %19 Unroll
3754 OpBranchConditional %23 %25 %24
3755 %25 = OpLabel
3756
3757 ; CHECK: [[phi0_0:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} [[phi1_0:%\w+]]
3758 ; CHECK: [[phi1_0]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} [[sub:%\w+]]
3759
3760 ; CHECK: [[sub]] = OpFSub {{%\w+}} [[phi1_0]] [[phi0_0]]
3761
3762 ; CHECK: [[phi0_1:%\w+]] = OpPhi {{%\w+}} [[phi0_0]]
3763 ; CHECK: [[phi1_1:%\w+]] = OpPhi {{%\w+}} [[phi1_0]]
3764
3765 ; CHECK: [[sub:%\w+]] = OpFSub {{%\w+}} [[phi1_1]] [[phi0_1]]
3766
3767 ; CHECK: OpFSub {{%\w+}} [[sub]] [[phi1_1]]
3768
3769 %20 = OpFSub %float %18 %17
3770 OpBranch %19
3771 %19 = OpLabel
3772 %22 = OpIAdd %uint %21 %uint_1
3773 OpBranch %16
3774 %24 = OpLabel
3775 OpReturn
3776 OpFunctionEnd
3777 )";
3778
3779 std::unique_ptr<IRContext> context =
3780 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
3781 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3782 Module* module = context->module();
3783 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
3784 << text << std::endl;
3785
3786 LoopUnroller loop_unroller;
3787 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
3788 SinglePassRunAndMatch<PartialUnrollerTestPass<2>>(text, true);
3789 }
3790
TEST_F(PassClassTest,DontUnrollInfiteLoop)3791 TEST_F(PassClassTest, DontUnrollInfiteLoop) {
3792 // This is an infinite loop that because the step is 0. We want to make sure
3793 // the unroller does not try to unroll it.
3794 const std::string text = R"(OpCapability Shader
3795 %1 = OpExtInstImport "GLSL.std.450"
3796 OpMemoryModel Logical GLSL450
3797 OpEntryPoint Fragment %2 "main"
3798 OpExecutionMode %2 OriginUpperLeft
3799 %void = OpTypeVoid
3800 %4 = OpTypeFunction %void
3801 %int = OpTypeInt 32 1
3802 %int_0 = OpConstant %int 0
3803 %int_50 = OpConstant %int 50
3804 %bool = OpTypeBool
3805 %int_0_0 = OpConstant %int 0
3806 %2 = OpFunction %void None %4
3807 %10 = OpLabel
3808 OpBranch %11
3809 %11 = OpLabel
3810 %12 = OpPhi %int %int_0 %10 %13 %14
3811 %15 = OpSLessThan %bool %12 %int_50
3812 OpLoopMerge %16 %14 Unroll
3813 OpBranchConditional %15 %14 %16
3814 %14 = OpLabel
3815 %13 = OpIAdd %int %12 %int_0_0
3816 OpBranch %11
3817 %16 = OpLabel
3818 OpReturn
3819 OpFunctionEnd
3820 )";
3821
3822 SinglePassRunAndCheck<LoopUnroller>(text, text, false);
3823 }
3824
3825 } // namespace
3826 } // namespace opt
3827 } // namespace spvtools
3828