• 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,FoldConstantCompositeInstrucitonsWithSpecConst)585 TEST_F(CCPTest, FoldConstantCompositeInstrucitonsWithSpecConst) {
586   const std::string spv_asm = R"(
587                OpCapability Shader
588                OpMemoryModel Logical GLSL450
589                OpEntryPoint Fragment %1 "main"
590                OpExecutionMode %1 OriginUpperLeft
591        %void = OpTypeVoid
592           %4 = OpTypeFunction %void
593        %bool = OpTypeBool
594      %v3bool = OpTypeVector %bool 3
595   %_struct_8 = OpTypeStruct %v3bool
596        %true = OpConstantTrue %bool
597 ; CHECK: [[spec_const:%\w+]] = OpSpecConstantComposite %v3bool
598          %11 = OpSpecConstantComposite %v3bool %true %true %true
599          %12 = OpConstantComposite %_struct_8 %11
600 ; CHECK: OpFunction
601           %1 = OpFunction %void None %4
602          %29 = OpLabel
603          %31 = OpCompositeExtract %v3bool %12 0
604 ; CHECK: OpCompositeExtract %bool [[spec_const]] 0
605          %32 = OpCompositeExtract %bool %31 0
606                OpReturn
607                OpFunctionEnd
608   )";
609 
610   auto result = SinglePassRunAndMatch<CCPPass>(spv_asm, true);
611   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
612 }
613 
TEST_F(CCPTest,UpdateSubsequentPhisToVarying)614 TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
615   const std::string text = R"(
616 OpCapability Shader
617 OpMemoryModel Logical GLSL450
618 OpEntryPoint Fragment %func "func" %in
619 OpExecutionMode %func OriginUpperLeft
620 %void = OpTypeVoid
621 %bool = OpTypeBool
622 %int = OpTypeInt 32 1
623 %false = OpConstantFalse %bool
624 %int0 = OpConstant %int 0
625 %int1 = OpConstant %int 1
626 %int6 = OpConstant %int 6
627 %int_ptr_Input = OpTypePointer Input %int
628 %in = OpVariable %int_ptr_Input Input
629 %undef = OpUndef %int
630 
631 ; Although no constants are propagated in this function, the propagator
632 ; generates a new %true value while visiting conditional statements.
633 ; CHECK: %true = OpConstantTrue %bool
634 
635 %functy = OpTypeFunction %void
636 %func = OpFunction %void None %functy
637 %1 = OpLabel
638 OpBranch %2
639 %2 = OpLabel
640 %outer_phi = OpPhi %int %int0 %1 %outer_add %15
641 %cond1 = OpSLessThanEqual %bool %outer_phi %int6
642 OpLoopMerge %3 %15 None
643 OpBranchConditional %cond1 %4 %3
644 %4 = OpLabel
645 %ld = OpLoad %int %in
646 %cond2 = OpSGreaterThanEqual %bool %int1 %ld
647 OpSelectionMerge %10 None
648 OpBranchConditional %cond2 %8 %9
649 %8 = OpLabel
650 OpBranch %10
651 %9 = OpLabel
652 OpBranch %10
653 %10 = OpLabel
654 %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
655 OpBranch %11
656 %11 = OpLabel
657 %inner_phi = OpPhi %int %int0 %10 %inner_add %13
658 %cond3 = OpSLessThanEqual %bool %inner_phi %int6
659 OpLoopMerge %14 %13 None
660 OpBranchConditional %cond3 %12 %14
661 %12 = OpLabel
662 OpBranch %13
663 %13 = OpLabel
664 %inner_add = OpIAdd %int %inner_phi %int1
665 OpBranch %11
666 %14 = OpLabel
667 OpBranch %15
668 %15 = OpLabel
669 %outer_add = OpIAdd %int %extra_phi %int1
670 OpBranch %2
671 %3 = OpLabel
672 OpReturn
673 OpFunctionEnd
674 )";
675 
676   auto result = SinglePassRunAndMatch<CCPPass>(text, true);
677   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
678 }
679 
TEST_F(CCPTest,UndefInPhi)680 TEST_F(CCPTest, UndefInPhi) {
681   const std::string text = R"(
682 ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
683 ; CHECK: [[phi:%\w+]] = OpPhi
684 ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
685                OpCapability Kernel
686                OpCapability Linkage
687                OpMemoryModel Logical OpenCL
688                OpDecorate %1 LinkageAttributes "func" Export
689        %void = OpTypeVoid
690        %bool = OpTypeBool
691        %uint = OpTypeInt 32 0
692      %uint_0 = OpConstant %uint 0
693      %uint_1 = OpConstant %uint 1
694           %7 = OpUndef %uint
695           %8 = OpTypeFunction %void %bool
696           %1 = OpFunction %void None %8
697           %9 = OpFunctionParameter %bool
698          %10 = OpLabel
699                OpBranchConditional %9 %11 %12
700          %11 = OpLabel
701                OpBranch %13
702          %12 = OpLabel
703                OpBranch %14
704          %14 = OpLabel
705                OpBranchConditional %9 %13 %15
706          %15 = OpLabel
707                OpBranch %13
708          %13 = OpLabel
709          %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
710          %17 = OpIAdd %uint %16 %uint_1
711                OpReturn
712                OpFunctionEnd
713 )";
714 
715   SinglePassRunAndMatch<CCPPass>(text, true);
716 }
717 
718 // Just test to make sure the constant fold rules are being used.  Will rely on
719 // the folding test for specific testing of specific rules.
TEST_F(CCPTest,UseConstantFoldingRules)720 TEST_F(CCPTest, UseConstantFoldingRules) {
721   const std::string text = R"(
722 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
723 ; CHECK: OpReturnValue [[float1]]
724                OpCapability Shader
725                OpCapability Linkage
726                OpMemoryModel Logical GLSL450
727                OpDecorate %1 LinkageAttributes "func" Export
728        %void = OpTypeVoid
729        %bool = OpTypeBool
730       %float = OpTypeFloat 32
731     %float_0 = OpConstant %float 0
732     %float_1 = OpConstant %float 1
733           %8 = OpTypeFunction %float
734           %1 = OpFunction %float None %8
735          %10 = OpLabel
736          %17 = OpFAdd %float %float_0 %float_1
737                OpReturnValue %17
738                OpFunctionEnd
739 )";
740 
741   SinglePassRunAndMatch<CCPPass>(text, true);
742 }
743 
744 // Test for #1300. Previously value for %5 would not settle during simulation.
TEST_F(CCPTest,SettlePhiLatticeValue)745 TEST_F(CCPTest, SettlePhiLatticeValue) {
746   const std::string text = R"(
747 OpCapability Kernel
748 OpCapability Linkage
749 OpMemoryModel Logical OpenCL
750 OpDecorate %func LinkageAttributes "func" Export
751 %void = OpTypeVoid
752 %bool = OpTypeBool
753 %true = OpConstantTrue %bool
754 %false = OpConstantFalse %bool
755 %functy = OpTypeFunction %void
756 %func = OpFunction %void None %functy
757 %1 = OpLabel
758 OpBranchConditional %true %2 %3
759 %3 = OpLabel
760 OpBranch %2
761 %2 = OpLabel
762 %5 = OpPhi %bool %true %1 %false %3
763 OpReturn
764 OpFunctionEnd
765 )";
766 
767   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
768   SinglePassRunToBinary<CCPPass>(text, true);
769 }
770 
TEST_F(CCPTest,NullBranchCondition)771 TEST_F(CCPTest, NullBranchCondition) {
772   const std::string text = R"(
773 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
774 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
775 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
776 OpCapability Shader
777 OpMemoryModel Logical GLSL450
778 OpEntryPoint Fragment %func "func"
779 OpExecutionMode %func OriginUpperLeft
780 %void = OpTypeVoid
781 %bool = OpTypeBool
782 %int = OpTypeInt 32 1
783 %null = OpConstantNull %bool
784 %int_1 = OpConstant %int 1
785 %int_2 = OpConstant %int 2
786 %functy = OpTypeFunction %void
787 %func = OpFunction %void None %functy
788 %1 = OpLabel
789 OpSelectionMerge %2 None
790 OpBranchConditional %null %2 %3
791 %3 = OpLabel
792 OpBranch %2
793 %2 = OpLabel
794 %phi = OpPhi %int %int_1 %1 %int_2 %3
795 %add = OpIAdd %int %int_1 %phi
796 OpReturn
797 OpFunctionEnd
798 )";
799 
800   SinglePassRunAndMatch<CCPPass>(text, true);
801 }
802 
TEST_F(CCPTest,UndefBranchCondition)803 TEST_F(CCPTest, UndefBranchCondition) {
804   const std::string text = R"(
805 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
806 ; CHECK: [[phi:%\w+]] = OpPhi
807 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
808 OpCapability Shader
809 OpMemoryModel Logical GLSL450
810 OpEntryPoint Fragment %func "func"
811 OpExecutionMode %func OriginUpperLeft
812 %void = OpTypeVoid
813 %bool = OpTypeBool
814 %int = OpTypeInt 32 1
815 %undef = OpUndef %bool
816 %int_1 = OpConstant %int 1
817 %int_2 = OpConstant %int 2
818 %functy = OpTypeFunction %void
819 %func = OpFunction %void None %functy
820 %1 = OpLabel
821 OpSelectionMerge %2 None
822 OpBranchConditional %undef %2 %3
823 %3 = OpLabel
824 OpBranch %2
825 %2 = OpLabel
826 %phi = OpPhi %int %int_1 %1 %int_2 %3
827 %add = OpIAdd %int %int_1 %phi
828 OpReturn
829 OpFunctionEnd
830 )";
831 
832   SinglePassRunAndMatch<CCPPass>(text, true);
833 }
834 
TEST_F(CCPTest,NullSwitchCondition)835 TEST_F(CCPTest, NullSwitchCondition) {
836   const std::string text = R"(
837 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
838 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
839 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
840 OpCapability Shader
841 OpMemoryModel Logical GLSL450
842 OpEntryPoint Fragment %func "func"
843 OpExecutionMode %func OriginUpperLeft
844 %void = OpTypeVoid
845 %int = OpTypeInt 32 1
846 %null = OpConstantNull %int
847 %int_1 = OpConstant %int 1
848 %int_2 = OpConstant %int 2
849 %functy = OpTypeFunction %void
850 %func = OpFunction %void None %functy
851 %1 = OpLabel
852 OpSelectionMerge %2 None
853 OpSwitch %null %2 0 %3
854 %3 = OpLabel
855 OpBranch %2
856 %2 = OpLabel
857 %phi = OpPhi %int %int_1 %1 %int_2 %3
858 %add = OpIAdd %int %int_1 %phi
859 OpReturn
860 OpFunctionEnd
861 )";
862 
863   SinglePassRunAndMatch<CCPPass>(text, true);
864 }
865 
TEST_F(CCPTest,UndefSwitchCondition)866 TEST_F(CCPTest, UndefSwitchCondition) {
867   const std::string text = R"(
868 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
869 ; CHECK: [[phi:%\w+]] = OpPhi
870 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
871 OpCapability Shader
872 OpMemoryModel Logical GLSL450
873 OpEntryPoint Fragment %func "func"
874 OpExecutionMode %func OriginUpperLeft
875 %void = OpTypeVoid
876 %int = OpTypeInt 32 1
877 %undef = OpUndef %int
878 %int_1 = OpConstant %int 1
879 %int_2 = OpConstant %int 2
880 %functy = OpTypeFunction %void
881 %func = OpFunction %void None %functy
882 %1 = OpLabel
883 OpSelectionMerge %2 None
884 OpSwitch %undef %2 0 %3
885 %3 = OpLabel
886 OpBranch %2
887 %2 = OpLabel
888 %phi = OpPhi %int %int_1 %1 %int_2 %3
889 %add = OpIAdd %int %int_1 %phi
890 OpReturn
891 OpFunctionEnd
892 )";
893 
894   SinglePassRunAndMatch<CCPPass>(text, true);
895 }
896 
897 // Test for #1361.
TEST_F(CCPTest,CompositeConstructOfGlobalValue)898 TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
899   const std::string text = R"(
900 ; CHECK: [[phi:%\w+]] = OpPhi
901 ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
902 OpCapability Shader
903 OpMemoryModel Logical GLSL450
904 OpEntryPoint Fragment %func "func" %in
905 OpExecutionMode %func OriginUpperLeft
906 %void = OpTypeVoid
907 %int = OpTypeInt 32 1
908 %bool = OpTypeBool
909 %functy = OpTypeFunction %void
910 %ptr_int_Input = OpTypePointer Input %int
911 %in = OpVariable %ptr_int_Input Input
912 %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
913 %struct_null = OpConstantNull %struct
914 %func = OpFunction %void None %functy
915 %1 = OpLabel
916 OpBranch %2
917 %2 = OpLabel
918 %phi = OpPhi %struct %struct_null %1 %5 %4
919 %extract = OpCompositeExtract %ptr_int_Input %phi 0
920 OpLoopMerge %3 %4 None
921 OpBranch %4
922 %4 = OpLabel
923 %5 = OpCompositeConstruct %struct %in %in
924 OpBranch %2
925 %3 = OpLabel
926 OpReturn
927 OpFunctionEnd
928 )";
929 
930   SinglePassRunAndMatch<CCPPass>(text, true);
931 }
932 
TEST_F(CCPTest,FoldWithDecoration)933 TEST_F(CCPTest, FoldWithDecoration) {
934   const std::string text = R"(
935 ; CHECK: OpCapability
936 ; CHECK-NOT: OpDecorate
937 ; CHECK: OpFunctionEnd
938                OpCapability Shader
939           %1 = OpExtInstImport "GLSL.std.450"
940                OpMemoryModel Logical GLSL450
941                OpEntryPoint Fragment %2 "main"
942                OpExecutionMode %2 OriginUpperLeft
943                OpSource ESSL 310
944                OpDecorate %3 RelaxedPrecision
945        %void = OpTypeVoid
946           %5 = OpTypeFunction %void
947       %float = OpTypeFloat 32
948     %v3float = OpTypeVector %float 3
949     %float_0 = OpConstant %float 0
950     %v4float = OpTypeVector %float 4
951          %10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
952           %2 = OpFunction %void None %5
953          %11 = OpLabel
954           %3 = OpVectorShuffle %v3float %10 %10 0 1 2
955                OpReturn
956                OpFunctionEnd
957 )";
958 
959   SinglePassRunAndMatch<CCPPass>(text, true);
960 }
961 
TEST_F(CCPTest,DebugSimpleFoldConstant)962 TEST_F(CCPTest, DebugSimpleFoldConstant) {
963   const std::string text = R"(
964                OpCapability Shader
965                OpCapability Linkage
966         %ext = OpExtInstImport "OpenCL.DebugInfo.100"
967                OpMemoryModel Logical GLSL450
968   %file_name = OpString "test"
969  %float_name = OpString "float"
970   %main_name = OpString "main"
971      %f_name = OpString "f"
972                OpDecorate %1 LinkageAttributes "func" Export
973        %void = OpTypeVoid
974        %bool = OpTypeBool
975       %float = OpTypeFloat 32
976     %float_0 = OpConstant %float 0
977 
978 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
979     %float_1 = OpConstant %float 1
980        %uint = OpTypeInt 32 0
981     %uint_32 = OpConstant %uint 32
982           %8 = OpTypeFunction %float
983   %null_expr = OpExtInst %void %ext DebugExpression
984         %src = OpExtInst %void %ext DebugSource %file_name
985          %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
986      %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
987     %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
988    %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %1
989       %dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
990           %1 = OpFunction %float None %8
991          %10 = OpLabel
992 
993 ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
994 ; CHECK: OpLine [[file:%\w+]] 1 0
995 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %float_1
996          %s0 = OpExtInst %void %ext DebugScope %dbg_main
997                OpLine %file_name 1 0
998          %17 = OpFAdd %float %float_0 %float_1
999         %val = OpExtInst %void %ext DebugValue %dbg_f %17 %null_expr
1000 
1001 ; CHECK: OpLine [[file]] 2 0
1002 ; CHECK: OpReturnValue [[float1]]
1003                OpLine %file_name 2 0
1004                OpReturnValue %17
1005                OpFunctionEnd
1006 )";
1007 
1008   SinglePassRunAndMatch<CCPPass>(text, true);
1009 }
1010 
TEST_F(CCPTest,DebugFoldMultipleForSingleConstant)1011 TEST_F(CCPTest, DebugFoldMultipleForSingleConstant) {
1012   const std::string text = R"(
1013                OpCapability Shader
1014           %1 = OpExtInstImport "GLSL.std.450"
1015         %ext = OpExtInstImport "OpenCL.DebugInfo.100"
1016                OpMemoryModel Logical GLSL450
1017                OpEntryPoint Fragment %main "main" %outparm
1018                OpExecutionMode %main OriginUpperLeft
1019                OpSource GLSL 450
1020   %file_name = OpString "test"
1021  %float_name = OpString "float"
1022   %main_name = OpString "main"
1023      %f_name = OpString "f"
1024                OpName %main "main"
1025                OpName %outparm "outparm"
1026                OpDecorate %outparm Location 0
1027        %void = OpTypeVoid
1028           %3 = OpTypeFunction %void
1029         %int = OpTypeInt 32 1
1030        %bool = OpTypeBool
1031 %_ptr_Function_int = OpTypePointer Function %int
1032       %int_4 = OpConstant %int 4
1033       %int_3 = OpConstant %int 3
1034       %int_1 = OpConstant %int 1
1035        %uint = OpTypeInt 32 0
1036     %uint_32 = OpConstant %uint 32
1037 %_ptr_Output_int = OpTypePointer Output %int
1038     %outparm = OpVariable %_ptr_Output_int Output
1039   %null_expr = OpExtInst %void %ext DebugExpression
1040         %src = OpExtInst %void %ext DebugSource %file_name
1041          %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
1042      %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
1043     %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
1044    %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
1045         %bb0 = OpExtInst %void %ext DebugLexicalBlock %src 0 0 %dbg_main
1046         %bb1 = OpExtInst %void %ext DebugLexicalBlock %src 1 0 %dbg_main
1047         %bb2 = OpExtInst %void %ext DebugLexicalBlock %src 2 0 %dbg_main
1048         %bb3 = OpExtInst %void %ext DebugLexicalBlock %src 3 0 %dbg_main
1049       %dbg_f0 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
1050       %dbg_f1 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 1 0 %dbg_main FlagIsLocal
1051       %dbg_f2 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 2 0 %dbg_main FlagIsLocal
1052        %main = OpFunction %void None %3
1053           %4 = OpLabel
1054 
1055 ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
1056 ; CHECK: OpLine [[file:%\w+]] 1 0
1057 ; CHECK: OpIAdd %int %int_4 %int_3
1058 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %int_7
1059          %s0 = OpExtInst %void %ext DebugScope %bb0
1060                OpLine %file_name 1 0
1061           %9 = OpIAdd %int %int_4 %int_3
1062        %val0 = OpExtInst %void %ext DebugValue %dbg_f0 %9 %null_expr
1063 
1064 ; CHECK: OpLine [[file]] 2 0
1065 ; CHECK: OpSGreaterThan %bool %int_7 %int_3
1066 ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %true
1067                OpLine %file_name 2 0
1068           %6 = OpSGreaterThan %bool %9 %int_3
1069        %val1 = OpExtInst %void %ext DebugValue %dbg_f1 %6 %null_expr
1070 
1071                OpSelectionMerge %25 None
1072                OpBranchConditional %6 %22 %23
1073          %22 = OpLabel
1074          %s1 = OpExtInst %void %ext DebugScope %bb1
1075           %7 = OpCopyObject %int %9
1076        %val2 = OpExtInst %void %ext DebugValue %dbg_f2 %7 %null_expr
1077                OpBranch %25
1078          %23 = OpLabel
1079          %s2 = OpExtInst %void %ext DebugScope %bb2
1080           %8 = OpCopyObject %int %int_4
1081                OpBranch %25
1082          %25 = OpLabel
1083          %s3 = OpExtInst %void %ext DebugScope %bb3
1084          %35 = OpPhi %int %7 %22 %8 %23
1085                OpStore %outparm %35
1086                OpReturn
1087                OpFunctionEnd
1088 )";
1089 
1090   SinglePassRunAndMatch<CCPPass>(text, true);
1091 }
1092 
1093 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3636
TEST_F(CCPTest,CCPNoChangeFailure)1094 TEST_F(CCPTest, CCPNoChangeFailure) {
1095   const std::string text = R"(
1096                OpCapability Shader
1097           %1 = OpExtInstImport "GLSL.std.450"
1098                OpMemoryModel Logical GLSL450
1099                OpEntryPoint Fragment %4 "main"
1100                OpExecutionMode %4 OriginUpperLeft
1101                OpSource ESSL 320
1102           %2 = OpTypeVoid
1103           %3 = OpTypeFunction %2
1104           %6 = OpTypeInt 32 1
1105           %7 = OpConstant %6 2
1106          %13 = OpConstant %6 4
1107          %21 = OpConstant %6 1
1108          %10 = OpTypeBool
1109          %17 = OpTypePointer Function %6
1110 
1111 ; CCP is generating two new constants during propagation that end up being
1112 ; dead because they cannot be replaced anywhere in the IR.  CCP was wrongly
1113 ; considering the IR to be unmodified because of this.
1114 ; CHECK: %true = OpConstantTrue %bool
1115 ; CHECK: %int_3 = OpConstant %int 3
1116 
1117           %4 = OpFunction %2 None %3
1118          %11 = OpLabel
1119                OpBranch %5
1120           %5 = OpLabel
1121          %23 = OpPhi %6 %7 %11 %20 %15
1122           %9 = OpSLessThan %10 %23 %13
1123                OpLoopMerge %8 %15 None
1124                OpBranchConditional %9 %15 %8
1125          %15 = OpLabel
1126          %20 = OpIAdd %6 %23 %21
1127                OpBranch %5
1128           %8 = OpLabel
1129                OpReturn
1130                OpFunctionEnd
1131 )";
1132 
1133   auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1134   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1135 }
1136 
1137 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3738
1138 // Similar to the previous one but more than one constant is generated in a
1139 // single call to the instruction folder.
TEST_F(CCPTest,CCPNoChangeFailureSeveralConstantsDuringFolding)1140 TEST_F(CCPTest, CCPNoChangeFailureSeveralConstantsDuringFolding) {
1141   const std::string text = R"(
1142                OpCapability Shader
1143           %1 = OpExtInstImport "GLSL.std.450"
1144                OpMemoryModel Logical GLSL450
1145                OpEntryPoint Fragment %2 "main"
1146                OpExecutionMode %2 OriginUpperLeft
1147        %void = OpTypeVoid
1148           %4 = OpTypeFunction %void
1149       %float = OpTypeFloat 32
1150     %v3float = OpTypeVector %float 3
1151        %uint = OpTypeInt 32 0
1152      %uint_0 = OpConstant %uint 0
1153        %bool = OpTypeBool
1154      %v3bool = OpTypeVector %bool 3
1155     %float_0 = OpConstant %float 0
1156          %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0
1157 %float_0_300000012 = OpConstant %float 0.300000012
1158          %14 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
1159 
1160 ; CCP is generating several constants during a single instruction evaluation.
1161 ; When folding %19, it generates the constants %true and %24.  They are dead
1162 ; because they cannot be replaced anywhere in the IR.  CCP was wrongly
1163 ; considering the IR to be unmodified because of this.
1164 ;
1165 ; CHECK: %true = OpConstantTrue %bool
1166 ; CHECK: %24 = OpConstantComposite %v3bool %true %true %true
1167 ; CHECK: %float_1 = OpConstant %float 1
1168 ; CHECK: %float_0_699999988 = OpConstant %float 0.699999988
1169 
1170           %2 = OpFunction %void None %4
1171          %15 = OpLabel
1172                OpBranch %16
1173          %16 = OpLabel
1174          %17 = OpPhi %v3float %12 %15 %14 %18
1175          %19 = OpFOrdLessThan %v3bool %17 %14
1176          %20 = OpAll %bool %19
1177                OpLoopMerge %21 %18 None
1178                OpBranchConditional %20 %18 %21
1179          %18 = OpLabel
1180                OpBranch %16
1181          %21 = OpLabel
1182          %22 = OpExtInst %v3float %1 FMix %12 %17 %14
1183                OpReturn
1184                OpFunctionEnd
1185 )";
1186 
1187   auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1188   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1189 }
1190 
1191 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3991
1192 // Similar to the previous one but constants are created even when no
1193 // instruction are ever folded during propagation.
TEST_F(CCPTest,CCPNoChangeFailureWithUnfoldableInstr)1194 TEST_F(CCPTest, CCPNoChangeFailureWithUnfoldableInstr) {
1195   const std::string text = R"(
1196                OpCapability Shader
1197           %1 = OpExtInstImport "GLSL.std.450"
1198                OpMemoryModel Logical GLSL450
1199                OpEntryPoint Fragment %2 "main"
1200                OpExecutionMode %2 OriginUpperLeft
1201        %void = OpTypeVoid
1202           %4 = OpTypeFunction %void
1203       %float = OpTypeFloat 32
1204     %v3float = OpTypeVector %float 3
1205        %uint = OpTypeInt 32 0
1206      %uint_0 = OpConstant %uint 0
1207        %bool = OpTypeBool
1208     %float_0 = OpConstant %float 0
1209          %11 = OpConstantComposite %v3float %float_0 %float_0 %float_0
1210 %float_0_300000012 = OpConstant %float 0.300000012
1211          %13 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
1212 
1213 ; CCP generates two constants when trying to fold an instruction, which it
1214 ; ultimately fails to fold. The instruction folder in CCP was only
1215 ; checking for newly added constants if the instruction folds successfully.
1216 ;
1217 ; CHECK: %float_1 = OpConstant %float 1
1218 ; CHECK: %float_0_699999988 = OpConstant %float 0.69999998
1219 
1220           %2 = OpFunction %void None %4
1221          %14 = OpLabel
1222          %15 = OpBitcast %uint %float_0_300000012
1223          %16 = OpUGreaterThan %bool %15 %uint_0
1224                OpBranch %17
1225          %17 = OpLabel
1226          %18 = OpPhi %v3float %11 %14 %13 %19
1227                OpLoopMerge %20 %19 None
1228                OpBranchConditional %16 %19 %20
1229          %19 = OpLabel
1230                OpBranch %17
1231          %20 = OpLabel
1232          %21 = OpExtInst %v3float %1 FMix %11 %18 %13
1233                OpReturn
1234                OpFunctionEnd
1235 )";
1236 
1237   auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1238   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1239 }
1240 
TEST_F(CCPTest,FunctionDeclaration)1241 TEST_F(CCPTest, FunctionDeclaration) {
1242   // Make sure the pass works with a function declaration that is called.
1243   const std::string text = R"(OpCapability Addresses
1244 OpCapability Linkage
1245 OpCapability Kernel
1246 OpCapability Int8
1247 %1 = OpExtInstImport "OpenCL.std"
1248 OpMemoryModel Physical64 OpenCL
1249 OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
1250 OpExecutionMode %2 ContractionOff
1251 OpSource Unknown 0
1252 OpDecorate %3 LinkageAttributes "julia_error_7712" Import
1253 %void = OpTypeVoid
1254 %5 = OpTypeFunction %void
1255 %3 = OpFunction %void None %5
1256 OpFunctionEnd
1257 %2 = OpFunction %void None %5
1258 %6 = OpLabel
1259 %7 = OpFunctionCall %void %3
1260 OpReturn
1261 OpFunctionEnd
1262 )";
1263 
1264   SinglePassRunAndCheck<CCPPass>(text, text, false);
1265 }
1266 
1267 // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/4462.
1268 // The test was causing a lateral movement in the constant lattice, which was
1269 // not being detected as varying by CCP. In this test, FClamp is evaluated
1270 // twice.  On the first evaluation, if computes FClamp(0.5, 0.5, -1) which
1271 // returns -1.  On the second evaluation, it computes FClamp(0.5, 0.5, VARYING)
1272 // which returns 0.5.
1273 //
1274 // Both fold() computations are correct given the semantics of FClamp() but
1275 // this causes a lateral transition in the constant lattice which was not being
1276 // considered VARYING by CCP.
TEST_F(CCPTest,LateralLatticeTransition)1277 TEST_F(CCPTest, LateralLatticeTransition) {
1278   const std::string text = R"(OpCapability Shader
1279           %1 = OpExtInstImport "GLSL.std.450"
1280                OpMemoryModel Logical GLSL450
1281                OpEntryPoint Fragment %main "main" %gl_FragCoord %outColor
1282                OpExecutionMode %main OriginUpperLeft
1283                OpSource ESSL 310
1284                OpName %main "main"
1285                OpName %gl_FragCoord "gl_FragCoord"
1286                OpName %outColor "outColor"
1287                OpDecorate %gl_FragCoord BuiltIn FragCoord
1288                OpDecorate %outColor Location 0
1289        %void = OpTypeVoid
1290           %6 = OpTypeFunction %void
1291       %float = OpTypeFloat 32
1292   %float_0_5 = OpConstant %float 0.5
1293     %v4float = OpTypeVector %float 4
1294 %_ptr_Input_v4float = OpTypePointer Input %v4float
1295 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1296        %uint = OpTypeInt 32 0
1297      %uint_0 = OpConstant %uint 0
1298 %_ptr_Input_float = OpTypePointer Input %float
1299     %float_0 = OpConstant %float 0
1300        %bool = OpTypeBool
1301    %float_n1 = OpConstant %float -1
1302     %float_1 = OpConstant %float 1
1303 %_ptr_Output_v4float = OpTypePointer Output %v4float
1304    %outColor = OpVariable %_ptr_Output_v4float Output
1305 
1306 ; This constant is created during the first evaluation of the CompositeConstruct
1307 ; CHECK: [[new_constant:%\d+]] = OpConstantComposite %v4float %float_n1 %float_0_5 %float_0 %float_1
1308 
1309        %main = OpFunction %void None %6
1310          %19 = OpLabel
1311          %20 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0
1312          %21 = OpLoad %float %20
1313          %22 = OpFOrdLessThan %bool %21 %float_0
1314                OpSelectionMerge %23 None
1315                OpBranchConditional %22 %24 %25
1316          %24 = OpLabel
1317                OpBranch %23
1318          %25 = OpLabel
1319                OpBranch %26
1320          %26 = OpLabel
1321                OpBranch %23
1322          %23 = OpLabel
1323          %27 = OpPhi %float %float_n1 %24 %float_0_5 %26
1324          %28 = OpExtInst %float %1 FClamp %float_0_5 %float_0_5 %27
1325 
1326          ; On first evaluation, the result from FClamp will return 0.5.
1327          ; But on second evaluation, FClamp should return VARYING.  Check
1328          ; that CCP is not keeping the first result.
1329          ; CHECK-NOT: %29 = OpCompositeConstruct %v4float %float_0_5 %float_0_5 %float_0 %float_1
1330          %29 = OpCompositeConstruct %v4float %28 %float_0_5 %float_0 %float_1
1331 
1332          ; CHECK-NOT: OpCopyObject %v4float [[new_constant]]
1333          %42 = OpCopyObject %v4float %29
1334 
1335          ; CHECK-NOT: OpStore %outColor [[new_constant]]
1336                OpStore %outColor %42
1337 
1338                OpReturn
1339                OpFunctionEnd
1340 )";
1341 
1342   auto result = SinglePassRunAndMatch<CCPPass>(text, true);
1343   EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
1344 }
1345 
1346 }  // namespace
1347 }  // namespace opt
1348 }  // namespace spvtools
1349