• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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