1 // Copyright (c) 2017 Google Inc.
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 <string>
16
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include "source/opt/ccp_pass.h"
20 #include "test/opt/pass_fixture.h"
21 #include "test/opt/pass_utils.h"
22
23 namespace spvtools {
24 namespace opt {
25 namespace {
26
27 using CCPTest = PassTest<::testing::Test>;
28
TEST_F(CCPTest,PropagateThroughPhis)29 TEST_F(CCPTest, PropagateThroughPhis) {
30 const std::string spv_asm = R"(
31 OpCapability Shader
32 %1 = OpExtInstImport "GLSL.std.450"
33 OpMemoryModel Logical GLSL450
34 OpEntryPoint Fragment %main "main" %x %outparm
35 OpExecutionMode %main OriginUpperLeft
36 OpSource GLSL 450
37 OpName %main "main"
38 OpName %x "x"
39 OpName %outparm "outparm"
40 OpDecorate %x Flat
41 OpDecorate %x Location 0
42 OpDecorate %outparm Location 0
43 %void = OpTypeVoid
44 %3 = OpTypeFunction %void
45 %int = OpTypeInt 32 1
46 %bool = OpTypeBool
47 %_ptr_Function_int = OpTypePointer Function %int
48 %int_4 = OpConstant %int 4
49 %int_3 = OpConstant %int 3
50 %int_1 = OpConstant %int 1
51 %_ptr_Input_int = OpTypePointer Input %int
52 %x = OpVariable %_ptr_Input_int Input
53 %_ptr_Output_int = OpTypePointer Output %int
54 %outparm = OpVariable %_ptr_Output_int Output
55 %main = OpFunction %void None %3
56 %4 = OpLabel
57 %5 = OpLoad %int %x
58 %9 = OpIAdd %int %int_1 %int_3
59 %6 = OpSGreaterThan %bool %5 %int_3
60 OpSelectionMerge %25 None
61 OpBranchConditional %6 %22 %23
62 %22 = OpLabel
63
64 ; CHECK: OpCopyObject %int %int_4
65 %7 = OpCopyObject %int %9
66
67 OpBranch %25
68 %23 = OpLabel
69 %8 = OpCopyObject %int %int_4
70 OpBranch %25
71 %25 = OpLabel
72
73 ; %int_4 should have propagated to both OpPhi operands.
74 ; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
75 %35 = OpPhi %int %7 %22 %8 %23
76
77 ; This function always returns 4. DCE should get rid of everything else.
78 ; CHECK OpStore %outparm %int_4
79 OpStore %outparm %35
80 OpReturn
81 OpFunctionEnd
82 )";
83
84 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
85 }
86
TEST_F(CCPTest,SimplifyConditionals)87 TEST_F(CCPTest, SimplifyConditionals) {
88 const std::string spv_asm = R"(
89 OpCapability Shader
90 %1 = OpExtInstImport "GLSL.std.450"
91 OpMemoryModel Logical GLSL450
92 OpEntryPoint Fragment %main "main" %outparm
93 OpExecutionMode %main OriginUpperLeft
94 OpSource GLSL 450
95 OpName %main "main"
96 OpName %outparm "outparm"
97 OpDecorate %outparm Location 0
98 %void = OpTypeVoid
99 %3 = OpTypeFunction %void
100 %int = OpTypeInt 32 1
101 %bool = OpTypeBool
102 %_ptr_Function_int = OpTypePointer Function %int
103 %int_4 = OpConstant %int 4
104 %int_3 = OpConstant %int 3
105 %int_1 = OpConstant %int 1
106 %_ptr_Output_int = OpTypePointer Output %int
107 %outparm = OpVariable %_ptr_Output_int Output
108 %main = OpFunction %void None %3
109 %4 = OpLabel
110 %9 = OpIAdd %int %int_4 %int_3
111 %6 = OpSGreaterThan %bool %9 %int_3
112 OpSelectionMerge %25 None
113 ; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
114 OpBranchConditional %6 %22 %23
115 ; CHECK: [[bb_taken]] = OpLabel
116 %22 = OpLabel
117 ; CHECK: OpCopyObject %int %int_7
118 %7 = OpCopyObject %int %9
119 OpBranch %25
120 ; CHECK: [[bb_not_taken]] = OpLabel
121 %23 = OpLabel
122 ; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
123 %8 = OpCopyObject %int %int_4
124 OpBranch %25
125 %25 = OpLabel
126
127 ; %int_7 should have propagated to the first OpPhi operand. But the else branch
128 ; is not executable (conditional is always true), so no values should be
129 ; propagated there and the value of the OpPhi should always be %int_7.
130 ; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
131 %35 = OpPhi %int %7 %22 %8 %23
132
133 ; Only the true path of the conditional is ever executed. The output of this
134 ; function is always %int_7.
135 ; CHECK: OpStore %outparm %int_7
136 OpStore %outparm %35
137 OpReturn
138 OpFunctionEnd
139 )";
140
141 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
142 }
143
TEST_F(CCPTest,SimplifySwitches)144 TEST_F(CCPTest, SimplifySwitches) {
145 const std::string spv_asm = R"(
146 OpCapability Shader
147 %1 = OpExtInstImport "GLSL.std.450"
148 OpMemoryModel Logical GLSL450
149 OpEntryPoint Fragment %main "main" %outparm
150 OpExecutionMode %main OriginUpperLeft
151 OpSource GLSL 450
152 OpName %main "main"
153 OpName %outparm "outparm"
154 OpDecorate %outparm Location 0
155 %void = OpTypeVoid
156 %6 = OpTypeFunction %void
157 %int = OpTypeInt 32 1
158 %_ptr_Function_int = OpTypePointer Function %int
159 %int_23 = OpConstant %int 23
160 %int_42 = OpConstant %int 42
161 %int_14 = OpConstant %int 14
162 %int_15 = OpConstant %int 15
163 %int_4 = OpConstant %int 4
164 %_ptr_Output_int = OpTypePointer Output %int
165 %outparm = OpVariable %_ptr_Output_int Output
166 %main = OpFunction %void None %6
167 %15 = OpLabel
168 OpSelectionMerge %17 None
169 OpSwitch %int_23 %17 10 %18 13 %19 23 %20
170 %18 = OpLabel
171 OpBranch %17
172 %19 = OpLabel
173 OpBranch %17
174 %20 = OpLabel
175 OpBranch %17
176 %17 = OpLabel
177 %24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
178
179 ; The switch will always jump to label %20, which carries the value %int_15.
180 ; CHECK: OpIAdd %int %int_15 %int_4
181 %22 = OpIAdd %int %24 %int_4
182
183 ; Consequently, the return value will always be %int_19.
184 ; CHECK: OpStore %outparm %int_19
185 OpStore %outparm %22
186 OpReturn
187 OpFunctionEnd
188 )";
189
190 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
191 }
192
TEST_F(CCPTest,SimplifySwitchesDefaultBranch)193 TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
194 const std::string spv_asm = R"(
195 OpCapability Shader
196 %1 = OpExtInstImport "GLSL.std.450"
197 OpMemoryModel Logical GLSL450
198 OpEntryPoint Fragment %main "main" %outparm
199 OpExecutionMode %main OriginUpperLeft
200 OpSource GLSL 450
201 OpName %main "main"
202 OpName %outparm "outparm"
203 OpDecorate %outparm Location 0
204 %void = OpTypeVoid
205 %6 = OpTypeFunction %void
206 %int = OpTypeInt 32 1
207 %_ptr_Function_int = OpTypePointer Function %int
208 %int_42 = OpConstant %int 42
209 %int_4 = OpConstant %int 4
210 %int_1 = OpConstant %int 1
211 %_ptr_Output_int = OpTypePointer Output %int
212 %outparm = OpVariable %_ptr_Output_int Output
213 %main = OpFunction %void None %6
214 %13 = OpLabel
215 %15 = OpIAdd %int %int_42 %int_4
216 OpSelectionMerge %16 None
217
218 ; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
219 OpSwitch %15 %17 10 %18
220 %18 = OpLabel
221 OpBranch %16
222 %17 = OpLabel
223 OpBranch %16
224 %16 = OpLabel
225 %22 = OpPhi %int %int_42 %18 %int_1 %17
226
227 ; The switch will always jump to the default label %17. This carries the value
228 ; %int_1.
229 ; CHECK: OpIAdd %int %int_1 %int_4
230 %20 = OpIAdd %int %22 %int_4
231
232 ; Resulting in a return value of %int_5.
233 ; CHECK: OpStore %outparm %int_5
234 OpStore %outparm %20
235 OpReturn
236 OpFunctionEnd
237 )";
238
239 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
240 }
241
TEST_F(CCPTest,SimplifyIntVector)242 TEST_F(CCPTest, SimplifyIntVector) {
243 const std::string spv_asm = R"(
244 OpCapability Shader
245 %1 = OpExtInstImport "GLSL.std.450"
246 OpMemoryModel Logical GLSL450
247 OpEntryPoint Fragment %main "main" %OutColor
248 OpExecutionMode %main OriginUpperLeft
249 OpSource GLSL 450
250 OpName %main "main"
251 OpName %v "v"
252 OpName %OutColor "OutColor"
253 OpDecorate %OutColor Location 0
254 %void = OpTypeVoid
255 %3 = OpTypeFunction %void
256 %int = OpTypeInt 32 1
257 %v4int = OpTypeVector %int 4
258 %_ptr_Function_v4int = OpTypePointer Function %v4int
259 %int_1 = OpConstant %int 1
260 %int_2 = OpConstant %int 2
261 %int_3 = OpConstant %int 3
262 %int_4 = OpConstant %int 4
263 %14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
264 %uint = OpTypeInt 32 0
265 %uint_0 = OpConstant %uint 0
266 %_ptr_Function_int = OpTypePointer Function %int
267 %_ptr_Output_v4int = OpTypePointer Output %v4int
268 %OutColor = OpVariable %_ptr_Output_v4int Output
269 %main = OpFunction %void None %3
270 %5 = OpLabel
271 %v = OpVariable %_ptr_Function_v4int Function
272 OpStore %v %14
273 %18 = OpAccessChain %_ptr_Function_int %v %uint_0
274 %19 = OpLoad %int %18
275
276 ; The constant folder does not see through access chains. To get this, the
277 ; vector would have to be scalarized.
278 ; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
279 %20 = OpIAdd %int %19 %int_1
280 %21 = OpAccessChain %_ptr_Function_int %v %uint_0
281
282 ; CHECK: OpStore {{%\d+}} [[result_id]]
283 OpStore %21 %20
284 %24 = OpLoad %v4int %v
285 OpStore %OutColor %24
286 OpReturn
287 OpFunctionEnd
288 )";
289
290 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
291 }
292
TEST_F(CCPTest,BadSimplifyFloatVector)293 TEST_F(CCPTest, BadSimplifyFloatVector) {
294 const std::string spv_asm = R"(
295 OpCapability Shader
296 %1 = OpExtInstImport "GLSL.std.450"
297 OpMemoryModel Logical GLSL450
298 OpEntryPoint Fragment %main "main" %OutColor
299 OpExecutionMode %main OriginUpperLeft
300 OpSource GLSL 450
301 OpName %main "main"
302 OpName %v "v"
303 OpName %OutColor "OutColor"
304 OpDecorate %OutColor Location 0
305 %void = OpTypeVoid
306 %3 = OpTypeFunction %void
307 %float = OpTypeFloat 32
308 %v4float = OpTypeVector %float 4
309 %_ptr_Function_v4float = OpTypePointer Function %v4float
310 %float_1 = OpConstant %float 1
311 %float_2 = OpConstant %float 2
312 %float_3 = OpConstant %float 3
313 %float_4 = OpConstant %float 4
314 %14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
315 %uint = OpTypeInt 32 0
316 %uint_0 = OpConstant %uint 0
317 %_ptr_Function_float = OpTypePointer Function %float
318 %_ptr_Output_v4float = OpTypePointer Output %v4float
319 %OutColor = OpVariable %_ptr_Output_v4float Output
320 %main = OpFunction %void None %3
321 %5 = OpLabel
322 %v = OpVariable %_ptr_Function_v4float Function
323 OpStore %v %14
324 %18 = OpAccessChain %_ptr_Function_float %v %uint_0
325 %19 = OpLoad %float %18
326
327 ; NOTE: This test should start failing once floating point folding is
328 ; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
329 ; This should be checking that we are adding %float_1 + %float_1.
330 ; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
331 %20 = OpFAdd %float %19 %float_1
332 %21 = OpAccessChain %_ptr_Function_float %v %uint_0
333
334 ; This should be checkint that we are storing %float_2 instead of result_it.
335 ; CHECK: OpStore {{%\d+}} [[result_id]]
336 OpStore %21 %20
337 %24 = OpLoad %v4float %v
338 OpStore %OutColor %24
339 OpReturn
340 OpFunctionEnd
341 )";
342
343 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
344 }
345
TEST_F(CCPTest,NoLoadStorePropagation)346 TEST_F(CCPTest, NoLoadStorePropagation) {
347 const std::string spv_asm = R"(
348 OpCapability Shader
349 %1 = OpExtInstImport "GLSL.std.450"
350 OpMemoryModel Logical GLSL450
351 OpEntryPoint Fragment %main "main" %outparm
352 OpExecutionMode %main OriginUpperLeft
353 OpSource GLSL 450
354 OpName %main "main"
355 OpName %x "x"
356 OpName %outparm "outparm"
357 OpDecorate %outparm Location 0
358 %void = OpTypeVoid
359 %3 = OpTypeFunction %void
360 %int = OpTypeInt 32 1
361 %_ptr_Function_int = OpTypePointer Function %int
362 %int_23 = OpConstant %int 23
363 %_ptr_Output_int = OpTypePointer Output %int
364 %outparm = OpVariable %_ptr_Output_int Output
365 %main = OpFunction %void None %3
366 %5 = OpLabel
367 %x = OpVariable %_ptr_Function_int Function
368 OpStore %x %int_23
369
370 ; int_23 should not propagate into this load.
371 ; CHECK: [[load_id:%\d+]] = OpLoad %int %x
372 %12 = OpLoad %int %x
373
374 ; Nor into this copy operation.
375 ; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
376 %13 = OpCopyObject %int %12
377
378 ; Likewise here.
379 ; CHECK: OpStore %outparm [[copy_id]]
380 OpStore %outparm %13
381 OpReturn
382 OpFunctionEnd
383 )";
384
385 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
386 }
387
TEST_F(CCPTest,HandleAbortInstructions)388 TEST_F(CCPTest, HandleAbortInstructions) {
389 const std::string spv_asm = R"(
390 OpCapability Shader
391 %1 = OpExtInstImport "GLSL.std.450"
392 OpMemoryModel Logical GLSL450
393 OpEntryPoint Fragment %main "main"
394 OpExecutionMode %main OriginUpperLeft
395 OpSource HLSL 500
396 OpName %main "main"
397 %void = OpTypeVoid
398 %3 = OpTypeFunction %void
399 %int = OpTypeInt 32 1
400 %bool = OpTypeBool
401 ; CHECK: %true = OpConstantTrue %bool
402 %int_3 = OpConstant %int 3
403 %int_1 = OpConstant %int 1
404 %main = OpFunction %void None %3
405 %4 = OpLabel
406 %9 = OpIAdd %int %int_3 %int_1
407 %6 = OpSGreaterThan %bool %9 %int_3
408 OpSelectionMerge %23 None
409 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
410 OpBranchConditional %6 %22 %23
411 %22 = OpLabel
412 OpKill
413 %23 = OpLabel
414 OpReturn
415 OpFunctionEnd
416 )";
417
418 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
419 }
420
TEST_F(CCPTest,SSAWebCycles)421 TEST_F(CCPTest, SSAWebCycles) {
422 // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
423 // When there is a cycle in the SSA def-use web, the propagator was getting
424 // into an infinite loop. SSA edges for Phi instructions should not be
425 // added to the edges to simulate.
426 const std::string spv_asm = R"(
427 OpCapability Shader
428 %1 = OpExtInstImport "GLSL.std.450"
429 OpMemoryModel Logical GLSL450
430 OpEntryPoint Fragment %main "main"
431 OpExecutionMode %main OriginUpperLeft
432 OpSource GLSL 450
433 OpName %main "main"
434 %void = OpTypeVoid
435 %3 = OpTypeFunction %void
436 %int = OpTypeInt 32 1
437 %_ptr_Function_int = OpTypePointer Function %int
438 %int_0 = OpConstant %int 0
439 %int_4 = OpConstant %int 4
440 %bool = OpTypeBool
441 %int_1 = OpConstant %int 1
442 %_ptr_Output_int = OpTypePointer Output %int
443 %main = OpFunction %void None %3
444 %5 = OpLabel
445 OpBranch %11
446 %11 = OpLabel
447 %29 = OpPhi %int %int_0 %5 %22 %14
448 %30 = OpPhi %int %int_0 %5 %25 %14
449 OpLoopMerge %13 %14 None
450 OpBranch %15
451 %15 = OpLabel
452 %19 = OpSLessThan %bool %30 %int_4
453 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
454 OpBranchConditional %19 %12 %13
455 %12 = OpLabel
456 ; CHECK: OpIAdd %int %int_0 %int_0
457 %22 = OpIAdd %int %29 %30
458 OpBranch %14
459 %14 = OpLabel
460 ; CHECK: OpPhi %int %int_0 {{%\d+}}
461 %25 = OpPhi %int %30 %12
462 OpBranch %11
463 %13 = OpLabel
464 OpReturn
465 OpFunctionEnd
466 )";
467
468 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
469 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
470 }
471
TEST_F(CCPTest,LoopInductionVariables)472 TEST_F(CCPTest, LoopInductionVariables) {
473 // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
474 // We are failing to properly consider the induction variable for this loop
475 // as Varying.
476 const std::string spv_asm = R"(
477 OpCapability Shader
478 %1 = OpExtInstImport "GLSL.std.450"
479 OpMemoryModel Logical GLSL450
480 OpEntryPoint Fragment %main "main"
481 OpExecutionMode %main OriginUpperLeft
482 OpSource GLSL 430
483 OpName %main "main"
484 %void = OpTypeVoid
485 %5 = OpTypeFunction %void
486 %int = OpTypeInt 32 1
487 %_ptr_Function_int = OpTypePointer Function %int
488 %int_0 = OpConstant %int 0
489 %int_10 = OpConstant %int 10
490 %bool = OpTypeBool
491 %int_1 = OpConstant %int 1
492 %main = OpFunction %void None %5
493 %12 = OpLabel
494 OpBranch %13
495 %13 = OpLabel
496
497 ; This Phi should not have all constant arguments:
498 ; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
499 %22 = OpPhi %int %int_0 %12 %21 %15
500 OpLoopMerge %14 %15 None
501 OpBranch %16
502 %16 = OpLabel
503
504 ; The Phi should never be considered to have the value %int_0.
505 ; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
506 %18 = OpSLessThan %bool %22 %int_10
507
508 ; This conditional was wrongly converted into an always-true jump due to the
509 ; bad meet evaluation of %22.
510 ; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
511 OpBranchConditional %18 %19 %14
512 %19 = OpLabel
513 OpBranch %15
514 %15 = OpLabel
515 ; CHECK: OpIAdd %int [[phi_id]] %int_1
516 %21 = OpIAdd %int %22 %int_1
517 OpBranch %13
518 %14 = OpLabel
519 OpReturn
520 OpFunctionEnd
521 )";
522
523 SinglePassRunAndMatch<CCPPass>(spv_asm, true);
524 }
525
TEST_F(CCPTest,HandleCompositeWithUndef)526 TEST_F(CCPTest, HandleCompositeWithUndef) {
527 // Check to make sure that CCP does not crash when given a "constant" struct
528 // with an undef. If at a later time CCP is enhanced to optimize this case,
529 // it is not wrong.
530 const std::string spv_asm = R"(
531 OpCapability Shader
532 %1 = OpExtInstImport "GLSL.std.450"
533 OpMemoryModel Logical GLSL450
534 OpEntryPoint Fragment %main "main"
535 OpExecutionMode %main OriginUpperLeft
536 OpSource HLSL 500
537 OpName %main "main"
538 %void = OpTypeVoid
539 %4 = OpTypeFunction %void
540 %int = OpTypeInt 32 1
541 %bool = OpTypeBool
542 %_struct_7 = OpTypeStruct %int %int
543 %int_1 = OpConstant %int 1
544 %9 = OpUndef %int
545 %10 = OpConstantComposite %_struct_7 %int_1 %9
546 %main = OpFunction %void None %4
547 %11 = OpLabel
548 %12 = OpCompositeExtract %int %10 0
549 %13 = OpCopyObject %int %12
550 OpReturn
551 OpFunctionEnd
552 )";
553
554 auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
555 EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
556 }
557
TEST_F(CCPTest,SkipSpecConstantInstrucitons)558 TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
559 const std::string spv_asm = R"(
560 OpCapability Shader
561 %1 = OpExtInstImport "GLSL.std.450"
562 OpMemoryModel Logical GLSL450
563 OpEntryPoint Fragment %main "main"
564 OpExecutionMode %main OriginUpperLeft
565 OpSource HLSL 500
566 OpName %main "main"
567 %void = OpTypeVoid
568 %4 = OpTypeFunction %void
569 %bool = OpTypeBool
570 %10 = OpSpecConstantFalse %bool
571 %main = OpFunction %void None %4
572 %11 = OpLabel
573 OpBranchConditional %10 %L1 %L2
574 %L1 = OpLabel
575 OpReturn
576 %L2 = OpLabel
577 OpReturn
578 OpFunctionEnd
579 )";
580
581 auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
582 EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
583 }
584
TEST_F(CCPTest,UpdateSubsequentPhisToVarying)585 TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
586 const std::string text = R"(
587 OpCapability Shader
588 OpMemoryModel Logical GLSL450
589 OpEntryPoint Fragment %func "func" %in
590 OpExecutionMode %func OriginUpperLeft
591 %void = OpTypeVoid
592 %bool = OpTypeBool
593 %int = OpTypeInt 32 1
594 %false = OpConstantFalse %bool
595 %int0 = OpConstant %int 0
596 %int1 = OpConstant %int 1
597 %int6 = OpConstant %int 6
598 %int_ptr_Input = OpTypePointer Input %int
599 %in = OpVariable %int_ptr_Input Input
600 %undef = OpUndef %int
601
602 ; Although no constants are propagated in this function, the propagator
603 ; generates a new %true value while visiting conditional statements.
604 ; CHECK: %true = OpConstantTrue %bool
605
606 %functy = OpTypeFunction %void
607 %func = OpFunction %void None %functy
608 %1 = OpLabel
609 OpBranch %2
610 %2 = OpLabel
611 %outer_phi = OpPhi %int %int0 %1 %outer_add %15
612 %cond1 = OpSLessThanEqual %bool %outer_phi %int6
613 OpLoopMerge %3 %15 None
614 OpBranchConditional %cond1 %4 %3
615 %4 = OpLabel
616 %ld = OpLoad %int %in
617 %cond2 = OpSGreaterThanEqual %bool %int1 %ld
618 OpSelectionMerge %10 None
619 OpBranchConditional %cond2 %8 %9
620 %8 = OpLabel
621 OpBranch %10
622 %9 = OpLabel
623 OpBranch %10
624 %10 = OpLabel
625 %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
626 OpBranch %11
627 %11 = OpLabel
628 %inner_phi = OpPhi %int %int0 %10 %inner_add %13
629 %cond3 = OpSLessThanEqual %bool %inner_phi %int6
630 OpLoopMerge %14 %13 None
631 OpBranchConditional %cond3 %12 %14
632 %12 = OpLabel
633 OpBranch %13
634 %13 = OpLabel
635 %inner_add = OpIAdd %int %inner_phi %int1
636 OpBranch %11
637 %14 = OpLabel
638 OpBranch %15
639 %15 = OpLabel
640 %outer_add = OpIAdd %int %extra_phi %int1
641 OpBranch %2
642 %3 = OpLabel
643 OpReturn
644 OpFunctionEnd
645 )";
646
647 auto result = SinglePassRunAndMatch<CCPPass>(text, true);
648 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
649 }
650
TEST_F(CCPTest,UndefInPhi)651 TEST_F(CCPTest, UndefInPhi) {
652 const std::string text = R"(
653 ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
654 ; CHECK: [[phi:%\w+]] = OpPhi
655 ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
656 OpCapability Kernel
657 OpCapability Linkage
658 OpMemoryModel Logical OpenCL
659 OpDecorate %1 LinkageAttributes "func" Export
660 %void = OpTypeVoid
661 %bool = OpTypeBool
662 %uint = OpTypeInt 32 0
663 %uint_0 = OpConstant %uint 0
664 %uint_1 = OpConstant %uint 1
665 %7 = OpUndef %uint
666 %8 = OpTypeFunction %void %bool
667 %1 = OpFunction %void None %8
668 %9 = OpFunctionParameter %bool
669 %10 = OpLabel
670 OpBranchConditional %9 %11 %12
671 %11 = OpLabel
672 OpBranch %13
673 %12 = OpLabel
674 OpBranch %14
675 %14 = OpLabel
676 OpBranchConditional %9 %13 %15
677 %15 = OpLabel
678 OpBranch %13
679 %13 = OpLabel
680 %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
681 %17 = OpIAdd %uint %16 %uint_1
682 OpReturn
683 OpFunctionEnd
684 )";
685
686 SinglePassRunAndMatch<CCPPass>(text, true);
687 }
688
689 // Just test to make sure the constant fold rules are being used. Will rely on
690 // the folding test for specific testing of specific rules.
TEST_F(CCPTest,UseConstantFoldingRules)691 TEST_F(CCPTest, UseConstantFoldingRules) {
692 const std::string text = R"(
693 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
694 ; CHECK: OpReturnValue [[float1]]
695 OpCapability Shader
696 OpCapability Linkage
697 OpMemoryModel Logical GLSL450
698 OpDecorate %1 LinkageAttributes "func" Export
699 %void = OpTypeVoid
700 %bool = OpTypeBool
701 %float = OpTypeFloat 32
702 %float_0 = OpConstant %float 0
703 %float_1 = OpConstant %float 1
704 %8 = OpTypeFunction %float
705 %1 = OpFunction %float None %8
706 %10 = OpLabel
707 %17 = OpFAdd %float %float_0 %float_1
708 OpReturnValue %17
709 OpFunctionEnd
710 )";
711
712 SinglePassRunAndMatch<CCPPass>(text, true);
713 }
714
715 // Test for #1300. Previously value for %5 would not settle during simulation.
TEST_F(CCPTest,SettlePhiLatticeValue)716 TEST_F(CCPTest, SettlePhiLatticeValue) {
717 const std::string text = R"(
718 OpCapability Kernel
719 OpCapability Linkage
720 OpMemoryModel Logical OpenCL
721 OpDecorate %func LinkageAttributes "func" Export
722 %void = OpTypeVoid
723 %bool = OpTypeBool
724 %true = OpConstantTrue %bool
725 %false = OpConstantFalse %bool
726 %functy = OpTypeFunction %void
727 %func = OpFunction %void None %functy
728 %1 = OpLabel
729 OpBranchConditional %true %2 %3
730 %3 = OpLabel
731 OpBranch %2
732 %2 = OpLabel
733 %5 = OpPhi %bool %true %1 %false %3
734 OpReturn
735 OpFunctionEnd
736 )";
737
738 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
739 SinglePassRunToBinary<CCPPass>(text, true);
740 }
741
TEST_F(CCPTest,NullBranchCondition)742 TEST_F(CCPTest, NullBranchCondition) {
743 const std::string text = R"(
744 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
745 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
746 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
747 OpCapability Shader
748 OpMemoryModel Logical GLSL450
749 OpEntryPoint Fragment %func "func"
750 OpExecutionMode %func OriginUpperLeft
751 %void = OpTypeVoid
752 %bool = OpTypeBool
753 %int = OpTypeInt 32 1
754 %null = OpConstantNull %bool
755 %int_1 = OpConstant %int 1
756 %int_2 = OpConstant %int 2
757 %functy = OpTypeFunction %void
758 %func = OpFunction %void None %functy
759 %1 = OpLabel
760 OpSelectionMerge %2 None
761 OpBranchConditional %null %2 %3
762 %3 = OpLabel
763 OpBranch %2
764 %2 = OpLabel
765 %phi = OpPhi %int %int_1 %1 %int_2 %3
766 %add = OpIAdd %int %int_1 %phi
767 OpReturn
768 OpFunctionEnd
769 )";
770
771 SinglePassRunAndMatch<CCPPass>(text, true);
772 }
773
TEST_F(CCPTest,UndefBranchCondition)774 TEST_F(CCPTest, UndefBranchCondition) {
775 const std::string text = R"(
776 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
777 ; CHECK: [[phi:%\w+]] = OpPhi
778 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
779 OpCapability Shader
780 OpMemoryModel Logical GLSL450
781 OpEntryPoint Fragment %func "func"
782 OpExecutionMode %func OriginUpperLeft
783 %void = OpTypeVoid
784 %bool = OpTypeBool
785 %int = OpTypeInt 32 1
786 %undef = OpUndef %bool
787 %int_1 = OpConstant %int 1
788 %int_2 = OpConstant %int 2
789 %functy = OpTypeFunction %void
790 %func = OpFunction %void None %functy
791 %1 = OpLabel
792 OpSelectionMerge %2 None
793 OpBranchConditional %undef %2 %3
794 %3 = OpLabel
795 OpBranch %2
796 %2 = OpLabel
797 %phi = OpPhi %int %int_1 %1 %int_2 %3
798 %add = OpIAdd %int %int_1 %phi
799 OpReturn
800 OpFunctionEnd
801 )";
802
803 SinglePassRunAndMatch<CCPPass>(text, true);
804 }
805
TEST_F(CCPTest,NullSwitchCondition)806 TEST_F(CCPTest, NullSwitchCondition) {
807 const std::string text = R"(
808 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
809 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
810 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
811 OpCapability Shader
812 OpMemoryModel Logical GLSL450
813 OpEntryPoint Fragment %func "func"
814 OpExecutionMode %func OriginUpperLeft
815 %void = OpTypeVoid
816 %int = OpTypeInt 32 1
817 %null = OpConstantNull %int
818 %int_1 = OpConstant %int 1
819 %int_2 = OpConstant %int 2
820 %functy = OpTypeFunction %void
821 %func = OpFunction %void None %functy
822 %1 = OpLabel
823 OpSelectionMerge %2 None
824 OpSwitch %null %2 0 %3
825 %3 = OpLabel
826 OpBranch %2
827 %2 = OpLabel
828 %phi = OpPhi %int %int_1 %1 %int_2 %3
829 %add = OpIAdd %int %int_1 %phi
830 OpReturn
831 OpFunctionEnd
832 )";
833
834 SinglePassRunAndMatch<CCPPass>(text, true);
835 }
836
TEST_F(CCPTest,UndefSwitchCondition)837 TEST_F(CCPTest, UndefSwitchCondition) {
838 const std::string text = R"(
839 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
840 ; CHECK: [[phi:%\w+]] = OpPhi
841 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
842 OpCapability Shader
843 OpMemoryModel Logical GLSL450
844 OpEntryPoint Fragment %func "func"
845 OpExecutionMode %func OriginUpperLeft
846 %void = OpTypeVoid
847 %int = OpTypeInt 32 1
848 %undef = OpUndef %int
849 %int_1 = OpConstant %int 1
850 %int_2 = OpConstant %int 2
851 %functy = OpTypeFunction %void
852 %func = OpFunction %void None %functy
853 %1 = OpLabel
854 OpSelectionMerge %2 None
855 OpSwitch %undef %2 0 %3
856 %3 = OpLabel
857 OpBranch %2
858 %2 = OpLabel
859 %phi = OpPhi %int %int_1 %1 %int_2 %3
860 %add = OpIAdd %int %int_1 %phi
861 OpReturn
862 OpFunctionEnd
863 )";
864
865 SinglePassRunAndMatch<CCPPass>(text, true);
866 }
867
868 // Test for #1361.
TEST_F(CCPTest,CompositeConstructOfGlobalValue)869 TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
870 const std::string text = R"(
871 ; CHECK: [[phi:%\w+]] = OpPhi
872 ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
873 OpCapability Shader
874 OpMemoryModel Logical GLSL450
875 OpEntryPoint Fragment %func "func" %in
876 OpExecutionMode %func OriginUpperLeft
877 %void = OpTypeVoid
878 %int = OpTypeInt 32 1
879 %bool = OpTypeBool
880 %functy = OpTypeFunction %void
881 %ptr_int_Input = OpTypePointer Input %int
882 %in = OpVariable %ptr_int_Input Input
883 %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
884 %struct_null = OpConstantNull %struct
885 %func = OpFunction %void None %functy
886 %1 = OpLabel
887 OpBranch %2
888 %2 = OpLabel
889 %phi = OpPhi %struct %struct_null %1 %5 %4
890 %extract = OpCompositeExtract %ptr_int_Input %phi 0
891 OpLoopMerge %3 %4 None
892 OpBranch %4
893 %4 = OpLabel
894 %5 = OpCompositeConstruct %struct %in %in
895 OpBranch %2
896 %3 = OpLabel
897 OpReturn
898 OpFunctionEnd
899 )";
900
901 SinglePassRunAndMatch<CCPPass>(text, true);
902 }
903
TEST_F(CCPTest,FoldWithDecoration)904 TEST_F(CCPTest, FoldWithDecoration) {
905 const std::string text = R"(
906 ; CHECK: OpCapability
907 ; CHECK-NOT: OpDecorate
908 ; CHECK: OpFunctionEnd
909 OpCapability Shader
910 %1 = OpExtInstImport "GLSL.std.450"
911 OpMemoryModel Logical GLSL450
912 OpEntryPoint Fragment %2 "main"
913 OpExecutionMode %2 OriginUpperLeft
914 OpSource ESSL 310
915 OpDecorate %3 RelaxedPrecision
916 %void = OpTypeVoid
917 %5 = OpTypeFunction %void
918 %float = OpTypeFloat 32
919 %v3float = OpTypeVector %float 3
920 %float_0 = OpConstant %float 0
921 %v4float = OpTypeVector %float 4
922 %10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
923 %2 = OpFunction %void None %5
924 %11 = OpLabel
925 %3 = OpVectorShuffle %v3float %10 %10 0 1 2
926 OpReturn
927 OpFunctionEnd
928 )";
929
930 SinglePassRunAndMatch<CCPPass>(text, true);
931 }
932
TEST_F(CCPTest,DebugSimpleFoldConstant)933 TEST_F(CCPTest, DebugSimpleFoldConstant) {
934 const std::string text = R"(
935 OpCapability Shader
936 OpCapability Linkage
937 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
938 OpMemoryModel Logical GLSL450
939 %file_name = OpString "test"
940 %float_name = OpString "float"
941 %main_name = OpString "main"
942 %f_name = OpString "f"
943 OpDecorate %1 LinkageAttributes "func" Export
944 %void = OpTypeVoid
945 %bool = OpTypeBool
946 %float = OpTypeFloat 32
947 %float_0 = OpConstant %float 0
948
949 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
950 %float_1 = OpConstant %float 1
951 %uint = OpTypeInt 32 0
952 %uint_32 = OpConstant %uint 32
953 %8 = OpTypeFunction %float
954 %null_expr = OpExtInst %void %ext DebugExpression
955 %src = OpExtInst %void %ext DebugSource %file_name
956 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
957 %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
958 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
959 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %1
960 %dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
961 %1 = OpFunction %float None %8
962 %10 = OpLabel
963
964 ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
965 ; CHECK: OpLine [[file:%\w+]] 1 0
966 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %float_1
967 %s0 = OpExtInst %void %ext DebugScope %dbg_main
968 OpLine %file_name 1 0
969 %17 = OpFAdd %float %float_0 %float_1
970 %val = OpExtInst %void %ext DebugValue %dbg_f %17 %null_expr
971
972 ; CHECK: OpLine [[file]] 2 0
973 ; CHECK: OpReturnValue [[float1]]
974 OpLine %file_name 2 0
975 OpReturnValue %17
976 OpFunctionEnd
977 )";
978
979 SinglePassRunAndMatch<CCPPass>(text, true);
980 }
981
TEST_F(CCPTest,DebugFoldMultipleForSingleConstant)982 TEST_F(CCPTest, DebugFoldMultipleForSingleConstant) {
983 const std::string text = R"(
984 OpCapability Shader
985 %1 = OpExtInstImport "GLSL.std.450"
986 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
987 OpMemoryModel Logical GLSL450
988 OpEntryPoint Fragment %main "main" %outparm
989 OpExecutionMode %main OriginUpperLeft
990 OpSource GLSL 450
991 %file_name = OpString "test"
992 %float_name = OpString "float"
993 %main_name = OpString "main"
994 %f_name = OpString "f"
995 OpName %main "main"
996 OpName %outparm "outparm"
997 OpDecorate %outparm Location 0
998 %void = OpTypeVoid
999 %3 = OpTypeFunction %void
1000 %int = OpTypeInt 32 1
1001 %bool = OpTypeBool
1002 %_ptr_Function_int = OpTypePointer Function %int
1003 %int_4 = OpConstant %int 4
1004 %int_3 = OpConstant %int 3
1005 %int_1 = OpConstant %int 1
1006 %uint = OpTypeInt 32 0
1007 %uint_32 = OpConstant %uint 32
1008 %_ptr_Output_int = OpTypePointer Output %int
1009 %outparm = OpVariable %_ptr_Output_int Output
1010 %null_expr = OpExtInst %void %ext DebugExpression
1011 %src = OpExtInst %void %ext DebugSource %file_name
1012 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
1013 %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
1014 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
1015 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
1016 %bb0 = OpExtInst %void %ext DebugLexicalBlock %src 0 0 %dbg_main
1017 %bb1 = OpExtInst %void %ext DebugLexicalBlock %src 1 0 %dbg_main
1018 %bb2 = OpExtInst %void %ext DebugLexicalBlock %src 2 0 %dbg_main
1019 %bb3 = OpExtInst %void %ext DebugLexicalBlock %src 3 0 %dbg_main
1020 %dbg_f0 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
1021 %dbg_f1 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 1 0 %dbg_main FlagIsLocal
1022 %dbg_f2 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 2 0 %dbg_main FlagIsLocal
1023 %main = OpFunction %void None %3
1024 %4 = OpLabel
1025
1026 ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
1027 ; CHECK: OpLine [[file:%\w+]] 1 0
1028 ; CHECK: OpIAdd %int %int_4 %int_3
1029 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %int_7
1030 %s0 = OpExtInst %void %ext DebugScope %bb0
1031 OpLine %file_name 1 0
1032 %9 = OpIAdd %int %int_4 %int_3
1033 %val0 = OpExtInst %void %ext DebugValue %dbg_f0 %9 %null_expr
1034
1035 ; CHECK: OpLine [[file]] 2 0
1036 ; CHECK: OpSGreaterThan %bool %int_7 %int_3
1037 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %true
1038 OpLine %file_name 2 0
1039 %6 = OpSGreaterThan %bool %9 %int_3
1040 %val1 = OpExtInst %void %ext DebugValue %dbg_f1 %6 %null_expr
1041
1042 OpSelectionMerge %25 None
1043 OpBranchConditional %6 %22 %23
1044 %22 = OpLabel
1045 %s1 = OpExtInst %void %ext DebugScope %bb1
1046 %7 = OpCopyObject %int %9
1047 %val2 = OpExtInst %void %ext DebugValue %dbg_f2 %7 %null_expr
1048 OpBranch %25
1049 %23 = OpLabel
1050 %s2 = OpExtInst %void %ext DebugScope %bb2
1051 %8 = OpCopyObject %int %int_4
1052 OpBranch %25
1053 %25 = OpLabel
1054 %s3 = OpExtInst %void %ext DebugScope %bb3
1055 %35 = OpPhi %int %7 %22 %8 %23
1056 OpStore %outparm %35
1057 OpReturn
1058 OpFunctionEnd
1059 )";
1060
1061 SinglePassRunAndMatch<CCPPass>(text, true);
1062 }
1063
1064 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3636
TEST_F(CCPTest,CCPNoChangeFailure)1065 TEST_F(CCPTest, CCPNoChangeFailure) {
1066 const std::string text = R"(
1067 OpCapability Shader
1068 %1 = OpExtInstImport "GLSL.std.450"
1069 OpMemoryModel Logical GLSL450
1070 OpEntryPoint Fragment %4 "main"
1071 OpExecutionMode %4 OriginUpperLeft
1072 OpSource ESSL 320
1073 %2 = OpTypeVoid
1074 %3 = OpTypeFunction %2
1075 %6 = OpTypeInt 32 1
1076 %7 = OpConstant %6 2
1077 %13 = OpConstant %6 4
1078 %21 = OpConstant %6 1
1079 %10 = OpTypeBool
1080 %17 = OpTypePointer Function %6
1081
1082 ; CCP is generating two new constants during propagation that end up being
1083 ; dead because they cannot be replaced anywhere in the IR. CCP was wrongly
1084 ; considering the IR to be unmodified because of this.
1085 ; CHECK: %true = OpConstantTrue %bool
1086 ; CHECK: %int_3 = OpConstant %int 3
1087
1088 %4 = OpFunction %2 None %3
1089 %11 = OpLabel
1090 OpBranch %5
1091 %5 = OpLabel
1092 %23 = OpPhi %6 %7 %11 %20 %15
1093 %9 = OpSLessThan %10 %23 %13
1094 OpLoopMerge %8 %15 None
1095 OpBranchConditional %9 %15 %8
1096 %15 = OpLabel
1097 %20 = OpIAdd %6 %23 %21
1098 OpBranch %5
1099 %8 = OpLabel
1100 OpReturn
1101 OpFunctionEnd
1102 )";
1103
1104 auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1105 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1106 }
1107
1108 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3738
1109 // Similar to the previous one but more than one constant is generated in a
1110 // single call to the instruction folder.
TEST_F(CCPTest,CCPNoChangeFailureSeveralConstantsDuringFolding)1111 TEST_F(CCPTest, CCPNoChangeFailureSeveralConstantsDuringFolding) {
1112 const std::string text = R"(
1113 OpCapability Shader
1114 %1 = OpExtInstImport "GLSL.std.450"
1115 OpMemoryModel Logical GLSL450
1116 OpEntryPoint Fragment %2 "main"
1117 OpExecutionMode %2 OriginUpperLeft
1118 %void = OpTypeVoid
1119 %4 = OpTypeFunction %void
1120 %float = OpTypeFloat 32
1121 %v3float = OpTypeVector %float 3
1122 %uint = OpTypeInt 32 0
1123 %uint_0 = OpConstant %uint 0
1124 %bool = OpTypeBool
1125 %v3bool = OpTypeVector %bool 3
1126 %float_0 = OpConstant %float 0
1127 %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0
1128 %float_0_300000012 = OpConstant %float 0.300000012
1129 %14 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
1130
1131 ; CCP is generating several constants during a single instruction evaluation.
1132 ; When folding %19, it generates the constants %true and %24. They are dead
1133 ; because they cannot be replaced anywhere in the IR. CCP was wrongly
1134 ; considering the IR to be unmodified because of this.
1135 ;
1136 ; CHECK: %true = OpConstantTrue %bool
1137 ; CHECK: %24 = OpConstantComposite %v3bool %true %true %true
1138 ; CHECK: %float_1 = OpConstant %float 1
1139 ; CHECK: %float_0_699999988 = OpConstant %float 0.699999988
1140
1141 %2 = OpFunction %void None %4
1142 %15 = OpLabel
1143 OpBranch %16
1144 %16 = OpLabel
1145 %17 = OpPhi %v3float %12 %15 %14 %18
1146 %19 = OpFOrdLessThan %v3bool %17 %14
1147 %20 = OpAll %bool %19
1148 OpLoopMerge %21 %18 None
1149 OpBranchConditional %20 %18 %21
1150 %18 = OpLabel
1151 OpBranch %16
1152 %21 = OpLabel
1153 %22 = OpExtInst %v3float %1 FMix %12 %17 %14
1154 OpReturn
1155 OpFunctionEnd
1156 )";
1157
1158 auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1159 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1160 }
1161
1162 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3991
1163 // Similar to the previous one but constants are created even when no
1164 // instruction are ever folded during propagation.
TEST_F(CCPTest,CCPNoChangeFailureWithUnfoldableInstr)1165 TEST_F(CCPTest, CCPNoChangeFailureWithUnfoldableInstr) {
1166 const std::string text = R"(
1167 OpCapability Shader
1168 %1 = OpExtInstImport "GLSL.std.450"
1169 OpMemoryModel Logical GLSL450
1170 OpEntryPoint Fragment %2 "main"
1171 OpExecutionMode %2 OriginUpperLeft
1172 %void = OpTypeVoid
1173 %4 = OpTypeFunction %void
1174 %float = OpTypeFloat 32
1175 %v3float = OpTypeVector %float 3
1176 %uint = OpTypeInt 32 0
1177 %uint_0 = OpConstant %uint 0
1178 %bool = OpTypeBool
1179 %float_0 = OpConstant %float 0
1180 %11 = OpConstantComposite %v3float %float_0 %float_0 %float_0
1181 %float_0_300000012 = OpConstant %float 0.300000012
1182 %13 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
1183
1184 ; CCP generates two constants when trying to fold an instruction, which it
1185 ; ultimately fails to fold. The instruction folder in CCP was only
1186 ; checking for newly added constants if the instruction folds successfully.
1187 ;
1188 ; CHECK: %float_1 = OpConstant %float 1
1189 ; CHECK: %float_0_699999988 = OpConstant %float 0.69999998
1190
1191 %2 = OpFunction %void None %4
1192 %14 = OpLabel
1193 %15 = OpBitcast %uint %float_0_300000012
1194 %16 = OpUGreaterThan %bool %15 %uint_0
1195 OpBranch %17
1196 %17 = OpLabel
1197 %18 = OpPhi %v3float %11 %14 %13 %19
1198 OpLoopMerge %20 %19 None
1199 OpBranchConditional %16 %19 %20
1200 %19 = OpLabel
1201 OpBranch %17
1202 %20 = OpLabel
1203 %21 = OpExtInst %v3float %1 FMix %11 %18 %13
1204 OpReturn
1205 OpFunctionEnd
1206 )";
1207
1208 auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1209 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1210 }
1211 } // namespace
1212 } // namespace opt
1213 } // namespace spvtools
1214