1 // Copyright (c) 2019 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 "source/reduce/remove_selection_reduction_opportunity_finder.h"
16
17 #include "source/opt/build_module.h"
18 #include "source/reduce/reduction_opportunity.h"
19 #include "test/reduce/reduce_test_util.h"
20
21 namespace spvtools {
22 namespace reduce {
23 namespace {
24
TEST(RemoveSelectionTest,OpportunityBecauseSameTargetBlock)25 TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlock) {
26 // A test with the following structure. The OpSelectionMerge instruction
27 // should be removed.
28 //
29 // header
30 // ||
31 // block
32 // |
33 // merge
34
35 std::string shader = R"(
36 OpCapability Shader
37 %1 = OpExtInstImport "GLSL.std.450"
38 OpMemoryModel Logical GLSL450
39 OpEntryPoint Fragment %2 "main"
40 OpExecutionMode %2 OriginUpperLeft
41 OpSource ESSL 310
42 OpName %2 "main"
43 %3 = OpTypeVoid
44 %4 = OpTypeFunction %3
45 %5 = OpTypeInt 32 1
46 %6 = OpTypePointer Function %5
47 %7 = OpTypeBool
48 %8 = OpConstantTrue %7
49 %2 = OpFunction %3 None %4
50 %9 = OpLabel
51 OpSelectionMerge %10 None
52 OpBranchConditional %8 %11 %11
53 %11 = OpLabel
54 OpBranch %10
55 %10 = OpLabel
56 OpReturn
57 OpFunctionEnd
58 )";
59
60 const auto env = SPV_ENV_UNIVERSAL_1_3;
61 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
62
63 auto ops =
64 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
65 context.get(), 0);
66
67 ASSERT_EQ(1, ops.size());
68
69 ASSERT_TRUE(ops[0]->PreconditionHolds());
70 ops[0]->TryToApply();
71 CheckValid(env, context.get());
72
73 std::string after = R"(
74 OpCapability Shader
75 %1 = OpExtInstImport "GLSL.std.450"
76 OpMemoryModel Logical GLSL450
77 OpEntryPoint Fragment %2 "main"
78 OpExecutionMode %2 OriginUpperLeft
79 OpSource ESSL 310
80 OpName %2 "main"
81 %3 = OpTypeVoid
82 %4 = OpTypeFunction %3
83 %5 = OpTypeInt 32 1
84 %6 = OpTypePointer Function %5
85 %7 = OpTypeBool
86 %8 = OpConstantTrue %7
87 %2 = OpFunction %3 None %4
88 %9 = OpLabel
89 OpBranchConditional %8 %11 %11
90 %11 = OpLabel
91 OpBranch %10
92 %10 = OpLabel
93 OpReturn
94 OpFunctionEnd
95 )";
96 CheckEqual(env, after, context.get());
97
98 ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
99 context.get(), 0);
100 ASSERT_EQ(0, ops.size());
101 }
102
TEST(RemoveSelectionTest,OpportunityBecauseSameTargetBlockMerge)103 TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlockMerge) {
104 // A test with the following structure. The OpSelectionMerge instruction
105 // should be removed.
106 //
107 // header
108 // ||
109 // merge
110
111 std::string shader = R"(
112 OpCapability Shader
113 %1 = OpExtInstImport "GLSL.std.450"
114 OpMemoryModel Logical GLSL450
115 OpEntryPoint Fragment %2 "main"
116 OpExecutionMode %2 OriginUpperLeft
117 OpSource ESSL 310
118 OpName %2 "main"
119 %3 = OpTypeVoid
120 %4 = OpTypeFunction %3
121 %5 = OpTypeInt 32 1
122 %6 = OpTypePointer Function %5
123 %7 = OpTypeBool
124 %8 = OpConstantTrue %7
125 %2 = OpFunction %3 None %4
126 %9 = OpLabel
127 OpSelectionMerge %10 None
128 OpBranchConditional %8 %10 %10
129 %10 = OpLabel
130 OpReturn
131 OpFunctionEnd
132 )";
133
134 const auto env = SPV_ENV_UNIVERSAL_1_3;
135 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
136
137 auto ops =
138 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
139 context.get(), 0);
140
141 ASSERT_EQ(1, ops.size());
142
143 ASSERT_TRUE(ops[0]->PreconditionHolds());
144 ops[0]->TryToApply();
145 CheckValid(env, context.get());
146
147 std::string after = R"(
148 OpCapability Shader
149 %1 = OpExtInstImport "GLSL.std.450"
150 OpMemoryModel Logical GLSL450
151 OpEntryPoint Fragment %2 "main"
152 OpExecutionMode %2 OriginUpperLeft
153 OpSource ESSL 310
154 OpName %2 "main"
155 %3 = OpTypeVoid
156 %4 = OpTypeFunction %3
157 %5 = OpTypeInt 32 1
158 %6 = OpTypePointer Function %5
159 %7 = OpTypeBool
160 %8 = OpConstantTrue %7
161 %2 = OpFunction %3 None %4
162 %9 = OpLabel
163 OpBranchConditional %8 %10 %10
164 %10 = OpLabel
165 OpReturn
166 OpFunctionEnd
167 )";
168 CheckEqual(env, after, context.get());
169
170 ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
171 context.get(), 0);
172 ASSERT_EQ(0, ops.size());
173 }
174
TEST(RemoveSelectionTest,NoOpportunityBecauseDifferentTargetBlocksOneMerge)175 TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocksOneMerge) {
176 // A test with the following structure. The OpSelectionMerge instruction
177 // should NOT be removed.
178 //
179 // header
180 // | |
181 // | block
182 // | |
183 // merge
184
185 std::string shader = R"(
186 OpCapability Shader
187 %1 = OpExtInstImport "GLSL.std.450"
188 OpMemoryModel Logical GLSL450
189 OpEntryPoint Fragment %2 "main"
190 OpExecutionMode %2 OriginUpperLeft
191 OpSource ESSL 310
192 OpName %2 "main"
193 %3 = OpTypeVoid
194 %4 = OpTypeFunction %3
195 %5 = OpTypeInt 32 1
196 %6 = OpTypePointer Function %5
197 %7 = OpTypeBool
198 %8 = OpConstantTrue %7
199 %2 = OpFunction %3 None %4
200 %9 = OpLabel
201 OpSelectionMerge %10 None
202 OpBranchConditional %8 %10 %11
203 %11 = OpLabel
204 OpBranch %10
205 %10 = OpLabel
206 OpReturn
207 OpFunctionEnd
208 )";
209
210 const auto env = SPV_ENV_UNIVERSAL_1_3;
211 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
212
213 auto ops =
214 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
215 context.get(), 0);
216 ASSERT_EQ(0, ops.size());
217 }
218
TEST(RemoveSelectionTest,NoOpportunityBecauseDifferentTargetBlocks)219 TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocks) {
220 // A test with the following structure. The OpSelectionMerge instruction
221 // should NOT be removed.
222 //
223 // header
224 // | |
225 // b b
226 // | |
227 // merge
228
229 std::string shader = R"(
230 OpCapability Shader
231 %1 = OpExtInstImport "GLSL.std.450"
232 OpMemoryModel Logical GLSL450
233 OpEntryPoint Fragment %2 "main"
234 OpExecutionMode %2 OriginUpperLeft
235 OpSource ESSL 310
236 OpName %2 "main"
237 %3 = OpTypeVoid
238 %4 = OpTypeFunction %3
239 %5 = OpTypeInt 32 1
240 %6 = OpTypePointer Function %5
241 %7 = OpTypeBool
242 %8 = OpConstantTrue %7
243 %2 = OpFunction %3 None %4
244 %9 = OpLabel
245 OpSelectionMerge %10 None
246 OpBranchConditional %8 %11 %12
247 %11 = OpLabel
248 OpBranch %10
249 %12 = OpLabel
250 OpBranch %10
251 %10 = OpLabel
252 OpReturn
253 OpFunctionEnd
254 )";
255
256 const auto env = SPV_ENV_UNIVERSAL_1_3;
257 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
258
259 auto ops =
260 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
261 context.get(), 0);
262 ASSERT_EQ(0, ops.size());
263 }
264
TEST(RemoveSelectionTest,NoOpportunityBecauseMergeUsed)265 TEST(RemoveSelectionTest, NoOpportunityBecauseMergeUsed) {
266 // A test with the following structure. The OpSelectionMerge instruction
267 // should NOT be removed.
268 //
269 // header
270 // ||
271 // block
272 // | |
273 // | block
274 // | |
275 // merge
276
277 std::string shader = R"(
278 OpCapability Shader
279 %1 = OpExtInstImport "GLSL.std.450"
280 OpMemoryModel Logical GLSL450
281 OpEntryPoint Fragment %2 "main"
282 OpExecutionMode %2 OriginUpperLeft
283 OpSource ESSL 310
284 OpName %2 "main"
285 %3 = OpTypeVoid
286 %4 = OpTypeFunction %3
287 %5 = OpTypeInt 32 1
288 %6 = OpTypePointer Function %5
289 %7 = OpTypeBool
290 %8 = OpConstantTrue %7
291 %2 = OpFunction %3 None %4
292 %9 = OpLabel
293 OpSelectionMerge %10 None
294 OpBranchConditional %8 %11 %12
295 %11 = OpLabel
296 OpBranchConditional %8 %10 %12
297 %12 = OpLabel
298 OpBranch %10
299 %10 = OpLabel
300 OpReturn
301 OpFunctionEnd
302 )";
303
304 const auto env = SPV_ENV_UNIVERSAL_1_3;
305 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
306
307 auto ops =
308 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
309 context.get(), 0);
310 ASSERT_EQ(0, ops.size());
311 }
312
TEST(RemoveSelectionTest,OpportunityBecauseLoopMergeUsed)313 TEST(RemoveSelectionTest, OpportunityBecauseLoopMergeUsed) {
314 // A test with the following structure. The OpSelectionMerge instruction
315 // should be removed.
316 //
317 // loop header
318 // |
319 // |
320 // s.header
321 // ||
322 // block
323 // | |
324 // | |
325 // | | ^ (to loop header)
326 // s.merge | |
327 // | / loop continue target (unreachable)
328 // loop merge
329 //
330 //
331 // which becomes:
332 //
333 // loop header
334 // |
335 // |
336 // block
337 // ||
338 // block
339 // | |
340 // | |
341 // | | ^ (to loop header)
342 // block | |
343 // | / loop continue target (unreachable)
344 // loop merge
345
346 std::string shader = R"(
347 OpCapability Shader
348 %1 = OpExtInstImport "GLSL.std.450"
349 OpMemoryModel Logical GLSL450
350 OpEntryPoint Fragment %2 "main"
351 OpExecutionMode %2 OriginUpperLeft
352 OpSource ESSL 310
353 OpName %2 "main"
354 %3 = OpTypeVoid
355 %4 = OpTypeFunction %3
356 %5 = OpTypeInt 32 1
357 %6 = OpTypePointer Function %5
358 %7 = OpTypeBool
359 %8 = OpConstantTrue %7
360 %2 = OpFunction %3 None %4
361 %9 = OpLabel
362 OpBranch %10
363 %10 = OpLabel
364 OpLoopMerge %11 %12 None
365 OpBranch %13
366 %13 = OpLabel
367 OpSelectionMerge %14 None
368 OpBranchConditional %8 %15 %15
369 %15 = OpLabel
370 OpBranchConditional %8 %14 %11
371 %14 = OpLabel
372 OpBranch %11
373 %12 = OpLabel
374 OpBranch %10
375 %11 = OpLabel
376 OpReturn
377 OpFunctionEnd
378 )";
379
380 const auto env = SPV_ENV_UNIVERSAL_1_3;
381 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
382
383 CheckValid(env, context.get());
384
385 auto ops =
386 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
387 context.get(), 0);
388
389 ASSERT_EQ(1, ops.size());
390
391 ASSERT_TRUE(ops[0]->PreconditionHolds());
392 ops[0]->TryToApply();
393 CheckValid(env, context.get());
394
395 std::string after = R"(
396 OpCapability Shader
397 %1 = OpExtInstImport "GLSL.std.450"
398 OpMemoryModel Logical GLSL450
399 OpEntryPoint Fragment %2 "main"
400 OpExecutionMode %2 OriginUpperLeft
401 OpSource ESSL 310
402 OpName %2 "main"
403 %3 = OpTypeVoid
404 %4 = OpTypeFunction %3
405 %5 = OpTypeInt 32 1
406 %6 = OpTypePointer Function %5
407 %7 = OpTypeBool
408 %8 = OpConstantTrue %7
409 %2 = OpFunction %3 None %4
410 %9 = OpLabel
411 OpBranch %10
412 %10 = OpLabel
413 OpLoopMerge %11 %12 None
414 OpBranch %13
415 %13 = OpLabel
416 OpBranchConditional %8 %15 %15
417 %15 = OpLabel
418 OpBranchConditional %8 %14 %11
419 %14 = OpLabel
420 OpBranch %11
421 %12 = OpLabel
422 OpBranch %10
423 %11 = OpLabel
424 OpReturn
425 OpFunctionEnd
426 )";
427 CheckEqual(env, after, context.get());
428
429 ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
430 context.get(), 0);
431 ASSERT_EQ(0, ops.size());
432 }
433
TEST(RemoveSelectionTest,OpportunityBecauseLoopContinueUsed)434 TEST(RemoveSelectionTest, OpportunityBecauseLoopContinueUsed) {
435 // A test with the following structure. The OpSelectionMerge instruction
436 // should be removed.
437 //
438 // loop header
439 // |
440 // |
441 // s.header
442 // ||
443 // block
444 // | |
445 // | |
446 // | | ^ (to loop header)
447 // s.merge | |
448 // | loop continue target
449 // loop merge
450 //
451 //
452 // which becomes:
453 //
454 // loop header
455 // |
456 // |
457 // block
458 // ||
459 // block
460 // | |
461 // | |
462 // | | ^ (to loop header)
463 // block | |
464 // | loop continue target
465 // loop merge
466
467 std::string shader = R"(
468 OpCapability Shader
469 %1 = OpExtInstImport "GLSL.std.450"
470 OpMemoryModel Logical GLSL450
471 OpEntryPoint Fragment %2 "main"
472 OpExecutionMode %2 OriginUpperLeft
473 OpSource ESSL 310
474 OpName %2 "main"
475 %3 = OpTypeVoid
476 %4 = OpTypeFunction %3
477 %5 = OpTypeInt 32 1
478 %6 = OpTypePointer Function %5
479 %7 = OpTypeBool
480 %8 = OpConstantTrue %7
481 %2 = OpFunction %3 None %4
482 %9 = OpLabel
483 OpBranch %10
484 %10 = OpLabel
485 OpLoopMerge %11 %12 None
486 OpBranch %13
487 %13 = OpLabel
488 OpSelectionMerge %14 None
489 OpBranchConditional %8 %15 %15
490 %15 = OpLabel
491 OpBranchConditional %8 %14 %12
492 %14 = OpLabel
493 OpBranch %11
494 %12 = OpLabel
495 OpBranch %10
496 %11 = OpLabel
497 OpReturn
498 OpFunctionEnd
499 )";
500
501 const auto env = SPV_ENV_UNIVERSAL_1_3;
502 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
503
504 CheckValid(env, context.get());
505
506 auto ops =
507 RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
508 context.get(), 0);
509
510 ASSERT_EQ(1, ops.size());
511
512 ASSERT_TRUE(ops[0]->PreconditionHolds());
513 ops[0]->TryToApply();
514 CheckValid(env, context.get());
515
516 std::string after = R"(
517 OpCapability Shader
518 %1 = OpExtInstImport "GLSL.std.450"
519 OpMemoryModel Logical GLSL450
520 OpEntryPoint Fragment %2 "main"
521 OpExecutionMode %2 OriginUpperLeft
522 OpSource ESSL 310
523 OpName %2 "main"
524 %3 = OpTypeVoid
525 %4 = OpTypeFunction %3
526 %5 = OpTypeInt 32 1
527 %6 = OpTypePointer Function %5
528 %7 = OpTypeBool
529 %8 = OpConstantTrue %7
530 %2 = OpFunction %3 None %4
531 %9 = OpLabel
532 OpBranch %10
533 %10 = OpLabel
534 OpLoopMerge %11 %12 None
535 OpBranch %13
536 %13 = OpLabel
537 OpBranchConditional %8 %15 %15
538 %15 = OpLabel
539 OpBranchConditional %8 %14 %12
540 %14 = OpLabel
541 OpBranch %11
542 %12 = OpLabel
543 OpBranch %10
544 %11 = OpLabel
545 OpReturn
546 OpFunctionEnd
547 )";
548 CheckEqual(env, after, context.get());
549
550 ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
551 context.get(), 0);
552 ASSERT_EQ(0, ops.size());
553 }
554
555 } // namespace
556 } // namespace reduce
557 } // namespace spvtools
558