1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 #include <vector>
18 
19 #include "test/opt/assembly_builder.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 AggressiveDCETest = PassTest<::testing::Test>;
28 
TEST_F(AggressiveDCETest,EliminateExtendedInst)29 TEST_F(AggressiveDCETest, EliminateExtendedInst) {
30   //  #version 140
31   //
32   //  in vec4 BaseColor;
33   //  in vec4 Dead;
34   //
35   //  void main()
36   //  {
37   //      vec4 v = BaseColor;
38   //      vec4 dv = sqrt(Dead);
39   //      gl_FragColor = v;
40   //  }
41 
42   const std::string predefs1 =
43       R"(OpCapability Shader
44 %1 = OpExtInstImport "GLSL.std.450"
45 OpMemoryModel Logical GLSL450
46 OpEntryPoint Fragment %main "main" %BaseColor %Dead %gl_FragColor
47 OpExecutionMode %main OriginUpperLeft
48 OpSource GLSL 140
49 )";
50 
51   const std::string names_before =
52       R"(OpName %main "main"
53 OpName %v "v"
54 OpName %BaseColor "BaseColor"
55 OpName %dv "dv"
56 OpName %Dead "Dead"
57 OpName %gl_FragColor "gl_FragColor"
58 )";
59 
60   const std::string names_after =
61       R"(OpName %main "main"
62 OpName %v "v"
63 OpName %BaseColor "BaseColor"
64 OpName %Dead "Dead"
65 OpName %gl_FragColor "gl_FragColor"
66 )";
67 
68   const std::string predefs2 =
69       R"(%void = OpTypeVoid
70 %9 = OpTypeFunction %void
71 %float = OpTypeFloat 32
72 %v4float = OpTypeVector %float 4
73 %_ptr_Function_v4float = OpTypePointer Function %v4float
74 %_ptr_Input_v4float = OpTypePointer Input %v4float
75 %BaseColor = OpVariable %_ptr_Input_v4float Input
76 %Dead = OpVariable %_ptr_Input_v4float Input
77 %_ptr_Output_v4float = OpTypePointer Output %v4float
78 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
79 )";
80 
81   const std::string func_before =
82       R"(%main = OpFunction %void None %9
83 %15 = OpLabel
84 %v = OpVariable %_ptr_Function_v4float Function
85 %dv = OpVariable %_ptr_Function_v4float Function
86 %16 = OpLoad %v4float %BaseColor
87 OpStore %v %16
88 %17 = OpLoad %v4float %Dead
89 %18 = OpExtInst %v4float %1 Sqrt %17
90 OpStore %dv %18
91 %19 = OpLoad %v4float %v
92 OpStore %gl_FragColor %19
93 OpReturn
94 OpFunctionEnd
95 )";
96 
97   const std::string func_after =
98       R"(%main = OpFunction %void None %9
99 %15 = OpLabel
100 %v = OpVariable %_ptr_Function_v4float Function
101 %16 = OpLoad %v4float %BaseColor
102 OpStore %v %16
103 %19 = OpLoad %v4float %v
104 OpStore %gl_FragColor %19
105 OpReturn
106 OpFunctionEnd
107 )";
108 
109   SinglePassRunAndCheck<AggressiveDCEPass>(
110       predefs1 + names_before + predefs2 + func_before,
111       predefs1 + names_after + predefs2 + func_after, true, true);
112 }
113 
TEST_F(AggressiveDCETest,NoEliminateFrexp)114 TEST_F(AggressiveDCETest, NoEliminateFrexp) {
115   // Note: SPIR-V hand-edited to utilize Frexp
116   //
117   // #version 450
118   //
119   // in vec4 BaseColor;
120   // in vec4 Dead;
121   // out vec4 Color;
122   // out ivec4 iv2;
123   //
124   // void main()
125   // {
126   //     vec4 v = BaseColor;
127   //     vec4 dv = frexp(Dead, iv2);
128   //     Color = v;
129   // }
130 
131   const std::string predefs1 =
132       R"(OpCapability Shader
133 %1 = OpExtInstImport "GLSL.std.450"
134 OpMemoryModel Logical GLSL450
135 OpEntryPoint Fragment %main "main" %BaseColor %Dead %iv2 %Color
136 OpExecutionMode %main OriginUpperLeft
137 OpSource GLSL 450
138 )";
139 
140   const std::string names_before =
141       R"(OpName %main "main"
142 OpName %v "v"
143 OpName %BaseColor "BaseColor"
144 OpName %dv "dv"
145 OpName %Dead "Dead"
146 OpName %iv2 "iv2"
147 OpName %ResType "ResType"
148 OpName %Color "Color"
149 )";
150 
151   const std::string names_after =
152       R"(OpName %main "main"
153 OpName %v "v"
154 OpName %BaseColor "BaseColor"
155 OpName %Dead "Dead"
156 OpName %iv2 "iv2"
157 OpName %Color "Color"
158 )";
159 
160   const std::string predefs2_before =
161       R"(%void = OpTypeVoid
162 %11 = OpTypeFunction %void
163 %float = OpTypeFloat 32
164 %v4float = OpTypeVector %float 4
165 %_ptr_Function_v4float = OpTypePointer Function %v4float
166 %_ptr_Input_v4float = OpTypePointer Input %v4float
167 %BaseColor = OpVariable %_ptr_Input_v4float Input
168 %Dead = OpVariable %_ptr_Input_v4float Input
169 %int = OpTypeInt 32 1
170 %v4int = OpTypeVector %int 4
171 %_ptr_Output_v4int = OpTypePointer Output %v4int
172 %iv2 = OpVariable %_ptr_Output_v4int Output
173 %ResType = OpTypeStruct %v4float %v4int
174 %_ptr_Output_v4float = OpTypePointer Output %v4float
175 %Color = OpVariable %_ptr_Output_v4float Output
176 )";
177 
178   const std::string predefs2_after =
179       R"(%void = OpTypeVoid
180 %11 = OpTypeFunction %void
181 %float = OpTypeFloat 32
182 %v4float = OpTypeVector %float 4
183 %_ptr_Function_v4float = OpTypePointer Function %v4float
184 %_ptr_Input_v4float = OpTypePointer Input %v4float
185 %BaseColor = OpVariable %_ptr_Input_v4float Input
186 %Dead = OpVariable %_ptr_Input_v4float Input
187 %int = OpTypeInt 32 1
188 %v4int = OpTypeVector %int 4
189 %_ptr_Output_v4int = OpTypePointer Output %v4int
190 %iv2 = OpVariable %_ptr_Output_v4int Output
191 %_ptr_Output_v4float = OpTypePointer Output %v4float
192 %Color = OpVariable %_ptr_Output_v4float Output
193 )";
194 
195   const std::string func_before =
196       R"(%main = OpFunction %void None %11
197 %20 = OpLabel
198 %v = OpVariable %_ptr_Function_v4float Function
199 %dv = OpVariable %_ptr_Function_v4float Function
200 %21 = OpLoad %v4float %BaseColor
201 OpStore %v %21
202 %22 = OpLoad %v4float %Dead
203 %23 = OpExtInst %v4float %1 Frexp %22 %iv2
204 OpStore %dv %23
205 %24 = OpLoad %v4float %v
206 OpStore %Color %24
207 OpReturn
208 OpFunctionEnd
209 )";
210 
211   const std::string func_after =
212       R"(%main = OpFunction %void None %11
213 %20 = OpLabel
214 %v = OpVariable %_ptr_Function_v4float Function
215 %21 = OpLoad %v4float %BaseColor
216 OpStore %v %21
217 %22 = OpLoad %v4float %Dead
218 %23 = OpExtInst %v4float %1 Frexp %22 %iv2
219 %24 = OpLoad %v4float %v
220 OpStore %Color %24
221 OpReturn
222 OpFunctionEnd
223 )";
224 
225   SinglePassRunAndCheck<AggressiveDCEPass>(
226       predefs1 + names_before + predefs2_before + func_before,
227       predefs1 + names_after + predefs2_after + func_after, true, true);
228 }
229 
TEST_F(AggressiveDCETest,EliminateDecorate)230 TEST_F(AggressiveDCETest, EliminateDecorate) {
231   // Note: The SPIR-V was hand-edited to add the OpDecorate
232   //
233   // #version 140
234   //
235   // in vec4 BaseColor;
236   // in vec4 Dead;
237   //
238   // void main()
239   // {
240   //     vec4 v = BaseColor;
241   //     vec4 dv = Dead * 0.5;
242   //     gl_FragColor = v;
243   // }
244 
245   const std::string predefs1 =
246       R"(OpCapability Shader
247 %1 = OpExtInstImport "GLSL.std.450"
248 OpMemoryModel Logical GLSL450
249 OpEntryPoint Fragment %main "main" %BaseColor %Dead %gl_FragColor
250 OpExecutionMode %main OriginUpperLeft
251 OpSource GLSL 140
252 )";
253 
254   const std::string names_before =
255       R"(OpName %main "main"
256 OpName %v "v"
257 OpName %BaseColor "BaseColor"
258 OpName %dv "dv"
259 OpName %Dead "Dead"
260 OpName %gl_FragColor "gl_FragColor"
261 OpDecorate %8 RelaxedPrecision
262 )";
263 
264   const std::string names_after =
265       R"(OpName %main "main"
266 OpName %v "v"
267 OpName %BaseColor "BaseColor"
268 OpName %Dead "Dead"
269 OpName %gl_FragColor "gl_FragColor"
270 )";
271 
272   const std::string predefs2_before =
273       R"(%void = OpTypeVoid
274 %10 = OpTypeFunction %void
275 %float = OpTypeFloat 32
276 %v4float = OpTypeVector %float 4
277 %_ptr_Function_v4float = OpTypePointer Function %v4float
278 %_ptr_Input_v4float = OpTypePointer Input %v4float
279 %BaseColor = OpVariable %_ptr_Input_v4float Input
280 %Dead = OpVariable %_ptr_Input_v4float Input
281 %float_0_5 = OpConstant %float 0.5
282 %_ptr_Output_v4float = OpTypePointer Output %v4float
283 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
284 )";
285 
286   const std::string predefs2_after =
287       R"(%void = OpTypeVoid
288 %10 = OpTypeFunction %void
289 %float = OpTypeFloat 32
290 %v4float = OpTypeVector %float 4
291 %_ptr_Function_v4float = OpTypePointer Function %v4float
292 %_ptr_Input_v4float = OpTypePointer Input %v4float
293 %BaseColor = OpVariable %_ptr_Input_v4float Input
294 %Dead = OpVariable %_ptr_Input_v4float Input
295 %_ptr_Output_v4float = OpTypePointer Output %v4float
296 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
297 )";
298 
299   const std::string func_before =
300       R"(%main = OpFunction %void None %10
301 %17 = OpLabel
302 %v = OpVariable %_ptr_Function_v4float Function
303 %dv = OpVariable %_ptr_Function_v4float Function
304 %18 = OpLoad %v4float %BaseColor
305 OpStore %v %18
306 %19 = OpLoad %v4float %Dead
307 %8 = OpVectorTimesScalar %v4float %19 %float_0_5
308 OpStore %dv %8
309 %20 = OpLoad %v4float %v
310 OpStore %gl_FragColor %20
311 OpReturn
312 OpFunctionEnd
313 )";
314 
315   const std::string func_after =
316       R"(%main = OpFunction %void None %10
317 %17 = OpLabel
318 %v = OpVariable %_ptr_Function_v4float Function
319 %18 = OpLoad %v4float %BaseColor
320 OpStore %v %18
321 %20 = OpLoad %v4float %v
322 OpStore %gl_FragColor %20
323 OpReturn
324 OpFunctionEnd
325 )";
326 
327   SinglePassRunAndCheck<AggressiveDCEPass>(
328       predefs1 + names_before + predefs2_before + func_before,
329       predefs1 + names_after + predefs2_after + func_after, true, true);
330 }
331 
TEST_F(AggressiveDCETest,Simple)332 TEST_F(AggressiveDCETest, Simple) {
333   //  #version 140
334   //
335   //  in vec4 BaseColor;
336   //  in vec4 Dead;
337   //
338   //  void main()
339   //  {
340   //      vec4 v = BaseColor;
341   //      vec4 dv = Dead;
342   //      gl_FragColor = v;
343   //  }
344 
345   const std::string predefs1 =
346       R"(OpCapability Shader
347 %1 = OpExtInstImport "GLSL.std.450"
348 OpMemoryModel Logical GLSL450
349 OpEntryPoint Fragment %main "main" %BaseColor %Dead %gl_FragColor
350 OpExecutionMode %main OriginUpperLeft
351 OpSource GLSL 140
352 )";
353 
354   const std::string names_before =
355       R"(OpName %main "main"
356 OpName %v "v"
357 OpName %BaseColor "BaseColor"
358 OpName %dv "dv"
359 OpName %Dead "Dead"
360 OpName %gl_FragColor "gl_FragColor"
361 )";
362 
363   const std::string names_after =
364       R"(OpName %main "main"
365 OpName %v "v"
366 OpName %BaseColor "BaseColor"
367 OpName %Dead "Dead"
368 OpName %gl_FragColor "gl_FragColor"
369 )";
370 
371   const std::string predefs2 =
372       R"(%void = OpTypeVoid
373 %9 = OpTypeFunction %void
374 %float = OpTypeFloat 32
375 %v4float = OpTypeVector %float 4
376 %_ptr_Function_v4float = OpTypePointer Function %v4float
377 %_ptr_Input_v4float = OpTypePointer Input %v4float
378 %BaseColor = OpVariable %_ptr_Input_v4float Input
379 %Dead = OpVariable %_ptr_Input_v4float Input
380 %_ptr_Output_v4float = OpTypePointer Output %v4float
381 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
382 )";
383 
384   const std::string func_before =
385       R"(%main = OpFunction %void None %9
386 %15 = OpLabel
387 %v = OpVariable %_ptr_Function_v4float Function
388 %dv = OpVariable %_ptr_Function_v4float Function
389 %16 = OpLoad %v4float %BaseColor
390 OpStore %v %16
391 %17 = OpLoad %v4float %Dead
392 OpStore %dv %17
393 %18 = OpLoad %v4float %v
394 OpStore %gl_FragColor %18
395 OpReturn
396 OpFunctionEnd
397 )";
398 
399   const std::string func_after =
400       R"(%main = OpFunction %void None %9
401 %15 = OpLabel
402 %v = OpVariable %_ptr_Function_v4float Function
403 %16 = OpLoad %v4float %BaseColor
404 OpStore %v %16
405 %18 = OpLoad %v4float %v
406 OpStore %gl_FragColor %18
407 OpReturn
408 OpFunctionEnd
409 )";
410 
411   SinglePassRunAndCheck<AggressiveDCEPass>(
412       predefs1 + names_before + predefs2 + func_before,
413       predefs1 + names_after + predefs2 + func_after, true, true);
414 }
415 
TEST_F(AggressiveDCETest,OptWhitelistExtension)416 TEST_F(AggressiveDCETest, OptWhitelistExtension) {
417   //  #version 140
418   //
419   //  in vec4 BaseColor;
420   //  in vec4 Dead;
421   //
422   //  void main()
423   //  {
424   //      vec4 v = BaseColor;
425   //      vec4 dv = Dead;
426   //      gl_FragColor = v;
427   //  }
428 
429   const std::string predefs1 =
430       R"(OpCapability Shader
431 OpExtension "SPV_AMD_gpu_shader_int16"
432 %1 = OpExtInstImport "GLSL.std.450"
433 OpMemoryModel Logical GLSL450
434 OpEntryPoint Fragment %main "main" %BaseColor %Dead %gl_FragColor
435 OpExecutionMode %main OriginUpperLeft
436 OpSource GLSL 140
437 )";
438 
439   const std::string names_before =
440       R"(OpName %main "main"
441 OpName %v "v"
442 OpName %BaseColor "BaseColor"
443 OpName %dv "dv"
444 OpName %Dead "Dead"
445 OpName %gl_FragColor "gl_FragColor"
446 )";
447 
448   const std::string names_after =
449       R"(OpName %main "main"
450 OpName %v "v"
451 OpName %BaseColor "BaseColor"
452 OpName %Dead "Dead"
453 OpName %gl_FragColor "gl_FragColor"
454 )";
455 
456   const std::string predefs2 =
457       R"(%void = OpTypeVoid
458 %9 = OpTypeFunction %void
459 %float = OpTypeFloat 32
460 %v4float = OpTypeVector %float 4
461 %_ptr_Function_v4float = OpTypePointer Function %v4float
462 %_ptr_Input_v4float = OpTypePointer Input %v4float
463 %BaseColor = OpVariable %_ptr_Input_v4float Input
464 %Dead = OpVariable %_ptr_Input_v4float Input
465 %_ptr_Output_v4float = OpTypePointer Output %v4float
466 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
467 )";
468 
469   const std::string func_before =
470       R"(%main = OpFunction %void None %9
471 %15 = OpLabel
472 %v = OpVariable %_ptr_Function_v4float Function
473 %dv = OpVariable %_ptr_Function_v4float Function
474 %16 = OpLoad %v4float %BaseColor
475 OpStore %v %16
476 %17 = OpLoad %v4float %Dead
477 OpStore %dv %17
478 %18 = OpLoad %v4float %v
479 OpStore %gl_FragColor %18
480 OpReturn
481 OpFunctionEnd
482 )";
483 
484   const std::string func_after =
485       R"(%main = OpFunction %void None %9
486 %15 = OpLabel
487 %v = OpVariable %_ptr_Function_v4float Function
488 %16 = OpLoad %v4float %BaseColor
489 OpStore %v %16
490 %18 = OpLoad %v4float %v
491 OpStore %gl_FragColor %18
492 OpReturn
493 OpFunctionEnd
494 )";
495 
496   SinglePassRunAndCheck<AggressiveDCEPass>(
497       predefs1 + names_before + predefs2 + func_before,
498       predefs1 + names_after + predefs2 + func_after, true, true);
499 }
500 
TEST_F(AggressiveDCETest,NoOptBlacklistExtension)501 TEST_F(AggressiveDCETest, NoOptBlacklistExtension) {
502   //  #version 140
503   //
504   //  in vec4 BaseColor;
505   //  in vec4 Dead;
506   //
507   //  void main()
508   //  {
509   //      vec4 v = BaseColor;
510   //      vec4 dv = Dead;
511   //      gl_FragColor = v;
512   //  }
513 
514   const std::string assembly =
515       R"(OpCapability Shader
516 OpExtension "SPV_KHR_variable_pointers"
517 %1 = OpExtInstImport "GLSL.std.450"
518 OpMemoryModel Logical GLSL450
519 OpEntryPoint Fragment %main "main" %BaseColor %Dead %gl_FragColor
520 OpExecutionMode %main OriginUpperLeft
521 OpSource GLSL 140
522 OpName %main "main"
523 OpName %v "v"
524 OpName %BaseColor "BaseColor"
525 OpName %dv "dv"
526 OpName %Dead "Dead"
527 OpName %gl_FragColor "gl_FragColor"
528 %void = OpTypeVoid
529 %9 = OpTypeFunction %void
530 %float = OpTypeFloat 32
531 %v4float = OpTypeVector %float 4
532 %_ptr_Function_v4float = OpTypePointer Function %v4float
533 %_ptr_Input_v4float = OpTypePointer Input %v4float
534 %BaseColor = OpVariable %_ptr_Input_v4float Input
535 %Dead = OpVariable %_ptr_Input_v4float Input
536 %_ptr_Output_v4float = OpTypePointer Output %v4float
537 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
538 %main = OpFunction %void None %9
539 %15 = OpLabel
540 %v = OpVariable %_ptr_Function_v4float Function
541 %dv = OpVariable %_ptr_Function_v4float Function
542 %16 = OpLoad %v4float %BaseColor
543 OpStore %v %16
544 %17 = OpLoad %v4float %Dead
545 OpStore %dv %17
546 %18 = OpLoad %v4float %v
547 OpStore %gl_FragColor %18
548 OpReturn
549 OpFunctionEnd
550 )";
551 
552   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
553 }
554 
TEST_F(AggressiveDCETest,ElimWithCall)555 TEST_F(AggressiveDCETest, ElimWithCall) {
556   // This demonstrates that "dead" function calls are not eliminated.
557   // Also demonstrates that DCE will happen in presence of function call.
558   // #version 140
559   // in vec4 i1;
560   // in vec4 i2;
561   //
562   // void nothing(vec4 v)
563   // {
564   // }
565   //
566   // void main()
567   // {
568   //     vec4 v1 = i1;
569   //     vec4 v2 = i2;
570   //     nothing(v1);
571   //     gl_FragColor = vec4(0.0);
572   // }
573 
574   const std::string defs_before =
575       R"( OpCapability Shader
576 %1 = OpExtInstImport "GLSL.std.450"
577 OpMemoryModel Logical GLSL450
578 OpEntryPoint Fragment %main "main" %i1 %i2 %gl_FragColor
579 OpExecutionMode %main OriginUpperLeft
580 OpSource GLSL 140
581 OpName %main "main"
582 OpName %nothing_vf4_ "nothing(vf4;"
583 OpName %v "v"
584 OpName %v1 "v1"
585 OpName %i1 "i1"
586 OpName %v2 "v2"
587 OpName %i2 "i2"
588 OpName %param "param"
589 OpName %gl_FragColor "gl_FragColor"
590 %void = OpTypeVoid
591 %12 = OpTypeFunction %void
592 %float = OpTypeFloat 32
593 %v4float = OpTypeVector %float 4
594 %_ptr_Function_v4float = OpTypePointer Function %v4float
595 %16 = OpTypeFunction %void %_ptr_Function_v4float
596 %_ptr_Input_v4float = OpTypePointer Input %v4float
597 %i1 = OpVariable %_ptr_Input_v4float Input
598 %i2 = OpVariable %_ptr_Input_v4float Input
599 %_ptr_Output_v4float = OpTypePointer Output %v4float
600 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
601 %float_0 = OpConstant %float 0
602 %20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
603 )";
604 
605   const std::string defs_after =
606       R"(OpCapability Shader
607 %1 = OpExtInstImport "GLSL.std.450"
608 OpMemoryModel Logical GLSL450
609 OpEntryPoint Fragment %main "main" %i1 %i2 %gl_FragColor
610 OpExecutionMode %main OriginUpperLeft
611 OpSource GLSL 140
612 OpName %main "main"
613 OpName %nothing_vf4_ "nothing(vf4;"
614 OpName %v "v"
615 OpName %v1 "v1"
616 OpName %i1 "i1"
617 OpName %i2 "i2"
618 OpName %param "param"
619 OpName %gl_FragColor "gl_FragColor"
620 %void = OpTypeVoid
621 %12 = OpTypeFunction %void
622 %float = OpTypeFloat 32
623 %v4float = OpTypeVector %float 4
624 %_ptr_Function_v4float = OpTypePointer Function %v4float
625 %16 = OpTypeFunction %void %_ptr_Function_v4float
626 %_ptr_Input_v4float = OpTypePointer Input %v4float
627 %i1 = OpVariable %_ptr_Input_v4float Input
628 %i2 = OpVariable %_ptr_Input_v4float Input
629 %_ptr_Output_v4float = OpTypePointer Output %v4float
630 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
631 %float_0 = OpConstant %float 0
632 %20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
633 )";
634 
635   const std::string func_before =
636       R"(%main = OpFunction %void None %12
637 %21 = OpLabel
638 %v1 = OpVariable %_ptr_Function_v4float Function
639 %v2 = OpVariable %_ptr_Function_v4float Function
640 %param = OpVariable %_ptr_Function_v4float Function
641 %22 = OpLoad %v4float %i1
642 OpStore %v1 %22
643 %23 = OpLoad %v4float %i2
644 OpStore %v2 %23
645 %24 = OpLoad %v4float %v1
646 OpStore %param %24
647 %25 = OpFunctionCall %void %nothing_vf4_ %param
648 OpStore %gl_FragColor %20
649 OpReturn
650 OpFunctionEnd
651 %nothing_vf4_ = OpFunction %void None %16
652 %v = OpFunctionParameter %_ptr_Function_v4float
653 %26 = OpLabel
654 OpReturn
655 OpFunctionEnd
656 )";
657 
658   const std::string func_after =
659       R"(%main = OpFunction %void None %12
660 %21 = OpLabel
661 %v1 = OpVariable %_ptr_Function_v4float Function
662 %param = OpVariable %_ptr_Function_v4float Function
663 %22 = OpLoad %v4float %i1
664 OpStore %v1 %22
665 %24 = OpLoad %v4float %v1
666 OpStore %param %24
667 %25 = OpFunctionCall %void %nothing_vf4_ %param
668 OpStore %gl_FragColor %20
669 OpReturn
670 OpFunctionEnd
671 %nothing_vf4_ = OpFunction %void None %16
672 %v = OpFunctionParameter %_ptr_Function_v4float
673 %26 = OpLabel
674 OpReturn
675 OpFunctionEnd
676 )";
677 
678   SinglePassRunAndCheck<AggressiveDCEPass>(defs_before + func_before,
679                                            defs_after + func_after, true, true);
680 }
681 
TEST_F(AggressiveDCETest,NoParamElim)682 TEST_F(AggressiveDCETest, NoParamElim) {
683   // This demonstrates that unused parameters are not eliminated, but
684   // dead uses of them are.
685   // #version 140
686   //
687   // in vec4 BaseColor;
688   //
689   // vec4 foo(vec4 v1, vec4 v2)
690   // {
691   //     vec4 t = -v1;
692   //     return v2;
693   // }
694   //
695   // void main()
696   // {
697   //     vec4 dead;
698   //     gl_FragColor = foo(dead, BaseColor);
699   // }
700 
701   const std::string defs_before =
702       R"(OpCapability Shader
703 %1 = OpExtInstImport "GLSL.std.450"
704 OpMemoryModel Logical GLSL450
705 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
706 OpExecutionMode %main OriginUpperLeft
707 OpSource GLSL 140
708 OpName %main "main"
709 OpName %foo_vf4_vf4_ "foo(vf4;vf4;"
710 OpName %v1 "v1"
711 OpName %v2 "v2"
712 OpName %t "t"
713 OpName %gl_FragColor "gl_FragColor"
714 OpName %dead "dead"
715 OpName %BaseColor "BaseColor"
716 OpName %param "param"
717 OpName %param_0 "param"
718 %void = OpTypeVoid
719 %13 = OpTypeFunction %void
720 %float = OpTypeFloat 32
721 %v4float = OpTypeVector %float 4
722 %_ptr_Function_v4float = OpTypePointer Function %v4float
723 %17 = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
724 %_ptr_Output_v4float = OpTypePointer Output %v4float
725 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
726 %_ptr_Input_v4float = OpTypePointer Input %v4float
727 %BaseColor = OpVariable %_ptr_Input_v4float Input
728 %main = OpFunction %void None %13
729 %20 = OpLabel
730 %dead = OpVariable %_ptr_Function_v4float Function
731 %param = OpVariable %_ptr_Function_v4float Function
732 %param_0 = OpVariable %_ptr_Function_v4float Function
733 %21 = OpLoad %v4float %dead
734 OpStore %param %21
735 %22 = OpLoad %v4float %BaseColor
736 OpStore %param_0 %22
737 %23 = OpFunctionCall %v4float %foo_vf4_vf4_ %param %param_0
738 OpStore %gl_FragColor %23
739 OpReturn
740 OpFunctionEnd
741 )";
742 
743   const std::string defs_after =
744       R"(OpCapability Shader
745 %1 = OpExtInstImport "GLSL.std.450"
746 OpMemoryModel Logical GLSL450
747 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
748 OpExecutionMode %main OriginUpperLeft
749 OpSource GLSL 140
750 OpName %main "main"
751 OpName %foo_vf4_vf4_ "foo(vf4;vf4;"
752 OpName %v1 "v1"
753 OpName %v2 "v2"
754 OpName %gl_FragColor "gl_FragColor"
755 OpName %dead "dead"
756 OpName %BaseColor "BaseColor"
757 OpName %param "param"
758 OpName %param_0 "param"
759 %void = OpTypeVoid
760 %13 = OpTypeFunction %void
761 %float = OpTypeFloat 32
762 %v4float = OpTypeVector %float 4
763 %_ptr_Function_v4float = OpTypePointer Function %v4float
764 %17 = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
765 %_ptr_Output_v4float = OpTypePointer Output %v4float
766 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
767 %_ptr_Input_v4float = OpTypePointer Input %v4float
768 %BaseColor = OpVariable %_ptr_Input_v4float Input
769 %main = OpFunction %void None %13
770 %20 = OpLabel
771 %dead = OpVariable %_ptr_Function_v4float Function
772 %param = OpVariable %_ptr_Function_v4float Function
773 %param_0 = OpVariable %_ptr_Function_v4float Function
774 %21 = OpLoad %v4float %dead
775 OpStore %param %21
776 %22 = OpLoad %v4float %BaseColor
777 OpStore %param_0 %22
778 %23 = OpFunctionCall %v4float %foo_vf4_vf4_ %param %param_0
779 OpStore %gl_FragColor %23
780 OpReturn
781 OpFunctionEnd
782 )";
783 
784   const std::string func_before =
785       R"(%foo_vf4_vf4_ = OpFunction %v4float None %17
786 %v1 = OpFunctionParameter %_ptr_Function_v4float
787 %v2 = OpFunctionParameter %_ptr_Function_v4float
788 %24 = OpLabel
789 %t = OpVariable %_ptr_Function_v4float Function
790 %25 = OpLoad %v4float %v1
791 %26 = OpFNegate %v4float %25
792 OpStore %t %26
793 %27 = OpLoad %v4float %v2
794 OpReturnValue %27
795 OpFunctionEnd
796 )";
797 
798   const std::string func_after =
799       R"(%foo_vf4_vf4_ = OpFunction %v4float None %17
800 %v1 = OpFunctionParameter %_ptr_Function_v4float
801 %v2 = OpFunctionParameter %_ptr_Function_v4float
802 %24 = OpLabel
803 %27 = OpLoad %v4float %v2
804 OpReturnValue %27
805 OpFunctionEnd
806 )";
807 
808   SinglePassRunAndCheck<AggressiveDCEPass>(defs_before + func_before,
809                                            defs_after + func_after, true, true);
810 }
811 
TEST_F(AggressiveDCETest,ElimOpaque)812 TEST_F(AggressiveDCETest, ElimOpaque) {
813   // SPIR-V not representable from GLSL; not generatable from HLSL
814   // for the moment.
815 
816   const std::string defs_before =
817       R"(OpCapability Shader
818 %1 = OpExtInstImport "GLSL.std.450"
819 OpMemoryModel Logical GLSL450
820 OpEntryPoint Fragment %main "main" %outColor %texCoords
821 OpExecutionMode %main OriginUpperLeft
822 OpSource GLSL 140
823 OpName %main "main"
824 OpName %S_t "S_t"
825 OpMemberName %S_t 0 "v0"
826 OpMemberName %S_t 1 "v1"
827 OpMemberName %S_t 2 "smp"
828 OpName %outColor "outColor"
829 OpName %sampler15 "sampler15"
830 OpName %s0 "s0"
831 OpName %texCoords "texCoords"
832 OpDecorate %sampler15 DescriptorSet 0
833 %void = OpTypeVoid
834 %9 = OpTypeFunction %void
835 %float = OpTypeFloat 32
836 %v2float = OpTypeVector %float 2
837 %v4float = OpTypeVector %float 4
838 %_ptr_Output_v4float = OpTypePointer Output %v4float
839 %outColor = OpVariable %_ptr_Output_v4float Output
840 %14 = OpTypeImage %float 2D 0 0 0 1 Unknown
841 %15 = OpTypeSampledImage %14
842 %S_t = OpTypeStruct %v2float %v2float %15
843 %_ptr_Function_S_t = OpTypePointer Function %S_t
844 %17 = OpTypeFunction %void %_ptr_Function_S_t
845 %_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
846 %_ptr_Function_15 = OpTypePointer Function %15
847 %sampler15 = OpVariable %_ptr_UniformConstant_15 UniformConstant
848 %int = OpTypeInt 32 1
849 %int_0 = OpConstant %int 0
850 %int_2 = OpConstant %int 2
851 %_ptr_Function_v2float = OpTypePointer Function %v2float
852 %_ptr_Input_v2float = OpTypePointer Input %v2float
853 %texCoords = OpVariable %_ptr_Input_v2float Input
854 )";
855 
856   const std::string defs_after =
857       R"(OpCapability Shader
858 %1 = OpExtInstImport "GLSL.std.450"
859 OpMemoryModel Logical GLSL450
860 OpEntryPoint Fragment %main "main" %outColor %texCoords
861 OpExecutionMode %main OriginUpperLeft
862 OpSource GLSL 140
863 OpName %main "main"
864 OpName %outColor "outColor"
865 OpName %sampler15 "sampler15"
866 OpName %texCoords "texCoords"
867 OpDecorate %sampler15 DescriptorSet 0
868 %void = OpTypeVoid
869 %9 = OpTypeFunction %void
870 %float = OpTypeFloat 32
871 %v2float = OpTypeVector %float 2
872 %v4float = OpTypeVector %float 4
873 %_ptr_Output_v4float = OpTypePointer Output %v4float
874 %outColor = OpVariable %_ptr_Output_v4float Output
875 %14 = OpTypeImage %float 2D 0 0 0 1 Unknown
876 %15 = OpTypeSampledImage %14
877 %_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
878 %sampler15 = OpVariable %_ptr_UniformConstant_15 UniformConstant
879 %_ptr_Input_v2float = OpTypePointer Input %v2float
880 %texCoords = OpVariable %_ptr_Input_v2float Input
881 )";
882 
883   const std::string func_before =
884       R"(%main = OpFunction %void None %9
885 %25 = OpLabel
886 %s0 = OpVariable %_ptr_Function_S_t Function
887 %26 = OpLoad %v2float %texCoords
888 %27 = OpLoad %S_t %s0
889 %28 = OpCompositeInsert %S_t %26 %27 0
890 %29 = OpLoad %15 %sampler15
891 %30 = OpCompositeInsert %S_t %29 %28 2
892 OpStore %s0 %30
893 %31 = OpImageSampleImplicitLod %v4float %29 %26
894 OpStore %outColor %31
895 OpReturn
896 OpFunctionEnd
897 )";
898 
899   const std::string func_after =
900       R"(%main = OpFunction %void None %9
901 %25 = OpLabel
902 %26 = OpLoad %v2float %texCoords
903 %29 = OpLoad %15 %sampler15
904 %31 = OpImageSampleImplicitLod %v4float %29 %26
905 OpStore %outColor %31
906 OpReturn
907 OpFunctionEnd
908 )";
909 
910   SinglePassRunAndCheck<AggressiveDCEPass>(defs_before + func_before,
911                                            defs_after + func_after, true, true);
912 }
913 
TEST_F(AggressiveDCETest,NoParamStoreElim)914 TEST_F(AggressiveDCETest, NoParamStoreElim) {
915   // Should not eliminate stores to params
916   //
917   // #version 450
918   //
919   // layout(location = 0) in vec4 BaseColor;
920   // layout(location = 0) out vec4 OutColor;
921   //
922   // void foo(in vec4 v1, out vec4 v2)
923   // {
924   //     v2 = -v1;
925   // }
926   //
927   // void main()
928   // {
929   //     foo(BaseColor, OutColor);
930   // }
931 
932   const std::string assembly =
933       R"(OpCapability Shader
934 %1 = OpExtInstImport "GLSL.std.450"
935 OpMemoryModel Logical GLSL450
936 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
937 OpExecutionMode %main OriginUpperLeft
938 OpSource GLSL 450
939 OpName %main "main"
940 OpName %foo_vf4_vf4_ "foo(vf4;vf4;"
941 OpName %v1 "v1"
942 OpName %v2 "v2"
943 OpName %BaseColor "BaseColor"
944 OpName %OutColor "OutColor"
945 OpName %param "param"
946 OpName %param_0 "param"
947 OpDecorate %BaseColor Location 0
948 OpDecorate %OutColor Location 0
949 %void = OpTypeVoid
950 %11 = OpTypeFunction %void
951 %float = OpTypeFloat 32
952 %v4float = OpTypeVector %float 4
953 %_ptr_Function_v4float = OpTypePointer Function %v4float
954 %15 = OpTypeFunction %void %_ptr_Function_v4float %_ptr_Function_v4float
955 %_ptr_Input_v4float = OpTypePointer Input %v4float
956 %BaseColor = OpVariable %_ptr_Input_v4float Input
957 %_ptr_Output_v4float = OpTypePointer Output %v4float
958 %OutColor = OpVariable %_ptr_Output_v4float Output
959 %main = OpFunction %void None %11
960 %18 = OpLabel
961 %param = OpVariable %_ptr_Function_v4float Function
962 %param_0 = OpVariable %_ptr_Function_v4float Function
963 %19 = OpLoad %v4float %BaseColor
964 OpStore %param %19
965 %20 = OpFunctionCall %void %foo_vf4_vf4_ %param %param_0
966 %21 = OpLoad %v4float %param_0
967 OpStore %OutColor %21
968 OpReturn
969 OpFunctionEnd
970 %foo_vf4_vf4_ = OpFunction %void None %15
971 %v1 = OpFunctionParameter %_ptr_Function_v4float
972 %v2 = OpFunctionParameter %_ptr_Function_v4float
973 %22 = OpLabel
974 %23 = OpLoad %v4float %v1
975 %24 = OpFNegate %v4float %23
976 OpStore %v2 %24
977 OpReturn
978 OpFunctionEnd
979 )";
980 
981   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
982 }
983 
TEST_F(AggressiveDCETest,PrivateStoreElimInEntryNoCalls)984 TEST_F(AggressiveDCETest, PrivateStoreElimInEntryNoCalls) {
985   // Eliminate stores to private in entry point with no calls
986   // Note: Not legal GLSL
987   //
988   // layout(location = 0) in vec4 BaseColor;
989   // layout(location = 1) in vec4 Dead;
990   // layout(location = 0) out vec4 OutColor;
991   //
992   // private vec4 dv;
993   //
994   // void main()
995   // {
996   //     vec4 v = BaseColor;
997   //     dv = Dead;
998   //     OutColor = v;
999   // }
1000 
1001   const std::string predefs_before =
1002       R"(OpCapability Shader
1003 %1 = OpExtInstImport "GLSL.std.450"
1004 OpMemoryModel Logical GLSL450
1005 OpEntryPoint Fragment %main "main" %BaseColor %Dead %OutColor
1006 OpExecutionMode %main OriginUpperLeft
1007 OpSource GLSL 450
1008 OpName %main "main"
1009 OpName %v "v"
1010 OpName %BaseColor "BaseColor"
1011 OpName %dv "dv"
1012 OpName %Dead "Dead"
1013 OpName %OutColor "OutColor"
1014 OpDecorate %BaseColor Location 0
1015 OpDecorate %Dead Location 1
1016 OpDecorate %OutColor Location 0
1017 %void = OpTypeVoid
1018 %9 = OpTypeFunction %void
1019 %float = OpTypeFloat 32
1020 %v4float = OpTypeVector %float 4
1021 %_ptr_Function_v4float = OpTypePointer Function %v4float
1022 %_ptr_Private_v4float = OpTypePointer Private %v4float
1023 %_ptr_Input_v4float = OpTypePointer Input %v4float
1024 %BaseColor = OpVariable %_ptr_Input_v4float Input
1025 %Dead = OpVariable %_ptr_Input_v4float Input
1026 %_ptr_Output_v4float = OpTypePointer Output %v4float
1027 %dv = OpVariable %_ptr_Private_v4float Private
1028 %OutColor = OpVariable %_ptr_Output_v4float Output
1029 )";
1030 
1031   const std::string predefs_after =
1032       R"(OpCapability Shader
1033 %1 = OpExtInstImport "GLSL.std.450"
1034 OpMemoryModel Logical GLSL450
1035 OpEntryPoint Fragment %main "main" %BaseColor %Dead %OutColor
1036 OpExecutionMode %main OriginUpperLeft
1037 OpSource GLSL 450
1038 OpName %main "main"
1039 OpName %v "v"
1040 OpName %BaseColor "BaseColor"
1041 OpName %Dead "Dead"
1042 OpName %OutColor "OutColor"
1043 OpDecorate %BaseColor Location 0
1044 OpDecorate %Dead Location 1
1045 OpDecorate %OutColor Location 0
1046 %void = OpTypeVoid
1047 %9 = OpTypeFunction %void
1048 %float = OpTypeFloat 32
1049 %v4float = OpTypeVector %float 4
1050 %_ptr_Function_v4float = OpTypePointer Function %v4float
1051 %_ptr_Input_v4float = OpTypePointer Input %v4float
1052 %BaseColor = OpVariable %_ptr_Input_v4float Input
1053 %Dead = OpVariable %_ptr_Input_v4float Input
1054 %_ptr_Output_v4float = OpTypePointer Output %v4float
1055 %OutColor = OpVariable %_ptr_Output_v4float Output
1056 )";
1057 
1058   const std::string main_before =
1059       R"(%main = OpFunction %void None %9
1060 %16 = OpLabel
1061 %v = OpVariable %_ptr_Function_v4float Function
1062 %17 = OpLoad %v4float %BaseColor
1063 OpStore %v %17
1064 %18 = OpLoad %v4float %Dead
1065 OpStore %dv %18
1066 %19 = OpLoad %v4float %v
1067 %20 = OpFNegate %v4float %19
1068 OpStore %OutColor %20
1069 OpReturn
1070 OpFunctionEnd
1071 )";
1072 
1073   const std::string main_after =
1074       R"(%main = OpFunction %void None %9
1075 %16 = OpLabel
1076 %v = OpVariable %_ptr_Function_v4float Function
1077 %17 = OpLoad %v4float %BaseColor
1078 OpStore %v %17
1079 %19 = OpLoad %v4float %v
1080 %20 = OpFNegate %v4float %19
1081 OpStore %OutColor %20
1082 OpReturn
1083 OpFunctionEnd
1084 )";
1085 
1086   SinglePassRunAndCheck<AggressiveDCEPass>(
1087       predefs_before + main_before, predefs_after + main_after, true, true);
1088 }
1089 
TEST_F(AggressiveDCETest,NoPrivateStoreElimIfLoad)1090 TEST_F(AggressiveDCETest, NoPrivateStoreElimIfLoad) {
1091   // Should not eliminate stores to private when there is a load
1092   // Note: Not legal GLSL
1093   //
1094   // #version 450
1095   //
1096   // layout(location = 0) in vec4 BaseColor;
1097   // layout(location = 0) out vec4 OutColor;
1098   //
1099   // private vec4 pv;
1100   //
1101   // void main()
1102   // {
1103   //     pv = BaseColor;
1104   //     OutColor = pv;
1105   // }
1106 
1107   const std::string assembly =
1108       R"(OpCapability Shader
1109 %1 = OpExtInstImport "GLSL.std.450"
1110 OpMemoryModel Logical GLSL450
1111 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1112 OpExecutionMode %main OriginUpperLeft
1113 OpSource GLSL 450
1114 OpName %main "main"
1115 OpName %pv "pv"
1116 OpName %BaseColor "BaseColor"
1117 OpName %OutColor "OutColor"
1118 OpDecorate %BaseColor Location 0
1119 OpDecorate %OutColor Location 0
1120 %void = OpTypeVoid
1121 %7 = OpTypeFunction %void
1122 %float = OpTypeFloat 32
1123 %v4float = OpTypeVector %float 4
1124 %_ptr_Private_v4float = OpTypePointer Private %v4float
1125 %_ptr_Input_v4float = OpTypePointer Input %v4float
1126 %BaseColor = OpVariable %_ptr_Input_v4float Input
1127 %_ptr_Output_v4float = OpTypePointer Output %v4float
1128 %OutColor = OpVariable %_ptr_Output_v4float Output
1129 %pv = OpVariable %_ptr_Private_v4float Private
1130 %main = OpFunction %void None %7
1131 %13 = OpLabel
1132 %14 = OpLoad %v4float %BaseColor
1133 OpStore %pv %14
1134 %15 = OpLoad %v4float %pv
1135 %16 = OpFNegate %v4float %15
1136 OpStore %OutColor %16
1137 OpReturn
1138 OpFunctionEnd
1139 )";
1140 
1141   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
1142 }
1143 
TEST_F(AggressiveDCETest,NoPrivateStoreElimWithCall)1144 TEST_F(AggressiveDCETest, NoPrivateStoreElimWithCall) {
1145   // Should not eliminate stores to private when function contains call
1146   // Note: Not legal GLSL
1147   //
1148   // #version 450
1149   //
1150   // layout(location = 0) in vec4 BaseColor;
1151   // layout(location = 0) out vec4 OutColor;
1152   //
1153   // private vec4 v1;
1154   //
1155   // void foo()
1156   // {
1157   //     OutColor = -v1;
1158   // }
1159   //
1160   // void main()
1161   // {
1162   //     v1 = BaseColor;
1163   //     foo();
1164   // }
1165 
1166   const std::string assembly =
1167       R"(OpCapability Shader
1168 %1 = OpExtInstImport "GLSL.std.450"
1169 OpMemoryModel Logical GLSL450
1170 OpEntryPoint Fragment %main "main" %OutColor %BaseColor
1171 OpExecutionMode %main OriginUpperLeft
1172 OpSource GLSL 450
1173 OpName %main "main"
1174 OpName %foo_ "foo("
1175 OpName %OutColor "OutColor"
1176 OpName %v1 "v1"
1177 OpName %BaseColor "BaseColor"
1178 OpDecorate %OutColor Location 0
1179 OpDecorate %BaseColor Location 0
1180 %void = OpTypeVoid
1181 %8 = OpTypeFunction %void
1182 %float = OpTypeFloat 32
1183 %v4float = OpTypeVector %float 4
1184 %_ptr_Output_v4float = OpTypePointer Output %v4float
1185 %OutColor = OpVariable %_ptr_Output_v4float Output
1186 %_ptr_Private_v4float = OpTypePointer Private %v4float
1187 %_ptr_Input_v4float = OpTypePointer Input %v4float
1188 %v1 = OpVariable %_ptr_Private_v4float Private
1189 %BaseColor = OpVariable %_ptr_Input_v4float Input
1190 %main = OpFunction %void None %8
1191 %14 = OpLabel
1192 %15 = OpLoad %v4float %BaseColor
1193 OpStore %v1 %15
1194 %16 = OpFunctionCall %void %foo_
1195 OpReturn
1196 OpFunctionEnd
1197 %foo_ = OpFunction %void None %8
1198 %17 = OpLabel
1199 %18 = OpLoad %v4float %v1
1200 %19 = OpFNegate %v4float %18
1201 OpStore %OutColor %19
1202 OpReturn
1203 OpFunctionEnd
1204 )";
1205 
1206   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
1207 }
1208 
TEST_F(AggressiveDCETest,NoPrivateStoreElimInNonEntry)1209 TEST_F(AggressiveDCETest, NoPrivateStoreElimInNonEntry) {
1210   // Should not eliminate stores to private when function is not entry point
1211   // Note: Not legal GLSL
1212   //
1213   // #version 450
1214   //
1215   // layout(location = 0) in vec4 BaseColor;
1216   // layout(location = 0) out vec4 OutColor;
1217   //
1218   // private vec4 v1;
1219   //
1220   // void foo()
1221   // {
1222   //     v1 = BaseColor;
1223   // }
1224   //
1225   // void main()
1226   // {
1227   //     foo();
1228   //     OutColor = -v1;
1229   // }
1230 
1231   const std::string assembly =
1232       R"(OpCapability Shader
1233 %1 = OpExtInstImport "GLSL.std.450"
1234 OpMemoryModel Logical GLSL450
1235 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1236 OpExecutionMode %main OriginUpperLeft
1237 OpSource GLSL 450
1238 OpName %main "main"
1239 OpName %foo_ "foo("
1240 OpName %v1 "v1"
1241 OpName %BaseColor "BaseColor"
1242 OpName %OutColor "OutColor"
1243 OpDecorate %BaseColor Location 0
1244 OpDecorate %OutColor Location 0
1245 %void = OpTypeVoid
1246 %8 = OpTypeFunction %void
1247 %float = OpTypeFloat 32
1248 %v4float = OpTypeVector %float 4
1249 %_ptr_Private_v4float = OpTypePointer Private %v4float
1250 %_ptr_Input_v4float = OpTypePointer Input %v4float
1251 %BaseColor = OpVariable %_ptr_Input_v4float Input
1252 %_ptr_Output_v4float = OpTypePointer Output %v4float
1253 %v1 = OpVariable %_ptr_Private_v4float Private
1254 %OutColor = OpVariable %_ptr_Output_v4float Output
1255 %main = OpFunction %void None %8
1256 %14 = OpLabel
1257 %15 = OpFunctionCall %void %foo_
1258 %16 = OpLoad %v4float %v1
1259 %17 = OpFNegate %v4float %16
1260 OpStore %OutColor %17
1261 OpReturn
1262 OpFunctionEnd
1263 %foo_ = OpFunction %void None %8
1264 %18 = OpLabel
1265 %19 = OpLoad %v4float %BaseColor
1266 OpStore %v1 %19
1267 OpReturn
1268 OpFunctionEnd
1269 )";
1270 
1271   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
1272 }
1273 
TEST_F(AggressiveDCETest,WorkgroupStoreElimInEntryNoCalls)1274 TEST_F(AggressiveDCETest, WorkgroupStoreElimInEntryNoCalls) {
1275   // Eliminate stores to private in entry point with no calls
1276   // Note: Not legal GLSL
1277   //
1278   // layout(location = 0) in vec4 BaseColor;
1279   // layout(location = 1) in vec4 Dead;
1280   // layout(location = 0) out vec4 OutColor;
1281   //
1282   // workgroup vec4 dv;
1283   //
1284   // void main()
1285   // {
1286   //     vec4 v = BaseColor;
1287   //     dv = Dead;
1288   //     OutColor = v;
1289   // }
1290 
1291   const std::string predefs_before =
1292       R"(OpCapability Shader
1293 %1 = OpExtInstImport "GLSL.std.450"
1294 OpMemoryModel Logical GLSL450
1295 OpEntryPoint Fragment %main "main" %BaseColor %Dead %OutColor
1296 OpExecutionMode %main OriginUpperLeft
1297 OpSource GLSL 450
1298 OpName %main "main"
1299 OpName %v "v"
1300 OpName %BaseColor "BaseColor"
1301 OpName %dv "dv"
1302 OpName %Dead "Dead"
1303 OpName %OutColor "OutColor"
1304 OpDecorate %BaseColor Location 0
1305 OpDecorate %Dead Location 1
1306 OpDecorate %OutColor Location 0
1307 %void = OpTypeVoid
1308 %9 = OpTypeFunction %void
1309 %float = OpTypeFloat 32
1310 %v4float = OpTypeVector %float 4
1311 %_ptr_Function_v4float = OpTypePointer Function %v4float
1312 %_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float
1313 %_ptr_Input_v4float = OpTypePointer Input %v4float
1314 %BaseColor = OpVariable %_ptr_Input_v4float Input
1315 %Dead = OpVariable %_ptr_Input_v4float Input
1316 %_ptr_Output_v4float = OpTypePointer Output %v4float
1317 %dv = OpVariable %_ptr_Workgroup_v4float Workgroup
1318 %OutColor = OpVariable %_ptr_Output_v4float Output
1319 )";
1320 
1321   const std::string predefs_after =
1322       R"(OpCapability Shader
1323 %1 = OpExtInstImport "GLSL.std.450"
1324 OpMemoryModel Logical GLSL450
1325 OpEntryPoint Fragment %main "main" %BaseColor %Dead %OutColor
1326 OpExecutionMode %main OriginUpperLeft
1327 OpSource GLSL 450
1328 OpName %main "main"
1329 OpName %v "v"
1330 OpName %BaseColor "BaseColor"
1331 OpName %Dead "Dead"
1332 OpName %OutColor "OutColor"
1333 OpDecorate %BaseColor Location 0
1334 OpDecorate %Dead Location 1
1335 OpDecorate %OutColor Location 0
1336 %void = OpTypeVoid
1337 %9 = OpTypeFunction %void
1338 %float = OpTypeFloat 32
1339 %v4float = OpTypeVector %float 4
1340 %_ptr_Function_v4float = OpTypePointer Function %v4float
1341 %_ptr_Input_v4float = OpTypePointer Input %v4float
1342 %BaseColor = OpVariable %_ptr_Input_v4float Input
1343 %Dead = OpVariable %_ptr_Input_v4float Input
1344 %_ptr_Output_v4float = OpTypePointer Output %v4float
1345 %OutColor = OpVariable %_ptr_Output_v4float Output
1346 )";
1347 
1348   const std::string main_before =
1349       R"(%main = OpFunction %void None %9
1350 %16 = OpLabel
1351 %v = OpVariable %_ptr_Function_v4float Function
1352 %17 = OpLoad %v4float %BaseColor
1353 OpStore %v %17
1354 %18 = OpLoad %v4float %Dead
1355 OpStore %dv %18
1356 %19 = OpLoad %v4float %v
1357 %20 = OpFNegate %v4float %19
1358 OpStore %OutColor %20
1359 OpReturn
1360 OpFunctionEnd
1361 )";
1362 
1363   const std::string main_after =
1364       R"(%main = OpFunction %void None %9
1365 %16 = OpLabel
1366 %v = OpVariable %_ptr_Function_v4float Function
1367 %17 = OpLoad %v4float %BaseColor
1368 OpStore %v %17
1369 %19 = OpLoad %v4float %v
1370 %20 = OpFNegate %v4float %19
1371 OpStore %OutColor %20
1372 OpReturn
1373 OpFunctionEnd
1374 )";
1375 
1376   SinglePassRunAndCheck<AggressiveDCEPass>(
1377       predefs_before + main_before, predefs_after + main_after, true, true);
1378 }
1379 
TEST_F(AggressiveDCETest,EliminateDeadIfThenElse)1380 TEST_F(AggressiveDCETest, EliminateDeadIfThenElse) {
1381   // #version 450
1382   //
1383   // layout(location = 0) in vec4 BaseColor;
1384   // layout(location = 0) out vec4 OutColor;
1385   //
1386   // void main()
1387   // {
1388   //     float d;
1389   //     if (BaseColor.x == 0)
1390   //       d = BaseColor.y;
1391   //     else
1392   //       d = BaseColor.z;
1393   //     OutColor = vec4(1.0,1.0,1.0,1.0);
1394   // }
1395 
1396   const std::string predefs_before =
1397       R"(OpCapability Shader
1398 %1 = OpExtInstImport "GLSL.std.450"
1399 OpMemoryModel Logical GLSL450
1400 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1401 OpExecutionMode %main OriginUpperLeft
1402 OpSource GLSL 450
1403 OpName %main "main"
1404 OpName %BaseColor "BaseColor"
1405 OpName %d "d"
1406 OpName %OutColor "OutColor"
1407 OpDecorate %BaseColor Location 0
1408 OpDecorate %OutColor Location 0
1409 %void = OpTypeVoid
1410 %7 = OpTypeFunction %void
1411 %float = OpTypeFloat 32
1412 %v4float = OpTypeVector %float 4
1413 %_ptr_Input_v4float = OpTypePointer Input %v4float
1414 %BaseColor = OpVariable %_ptr_Input_v4float Input
1415 %uint = OpTypeInt 32 0
1416 %uint_0 = OpConstant %uint 0
1417 %_ptr_Input_float = OpTypePointer Input %float
1418 %float_0 = OpConstant %float 0
1419 %bool = OpTypeBool
1420 %_ptr_Function_float = OpTypePointer Function %float
1421 %uint_1 = OpConstant %uint 1
1422 %uint_2 = OpConstant %uint 2
1423 %_ptr_Output_v4float = OpTypePointer Output %v4float
1424 %OutColor = OpVariable %_ptr_Output_v4float Output
1425 %float_1 = OpConstant %float 1
1426 %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1427 )";
1428 
1429   const std::string predefs_after =
1430       R"(OpCapability Shader
1431 %1 = OpExtInstImport "GLSL.std.450"
1432 OpMemoryModel Logical GLSL450
1433 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1434 OpExecutionMode %main OriginUpperLeft
1435 OpSource GLSL 450
1436 OpName %main "main"
1437 OpName %BaseColor "BaseColor"
1438 OpName %OutColor "OutColor"
1439 OpDecorate %BaseColor Location 0
1440 OpDecorate %OutColor Location 0
1441 %void = OpTypeVoid
1442 %7 = OpTypeFunction %void
1443 %float = OpTypeFloat 32
1444 %v4float = OpTypeVector %float 4
1445 %_ptr_Input_v4float = OpTypePointer Input %v4float
1446 %BaseColor = OpVariable %_ptr_Input_v4float Input
1447 %_ptr_Output_v4float = OpTypePointer Output %v4float
1448 %OutColor = OpVariable %_ptr_Output_v4float Output
1449 %float_1 = OpConstant %float 1
1450 %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1451 )";
1452 
1453   const std::string func_before =
1454       R"(%main = OpFunction %void None %7
1455 %22 = OpLabel
1456 %d = OpVariable %_ptr_Function_float Function
1457 %23 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
1458 %24 = OpLoad %float %23
1459 %25 = OpFOrdEqual %bool %24 %float_0
1460 OpSelectionMerge %26 None
1461 OpBranchConditional %25 %27 %28
1462 %27 = OpLabel
1463 %29 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1464 %30 = OpLoad %float %29
1465 OpStore %d %30
1466 OpBranch %26
1467 %28 = OpLabel
1468 %31 = OpAccessChain %_ptr_Input_float %BaseColor %uint_2
1469 %32 = OpLoad %float %31
1470 OpStore %d %32
1471 OpBranch %26
1472 %26 = OpLabel
1473 OpStore %OutColor %21
1474 OpReturn
1475 OpFunctionEnd
1476 )";
1477 
1478   const std::string func_after =
1479       R"(%main = OpFunction %void None %7
1480 %22 = OpLabel
1481 OpBranch %26
1482 %26 = OpLabel
1483 OpStore %OutColor %21
1484 OpReturn
1485 OpFunctionEnd
1486 )";
1487 
1488   SinglePassRunAndCheck<AggressiveDCEPass>(
1489       predefs_before + func_before, predefs_after + func_after, true, true);
1490 }
1491 
TEST_F(AggressiveDCETest,EliminateDeadIfThen)1492 TEST_F(AggressiveDCETest, EliminateDeadIfThen) {
1493   // #version 450
1494   //
1495   // layout(location = 0) in vec4 BaseColor;
1496   // layout(location = 0) out vec4 OutColor;
1497   //
1498   // void main()
1499   // {
1500   //     float d;
1501   //     if (BaseColor.x == 0)
1502   //       d = BaseColor.y;
1503   //     OutColor = vec4(1.0,1.0,1.0,1.0);
1504   // }
1505 
1506   const std::string predefs_before =
1507       R"(OpCapability Shader
1508 %1 = OpExtInstImport "GLSL.std.450"
1509 OpMemoryModel Logical GLSL450
1510 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1511 OpExecutionMode %main OriginUpperLeft
1512 OpSource GLSL 450
1513 OpName %main "main"
1514 OpName %BaseColor "BaseColor"
1515 OpName %d "d"
1516 OpName %OutColor "OutColor"
1517 OpDecorate %BaseColor Location 0
1518 OpDecorate %OutColor Location 0
1519 %void = OpTypeVoid
1520 %7 = OpTypeFunction %void
1521 %float = OpTypeFloat 32
1522 %v4float = OpTypeVector %float 4
1523 %_ptr_Input_v4float = OpTypePointer Input %v4float
1524 %BaseColor = OpVariable %_ptr_Input_v4float Input
1525 %uint = OpTypeInt 32 0
1526 %uint_0 = OpConstant %uint 0
1527 %_ptr_Input_float = OpTypePointer Input %float
1528 %float_0 = OpConstant %float 0
1529 %bool = OpTypeBool
1530 %_ptr_Function_float = OpTypePointer Function %float
1531 %uint_1 = OpConstant %uint 1
1532 %_ptr_Output_v4float = OpTypePointer Output %v4float
1533 %OutColor = OpVariable %_ptr_Output_v4float Output
1534 %float_1 = OpConstant %float 1
1535 %20 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1536 )";
1537 
1538   const std::string predefs_after =
1539       R"(OpCapability Shader
1540 %1 = OpExtInstImport "GLSL.std.450"
1541 OpMemoryModel Logical GLSL450
1542 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1543 OpExecutionMode %main OriginUpperLeft
1544 OpSource GLSL 450
1545 OpName %main "main"
1546 OpName %BaseColor "BaseColor"
1547 OpName %OutColor "OutColor"
1548 OpDecorate %BaseColor Location 0
1549 OpDecorate %OutColor Location 0
1550 %void = OpTypeVoid
1551 %7 = OpTypeFunction %void
1552 %float = OpTypeFloat 32
1553 %v4float = OpTypeVector %float 4
1554 %_ptr_Input_v4float = OpTypePointer Input %v4float
1555 %BaseColor = OpVariable %_ptr_Input_v4float Input
1556 %_ptr_Output_v4float = OpTypePointer Output %v4float
1557 %OutColor = OpVariable %_ptr_Output_v4float Output
1558 %float_1 = OpConstant %float 1
1559 %20 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1560 )";
1561 
1562   const std::string func_before =
1563       R"(%main = OpFunction %void None %7
1564 %21 = OpLabel
1565 %d = OpVariable %_ptr_Function_float Function
1566 %22 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
1567 %23 = OpLoad %float %22
1568 %24 = OpFOrdEqual %bool %23 %float_0
1569 OpSelectionMerge %25 None
1570 OpBranchConditional %24 %26 %25
1571 %26 = OpLabel
1572 %27 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1573 %28 = OpLoad %float %27
1574 OpStore %d %28
1575 OpBranch %25
1576 %25 = OpLabel
1577 OpStore %OutColor %20
1578 OpReturn
1579 OpFunctionEnd
1580 )";
1581 
1582   const std::string func_after =
1583       R"(%main = OpFunction %void None %7
1584 %21 = OpLabel
1585 OpBranch %25
1586 %25 = OpLabel
1587 OpStore %OutColor %20
1588 OpReturn
1589 OpFunctionEnd
1590 )";
1591 
1592   SinglePassRunAndCheck<AggressiveDCEPass>(
1593       predefs_before + func_before, predefs_after + func_after, true, true);
1594 }
1595 
TEST_F(AggressiveDCETest,EliminateDeadSwitch)1596 TEST_F(AggressiveDCETest, EliminateDeadSwitch) {
1597   // #version 450
1598   //
1599   // layout(location = 0) in vec4 BaseColor;
1600   // layout(location = 1) in flat int x;
1601   // layout(location = 0) out vec4 OutColor;
1602   //
1603   // void main()
1604   // {
1605   //     float d;
1606   //     switch (x) {
1607   //       case 0:
1608   //         d = BaseColor.y;
1609   //     }
1610   //     OutColor = vec4(1.0,1.0,1.0,1.0);
1611   // }
1612   const std::string before =
1613       R"(OpCapability Shader
1614           %1 = OpExtInstImport "GLSL.std.450"
1615                OpMemoryModel Logical GLSL450
1616                OpEntryPoint Fragment %main "main" %x %BaseColor %OutColor
1617                OpExecutionMode %main OriginUpperLeft
1618                OpSource GLSL 450
1619                OpName %main "main"
1620                OpName %x "x"
1621                OpName %d "d"
1622                OpName %BaseColor "BaseColor"
1623                OpName %OutColor "OutColor"
1624                OpDecorate %x Flat
1625                OpDecorate %x Location 1
1626                OpDecorate %BaseColor Location 0
1627                OpDecorate %OutColor Location 0
1628        %void = OpTypeVoid
1629           %3 = OpTypeFunction %void
1630         %int = OpTypeInt 32 1
1631 %_ptr_Input_int = OpTypePointer Input %int
1632           %x = OpVariable %_ptr_Input_int Input
1633       %float = OpTypeFloat 32
1634 %_ptr_Function_float = OpTypePointer Function %float
1635     %v4float = OpTypeVector %float 4
1636 %_ptr_Input_v4float = OpTypePointer Input %v4float
1637   %BaseColor = OpVariable %_ptr_Input_v4float Input
1638        %uint = OpTypeInt 32 0
1639      %uint_1 = OpConstant %uint 1
1640 %_ptr_Input_float = OpTypePointer Input %float
1641 %_ptr_Output_v4float = OpTypePointer Output %v4float
1642    %OutColor = OpVariable %_ptr_Output_v4float Output
1643     %float_1 = OpConstant %float 1
1644          %27 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1645        %main = OpFunction %void None %3
1646           %5 = OpLabel
1647           %d = OpVariable %_ptr_Function_float Function
1648           %9 = OpLoad %int %x
1649                OpSelectionMerge %11 None
1650                OpSwitch %9 %11 0 %10
1651          %10 = OpLabel
1652          %21 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1653          %22 = OpLoad %float %21
1654                OpStore %d %22
1655                OpBranch %11
1656          %11 = OpLabel
1657                OpStore %OutColor %27
1658                OpReturn
1659                OpFunctionEnd)";
1660 
1661   const std::string after =
1662       R"(OpCapability Shader
1663 %1 = OpExtInstImport "GLSL.std.450"
1664 OpMemoryModel Logical GLSL450
1665 OpEntryPoint Fragment %main "main" %x %BaseColor %OutColor
1666 OpExecutionMode %main OriginUpperLeft
1667 OpSource GLSL 450
1668 OpName %main "main"
1669 OpName %x "x"
1670 OpName %BaseColor "BaseColor"
1671 OpName %OutColor "OutColor"
1672 OpDecorate %x Flat
1673 OpDecorate %x Location 1
1674 OpDecorate %BaseColor Location 0
1675 OpDecorate %OutColor Location 0
1676 %void = OpTypeVoid
1677 %3 = OpTypeFunction %void
1678 %int = OpTypeInt 32 1
1679 %_ptr_Input_int = OpTypePointer Input %int
1680 %x = OpVariable %_ptr_Input_int Input
1681 %float = OpTypeFloat 32
1682 %v4float = OpTypeVector %float 4
1683 %_ptr_Input_v4float = OpTypePointer Input %v4float
1684 %BaseColor = OpVariable %_ptr_Input_v4float Input
1685 %_ptr_Output_v4float = OpTypePointer Output %v4float
1686 %OutColor = OpVariable %_ptr_Output_v4float Output
1687 %float_1 = OpConstant %float 1
1688 %27 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1689 %main = OpFunction %void None %3
1690 %5 = OpLabel
1691 OpBranch %11
1692 %11 = OpLabel
1693 OpStore %OutColor %27
1694 OpReturn
1695 OpFunctionEnd
1696 )";
1697 
1698   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1699   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
1700 }
1701 
TEST_F(AggressiveDCETest,EliminateDeadIfThenElseNested)1702 TEST_F(AggressiveDCETest, EliminateDeadIfThenElseNested) {
1703   // #version 450
1704   //
1705   // layout(location = 0) in vec4 BaseColor;
1706   // layout(location = 0) out vec4 OutColor;
1707   //
1708   // void main()
1709   // {
1710   //     float d;
1711   //     if (BaseColor.x == 0)
1712   //       if (BaseColor.y == 0)
1713   //         d = 0.0;
1714   //       else
1715   //         d = 0.25;
1716   //     else
1717   //       if (BaseColor.y == 0)
1718   //         d = 0.5;
1719   //       else
1720   //         d = 0.75;
1721   //     OutColor = vec4(1.0,1.0,1.0,1.0);
1722   // }
1723 
1724   const std::string predefs_before =
1725       R"(OpCapability Shader
1726 %1 = OpExtInstImport "GLSL.std.450"
1727 OpMemoryModel Logical GLSL450
1728 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1729 OpExecutionMode %main OriginUpperLeft
1730 OpSource GLSL 450
1731 OpName %main "main"
1732 OpName %BaseColor "BaseColor"
1733 OpName %d "d"
1734 OpName %OutColor "OutColor"
1735 OpDecorate %BaseColor Location 0
1736 OpDecorate %OutColor Location 0
1737 %void = OpTypeVoid
1738 %7 = OpTypeFunction %void
1739 %float = OpTypeFloat 32
1740 %v4float = OpTypeVector %float 4
1741 %_ptr_Input_v4float = OpTypePointer Input %v4float
1742 %BaseColor = OpVariable %_ptr_Input_v4float Input
1743 %uint = OpTypeInt 32 0
1744 %uint_0 = OpConstant %uint 0
1745 %_ptr_Input_float = OpTypePointer Input %float
1746 %float_0 = OpConstant %float 0
1747 %bool = OpTypeBool
1748 %uint_1 = OpConstant %uint 1
1749 %_ptr_Function_float = OpTypePointer Function %float
1750 %float_0_25 = OpConstant %float 0.25
1751 %float_0_5 = OpConstant %float 0.5
1752 %float_0_75 = OpConstant %float 0.75
1753 %_ptr_Output_v4float = OpTypePointer Output %v4float
1754 %OutColor = OpVariable %_ptr_Output_v4float Output
1755 %float_1 = OpConstant %float 1
1756 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1757 )";
1758 
1759   const std::string predefs_after =
1760       R"(OpCapability Shader
1761 %1 = OpExtInstImport "GLSL.std.450"
1762 OpMemoryModel Logical GLSL450
1763 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1764 OpExecutionMode %main OriginUpperLeft
1765 OpSource GLSL 450
1766 OpName %main "main"
1767 OpName %BaseColor "BaseColor"
1768 OpName %OutColor "OutColor"
1769 OpDecorate %BaseColor Location 0
1770 OpDecorate %OutColor Location 0
1771 %void = OpTypeVoid
1772 %7 = OpTypeFunction %void
1773 %float = OpTypeFloat 32
1774 %v4float = OpTypeVector %float 4
1775 %_ptr_Input_v4float = OpTypePointer Input %v4float
1776 %BaseColor = OpVariable %_ptr_Input_v4float Input
1777 %_ptr_Output_v4float = OpTypePointer Output %v4float
1778 %OutColor = OpVariable %_ptr_Output_v4float Output
1779 %float_1 = OpConstant %float 1
1780 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
1781 )";
1782 
1783   const std::string func_before =
1784       R"(%main = OpFunction %void None %7
1785 %24 = OpLabel
1786 %d = OpVariable %_ptr_Function_float Function
1787 %25 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
1788 %26 = OpLoad %float %25
1789 %27 = OpFOrdEqual %bool %26 %float_0
1790 OpSelectionMerge %28 None
1791 OpBranchConditional %27 %29 %30
1792 %29 = OpLabel
1793 %31 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1794 %32 = OpLoad %float %31
1795 %33 = OpFOrdEqual %bool %32 %float_0
1796 OpSelectionMerge %34 None
1797 OpBranchConditional %33 %35 %36
1798 %35 = OpLabel
1799 OpStore %d %float_0
1800 OpBranch %34
1801 %36 = OpLabel
1802 OpStore %d %float_0_25
1803 OpBranch %34
1804 %34 = OpLabel
1805 OpBranch %28
1806 %30 = OpLabel
1807 %37 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1808 %38 = OpLoad %float %37
1809 %39 = OpFOrdEqual %bool %38 %float_0
1810 OpSelectionMerge %40 None
1811 OpBranchConditional %39 %41 %42
1812 %41 = OpLabel
1813 OpStore %d %float_0_5
1814 OpBranch %40
1815 %42 = OpLabel
1816 OpStore %d %float_0_75
1817 OpBranch %40
1818 %40 = OpLabel
1819 OpBranch %28
1820 %28 = OpLabel
1821 OpStore %OutColor %23
1822 OpReturn
1823 OpFunctionEnd
1824 )";
1825 
1826   const std::string func_after =
1827       R"(%main = OpFunction %void None %7
1828 %24 = OpLabel
1829 OpBranch %28
1830 %28 = OpLabel
1831 OpStore %OutColor %23
1832 OpReturn
1833 OpFunctionEnd
1834 )";
1835 
1836   SinglePassRunAndCheck<AggressiveDCEPass>(
1837       predefs_before + func_before, predefs_after + func_after, true, true);
1838 }
1839 
TEST_F(AggressiveDCETest,NoEliminateLiveIfThenElse)1840 TEST_F(AggressiveDCETest, NoEliminateLiveIfThenElse) {
1841   // #version 450
1842   //
1843   // layout(location = 0) in vec4 BaseColor;
1844   // layout(location = 0) out vec4 OutColor;
1845   //
1846   // void main()
1847   // {
1848   //     float t;
1849   //     if (BaseColor.x == 0)
1850   //       t = BaseColor.y;
1851   //     else
1852   //       t = BaseColor.z;
1853   //     OutColor = vec4(t);
1854   // }
1855 
1856   const std::string assembly =
1857       R"(OpCapability Shader
1858 %1 = OpExtInstImport "GLSL.std.450"
1859 OpMemoryModel Logical GLSL450
1860 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1861 OpExecutionMode %main OriginUpperLeft
1862 OpSource GLSL 450
1863 OpName %main "main"
1864 OpName %BaseColor "BaseColor"
1865 OpName %t "t"
1866 OpName %OutColor "OutColor"
1867 OpDecorate %BaseColor Location 0
1868 OpDecorate %OutColor Location 0
1869 %void = OpTypeVoid
1870 %7 = OpTypeFunction %void
1871 %float = OpTypeFloat 32
1872 %v4float = OpTypeVector %float 4
1873 %_ptr_Input_v4float = OpTypePointer Input %v4float
1874 %BaseColor = OpVariable %_ptr_Input_v4float Input
1875 %uint = OpTypeInt 32 0
1876 %uint_0 = OpConstant %uint 0
1877 %_ptr_Input_float = OpTypePointer Input %float
1878 %float_0 = OpConstant %float 0
1879 %bool = OpTypeBool
1880 %_ptr_Function_float = OpTypePointer Function %float
1881 %uint_1 = OpConstant %uint 1
1882 %uint_2 = OpConstant %uint 2
1883 %_ptr_Output_v4float = OpTypePointer Output %v4float
1884 %OutColor = OpVariable %_ptr_Output_v4float Output
1885 %main = OpFunction %void None %7
1886 %20 = OpLabel
1887 %t = OpVariable %_ptr_Function_float Function
1888 %21 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
1889 %22 = OpLoad %float %21
1890 %23 = OpFOrdEqual %bool %22 %float_0
1891 OpSelectionMerge %24 None
1892 OpBranchConditional %23 %25 %26
1893 %25 = OpLabel
1894 %27 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1895 %28 = OpLoad %float %27
1896 OpStore %t %28
1897 OpBranch %24
1898 %26 = OpLabel
1899 %29 = OpAccessChain %_ptr_Input_float %BaseColor %uint_2
1900 %30 = OpLoad %float %29
1901 OpStore %t %30
1902 OpBranch %24
1903 %24 = OpLabel
1904 %31 = OpLoad %float %t
1905 %32 = OpCompositeConstruct %v4float %31 %31 %31 %31
1906 OpStore %OutColor %32
1907 OpReturn
1908 OpFunctionEnd
1909 )";
1910 
1911   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
1912 }
1913 
TEST_F(AggressiveDCETest,NoEliminateLiveIfThenElseNested)1914 TEST_F(AggressiveDCETest, NoEliminateLiveIfThenElseNested) {
1915   // #version 450
1916   //
1917   // layout(location = 0) in vec4 BaseColor;
1918   // layout(location = 0) out vec4 OutColor;
1919   //
1920   // void main()
1921   // {
1922   //     float t;
1923   //     if (BaseColor.x == 0)
1924   //       if (BaseColor.y == 0)
1925   //         t = 0.0;
1926   //       else
1927   //         t = 0.25;
1928   //     else
1929   //       if (BaseColor.y == 0)
1930   //         t = 0.5;
1931   //       else
1932   //         t = 0.75;
1933   //     OutColor = vec4(t);
1934   // }
1935 
1936   const std::string assembly =
1937       R"(OpCapability Shader
1938 %1 = OpExtInstImport "GLSL.std.450"
1939 OpMemoryModel Logical GLSL450
1940 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
1941 OpExecutionMode %main OriginUpperLeft
1942 OpSource GLSL 450
1943 OpName %main "main"
1944 OpName %BaseColor "BaseColor"
1945 OpName %t "t"
1946 OpName %OutColor "OutColor"
1947 OpDecorate %BaseColor Location 0
1948 OpDecorate %OutColor Location 0
1949 %void = OpTypeVoid
1950 %7 = OpTypeFunction %void
1951 %float = OpTypeFloat 32
1952 %v4float = OpTypeVector %float 4
1953 %_ptr_Input_v4float = OpTypePointer Input %v4float
1954 %BaseColor = OpVariable %_ptr_Input_v4float Input
1955 %uint = OpTypeInt 32 0
1956 %uint_0 = OpConstant %uint 0
1957 %_ptr_Input_float = OpTypePointer Input %float
1958 %float_0 = OpConstant %float 0
1959 %bool = OpTypeBool
1960 %uint_1 = OpConstant %uint 1
1961 %_ptr_Function_float = OpTypePointer Function %float
1962 %float_0_25 = OpConstant %float 0.25
1963 %float_0_5 = OpConstant %float 0.5
1964 %float_0_75 = OpConstant %float 0.75
1965 %_ptr_Output_v4float = OpTypePointer Output %v4float
1966 %OutColor = OpVariable %_ptr_Output_v4float Output
1967 %main = OpFunction %void None %7
1968 %22 = OpLabel
1969 %t = OpVariable %_ptr_Function_float Function
1970 %23 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
1971 %24 = OpLoad %float %23
1972 %25 = OpFOrdEqual %bool %24 %float_0
1973 OpSelectionMerge %26 None
1974 OpBranchConditional %25 %27 %28
1975 %27 = OpLabel
1976 %29 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1977 %30 = OpLoad %float %29
1978 %31 = OpFOrdEqual %bool %30 %float_0
1979 OpSelectionMerge %32 None
1980 OpBranchConditional %31 %33 %34
1981 %33 = OpLabel
1982 OpStore %t %float_0
1983 OpBranch %32
1984 %34 = OpLabel
1985 OpStore %t %float_0_25
1986 OpBranch %32
1987 %32 = OpLabel
1988 OpBranch %26
1989 %28 = OpLabel
1990 %35 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
1991 %36 = OpLoad %float %35
1992 %37 = OpFOrdEqual %bool %36 %float_0
1993 OpSelectionMerge %38 None
1994 OpBranchConditional %37 %39 %40
1995 %39 = OpLabel
1996 OpStore %t %float_0_5
1997 OpBranch %38
1998 %40 = OpLabel
1999 OpStore %t %float_0_75
2000 OpBranch %38
2001 %38 = OpLabel
2002 OpBranch %26
2003 %26 = OpLabel
2004 %41 = OpLoad %float %t
2005 %42 = OpCompositeConstruct %v4float %41 %41 %41 %41
2006 OpStore %OutColor %42
2007 OpReturn
2008 OpFunctionEnd
2009 )";
2010 
2011   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2012 }
2013 
TEST_F(AggressiveDCETest,NoEliminateIfWithPhi)2014 TEST_F(AggressiveDCETest, NoEliminateIfWithPhi) {
2015   // Note: Assembly hand-optimized from GLSL
2016   //
2017   // #version 450
2018   //
2019   // layout(location = 0) in vec4 BaseColor;
2020   // layout(location = 0) out vec4 OutColor;
2021   //
2022   // void main()
2023   // {
2024   //     float t;
2025   //     if (BaseColor.x == 0)
2026   //       t = 0.0;
2027   //     else
2028   //       t = 1.0;
2029   //     OutColor = vec4(t);
2030   // }
2031 
2032   const std::string assembly =
2033       R"(OpCapability Shader
2034 %1 = OpExtInstImport "GLSL.std.450"
2035 OpMemoryModel Logical GLSL450
2036 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
2037 OpExecutionMode %main OriginUpperLeft
2038 OpSource GLSL 450
2039 OpName %main "main"
2040 OpName %BaseColor "BaseColor"
2041 OpName %OutColor "OutColor"
2042 OpDecorate %BaseColor Location 0
2043 OpDecorate %OutColor Location 0
2044 %void = OpTypeVoid
2045 %6 = OpTypeFunction %void
2046 %float = OpTypeFloat 32
2047 %v4float = OpTypeVector %float 4
2048 %_ptr_Input_v4float = OpTypePointer Input %v4float
2049 %BaseColor = OpVariable %_ptr_Input_v4float Input
2050 %uint = OpTypeInt 32 0
2051 %uint_0 = OpConstant %uint 0
2052 %_ptr_Input_float = OpTypePointer Input %float
2053 %float_0 = OpConstant %float 0
2054 %bool = OpTypeBool
2055 %float_1 = OpConstant %float 1
2056 %_ptr_Output_v4float = OpTypePointer Output %v4float
2057 %OutColor = OpVariable %_ptr_Output_v4float Output
2058 %main = OpFunction %void None %6
2059 %17 = OpLabel
2060 %18 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
2061 %19 = OpLoad %float %18
2062 %20 = OpFOrdEqual %bool %19 %float_0
2063 OpSelectionMerge %21 None
2064 OpBranchConditional %20 %22 %23
2065 %22 = OpLabel
2066 OpBranch %21
2067 %23 = OpLabel
2068 OpBranch %21
2069 %21 = OpLabel
2070 %24 = OpPhi %float %float_0 %22 %float_1 %23
2071 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
2072 OpStore %OutColor %25
2073 OpReturn
2074 OpFunctionEnd
2075 )";
2076 
2077   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2078 }
2079 
TEST_F(AggressiveDCETest,NoEliminateIfBreak)2080 TEST_F(AggressiveDCETest, NoEliminateIfBreak) {
2081   // Note: Assembly optimized from GLSL
2082   //
2083   // #version 450
2084   //
2085   // layout(location=0) in vec4 InColor;
2086   // layout(location=0) out vec4 OutColor;
2087   //
2088   // void main()
2089   // {
2090   //     float f = 0.0;
2091   //     for (;;) {
2092   //         f += 2.0;
2093   //         if (f > 20.0)
2094   //             break;
2095   //     }
2096   //
2097   //     OutColor = InColor / f;
2098   // }
2099 
2100   const std::string assembly =
2101       R"(OpCapability Shader
2102 %1 = OpExtInstImport "GLSL.std.450"
2103 OpMemoryModel Logical GLSL450
2104 OpEntryPoint Fragment %main "main" %OutColor %InColor
2105 OpExecutionMode %main OriginUpperLeft
2106 OpSource GLSL 450
2107 OpName %main "main"
2108 OpName %f "f"
2109 OpName %OutColor "OutColor"
2110 OpName %InColor "InColor"
2111 OpDecorate %OutColor Location 0
2112 OpDecorate %InColor Location 0
2113 %void = OpTypeVoid
2114 %7 = OpTypeFunction %void
2115 %float = OpTypeFloat 32
2116 %_ptr_Function_float = OpTypePointer Function %float
2117 %float_0 = OpConstant %float 0
2118 %float_2 = OpConstant %float 2
2119 %float_20 = OpConstant %float 20
2120 %bool = OpTypeBool
2121 %v4float = OpTypeVector %float 4
2122 %_ptr_Output_v4float = OpTypePointer Output %v4float
2123 %OutColor = OpVariable %_ptr_Output_v4float Output
2124 %_ptr_Input_v4float = OpTypePointer Input %v4float
2125 %InColor = OpVariable %_ptr_Input_v4float Input
2126 %main = OpFunction %void None %7
2127 %17 = OpLabel
2128 %f = OpVariable %_ptr_Function_float Function
2129 OpStore %f %float_0
2130 OpBranch %18
2131 %18 = OpLabel
2132 OpLoopMerge %19 %20 None
2133 OpBranch %21
2134 %21 = OpLabel
2135 %22 = OpLoad %float %f
2136 %23 = OpFAdd %float %22 %float_2
2137 OpStore %f %23
2138 %24 = OpLoad %float %f
2139 %25 = OpFOrdGreaterThan %bool %24 %float_20
2140 OpSelectionMerge %26 None
2141 OpBranchConditional %25 %27 %26
2142 %27 = OpLabel
2143 OpBranch %19
2144 %26 = OpLabel
2145 OpBranch %20
2146 %20 = OpLabel
2147 OpBranch %18
2148 %19 = OpLabel
2149 %28 = OpLoad %v4float %InColor
2150 %29 = OpLoad %float %f
2151 %30 = OpCompositeConstruct %v4float %29 %29 %29 %29
2152 %31 = OpFDiv %v4float %28 %30
2153 OpStore %OutColor %31
2154 OpReturn
2155 OpFunctionEnd
2156 )";
2157 
2158   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2159 }
2160 
TEST_F(AggressiveDCETest,NoEliminateIfBreak2)2161 TEST_F(AggressiveDCETest, NoEliminateIfBreak2) {
2162   // Do not eliminate break as conditional branch with merge instruction
2163   // Note: SPIR-V edited to add merge instruction before break.
2164   //
2165   // #version 430
2166   //
2167   // layout(std430) buffer U_t
2168   // {
2169   //     float g_F[10];
2170   // };
2171   //
2172   // layout(location = 0)out float o;
2173   //
2174   // void main(void)
2175   // {
2176   //     float s = 0.0;
2177   //     for (int i=0; i<10; i++)
2178   //         s += g_F[i];
2179   //     o = s;
2180   // }
2181 
2182   const std::string assembly =
2183       R"(OpCapability Shader
2184 %1 = OpExtInstImport "GLSL.std.450"
2185 OpMemoryModel Logical GLSL450
2186 OpEntryPoint Fragment %main "main" %o
2187 OpExecutionMode %main OriginUpperLeft
2188 OpSource GLSL 430
2189 OpName %main "main"
2190 OpName %s "s"
2191 OpName %i "i"
2192 OpName %U_t "U_t"
2193 OpMemberName %U_t 0 "g_F"
2194 OpName %_ ""
2195 OpName %o "o"
2196 OpDecorate %_arr_float_uint_10 ArrayStride 4
2197 OpMemberDecorate %U_t 0 Offset 0
2198 OpDecorate %U_t BufferBlock
2199 OpDecorate %_ DescriptorSet 0
2200 OpDecorate %o Location 0
2201 %void = OpTypeVoid
2202 %10 = OpTypeFunction %void
2203 %float = OpTypeFloat 32
2204 %_ptr_Function_float = OpTypePointer Function %float
2205 %float_0 = OpConstant %float 0
2206 %int = OpTypeInt 32 1
2207 %_ptr_Function_int = OpTypePointer Function %int
2208 %int_0 = OpConstant %int 0
2209 %int_10 = OpConstant %int 10
2210 %bool = OpTypeBool
2211 %uint = OpTypeInt 32 0
2212 %uint_10 = OpConstant %uint 10
2213 %_arr_float_uint_10 = OpTypeArray %float %uint_10
2214 %U_t = OpTypeStruct %_arr_float_uint_10
2215 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2216 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2217 %_ptr_Uniform_float = OpTypePointer Uniform %float
2218 %int_1 = OpConstant %int 1
2219 %_ptr_Output_float = OpTypePointer Output %float
2220 %o = OpVariable %_ptr_Output_float Output
2221 %main = OpFunction %void None %10
2222 %25 = OpLabel
2223 %s = OpVariable %_ptr_Function_float Function
2224 %i = OpVariable %_ptr_Function_int Function
2225 OpStore %s %float_0
2226 OpStore %i %int_0
2227 OpBranch %26
2228 %26 = OpLabel
2229 OpLoopMerge %27 %28 None
2230 OpBranch %29
2231 %29 = OpLabel
2232 %30 = OpLoad %int %i
2233 %31 = OpSLessThan %bool %30 %int_10
2234 OpSelectionMerge %32 None
2235 OpBranchConditional %31 %32 %27
2236 %32 = OpLabel
2237 %33 = OpLoad %int %i
2238 %34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %33
2239 %35 = OpLoad %float %34
2240 %36 = OpLoad %float %s
2241 %37 = OpFAdd %float %36 %35
2242 OpStore %s %37
2243 OpBranch %28
2244 %28 = OpLabel
2245 %38 = OpLoad %int %i
2246 %39 = OpIAdd %int %38 %int_1
2247 OpStore %i %39
2248 OpBranch %26
2249 %27 = OpLabel
2250 %40 = OpLoad %float %s
2251 OpStore %o %40
2252 OpReturn
2253 OpFunctionEnd
2254 )";
2255 
2256   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2257 }
2258 
TEST_F(AggressiveDCETest,EliminateEntireUselessLoop)2259 TEST_F(AggressiveDCETest, EliminateEntireUselessLoop) {
2260   // #version 140
2261   // in vec4 BaseColor;
2262   //
2263   // layout(std140) uniform U_t
2264   // {
2265   //     int g_I ;
2266   // } ;
2267   //
2268   // void main()
2269   // {
2270   //     vec4 v = BaseColor;
2271   //     float df = 0.0;
2272   //     int i = 0;
2273   //     while (i < g_I) {
2274   //       df = df * 0.5;
2275   //       i = i + 1;
2276   //     }
2277   //     gl_FragColor = v;
2278   // }
2279 
2280   const std::string predefs1 =
2281       R"(OpCapability Shader
2282 %1 = OpExtInstImport "GLSL.std.450"
2283 OpMemoryModel Logical GLSL450
2284 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
2285 OpExecutionMode %main OriginUpperLeft
2286 OpSource GLSL 140
2287 )";
2288 
2289   const std::string names_before =
2290       R"(OpName %main "main"
2291 OpName %v "v"
2292 OpName %BaseColor "BaseColor"
2293 OpName %df "df"
2294 OpName %i "i"
2295 OpName %U_t "U_t"
2296 OpMemberName %U_t 0 "g_I"
2297 OpName %_ ""
2298 OpName %gl_FragColor "gl_FragColor"
2299 )";
2300 
2301   const std::string names_after =
2302       R"(OpName %main "main"
2303 OpName %v "v"
2304 OpName %BaseColor "BaseColor"
2305 OpName %gl_FragColor "gl_FragColor"
2306 )";
2307 
2308   const std::string predefs2_before =
2309       R"(OpMemberDecorate %U_t 0 Offset 0
2310 OpDecorate %U_t Block
2311 OpDecorate %_ DescriptorSet 0
2312 %void = OpTypeVoid
2313 %11 = OpTypeFunction %void
2314 %float = OpTypeFloat 32
2315 %v4float = OpTypeVector %float 4
2316 %_ptr_Function_v4float = OpTypePointer Function %v4float
2317 %_ptr_Input_v4float = OpTypePointer Input %v4float
2318 %BaseColor = OpVariable %_ptr_Input_v4float Input
2319 %_ptr_Function_float = OpTypePointer Function %float
2320 %float_0 = OpConstant %float 0
2321 %int = OpTypeInt 32 1
2322 %_ptr_Function_int = OpTypePointer Function %int
2323 %int_0 = OpConstant %int 0
2324 %U_t = OpTypeStruct %int
2325 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2326 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2327 %_ptr_Uniform_int = OpTypePointer Uniform %int
2328 %bool = OpTypeBool
2329 %float_0_5 = OpConstant %float 0.5
2330 %int_1 = OpConstant %int 1
2331 %_ptr_Output_v4float = OpTypePointer Output %v4float
2332 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2333 )";
2334 
2335   const std::string predefs2_after =
2336       R"(%void = OpTypeVoid
2337 %11 = OpTypeFunction %void
2338 %float = OpTypeFloat 32
2339 %v4float = OpTypeVector %float 4
2340 %_ptr_Function_v4float = OpTypePointer Function %v4float
2341 %_ptr_Input_v4float = OpTypePointer Input %v4float
2342 %BaseColor = OpVariable %_ptr_Input_v4float Input
2343 %_ptr_Output_v4float = OpTypePointer Output %v4float
2344 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2345 )";
2346 
2347   const std::string func_before =
2348       R"(%main = OpFunction %void None %11
2349 %27 = OpLabel
2350 %v = OpVariable %_ptr_Function_v4float Function
2351 %df = OpVariable %_ptr_Function_float Function
2352 %i = OpVariable %_ptr_Function_int Function
2353 %28 = OpLoad %v4float %BaseColor
2354 OpStore %v %28
2355 OpStore %df %float_0
2356 OpStore %i %int_0
2357 OpBranch %29
2358 %29 = OpLabel
2359 OpLoopMerge %30 %31 None
2360 OpBranch %32
2361 %32 = OpLabel
2362 %33 = OpLoad %int %i
2363 %34 = OpAccessChain %_ptr_Uniform_int %_ %int_0
2364 %35 = OpLoad %int %34
2365 %36 = OpSLessThan %bool %33 %35
2366 OpBranchConditional %36 %37 %30
2367 %37 = OpLabel
2368 %38 = OpLoad %float %df
2369 %39 = OpFMul %float %38 %float_0_5
2370 OpStore %df %39
2371 %40 = OpLoad %int %i
2372 %41 = OpIAdd %int %40 %int_1
2373 OpStore %i %41
2374 OpBranch %31
2375 %31 = OpLabel
2376 OpBranch %29
2377 %30 = OpLabel
2378 %42 = OpLoad %v4float %v
2379 OpStore %gl_FragColor %42
2380 OpReturn
2381 OpFunctionEnd
2382 )";
2383 
2384   const std::string func_after =
2385       R"(%main = OpFunction %void None %11
2386 %27 = OpLabel
2387 %v = OpVariable %_ptr_Function_v4float Function
2388 %28 = OpLoad %v4float %BaseColor
2389 OpStore %v %28
2390 OpBranch %29
2391 %29 = OpLabel
2392 OpBranch %30
2393 %30 = OpLabel
2394 %42 = OpLoad %v4float %v
2395 OpStore %gl_FragColor %42
2396 OpReturn
2397 OpFunctionEnd
2398 )";
2399 
2400   SinglePassRunAndCheck<AggressiveDCEPass>(
2401       predefs1 + names_before + predefs2_before + func_before,
2402       predefs1 + names_after + predefs2_after + func_after, true, true);
2403 }
2404 
TEST_F(AggressiveDCETest,NoEliminateBusyLoop)2405 TEST_F(AggressiveDCETest, NoEliminateBusyLoop) {
2406   // Note: SPIR-V edited to replace AtomicAdd(i,0) with AtomicLoad(i)
2407   //
2408   // #version 450
2409   //
2410   // layout(std430) buffer I_t
2411   // {
2412   // 	int g_I;
2413   // 	int g_I2;
2414   // };
2415   //
2416   // layout(location = 0) out int o;
2417   //
2418   // void main(void)
2419   // {
2420   // 	while (atomicAdd(g_I, 0) == 0) {}
2421   // 	o = g_I2;
2422   // }
2423 
2424   const std::string assembly =
2425       R"(OpCapability Shader
2426 %1 = OpExtInstImport "GLSL.std.450"
2427 OpMemoryModel Logical GLSL450
2428 OpEntryPoint Fragment %main "main" %o
2429 OpExecutionMode %main OriginUpperLeft
2430 OpSource GLSL 450
2431 OpName %main "main"
2432 OpName %I_t "I_t"
2433 OpMemberName %I_t 0 "g_I"
2434 OpMemberName %I_t 1 "g_I2"
2435 OpName %_ ""
2436 OpName %o "o"
2437 OpMemberDecorate %I_t 0 Offset 0
2438 OpMemberDecorate %I_t 1 Offset 4
2439 OpDecorate %I_t BufferBlock
2440 OpDecorate %_ DescriptorSet 0
2441 OpDecorate %o Location 0
2442 %void = OpTypeVoid
2443 %7 = OpTypeFunction %void
2444 %int = OpTypeInt 32 1
2445 %I_t = OpTypeStruct %int %int
2446 %_ptr_Uniform_I_t = OpTypePointer Uniform %I_t
2447 %_ = OpVariable %_ptr_Uniform_I_t Uniform
2448 %int_0 = OpConstant %int 0
2449 %int_1 = OpConstant %int 1
2450 %_ptr_Uniform_int = OpTypePointer Uniform %int
2451 %uint = OpTypeInt 32 0
2452 %uint_1 = OpConstant %uint 1
2453 %uint_0 = OpConstant %uint 0
2454 %bool = OpTypeBool
2455 %_ptr_Output_int = OpTypePointer Output %int
2456 %o = OpVariable %_ptr_Output_int Output
2457 %main = OpFunction %void None %7
2458 %18 = OpLabel
2459 OpBranch %19
2460 %19 = OpLabel
2461 OpLoopMerge %20 %21 None
2462 OpBranch %22
2463 %22 = OpLabel
2464 %23 = OpAccessChain %_ptr_Uniform_int %_ %int_0
2465 %24 = OpAtomicLoad %int %23 %uint_1 %uint_0
2466 %25 = OpIEqual %bool %24 %int_0
2467 OpBranchConditional %25 %26 %20
2468 %26 = OpLabel
2469 OpBranch %21
2470 %21 = OpLabel
2471 OpBranch %19
2472 %20 = OpLabel
2473 %27 = OpAccessChain %_ptr_Uniform_int %_ %int_1
2474 %28 = OpLoad %int %27
2475 OpStore %o %28
2476 OpReturn
2477 OpFunctionEnd
2478 )";
2479 
2480   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2481 }
2482 
TEST_F(AggressiveDCETest,NoEliminateLiveLoop)2483 TEST_F(AggressiveDCETest, NoEliminateLiveLoop) {
2484   // Note: SPIR-V optimized
2485   //
2486   // #version 430
2487   //
2488   // layout(std430) buffer U_t
2489   // {
2490   //     float g_F[10];
2491   // };
2492   //
2493   // layout(location = 0)out float o;
2494   //
2495   // void main(void)
2496   // {
2497   //     float s = 0.0;
2498   //     for (int i=0; i<10; i++)
2499   //         s += g_F[i];
2500   //     o = s;
2501   // }
2502 
2503   const std::string assembly =
2504       R"(OpCapability Shader
2505 %1 = OpExtInstImport "GLSL.std.450"
2506 OpMemoryModel Logical GLSL450
2507 OpEntryPoint Fragment %main "main" %o
2508 OpExecutionMode %main OriginUpperLeft
2509 OpSource GLSL 430
2510 OpName %main "main"
2511 OpName %U_t "U_t"
2512 OpMemberName %U_t 0 "g_F"
2513 OpName %_ ""
2514 OpName %o "o"
2515 OpDecorate %_arr_float_uint_10 ArrayStride 4
2516 OpMemberDecorate %U_t 0 Offset 0
2517 OpDecorate %U_t BufferBlock
2518 OpDecorate %_ DescriptorSet 0
2519 OpDecorate %o Location 0
2520 %void = OpTypeVoid
2521 %8 = OpTypeFunction %void
2522 %float = OpTypeFloat 32
2523 %float_0 = OpConstant %float 0
2524 %int = OpTypeInt 32 1
2525 %int_0 = OpConstant %int 0
2526 %int_10 = OpConstant %int 10
2527 %bool = OpTypeBool
2528 %uint = OpTypeInt 32 0
2529 %uint_10 = OpConstant %uint 10
2530 %_arr_float_uint_10 = OpTypeArray %float %uint_10
2531 %U_t = OpTypeStruct %_arr_float_uint_10
2532 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2533 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2534 %_ptr_Uniform_float = OpTypePointer Uniform %float
2535 %int_1 = OpConstant %int 1
2536 %_ptr_Output_float = OpTypePointer Output %float
2537 %o = OpVariable %_ptr_Output_float Output
2538 %main = OpFunction %void None %8
2539 %21 = OpLabel
2540 OpBranch %22
2541 %22 = OpLabel
2542 %23 = OpPhi %float %float_0 %21 %24 %25
2543 %26 = OpPhi %int %int_0 %21 %27 %25
2544 OpLoopMerge %28 %25 None
2545 OpBranch %29
2546 %29 = OpLabel
2547 %30 = OpSLessThan %bool %26 %int_10
2548 OpBranchConditional %30 %31 %28
2549 %31 = OpLabel
2550 %32 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %26
2551 %33 = OpLoad %float %32
2552 %24 = OpFAdd %float %23 %33
2553 OpBranch %25
2554 %25 = OpLabel
2555 %27 = OpIAdd %int %26 %int_1
2556 OpBranch %22
2557 %28 = OpLabel
2558 OpStore %o %23
2559 OpReturn
2560 OpFunctionEnd
2561 )";
2562 
2563   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
2564 }
2565 
TEST_F(AggressiveDCETest,EliminateEntireFunctionBody)2566 TEST_F(AggressiveDCETest, EliminateEntireFunctionBody) {
2567   // #version 450
2568   //
2569   // layout(location = 0) in vec4 BaseColor;
2570   // layout(location = 0) out vec4 OutColor;
2571   //
2572   // void main()
2573   // {
2574   //     float d;
2575   //     if (BaseColor.x == 0)
2576   //       d = BaseColor.y;
2577   //     else
2578   //       d = BaseColor.z;
2579   // }
2580 
2581   const std::string predefs_before =
2582       R"(OpCapability Shader
2583 %1 = OpExtInstImport "GLSL.std.450"
2584 OpMemoryModel Logical GLSL450
2585 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
2586 OpExecutionMode %main OriginUpperLeft
2587 OpSource GLSL 450
2588 OpName %main "main"
2589 OpName %BaseColor "BaseColor"
2590 OpName %d "d"
2591 OpName %OutColor "OutColor"
2592 OpDecorate %BaseColor Location 0
2593 OpDecorate %OutColor Location 0
2594 %void = OpTypeVoid
2595 %7 = OpTypeFunction %void
2596 %float = OpTypeFloat 32
2597 %v4float = OpTypeVector %float 4
2598 %_ptr_Input_v4float = OpTypePointer Input %v4float
2599 %BaseColor = OpVariable %_ptr_Input_v4float Input
2600 %uint = OpTypeInt 32 0
2601 %uint_0 = OpConstant %uint 0
2602 %_ptr_Input_float = OpTypePointer Input %float
2603 %float_0 = OpConstant %float 0
2604 %bool = OpTypeBool
2605 %_ptr_Function_float = OpTypePointer Function %float
2606 %uint_1 = OpConstant %uint 1
2607 %uint_2 = OpConstant %uint 2
2608 %_ptr_Output_v4float = OpTypePointer Output %v4float
2609 %OutColor = OpVariable %_ptr_Output_v4float Output
2610 )";
2611 
2612   const std::string predefs_after =
2613       R"(OpCapability Shader
2614 %1 = OpExtInstImport "GLSL.std.450"
2615 OpMemoryModel Logical GLSL450
2616 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
2617 OpExecutionMode %main OriginUpperLeft
2618 OpSource GLSL 450
2619 OpName %main "main"
2620 OpName %BaseColor "BaseColor"
2621 OpName %OutColor "OutColor"
2622 OpDecorate %BaseColor Location 0
2623 OpDecorate %OutColor Location 0
2624 %void = OpTypeVoid
2625 %7 = OpTypeFunction %void
2626 %float = OpTypeFloat 32
2627 %v4float = OpTypeVector %float 4
2628 %_ptr_Input_v4float = OpTypePointer Input %v4float
2629 %BaseColor = OpVariable %_ptr_Input_v4float Input
2630 %_ptr_Output_v4float = OpTypePointer Output %v4float
2631 %OutColor = OpVariable %_ptr_Output_v4float Output
2632 )";
2633 
2634   const std::string func_before =
2635       R"(%main = OpFunction %void None %7
2636 %20 = OpLabel
2637 %d = OpVariable %_ptr_Function_float Function
2638 %21 = OpAccessChain %_ptr_Input_float %BaseColor %uint_0
2639 %22 = OpLoad %float %21
2640 %23 = OpFOrdEqual %bool %22 %float_0
2641 OpSelectionMerge %24 None
2642 OpBranchConditional %23 %25 %26
2643 %25 = OpLabel
2644 %27 = OpAccessChain %_ptr_Input_float %BaseColor %uint_1
2645 %28 = OpLoad %float %27
2646 OpStore %d %28
2647 OpBranch %24
2648 %26 = OpLabel
2649 %29 = OpAccessChain %_ptr_Input_float %BaseColor %uint_2
2650 %30 = OpLoad %float %29
2651 OpStore %d %30
2652 OpBranch %24
2653 %24 = OpLabel
2654 OpReturn
2655 OpFunctionEnd
2656 )";
2657 
2658   const std::string func_after =
2659       R"(%main = OpFunction %void None %7
2660 %20 = OpLabel
2661 OpBranch %24
2662 %24 = OpLabel
2663 OpReturn
2664 OpFunctionEnd
2665 )";
2666 
2667   SinglePassRunAndCheck<AggressiveDCEPass>(
2668       predefs_before + func_before, predefs_after + func_after, true, true);
2669 }
2670 
TEST_F(AggressiveDCETest,EliminateUselessInnerLoop)2671 TEST_F(AggressiveDCETest, EliminateUselessInnerLoop) {
2672   // #version 430
2673   //
2674   // layout(std430) buffer U_t
2675   // {
2676   //     float g_F[10];
2677   // };
2678   //
2679   // layout(location = 0)out float o;
2680   //
2681   // void main(void)
2682   // {
2683   //     float s = 0.0;
2684   //     for (int i=0; i<10; i++) {
2685   //         for (int j=0; j<10; j++) {
2686   //         }
2687   //         s += g_F[i];
2688   //     }
2689   //     o = s;
2690   // }
2691 
2692   const std::string predefs_before =
2693       R"(OpCapability Shader
2694 %1 = OpExtInstImport "GLSL.std.450"
2695 OpMemoryModel Logical GLSL450
2696 OpEntryPoint Fragment %main "main" %o
2697 OpExecutionMode %main OriginUpperLeft
2698 OpSource GLSL 430
2699 OpName %main "main"
2700 OpName %s "s"
2701 OpName %i "i"
2702 OpName %j "j"
2703 OpName %U_t "U_t"
2704 OpMemberName %U_t 0 "g_F"
2705 OpName %_ ""
2706 OpName %o "o"
2707 OpDecorate %_arr_float_uint_10 ArrayStride 4
2708 OpMemberDecorate %U_t 0 Offset 0
2709 OpDecorate %U_t BufferBlock
2710 OpDecorate %_ DescriptorSet 0
2711 OpDecorate %o Location 0
2712 %void = OpTypeVoid
2713 %11 = OpTypeFunction %void
2714 %float = OpTypeFloat 32
2715 %_ptr_Function_float = OpTypePointer Function %float
2716 %float_0 = OpConstant %float 0
2717 %int = OpTypeInt 32 1
2718 %_ptr_Function_int = OpTypePointer Function %int
2719 %int_0 = OpConstant %int 0
2720 %int_10 = OpConstant %int 10
2721 %bool = OpTypeBool
2722 %int_1 = OpConstant %int 1
2723 %uint = OpTypeInt 32 0
2724 %uint_10 = OpConstant %uint 10
2725 %_arr_float_uint_10 = OpTypeArray %float %uint_10
2726 %U_t = OpTypeStruct %_arr_float_uint_10
2727 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2728 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2729 %_ptr_Uniform_float = OpTypePointer Uniform %float
2730 %_ptr_Output_float = OpTypePointer Output %float
2731 %o = OpVariable %_ptr_Output_float Output
2732 )";
2733 
2734   const std::string predefs_after =
2735       R"(OpCapability Shader
2736 %1 = OpExtInstImport "GLSL.std.450"
2737 OpMemoryModel Logical GLSL450
2738 OpEntryPoint Fragment %main "main" %o
2739 OpExecutionMode %main OriginUpperLeft
2740 OpSource GLSL 430
2741 OpName %main "main"
2742 OpName %s "s"
2743 OpName %i "i"
2744 OpName %U_t "U_t"
2745 OpMemberName %U_t 0 "g_F"
2746 OpName %_ ""
2747 OpName %o "o"
2748 OpDecorate %_arr_float_uint_10 ArrayStride 4
2749 OpMemberDecorate %U_t 0 Offset 0
2750 OpDecorate %U_t BufferBlock
2751 OpDecorate %_ DescriptorSet 0
2752 OpDecorate %o Location 0
2753 %void = OpTypeVoid
2754 %11 = OpTypeFunction %void
2755 %float = OpTypeFloat 32
2756 %_ptr_Function_float = OpTypePointer Function %float
2757 %float_0 = OpConstant %float 0
2758 %int = OpTypeInt 32 1
2759 %_ptr_Function_int = OpTypePointer Function %int
2760 %int_0 = OpConstant %int 0
2761 %int_10 = OpConstant %int 10
2762 %bool = OpTypeBool
2763 %int_1 = OpConstant %int 1
2764 %uint = OpTypeInt 32 0
2765 %uint_10 = OpConstant %uint 10
2766 %_arr_float_uint_10 = OpTypeArray %float %uint_10
2767 %U_t = OpTypeStruct %_arr_float_uint_10
2768 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2769 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2770 %_ptr_Uniform_float = OpTypePointer Uniform %float
2771 %_ptr_Output_float = OpTypePointer Output %float
2772 %o = OpVariable %_ptr_Output_float Output
2773 )";
2774 
2775   const std::string func_before =
2776       R"(%main = OpFunction %void None %11
2777 %26 = OpLabel
2778 %s = OpVariable %_ptr_Function_float Function
2779 %i = OpVariable %_ptr_Function_int Function
2780 %j = OpVariable %_ptr_Function_int Function
2781 OpStore %s %float_0
2782 OpStore %i %int_0
2783 OpBranch %27
2784 %27 = OpLabel
2785 OpLoopMerge %28 %29 None
2786 OpBranch %30
2787 %30 = OpLabel
2788 %31 = OpLoad %int %i
2789 %32 = OpSLessThan %bool %31 %int_10
2790 OpBranchConditional %32 %33 %28
2791 %33 = OpLabel
2792 OpStore %j %int_0
2793 OpBranch %34
2794 %34 = OpLabel
2795 OpLoopMerge %35 %36 None
2796 OpBranch %37
2797 %37 = OpLabel
2798 %38 = OpLoad %int %j
2799 %39 = OpSLessThan %bool %38 %int_10
2800 OpBranchConditional %39 %40 %35
2801 %40 = OpLabel
2802 OpBranch %36
2803 %36 = OpLabel
2804 %41 = OpLoad %int %j
2805 %42 = OpIAdd %int %41 %int_1
2806 OpStore %j %42
2807 OpBranch %34
2808 %35 = OpLabel
2809 %43 = OpLoad %int %i
2810 %44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %43
2811 %45 = OpLoad %float %44
2812 %46 = OpLoad %float %s
2813 %47 = OpFAdd %float %46 %45
2814 OpStore %s %47
2815 OpBranch %29
2816 %29 = OpLabel
2817 %48 = OpLoad %int %i
2818 %49 = OpIAdd %int %48 %int_1
2819 OpStore %i %49
2820 OpBranch %27
2821 %28 = OpLabel
2822 %50 = OpLoad %float %s
2823 OpStore %o %50
2824 OpReturn
2825 OpFunctionEnd
2826 )";
2827 
2828   const std::string func_after =
2829       R"(%main = OpFunction %void None %11
2830 %26 = OpLabel
2831 %s = OpVariable %_ptr_Function_float Function
2832 %i = OpVariable %_ptr_Function_int Function
2833 OpStore %s %float_0
2834 OpStore %i %int_0
2835 OpBranch %27
2836 %27 = OpLabel
2837 OpLoopMerge %28 %29 None
2838 OpBranch %30
2839 %30 = OpLabel
2840 %31 = OpLoad %int %i
2841 %32 = OpSLessThan %bool %31 %int_10
2842 OpBranchConditional %32 %33 %28
2843 %33 = OpLabel
2844 OpBranch %34
2845 %34 = OpLabel
2846 OpBranch %35
2847 %35 = OpLabel
2848 %43 = OpLoad %int %i
2849 %44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %43
2850 %45 = OpLoad %float %44
2851 %46 = OpLoad %float %s
2852 %47 = OpFAdd %float %46 %45
2853 OpStore %s %47
2854 OpBranch %29
2855 %29 = OpLabel
2856 %48 = OpLoad %int %i
2857 %49 = OpIAdd %int %48 %int_1
2858 OpStore %i %49
2859 OpBranch %27
2860 %28 = OpLabel
2861 %50 = OpLoad %float %s
2862 OpStore %o %50
2863 OpReturn
2864 OpFunctionEnd
2865 )";
2866 
2867   SinglePassRunAndCheck<AggressiveDCEPass>(
2868       predefs_before + func_before, predefs_after + func_after, true, true);
2869 }
2870 
TEST_F(AggressiveDCETest,EliminateUselessNestedLoopWithIf)2871 TEST_F(AggressiveDCETest, EliminateUselessNestedLoopWithIf) {
2872   // #version 430
2873   //
2874   // layout(std430) buffer U_t
2875   // {
2876   //     float g_F[10][10];
2877   // };
2878   //
2879   // layout(location = 0)out float o;
2880   //
2881   // void main(void)
2882   // {
2883   //     float s = 0.0;
2884   //     for (int i=0; i<10; i++) {
2885   //         for (int j=0; j<10; j++) {
2886   //             float t = g_F[i][j];
2887   //             if (t > 0.0)
2888   //                 s += t;
2889   //         }
2890   //     }
2891   //     o = 0.0;
2892   // }
2893 
2894   const std::string predefs_before =
2895       R"(OpCapability Shader
2896 %1 = OpExtInstImport "GLSL.std.450"
2897 OpMemoryModel Logical GLSL450
2898 OpEntryPoint Fragment %main "main" %o
2899 OpExecutionMode %main OriginUpperLeft
2900 OpSource GLSL 430
2901 OpName %main "main"
2902 OpName %s "s"
2903 OpName %i "i"
2904 OpName %j "j"
2905 OpName %U_t "U_t"
2906 OpMemberName %U_t 0 "g_F"
2907 OpName %_ ""
2908 OpName %o "o"
2909 OpDecorate %_arr_float_uint_10 ArrayStride 4
2910 OpDecorate %_arr__arr_float_uint_10_uint_10 ArrayStride 40
2911 OpMemberDecorate %U_t 0 Offset 0
2912 OpDecorate %U_t BufferBlock
2913 OpDecorate %_ DescriptorSet 0
2914 OpDecorate %o Location 0
2915 %void = OpTypeVoid
2916 %12 = OpTypeFunction %void
2917 %float = OpTypeFloat 32
2918 %_ptr_Function_float = OpTypePointer Function %float
2919 %float_0 = OpConstant %float 0
2920 %int = OpTypeInt 32 1
2921 %_ptr_Function_int = OpTypePointer Function %int
2922 %int_0 = OpConstant %int 0
2923 %int_10 = OpConstant %int 10
2924 %bool = OpTypeBool
2925 %uint = OpTypeInt 32 0
2926 %uint_10 = OpConstant %uint 10
2927 %_arr_float_uint_10 = OpTypeArray %float %uint_10
2928 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
2929 %U_t = OpTypeStruct %_arr__arr_float_uint_10_uint_10
2930 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
2931 %_ = OpVariable %_ptr_Uniform_U_t Uniform
2932 %_ptr_Uniform_float = OpTypePointer Uniform %float
2933 %int_1 = OpConstant %int 1
2934 %_ptr_Output_float = OpTypePointer Output %float
2935 %o = OpVariable %_ptr_Output_float Output
2936 )";
2937 
2938   const std::string predefs_after =
2939       R"(OpCapability Shader
2940 %1 = OpExtInstImport "GLSL.std.450"
2941 OpMemoryModel Logical GLSL450
2942 OpEntryPoint Fragment %main "main" %o
2943 OpExecutionMode %main OriginUpperLeft
2944 OpSource GLSL 430
2945 OpName %main "main"
2946 OpName %o "o"
2947 OpDecorate %o Location 0
2948 %void = OpTypeVoid
2949 %12 = OpTypeFunction %void
2950 %float = OpTypeFloat 32
2951 %float_0 = OpConstant %float 0
2952 %_ptr_Output_float = OpTypePointer Output %float
2953 %o = OpVariable %_ptr_Output_float Output
2954 )";
2955 
2956   const std::string func_before =
2957       R"(%main = OpFunction %void None %12
2958 %27 = OpLabel
2959 %s = OpVariable %_ptr_Function_float Function
2960 %i = OpVariable %_ptr_Function_int Function
2961 %j = OpVariable %_ptr_Function_int Function
2962 OpStore %s %float_0
2963 OpStore %i %int_0
2964 OpBranch %28
2965 %28 = OpLabel
2966 OpLoopMerge %29 %30 None
2967 OpBranch %31
2968 %31 = OpLabel
2969 %32 = OpLoad %int %i
2970 %33 = OpSLessThan %bool %32 %int_10
2971 OpBranchConditional %33 %34 %29
2972 %34 = OpLabel
2973 OpStore %j %int_0
2974 OpBranch %35
2975 %35 = OpLabel
2976 OpLoopMerge %36 %37 None
2977 OpBranch %38
2978 %38 = OpLabel
2979 %39 = OpLoad %int %j
2980 %40 = OpSLessThan %bool %39 %int_10
2981 OpBranchConditional %40 %41 %36
2982 %41 = OpLabel
2983 %42 = OpLoad %int %i
2984 %43 = OpLoad %int %j
2985 %44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %42 %43
2986 %45 = OpLoad %float %44
2987 %46 = OpFOrdGreaterThan %bool %45 %float_0
2988 OpSelectionMerge %47 None
2989 OpBranchConditional %46 %48 %47
2990 %48 = OpLabel
2991 %49 = OpLoad %float %s
2992 %50 = OpFAdd %float %49 %45
2993 OpStore %s %50
2994 OpBranch %47
2995 %47 = OpLabel
2996 OpBranch %37
2997 %37 = OpLabel
2998 %51 = OpLoad %int %j
2999 %52 = OpIAdd %int %51 %int_1
3000 OpStore %j %52
3001 OpBranch %35
3002 %36 = OpLabel
3003 OpBranch %30
3004 %30 = OpLabel
3005 %53 = OpLoad %int %i
3006 %54 = OpIAdd %int %53 %int_1
3007 OpStore %i %54
3008 OpBranch %28
3009 %29 = OpLabel
3010 OpStore %o %float_0
3011 OpReturn
3012 OpFunctionEnd
3013 )";
3014 
3015   const std::string func_after =
3016       R"(%main = OpFunction %void None %12
3017 %27 = OpLabel
3018 OpBranch %28
3019 %28 = OpLabel
3020 OpBranch %29
3021 %29 = OpLabel
3022 OpStore %o %float_0
3023 OpReturn
3024 OpFunctionEnd
3025 )";
3026 
3027   SinglePassRunAndCheck<AggressiveDCEPass>(
3028       predefs_before + func_before, predefs_after + func_after, true, true);
3029 }
3030 
TEST_F(AggressiveDCETest,EliminateEmptyIfBeforeContinue)3031 TEST_F(AggressiveDCETest, EliminateEmptyIfBeforeContinue) {
3032   // #version 430
3033   //
3034   // layout(location = 0)out float o;
3035   //
3036   // void main(void)
3037   // {
3038   //     float s = 0.0;
3039   //     for (int i=0; i<10; i++) {
3040   //         s += 1.0;
3041   //         if (i > s) {}
3042   //     }
3043   //     o = s;
3044   // }
3045 
3046   const std::string predefs_before =
3047       R"(OpCapability Shader
3048 %1 = OpExtInstImport "GLSL.std.450"
3049 OpMemoryModel Logical GLSL450
3050 OpEntryPoint Fragment %main "main" %3
3051 OpExecutionMode %main OriginUpperLeft
3052 OpSource GLSL 430
3053 OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
3054 OpSourceExtension "GL_GOOGLE_include_directive"
3055 OpName %main "main"
3056 OpDecorate %3 Location 0
3057 %void = OpTypeVoid
3058 %5 = OpTypeFunction %void
3059 %float = OpTypeFloat 32
3060 %float_0 = OpConstant %float 0
3061 %int = OpTypeInt 32 1
3062 %_ptr_Function_int = OpTypePointer Function %int
3063 %int_0 = OpConstant %int 0
3064 %int_10 = OpConstant %int 10
3065 %bool = OpTypeBool
3066 %float_1 = OpConstant %float 1
3067 %int_1 = OpConstant %int 1
3068 %_ptr_Output_float = OpTypePointer Output %float
3069 %3 = OpVariable %_ptr_Output_float Output
3070 )";
3071 
3072   const std::string predefs_after =
3073       R"(OpCapability Shader
3074 %1 = OpExtInstImport "GLSL.std.450"
3075 OpMemoryModel Logical GLSL450
3076 OpEntryPoint Fragment %main "main" %3
3077 OpExecutionMode %main OriginUpperLeft
3078 OpSource GLSL 430
3079 OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
3080 OpSourceExtension "GL_GOOGLE_include_directive"
3081 OpName %main "main"
3082 OpDecorate %3 Location 0
3083 %void = OpTypeVoid
3084 %5 = OpTypeFunction %void
3085 %float = OpTypeFloat 32
3086 %float_0 = OpConstant %float 0
3087 %int = OpTypeInt 32 1
3088 %int_0 = OpConstant %int 0
3089 %int_10 = OpConstant %int 10
3090 %bool = OpTypeBool
3091 %float_1 = OpConstant %float 1
3092 %int_1 = OpConstant %int 1
3093 %_ptr_Output_float = OpTypePointer Output %float
3094 %3 = OpVariable %_ptr_Output_float Output
3095 )";
3096 
3097   const std::string func_before =
3098       R"(%main = OpFunction %void None %5
3099 %16 = OpLabel
3100 OpBranch %17
3101 %17 = OpLabel
3102 %18 = OpPhi %float %float_0 %16 %19 %20
3103 %21 = OpPhi %int %int_0 %16 %22 %20
3104 OpLoopMerge %23 %20 None
3105 OpBranch %24
3106 %24 = OpLabel
3107 %25 = OpSLessThan %bool %21 %int_10
3108 OpBranchConditional %25 %26 %23
3109 %26 = OpLabel
3110 %19 = OpFAdd %float %18 %float_1
3111 %27 = OpConvertFToS %int %19
3112 %28 = OpSGreaterThan %bool %21 %27
3113 OpSelectionMerge %20 None
3114 OpBranchConditional %28 %29 %20
3115 %29 = OpLabel
3116 OpBranch %20
3117 %20 = OpLabel
3118 %22 = OpIAdd %int %21 %int_1
3119 OpBranch %17
3120 %23 = OpLabel
3121 OpStore %3 %18
3122 OpReturn
3123 OpFunctionEnd
3124 )";
3125 
3126   const std::string func_after =
3127       R"(%main = OpFunction %void None %5
3128 %16 = OpLabel
3129 OpBranch %17
3130 %17 = OpLabel
3131 %18 = OpPhi %float %float_0 %16 %19 %20
3132 %21 = OpPhi %int %int_0 %16 %22 %20
3133 OpLoopMerge %23 %20 None
3134 OpBranch %24
3135 %24 = OpLabel
3136 %25 = OpSLessThan %bool %21 %int_10
3137 OpBranchConditional %25 %26 %23
3138 %26 = OpLabel
3139 %19 = OpFAdd %float %18 %float_1
3140 OpBranch %20
3141 %20 = OpLabel
3142 %22 = OpIAdd %int %21 %int_1
3143 OpBranch %17
3144 %23 = OpLabel
3145 OpStore %3 %18
3146 OpReturn
3147 OpFunctionEnd
3148 )";
3149 
3150   SinglePassRunAndCheck<AggressiveDCEPass>(
3151       predefs_before + func_before, predefs_after + func_after, true, true);
3152 }
3153 
TEST_F(AggressiveDCETest,NoEliminateLiveNestedLoopWithIf)3154 TEST_F(AggressiveDCETest, NoEliminateLiveNestedLoopWithIf) {
3155   // Note: SPIR-V optimized
3156   //
3157   // #version 430
3158   //
3159   // layout(std430) buffer U_t
3160   // {
3161   //     float g_F[10][10];
3162   // };
3163   //
3164   // layout(location = 0)out float o;
3165   //
3166   // void main(void)
3167   // {
3168   //     float s = 0.0;
3169   //     for (int i=0; i<10; i++) {
3170   //         for (int j=0; j<10; j++) {
3171   //             float t = g_F[i][j];
3172   //             if (t > 0.0)
3173   //                 s += t;
3174   //         }
3175   //     }
3176   //     o = s;
3177   // }
3178 
3179   const std::string assembly =
3180       R"(OpCapability Shader
3181 %1 = OpExtInstImport "GLSL.std.450"
3182 OpMemoryModel Logical GLSL450
3183 OpEntryPoint Fragment %main "main" %o
3184 OpExecutionMode %main OriginUpperLeft
3185 OpSource GLSL 430
3186 OpName %main "main"
3187 OpName %s "s"
3188 OpName %i "i"
3189 OpName %j "j"
3190 OpName %U_t "U_t"
3191 OpMemberName %U_t 0 "g_F"
3192 OpName %_ ""
3193 OpName %o "o"
3194 OpDecorate %_arr_float_uint_10 ArrayStride 4
3195 OpDecorate %_arr__arr_float_uint_10_uint_10 ArrayStride 40
3196 OpMemberDecorate %U_t 0 Offset 0
3197 OpDecorate %U_t BufferBlock
3198 OpDecorate %_ DescriptorSet 0
3199 OpDecorate %o Location 0
3200 %void = OpTypeVoid
3201 %12 = OpTypeFunction %void
3202 %float = OpTypeFloat 32
3203 %_ptr_Function_float = OpTypePointer Function %float
3204 %float_0 = OpConstant %float 0
3205 %int = OpTypeInt 32 1
3206 %_ptr_Function_int = OpTypePointer Function %int
3207 %int_0 = OpConstant %int 0
3208 %int_10 = OpConstant %int 10
3209 %bool = OpTypeBool
3210 %uint = OpTypeInt 32 0
3211 %uint_10 = OpConstant %uint 10
3212 %_arr_float_uint_10 = OpTypeArray %float %uint_10
3213 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
3214 %U_t = OpTypeStruct %_arr__arr_float_uint_10_uint_10
3215 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
3216 %_ = OpVariable %_ptr_Uniform_U_t Uniform
3217 %_ptr_Uniform_float = OpTypePointer Uniform %float
3218 %int_1 = OpConstant %int 1
3219 %_ptr_Output_float = OpTypePointer Output %float
3220 %o = OpVariable %_ptr_Output_float Output
3221 %main = OpFunction %void None %12
3222 %27 = OpLabel
3223 %s = OpVariable %_ptr_Function_float Function
3224 %i = OpVariable %_ptr_Function_int Function
3225 %j = OpVariable %_ptr_Function_int Function
3226 OpStore %s %float_0
3227 OpStore %i %int_0
3228 OpBranch %28
3229 %28 = OpLabel
3230 OpLoopMerge %29 %30 None
3231 OpBranch %31
3232 %31 = OpLabel
3233 %32 = OpLoad %int %i
3234 %33 = OpSLessThan %bool %32 %int_10
3235 OpBranchConditional %33 %34 %29
3236 %34 = OpLabel
3237 OpStore %j %int_0
3238 OpBranch %35
3239 %35 = OpLabel
3240 OpLoopMerge %36 %37 None
3241 OpBranch %38
3242 %38 = OpLabel
3243 %39 = OpLoad %int %j
3244 %40 = OpSLessThan %bool %39 %int_10
3245 OpBranchConditional %40 %41 %36
3246 %41 = OpLabel
3247 %42 = OpLoad %int %i
3248 %43 = OpLoad %int %j
3249 %44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %42 %43
3250 %45 = OpLoad %float %44
3251 %46 = OpFOrdGreaterThan %bool %45 %float_0
3252 OpSelectionMerge %47 None
3253 OpBranchConditional %46 %48 %47
3254 %48 = OpLabel
3255 %49 = OpLoad %float %s
3256 %50 = OpFAdd %float %49 %45
3257 OpStore %s %50
3258 OpBranch %47
3259 %47 = OpLabel
3260 OpBranch %37
3261 %37 = OpLabel
3262 %51 = OpLoad %int %j
3263 %52 = OpIAdd %int %51 %int_1
3264 OpStore %j %52
3265 OpBranch %35
3266 %36 = OpLabel
3267 OpBranch %30
3268 %30 = OpLabel
3269 %53 = OpLoad %int %i
3270 %54 = OpIAdd %int %53 %int_1
3271 OpStore %i %54
3272 OpBranch %28
3273 %29 = OpLabel
3274 %55 = OpLoad %float %s
3275 OpStore %o %55
3276 OpReturn
3277 OpFunctionEnd
3278 )";
3279 
3280   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
3281 }
3282 
TEST_F(AggressiveDCETest,NoEliminateIfContinue)3283 TEST_F(AggressiveDCETest, NoEliminateIfContinue) {
3284   // Do not eliminate continue embedded in if construct
3285   //
3286   // #version 430
3287   //
3288   // layout(std430) buffer U_t
3289   // {
3290   //     float g_F[10];
3291   // };
3292   //
3293   // layout(location = 0)out float o;
3294   //
3295   // void main(void)
3296   // {
3297   //     float s = 0.0;
3298   //     for (int i=0; i<10; i++) {
3299   //         if (i % 2 == 0) continue;
3300   //         s += g_F[i];
3301   //     }
3302   //     o = s;
3303   // }
3304 
3305   const std::string assembly =
3306       R"(OpCapability Shader
3307 %1 = OpExtInstImport "GLSL.std.450"
3308 OpMemoryModel Logical GLSL450
3309 OpEntryPoint Fragment %main "main" %o
3310 OpExecutionMode %main OriginUpperLeft
3311 OpSource GLSL 430
3312 OpName %main "main"
3313 OpName %s "s"
3314 OpName %i "i"
3315 OpName %U_t "U_t"
3316 OpMemberName %U_t 0 "g_F"
3317 OpName %_ ""
3318 OpName %o "o"
3319 OpDecorate %_arr_float_uint_10 ArrayStride 4
3320 OpMemberDecorate %U_t 0 Offset 0
3321 OpDecorate %U_t BufferBlock
3322 OpDecorate %_ DescriptorSet 0
3323 OpDecorate %o Location 0
3324 %void = OpTypeVoid
3325 %10 = OpTypeFunction %void
3326 %float = OpTypeFloat 32
3327 %_ptr_Function_float = OpTypePointer Function %float
3328 %float_0 = OpConstant %float 0
3329 %int = OpTypeInt 32 1
3330 %_ptr_Function_int = OpTypePointer Function %int
3331 %int_0 = OpConstant %int 0
3332 %int_10 = OpConstant %int 10
3333 %bool = OpTypeBool
3334 %int_2 = OpConstant %int 2
3335 %uint = OpTypeInt 32 0
3336 %uint_10 = OpConstant %uint 10
3337 %_arr_float_uint_10 = OpTypeArray %float %uint_10
3338 %U_t = OpTypeStruct %_arr_float_uint_10
3339 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
3340 %_ = OpVariable %_ptr_Uniform_U_t Uniform
3341 %_ptr_Uniform_float = OpTypePointer Uniform %float
3342 %int_1 = OpConstant %int 1
3343 %_ptr_Output_float = OpTypePointer Output %float
3344 %o = OpVariable %_ptr_Output_float Output
3345 %main = OpFunction %void None %10
3346 %26 = OpLabel
3347 %s = OpVariable %_ptr_Function_float Function
3348 %i = OpVariable %_ptr_Function_int Function
3349 OpStore %s %float_0
3350 OpStore %i %int_0
3351 OpBranch %27
3352 %27 = OpLabel
3353 OpLoopMerge %28 %29 None
3354 OpBranch %30
3355 %30 = OpLabel
3356 %31 = OpLoad %int %i
3357 %32 = OpSLessThan %bool %31 %int_10
3358 OpBranchConditional %32 %33 %28
3359 %33 = OpLabel
3360 %34 = OpLoad %int %i
3361 %35 = OpSMod %int %34 %int_2
3362 %36 = OpIEqual %bool %35 %int_0
3363 OpSelectionMerge %37 None
3364 OpBranchConditional %36 %38 %37
3365 %38 = OpLabel
3366 OpBranch %29
3367 %37 = OpLabel
3368 %39 = OpLoad %int %i
3369 %40 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %39
3370 %41 = OpLoad %float %40
3371 %42 = OpLoad %float %s
3372 %43 = OpFAdd %float %42 %41
3373 OpStore %s %43
3374 OpBranch %29
3375 %29 = OpLabel
3376 %44 = OpLoad %int %i
3377 %45 = OpIAdd %int %44 %int_1
3378 OpStore %i %45
3379 OpBranch %27
3380 %28 = OpLabel
3381 %46 = OpLoad %float %s
3382 OpStore %o %46
3383 OpReturn
3384 OpFunctionEnd
3385 )";
3386 
3387   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
3388 }
3389 
TEST_F(AggressiveDCETest,NoEliminateIfContinue2)3390 TEST_F(AggressiveDCETest, NoEliminateIfContinue2) {
3391   // Do not eliminate continue not embedded in if construct
3392   //
3393   // #version 430
3394   //
3395   // layout(std430) buffer U_t
3396   // {
3397   //     float g_F[10];
3398   // };
3399   //
3400   // layout(location = 0)out float o;
3401   //
3402   // void main(void)
3403   // {
3404   //     float s = 0.0;
3405   //     for (int i=0; i<10; i++) {
3406   //         if (i % 2 == 0) continue;
3407   //         s += g_F[i];
3408   //     }
3409   //     o = s;
3410   // }
3411 
3412   const std::string assembly =
3413       R"(OpCapability Shader
3414 %1 = OpExtInstImport "GLSL.std.450"
3415 OpMemoryModel Logical GLSL450
3416 OpEntryPoint Fragment %main "main" %o
3417 OpExecutionMode %main OriginUpperLeft
3418 OpSource GLSL 430
3419 OpName %main "main"
3420 OpName %s "s"
3421 OpName %i "i"
3422 OpName %U_t "U_t"
3423 OpMemberName %U_t 0 "g_F"
3424 OpName %_ ""
3425 OpName %o "o"
3426 OpDecorate %_arr_float_uint_10 ArrayStride 4
3427 OpMemberDecorate %U_t 0 Offset 0
3428 OpDecorate %U_t BufferBlock
3429 OpDecorate %_ DescriptorSet 0
3430 OpDecorate %o Location 0
3431 %void = OpTypeVoid
3432 %10 = OpTypeFunction %void
3433 %float = OpTypeFloat 32
3434 %_ptr_Function_float = OpTypePointer Function %float
3435 %float_0 = OpConstant %float 0
3436 %int = OpTypeInt 32 1
3437 %_ptr_Function_int = OpTypePointer Function %int
3438 %int_0 = OpConstant %int 0
3439 %int_10 = OpConstant %int 10
3440 %bool = OpTypeBool
3441 %int_2 = OpConstant %int 2
3442 %uint = OpTypeInt 32 0
3443 %uint_10 = OpConstant %uint 10
3444 %_arr_float_uint_10 = OpTypeArray %float %uint_10
3445 %U_t = OpTypeStruct %_arr_float_uint_10
3446 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
3447 %_ = OpVariable %_ptr_Uniform_U_t Uniform
3448 %_ptr_Uniform_float = OpTypePointer Uniform %float
3449 %int_1 = OpConstant %int 1
3450 %_ptr_Output_float = OpTypePointer Output %float
3451 %o = OpVariable %_ptr_Output_float Output
3452 %main = OpFunction %void None %10
3453 %26 = OpLabel
3454 %s = OpVariable %_ptr_Function_float Function
3455 %i = OpVariable %_ptr_Function_int Function
3456 OpStore %s %float_0
3457 OpStore %i %int_0
3458 OpBranch %27
3459 %27 = OpLabel
3460 OpLoopMerge %28 %29 None
3461 OpBranch %30
3462 %30 = OpLabel
3463 %31 = OpLoad %int %i
3464 %32 = OpSLessThan %bool %31 %int_10
3465 OpBranchConditional %32 %33 %28
3466 %33 = OpLabel
3467 %34 = OpLoad %int %i
3468 %35 = OpSMod %int %34 %int_2
3469 %36 = OpIEqual %bool %35 %int_0
3470 OpBranchConditional %36 %29 %37
3471 %37 = OpLabel
3472 %38 = OpLoad %int %i
3473 %39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %38
3474 %40 = OpLoad %float %39
3475 %41 = OpLoad %float %s
3476 %42 = OpFAdd %float %41 %40
3477 OpStore %s %42
3478 OpBranch %29
3479 %29 = OpLabel
3480 %43 = OpLoad %int %i
3481 %44 = OpIAdd %int %43 %int_1
3482 OpStore %i %44
3483 OpBranch %27
3484 %28 = OpLabel
3485 %45 = OpLoad %float %s
3486 OpStore %o %45
3487 OpReturn
3488 OpFunctionEnd
3489 )";
3490 
3491   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
3492 }
3493 
TEST_F(AggressiveDCETest,NoEliminateIfContinue3)3494 TEST_F(AggressiveDCETest, NoEliminateIfContinue3) {
3495   // Do not eliminate continue as conditional branch with merge instruction
3496   // Note: SPIR-V edited to add merge instruction before continue.
3497   //
3498   // #version 430
3499   //
3500   // layout(std430) buffer U_t
3501   // {
3502   //     float g_F[10];
3503   // };
3504   //
3505   // layout(location = 0)out float o;
3506   //
3507   // void main(void)
3508   // {
3509   //     float s = 0.0;
3510   //     for (int i=0; i<10; i++) {
3511   //         if (i % 2 == 0) continue;
3512   //         s += g_F[i];
3513   //     }
3514   //     o = s;
3515   // }
3516 
3517   const std::string assembly =
3518       R"(OpCapability Shader
3519 %1 = OpExtInstImport "GLSL.std.450"
3520 OpMemoryModel Logical GLSL450
3521 OpEntryPoint Fragment %main "main" %o
3522 OpExecutionMode %main OriginUpperLeft
3523 OpSource GLSL 430
3524 OpName %main "main"
3525 OpName %s "s"
3526 OpName %i "i"
3527 OpName %U_t "U_t"
3528 OpMemberName %U_t 0 "g_F"
3529 OpName %_ ""
3530 OpName %o "o"
3531 OpDecorate %_arr_float_uint_10 ArrayStride 4
3532 OpMemberDecorate %U_t 0 Offset 0
3533 OpDecorate %U_t BufferBlock
3534 OpDecorate %_ DescriptorSet 0
3535 OpDecorate %o Location 0
3536 %void = OpTypeVoid
3537 %10 = OpTypeFunction %void
3538 %float = OpTypeFloat 32
3539 %_ptr_Function_float = OpTypePointer Function %float
3540 %float_0 = OpConstant %float 0
3541 %int = OpTypeInt 32 1
3542 %_ptr_Function_int = OpTypePointer Function %int
3543 %int_0 = OpConstant %int 0
3544 %int_10 = OpConstant %int 10
3545 %bool = OpTypeBool
3546 %int_2 = OpConstant %int 2
3547 %uint = OpTypeInt 32 0
3548 %uint_10 = OpConstant %uint 10
3549 %_arr_float_uint_10 = OpTypeArray %float %uint_10
3550 %U_t = OpTypeStruct %_arr_float_uint_10
3551 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
3552 %_ = OpVariable %_ptr_Uniform_U_t Uniform
3553 %_ptr_Uniform_float = OpTypePointer Uniform %float
3554 %int_1 = OpConstant %int 1
3555 %_ptr_Output_float = OpTypePointer Output %float
3556 %o = OpVariable %_ptr_Output_float Output
3557 %main = OpFunction %void None %10
3558 %26 = OpLabel
3559 %s = OpVariable %_ptr_Function_float Function
3560 %i = OpVariable %_ptr_Function_int Function
3561 OpStore %s %float_0
3562 OpStore %i %int_0
3563 OpBranch %27
3564 %27 = OpLabel
3565 OpLoopMerge %28 %29 None
3566 OpBranch %30
3567 %30 = OpLabel
3568 %31 = OpLoad %int %i
3569 %32 = OpSLessThan %bool %31 %int_10
3570 OpBranchConditional %32 %33 %28
3571 %33 = OpLabel
3572 %34 = OpLoad %int %i
3573 %35 = OpSMod %int %34 %int_2
3574 %36 = OpIEqual %bool %35 %int_0
3575 OpSelectionMerge %37 None
3576 OpBranchConditional %36 %29 %37
3577 %37 = OpLabel
3578 %38 = OpLoad %int %i
3579 %39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %38
3580 %40 = OpLoad %float %39
3581 %41 = OpLoad %float %s
3582 %42 = OpFAdd %float %41 %40
3583 OpStore %s %42
3584 OpBranch %29
3585 %29 = OpLabel
3586 %43 = OpLoad %int %i
3587 %44 = OpIAdd %int %43 %int_1
3588 OpStore %i %44
3589 OpBranch %27
3590 %28 = OpLabel
3591 %45 = OpLoad %float %s
3592 OpStore %o %45
3593 OpReturn
3594 OpFunctionEnd
3595 )";
3596 
3597   SinglePassRunAndCheck<AggressiveDCEPass>(assembly, assembly, true, true);
3598 }
3599 
3600 // This is not valid input and ADCE does not support variable pointers and only
3601 // supports shaders.
TEST_F(AggressiveDCETest,PointerVariable)3602 TEST_F(AggressiveDCETest, PointerVariable) {
3603   // ADCE is able to handle code that contains a load whose base address
3604   // comes from a load and not an OpVariable.  I want to see an instruction
3605   // removed to be sure that ADCE is not exiting early.
3606 
3607   const std::string before =
3608       R"(OpCapability Shader
3609 OpMemoryModel Logical GLSL450
3610 OpEntryPoint Fragment %1 "main" %2
3611 OpExecutionMode %1 OriginUpperLeft
3612 OpMemberDecorate %_struct_3 0 Offset 0
3613 OpDecorate %_runtimearr__struct_3 ArrayStride 16
3614 OpMemberDecorate %_struct_5 0 Offset 0
3615 OpDecorate %_struct_5 BufferBlock
3616 OpMemberDecorate %_struct_6 0 Offset 0
3617 OpDecorate %_struct_6 BufferBlock
3618 OpDecorate %2 Location 0
3619 OpDecorate %7 DescriptorSet 0
3620 OpDecorate %7 Binding 0
3621 OpDecorate %8 DescriptorSet 0
3622 OpDecorate %8 Binding 1
3623 %void = OpTypeVoid
3624 %10 = OpTypeFunction %void
3625 %int = OpTypeInt 32 1
3626 %uint = OpTypeInt 32 0
3627 %float = OpTypeFloat 32
3628 %v4float = OpTypeVector %float 4
3629 %_ptr_Output_v4float = OpTypePointer Output %v4float
3630 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
3631 %_struct_3 = OpTypeStruct %v4float
3632 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
3633 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
3634 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
3635 %_struct_6 = OpTypeStruct %int
3636 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
3637 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
3638 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
3639 %int_0 = OpConstant %int 0
3640 %uint_0 = OpConstant %uint 0
3641 %2 = OpVariable %_ptr_Output_v4float Output
3642 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
3643 %8 = OpVariable %_ptr_Uniform__struct_6 Uniform
3644 %1 = OpFunction %void None %10
3645 %23 = OpLabel
3646 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
3647 OpStore %24 %7
3648 %26 = OpLoad %_ptr_Uniform__struct_5 %24
3649 %27 = OpAccessChain %_ptr_Uniform_v4float %26 %int_0 %uint_0 %int_0
3650 %28 = OpLoad %v4float %27
3651 %29 = OpCopyObject %v4float %28
3652 OpStore %2 %28
3653 OpReturn
3654 OpFunctionEnd
3655 )";
3656 
3657   const std::string after =
3658       R"(OpCapability Shader
3659 OpMemoryModel Logical GLSL450
3660 OpEntryPoint Fragment %1 "main" %2
3661 OpExecutionMode %1 OriginUpperLeft
3662 OpMemberDecorate %_struct_3 0 Offset 0
3663 OpDecorate %_runtimearr__struct_3 ArrayStride 16
3664 OpMemberDecorate %_struct_5 0 Offset 0
3665 OpDecorate %_struct_5 BufferBlock
3666 OpDecorate %2 Location 0
3667 OpDecorate %7 DescriptorSet 0
3668 OpDecorate %7 Binding 0
3669 %void = OpTypeVoid
3670 %10 = OpTypeFunction %void
3671 %int = OpTypeInt 32 1
3672 %uint = OpTypeInt 32 0
3673 %float = OpTypeFloat 32
3674 %v4float = OpTypeVector %float 4
3675 %_ptr_Output_v4float = OpTypePointer Output %v4float
3676 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
3677 %_struct_3 = OpTypeStruct %v4float
3678 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
3679 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
3680 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
3681 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
3682 %int_0 = OpConstant %int 0
3683 %uint_0 = OpConstant %uint 0
3684 %2 = OpVariable %_ptr_Output_v4float Output
3685 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
3686 %1 = OpFunction %void None %10
3687 %23 = OpLabel
3688 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
3689 OpStore %24 %7
3690 %25 = OpLoad %_ptr_Uniform__struct_5 %24
3691 %26 = OpAccessChain %_ptr_Uniform_v4float %25 %int_0 %uint_0 %int_0
3692 %27 = OpLoad %v4float %26
3693 OpStore %2 %27
3694 OpReturn
3695 OpFunctionEnd
3696 )";
3697 
3698   // The input is not valid and ADCE only supports shaders, but not variable
3699   // pointers. Workaround this by enabling relaxed logical pointers in the
3700   // validator.
3701   ValidatorOptions()->relax_logical_pointer = true;
3702   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
3703 }
3704 
3705 // %dead is unused.  Make sure we remove it along with its name.
TEST_F(AggressiveDCETest,RemoveUnreferenced)3706 TEST_F(AggressiveDCETest, RemoveUnreferenced) {
3707   const std::string before =
3708       R"(OpCapability Shader
3709 OpCapability Linkage
3710 %1 = OpExtInstImport "GLSL.std.450"
3711 OpMemoryModel Logical GLSL450
3712 OpEntryPoint Fragment %main "main"
3713 OpExecutionMode %main OriginUpperLeft
3714 OpSource GLSL 150
3715 OpName %main "main"
3716 OpName %dead "dead"
3717 %void = OpTypeVoid
3718 %5 = OpTypeFunction %void
3719 %float = OpTypeFloat 32
3720 %_ptr_Private_float = OpTypePointer Private %float
3721 %dead = OpVariable %_ptr_Private_float Private
3722 %main = OpFunction %void None %5
3723 %8 = OpLabel
3724 OpReturn
3725 OpFunctionEnd
3726 )";
3727 
3728   const std::string after =
3729       R"(OpCapability Shader
3730 OpCapability Linkage
3731 %1 = OpExtInstImport "GLSL.std.450"
3732 OpMemoryModel Logical GLSL450
3733 OpEntryPoint Fragment %main "main"
3734 OpExecutionMode %main OriginUpperLeft
3735 OpSource GLSL 150
3736 OpName %main "main"
3737 %void = OpTypeVoid
3738 %5 = OpTypeFunction %void
3739 %main = OpFunction %void None %5
3740 %8 = OpLabel
3741 OpReturn
3742 OpFunctionEnd
3743 )";
3744 
3745   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3746   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
3747 }
3748 
3749 // Delete %dead because it is unreferenced.  Then %initializer becomes
3750 // unreferenced, so remove it as well.
TEST_F(AggressiveDCETest,RemoveUnreferencedWithInit1)3751 TEST_F(AggressiveDCETest, RemoveUnreferencedWithInit1) {
3752   const std::string before =
3753       R"(OpCapability Shader
3754 OpCapability Linkage
3755 %1 = OpExtInstImport "GLSL.std.450"
3756 OpMemoryModel Logical GLSL450
3757 OpEntryPoint Fragment %main "main"
3758 OpExecutionMode %main OriginUpperLeft
3759 OpSource GLSL 150
3760 OpName %main "main"
3761 OpName %dead "dead"
3762 OpName %initializer "initializer"
3763 %void = OpTypeVoid
3764 %6 = OpTypeFunction %void
3765 %float = OpTypeFloat 32
3766 %_ptr_Private_float = OpTypePointer Private %float
3767 %initializer = OpVariable %_ptr_Private_float Private
3768 %dead = OpVariable %_ptr_Private_float Private %initializer
3769 %main = OpFunction %void None %6
3770 %9 = OpLabel
3771 OpReturn
3772 OpFunctionEnd
3773 )";
3774 
3775   const std::string after =
3776       R"(OpCapability Shader
3777 OpCapability Linkage
3778 %1 = OpExtInstImport "GLSL.std.450"
3779 OpMemoryModel Logical GLSL450
3780 OpEntryPoint Fragment %main "main"
3781 OpExecutionMode %main OriginUpperLeft
3782 OpSource GLSL 150
3783 OpName %main "main"
3784 %void = OpTypeVoid
3785 %6 = OpTypeFunction %void
3786 %main = OpFunction %void None %6
3787 %9 = OpLabel
3788 OpReturn
3789 OpFunctionEnd
3790 )";
3791 
3792   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3793   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
3794 }
3795 
3796 // Keep %live because it is used, and its initializer.
TEST_F(AggressiveDCETest,KeepReferenced)3797 TEST_F(AggressiveDCETest, KeepReferenced) {
3798   const std::string before =
3799       R"(OpCapability Shader
3800 OpCapability Linkage
3801 %1 = OpExtInstImport "GLSL.std.450"
3802 OpMemoryModel Logical GLSL450
3803 OpEntryPoint Fragment %main "main" %output
3804 OpExecutionMode %main OriginUpperLeft
3805 OpSource GLSL 150
3806 OpName %main "main"
3807 OpName %live "live"
3808 OpName %initializer "initializer"
3809 OpName %output "output"
3810 %void = OpTypeVoid
3811 %6 = OpTypeFunction %void
3812 %float = OpTypeFloat 32
3813 %_ptr_Private_float = OpTypePointer Private %float
3814 %initializer = OpConstant %float 0
3815 %live = OpVariable %_ptr_Private_float Private %initializer
3816 %_ptr_Output_float = OpTypePointer Output %float
3817 %output = OpVariable %_ptr_Output_float Output
3818 %main = OpFunction %void None %6
3819 %9 = OpLabel
3820 %10 = OpLoad %float %live
3821 OpStore %output %10
3822 OpReturn
3823 OpFunctionEnd
3824 )";
3825 
3826   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3827   SinglePassRunAndCheck<AggressiveDCEPass>(before, before, true, true);
3828 }
3829 
3830 // This test that the decoration associated with a variable are removed when the
3831 // variable is removed.
TEST_F(AggressiveDCETest,RemoveVariableAndDecorations)3832 TEST_F(AggressiveDCETest, RemoveVariableAndDecorations) {
3833   const std::string before =
3834       R"(OpCapability Shader
3835 %1 = OpExtInstImport "GLSL.std.450"
3836 OpMemoryModel Logical GLSL450
3837 OpEntryPoint Vertex %main "main"
3838 OpSource GLSL 450
3839 OpName %main "main"
3840 OpName %B "B"
3841 OpMemberName %B 0 "a"
3842 OpName %Bdat "Bdat"
3843 OpMemberDecorate %B 0 Offset 0
3844 OpDecorate %B BufferBlock
3845 OpDecorate %Bdat DescriptorSet 0
3846 OpDecorate %Bdat Binding 0
3847 %void = OpTypeVoid
3848 %6 = OpTypeFunction %void
3849 %uint = OpTypeInt 32 0
3850 %B = OpTypeStruct %uint
3851 %_ptr_Uniform_B = OpTypePointer Uniform %B
3852 %Bdat = OpVariable %_ptr_Uniform_B Uniform
3853 %int = OpTypeInt 32 1
3854 %int_0 = OpConstant %int 0
3855 %uint_1 = OpConstant %uint 1
3856 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
3857 %main = OpFunction %void None %6
3858 %13 = OpLabel
3859 OpReturn
3860 OpFunctionEnd
3861 )";
3862 
3863   const std::string after =
3864       R"(OpCapability Shader
3865 %1 = OpExtInstImport "GLSL.std.450"
3866 OpMemoryModel Logical GLSL450
3867 OpEntryPoint Vertex %main "main"
3868 OpSource GLSL 450
3869 OpName %main "main"
3870 %void = OpTypeVoid
3871 %6 = OpTypeFunction %void
3872 %main = OpFunction %void None %6
3873 %13 = OpLabel
3874 OpReturn
3875 OpFunctionEnd
3876 )";
3877 
3878   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3879   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
3880 }
3881 
TEST_F(AggressiveDCETest,DeadNestedSwitch)3882 TEST_F(AggressiveDCETest, DeadNestedSwitch) {
3883   const std::string text = R"(
3884 ; CHECK: OpLabel
3885 ; CHECK: OpBranch [[block:%\w+]]
3886 ; CHECK-NOT: OpSwitch
3887 ; CHECK-NEXT: [[block]] = OpLabel
3888 ; CHECK: OpBranch [[block:%\w+]]
3889 ; CHECK-NOT: OpSwitch
3890 ; CHECK-NEXT: [[block]] = OpLabel
3891 ; CHECK-NEXT: OpStore
3892 OpCapability Shader
3893 OpMemoryModel Logical GLSL450
3894 OpEntryPoint Fragment %func "func" %x
3895 OpExecutionMode %func OriginUpperLeft
3896 OpName %func "func"
3897 %void = OpTypeVoid
3898 %1 = OpTypeFunction %void
3899 %uint = OpTypeInt 32 0
3900 %uint_0 = OpConstant %uint 0
3901 %uint_ptr_Output = OpTypePointer Output %uint
3902 %uint_ptr_Input = OpTypePointer Input %uint
3903 %x = OpVariable %uint_ptr_Output Output
3904 %a = OpVariable %uint_ptr_Input Input
3905 %func = OpFunction %void None %1
3906 %entry = OpLabel
3907 OpBranch %header
3908 %header = OpLabel
3909 %ld = OpLoad %uint %a
3910 OpLoopMerge %merge %continue None
3911 OpBranch %postheader
3912 %postheader = OpLabel
3913 ; This switch doesn't require an OpSelectionMerge and is nested in the dead loop.
3914 OpSwitch %ld %merge 0 %extra 1 %continue
3915 %extra = OpLabel
3916 OpBranch %continue
3917 %continue = OpLabel
3918 OpBranch %header
3919 %merge = OpLabel
3920 OpStore %x %uint_0
3921 OpReturn
3922 OpFunctionEnd
3923 )";
3924 
3925   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
3926 }
3927 
TEST_F(AggressiveDCETest,LiveNestedSwitch)3928 TEST_F(AggressiveDCETest, LiveNestedSwitch) {
3929   const std::string text = R"(OpCapability Shader
3930 OpMemoryModel Logical GLSL450
3931 OpEntryPoint Fragment %func "func" %3 %10
3932 OpExecutionMode %func OriginUpperLeft
3933 OpName %func "func"
3934 %void = OpTypeVoid
3935 %1 = OpTypeFunction %void
3936 %uint = OpTypeInt 32 0
3937 %uint_0 = OpConstant %uint 0
3938 %uint_1 = OpConstant %uint 1
3939 %_ptr_Output_uint = OpTypePointer Output %uint
3940 %_ptr_Input_uint = OpTypePointer Input %uint
3941 %3 = OpVariable %_ptr_Output_uint Output
3942 %10 = OpVariable %_ptr_Input_uint Input
3943 %func = OpFunction %void None %1
3944 %11 = OpLabel
3945 OpBranch %12
3946 %12 = OpLabel
3947 %13 = OpLoad %uint %10
3948 OpLoopMerge %14 %15 None
3949 OpBranch %16
3950 %16 = OpLabel
3951 OpSwitch %13 %14 0 %17 1 %15
3952 %17 = OpLabel
3953 OpStore %3 %uint_1
3954 OpBranch %15
3955 %15 = OpLabel
3956 OpBranch %12
3957 %14 = OpLabel
3958 OpStore %3 %uint_0
3959 OpReturn
3960 OpFunctionEnd
3961 )";
3962 
3963   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3964   SinglePassRunAndCheck<AggressiveDCEPass>(text, text, false, true);
3965 }
3966 
TEST_F(AggressiveDCETest,BasicDeleteDeadFunction)3967 TEST_F(AggressiveDCETest, BasicDeleteDeadFunction) {
3968   // The function Dead should be removed because it is never called.
3969   const std::vector<const char*> common_code = {
3970       // clang-format off
3971                "OpCapability Shader",
3972                "OpMemoryModel Logical GLSL450",
3973                "OpEntryPoint Fragment %main \"main\"",
3974                "OpName %main \"main\"",
3975                "OpName %Live \"Live\"",
3976        "%void = OpTypeVoid",
3977           "%7 = OpTypeFunction %void",
3978        "%main = OpFunction %void None %7",
3979          "%15 = OpLabel",
3980          "%16 = OpFunctionCall %void %Live",
3981          "%17 = OpFunctionCall %void %Live",
3982                "OpReturn",
3983                "OpFunctionEnd",
3984   "%Live = OpFunction %void None %7",
3985          "%20 = OpLabel",
3986                "OpReturn",
3987                "OpFunctionEnd"
3988       // clang-format on
3989   };
3990 
3991   const std::vector<const char*> dead_function = {
3992       // clang-format off
3993       "%Dead = OpFunction %void None %7",
3994          "%19 = OpLabel",
3995                "OpReturn",
3996                "OpFunctionEnd",
3997       // clang-format on
3998   };
3999 
4000   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4001   SinglePassRunAndCheck<AggressiveDCEPass>(
4002       JoinAllInsts(Concat(common_code, dead_function)),
4003       JoinAllInsts(common_code), /* skip_nop = */ true);
4004 }
4005 
TEST_F(AggressiveDCETest,BasicKeepLiveFunction)4006 TEST_F(AggressiveDCETest, BasicKeepLiveFunction) {
4007   // Everything is reachable from an entry point, so no functions should be
4008   // deleted.
4009   const std::vector<const char*> text = {
4010       // clang-format off
4011                "OpCapability Shader",
4012                "OpMemoryModel Logical GLSL450",
4013                "OpEntryPoint Fragment %main \"main\"",
4014                "OpName %main \"main\"",
4015                "OpName %Live1 \"Live1\"",
4016                "OpName %Live2 \"Live2\"",
4017        "%void = OpTypeVoid",
4018           "%7 = OpTypeFunction %void",
4019        "%main = OpFunction %void None %7",
4020          "%15 = OpLabel",
4021          "%16 = OpFunctionCall %void %Live2",
4022          "%17 = OpFunctionCall %void %Live1",
4023                "OpReturn",
4024                "OpFunctionEnd",
4025       "%Live1 = OpFunction %void None %7",
4026          "%19 = OpLabel",
4027                "OpReturn",
4028                "OpFunctionEnd",
4029       "%Live2 = OpFunction %void None %7",
4030          "%20 = OpLabel",
4031                "OpReturn",
4032                "OpFunctionEnd"
4033       // clang-format on
4034   };
4035 
4036   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4037   std::string assembly = JoinAllInsts(text);
4038   auto result = SinglePassRunAndDisassemble<AggressiveDCEPass>(
4039       assembly, /* skip_nop = */ true, /* do_validation = */ false);
4040   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
4041   EXPECT_EQ(assembly, std::get<0>(result));
4042 }
4043 
TEST_F(AggressiveDCETest,BasicRemoveDecorationsAndNames)4044 TEST_F(AggressiveDCETest, BasicRemoveDecorationsAndNames) {
4045   // We want to remove the names and decorations associated with results that
4046   // are removed.  This test will check for that.
4047   const std::string text = R"(
4048                OpCapability Shader
4049                OpMemoryModel Logical GLSL450
4050                OpEntryPoint Vertex %main "main"
4051                OpName %main "main"
4052                OpName %Dead "Dead"
4053                OpName %x "x"
4054                OpName %y "y"
4055                OpName %z "z"
4056                OpDecorate %x RelaxedPrecision
4057                OpDecorate %y RelaxedPrecision
4058                OpDecorate %z RelaxedPrecision
4059                OpDecorate %6 RelaxedPrecision
4060                OpDecorate %7 RelaxedPrecision
4061                OpDecorate %8 RelaxedPrecision
4062        %void = OpTypeVoid
4063          %10 = OpTypeFunction %void
4064       %float = OpTypeFloat 32
4065 %_ptr_Function_float = OpTypePointer Function %float
4066     %float_1 = OpConstant %float 1
4067        %main = OpFunction %void None %10
4068          %14 = OpLabel
4069                OpReturn
4070                OpFunctionEnd
4071        %Dead = OpFunction %void None %10
4072          %15 = OpLabel
4073           %x = OpVariable %_ptr_Function_float Function
4074           %y = OpVariable %_ptr_Function_float Function
4075           %z = OpVariable %_ptr_Function_float Function
4076                OpStore %x %float_1
4077                OpStore %y %float_1
4078           %6 = OpLoad %float %x
4079           %7 = OpLoad %float %y
4080           %8 = OpFAdd %float %6 %7
4081                OpStore %z %8
4082                OpReturn
4083                OpFunctionEnd)";
4084 
4085   const std::string expected_output = R"(OpCapability Shader
4086 OpMemoryModel Logical GLSL450
4087 OpEntryPoint Vertex %main "main"
4088 OpName %main "main"
4089 %void = OpTypeVoid
4090 %10 = OpTypeFunction %void
4091 %main = OpFunction %void None %10
4092 %14 = OpLabel
4093 OpReturn
4094 OpFunctionEnd
4095 )";
4096 
4097   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4098   SinglePassRunAndCheck<AggressiveDCEPass>(text, expected_output,
4099                                            /* skip_nop = */ true);
4100 }
4101 
TEST_F(AggressiveDCETest,BasicAllDeadConstants)4102 TEST_F(AggressiveDCETest, BasicAllDeadConstants) {
4103   const std::string text = R"(
4104   ; CHECK-NOT: OpConstant
4105                OpCapability Shader
4106                OpCapability Float64
4107           %1 = OpExtInstImport "GLSL.std.450"
4108                OpMemoryModel Logical GLSL450
4109                OpEntryPoint Vertex %main "main"
4110                OpName %main "main"
4111        %void = OpTypeVoid
4112           %4 = OpTypeFunction %void
4113        %bool = OpTypeBool
4114        %true = OpConstantTrue %bool
4115       %false = OpConstantFalse %bool
4116         %int = OpTypeInt 32 1
4117           %9 = OpConstant %int 1
4118        %uint = OpTypeInt 32 0
4119          %11 = OpConstant %uint 2
4120       %float = OpTypeFloat 32
4121          %13 = OpConstant %float 3.1415
4122      %double = OpTypeFloat 64
4123          %15 = OpConstant %double 3.14159265358979
4124        %main = OpFunction %void None %4
4125          %16 = OpLabel
4126                OpReturn
4127                OpFunctionEnd
4128   )";
4129 
4130   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
4131 }
4132 
TEST_F(AggressiveDCETest,BasicNoneDeadConstants)4133 TEST_F(AggressiveDCETest, BasicNoneDeadConstants) {
4134   const std::vector<const char*> text = {
4135       // clang-format off
4136                 "OpCapability Shader",
4137                 "OpCapability Float64",
4138            "%1 = OpExtInstImport \"GLSL.std.450\"",
4139                 "OpMemoryModel Logical GLSL450",
4140                 "OpEntryPoint Vertex %main \"main\" %btv %bfv %iv %uv %fv %dv",
4141                 "OpName %main \"main\"",
4142                 "OpName %btv \"btv\"",
4143                 "OpName %bfv \"bfv\"",
4144                 "OpName %iv \"iv\"",
4145                 "OpName %uv \"uv\"",
4146                 "OpName %fv \"fv\"",
4147                 "OpName %dv \"dv\"",
4148         "%void = OpTypeVoid",
4149           "%10 = OpTypeFunction %void",
4150         "%bool = OpTypeBool",
4151  "%_ptr_Output_bool = OpTypePointer Output %bool",
4152         "%true = OpConstantTrue %bool",
4153        "%false = OpConstantFalse %bool",
4154          "%int = OpTypeInt 32 1",
4155  "%_ptr_Output_int = OpTypePointer Output %int",
4156        "%int_1 = OpConstant %int 1",
4157         "%uint = OpTypeInt 32 0",
4158  "%_ptr_Output_uint = OpTypePointer Output %uint",
4159       "%uint_2 = OpConstant %uint 2",
4160        "%float = OpTypeFloat 32",
4161  "%_ptr_Output_float = OpTypePointer Output %float",
4162   "%float_3_1415 = OpConstant %float 3.1415",
4163       "%double = OpTypeFloat 64",
4164  "%_ptr_Output_double = OpTypePointer Output %double",
4165  "%double_3_14159265358979 = OpConstant %double 3.14159265358979",
4166          "%btv = OpVariable %_ptr_Output_bool Output",
4167          "%bfv = OpVariable %_ptr_Output_bool Output",
4168           "%iv = OpVariable %_ptr_Output_int Output",
4169           "%uv = OpVariable %_ptr_Output_uint Output",
4170           "%fv = OpVariable %_ptr_Output_float Output",
4171           "%dv = OpVariable %_ptr_Output_double Output",
4172         "%main = OpFunction %void None %10",
4173           "%27 = OpLabel",
4174                 "OpStore %btv %true",
4175                 "OpStore %bfv %false",
4176                 "OpStore %iv %int_1",
4177                 "OpStore %uv %uint_2",
4178                 "OpStore %fv %float_3_1415",
4179                 "OpStore %dv %double_3_14159265358979",
4180                 "OpReturn",
4181                 "OpFunctionEnd",
4182       // clang-format on
4183   };
4184   // All constants are used, so none of them should be eliminated.
4185   SinglePassRunAndCheck<AggressiveDCEPass>(
4186       JoinAllInsts(text), JoinAllInsts(text), /* skip_nop = */ true);
4187 }
4188 
4189 struct AggressiveEliminateDeadConstantTestCase {
4190   // Type declarations and constants that should be kept.
4191   std::vector<std::string> used_consts;
4192   // Instructions that refer to constants, this is added to create uses for
4193   // some constants so they won't be treated as dead constants.
4194   std::vector<std::string> main_insts;
4195   // Dead constants that should be removed.
4196   std::vector<std::string> dead_consts;
4197   // Expectations
4198   std::vector<std::string> checks;
4199 };
4200 
4201 // All types that are potentially required in
4202 // AggressiveEliminateDeadConstantTest.
4203 const std::vector<std::string> CommonTypes = {
4204     // clang-format off
4205     // scalar types
4206     "%bool = OpTypeBool",
4207     "%uint = OpTypeInt 32 0",
4208     "%int = OpTypeInt 32 1",
4209     "%float = OpTypeFloat 32",
4210     "%double = OpTypeFloat 64",
4211     // vector types
4212     "%v2bool = OpTypeVector %bool 2",
4213     "%v2uint = OpTypeVector %uint 2",
4214     "%v2int = OpTypeVector %int 2",
4215     "%v3int = OpTypeVector %int 3",
4216     "%v4int = OpTypeVector %int 4",
4217     "%v2float = OpTypeVector %float 2",
4218     "%v3float = OpTypeVector %float 3",
4219     "%v2double = OpTypeVector %double 2",
4220     // variable pointer types
4221     "%_pf_bool = OpTypePointer Output %bool",
4222     "%_pf_uint = OpTypePointer Output %uint",
4223     "%_pf_int = OpTypePointer Output %int",
4224     "%_pf_float = OpTypePointer Output %float",
4225     "%_pf_double = OpTypePointer Output %double",
4226     "%_pf_v2int = OpTypePointer Output %v2int",
4227     "%_pf_v3int = OpTypePointer Output %v3int",
4228     "%_pf_v2float = OpTypePointer Output %v2float",
4229     "%_pf_v3float = OpTypePointer Output %v3float",
4230     "%_pf_v2double = OpTypePointer Output %v2double",
4231     // struct types
4232     "%inner_struct = OpTypeStruct %bool %int %float %double",
4233     "%outer_struct = OpTypeStruct %inner_struct %int %double",
4234     "%flat_struct = OpTypeStruct %bool %int %float %double",
4235     // clang-format on
4236 };
4237 
4238 using AggressiveEliminateDeadConstantTest =
4239     PassTest<::testing::TestWithParam<AggressiveEliminateDeadConstantTestCase>>;
4240 
TEST_P(AggressiveEliminateDeadConstantTest,Custom)4241 TEST_P(AggressiveEliminateDeadConstantTest, Custom) {
4242   auto& tc = GetParam();
4243   AssemblyBuilder builder;
4244   builder.AppendTypesConstantsGlobals(CommonTypes)
4245       .AppendTypesConstantsGlobals(tc.used_consts)
4246       .AppendInMain(tc.main_insts);
4247   const std::string expected = builder.GetCode();
4248   builder.AppendTypesConstantsGlobals(tc.dead_consts);
4249   builder.PrependPreamble(tc.checks);
4250   const std::string assembly_with_dead_const = builder.GetCode();
4251 
4252   // Do not enable validation. As the input code is invalid from the base
4253   // tests (ported from other passes).
4254   SinglePassRunAndMatch<AggressiveDCEPass>(assembly_with_dead_const, false);
4255 }
4256 
4257 INSTANTIATE_TEST_SUITE_P(
4258     ScalarTypeConstants, AggressiveEliminateDeadConstantTest,
4259     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4260         // clang-format off
4261         // Scalar type constants, one dead constant and one used constant.
4262         {
4263             /* .used_consts = */
4264             {
4265               "%used_const_int = OpConstant %int 1",
4266             },
4267             /* .main_insts = */
4268             {
4269               "%int_var = OpVariable %_pf_int Output",
4270               "OpStore %int_var %used_const_int",
4271             },
4272             /* .dead_consts = */
4273             {
4274               "%dead_const_int = OpConstant %int 1",
4275             },
4276             /* .checks = */
4277             {
4278               "; CHECK: [[const:%\\w+]] = OpConstant %int 1",
4279               "; CHECK-NOT: OpConstant",
4280               "; CHECK: OpStore {{%\\w+}} [[const]]",
4281             },
4282         },
4283         {
4284             /* .used_consts = */
4285             {
4286               "%used_const_uint = OpConstant %uint 1",
4287             },
4288             /* .main_insts = */
4289             {
4290               "%uint_var = OpVariable %_pf_uint Output",
4291               "OpStore %uint_var %used_const_uint",
4292             },
4293             /* .dead_consts = */
4294             {
4295               "%dead_const_uint = OpConstant %uint 1",
4296             },
4297             /* .checks = */
4298             {
4299               "; CHECK: [[const:%\\w+]] = OpConstant %uint 1",
4300               "; CHECK-NOT: OpConstant",
4301               "; CHECK: OpStore {{%\\w+}} [[const]]",
4302             },
4303         },
4304         {
4305             /* .used_consts = */
4306             {
4307               "%used_const_float = OpConstant %float 3.1415",
4308             },
4309             /* .main_insts = */
4310             {
4311               "%float_var = OpVariable %_pf_float Output",
4312               "OpStore %float_var %used_const_float",
4313             },
4314             /* .dead_consts = */
4315             {
4316               "%dead_const_float = OpConstant %float 3.1415",
4317             },
4318             /* .checks = */
4319             {
4320               "; CHECK: [[const:%\\w+]] = OpConstant %float 3.1415",
4321               "; CHECK-NOT: OpConstant",
4322               "; CHECK: OpStore {{%\\w+}} [[const]]",
4323             },
4324         },
4325         {
4326             /* .used_consts = */
4327             {
4328               "%used_const_double = OpConstant %double 3.14",
4329             },
4330             /* .main_insts = */
4331             {
4332               "%double_var = OpVariable %_pf_double Output",
4333               "OpStore %double_var %used_const_double",
4334             },
4335             /* .dead_consts = */
4336             {
4337               "%dead_const_double = OpConstant %double 3.14",
4338             },
4339             /* .checks = */
4340             {
4341               "; CHECK: [[const:%\\w+]] = OpConstant %double 3.14",
4342               "; CHECK-NOT: OpConstant",
4343               "; CHECK: OpStore {{%\\w+}} [[const]]",
4344             },
4345         },
4346         // clang-format on
4347     })));
4348 
4349 INSTANTIATE_TEST_SUITE_P(
4350     VectorTypeConstants, AggressiveEliminateDeadConstantTest,
4351     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4352         // clang-format off
4353         // Tests eliminating dead constant type ivec2. One dead constant vector
4354         // and one used constant vector, each built from its own group of
4355         // scalar constants.
4356         {
4357             /* .used_consts = */
4358             {
4359               "%used_int_x = OpConstant %int 1",
4360               "%used_int_y = OpConstant %int 2",
4361               "%used_v2int = OpConstantComposite %v2int %used_int_x %used_int_y",
4362             },
4363             /* .main_insts = */
4364             {
4365               "%v2int_var = OpVariable %_pf_v2int Output",
4366               "OpStore %v2int_var %used_v2int",
4367             },
4368             /* .dead_consts = */
4369             {
4370               "%dead_int_x = OpConstant %int 1",
4371               "%dead_int_y = OpConstant %int 2",
4372               "%dead_v2int = OpConstantComposite %v2int %dead_int_x %dead_int_y",
4373             },
4374             /* .checks = */
4375             {
4376               "; CHECK: [[constx:%\\w+]] = OpConstant %int 1",
4377               "; CHECK: [[consty:%\\w+]] = OpConstant %int 2",
4378               "; CHECK: [[const:%\\w+]] = OpConstantComposite %v2int [[constx]] [[consty]]",
4379               "; CHECK-NOT: OpConstant",
4380               "; CHECK: OpStore {{%\\w+}} [[const]]",
4381             },
4382         },
4383         // Tests eliminating dead constant ivec3. One dead constant vector and
4384         // one used constant vector. But both built from a same group of
4385         // scalar constants.
4386         {
4387             /* .used_consts = */
4388             {
4389               "%used_int_x = OpConstant %int 1",
4390               "%used_int_y = OpConstant %int 2",
4391               "%used_int_z = OpConstant %int 3",
4392               "%used_v3int = OpConstantComposite %v3int %used_int_x %used_int_y %used_int_z",
4393             },
4394             /* .main_insts = */
4395             {
4396               "%v3int_var = OpVariable %_pf_v3int Output",
4397               "OpStore %v3int_var %used_v3int",
4398             },
4399             /* .dead_consts = */
4400             {
4401               "%dead_v3int = OpConstantComposite %v3int %used_int_x %used_int_y %used_int_z",
4402             },
4403             /* .checks = */
4404             {
4405               "; CHECK: [[constx:%\\w+]] = OpConstant %int 1",
4406               "; CHECK: [[consty:%\\w+]] = OpConstant %int 2",
4407               "; CHECK: [[constz:%\\w+]] = OpConstant %int 3",
4408               "; CHECK: [[const:%\\w+]] = OpConstantComposite %v3int [[constx]] [[consty]] [[constz]]",
4409               "; CHECK-NOT: OpConstant",
4410               "; CHECK: OpStore {{%\\w+}} [[const]]",
4411             },
4412         },
4413         // Tests eliminating dead constant vec2. One dead constant vector and
4414         // one used constant vector. Each built from its own group of scalar
4415         // constants.
4416         {
4417             /* .used_consts = */
4418             {
4419               "%used_float_x = OpConstant %float 3.1415",
4420               "%used_float_y = OpConstant %float 4.13",
4421               "%used_v2float = OpConstantComposite %v2float %used_float_x %used_float_y",
4422             },
4423             /* .main_insts = */
4424             {
4425               "%v2float_var = OpVariable %_pf_v2float Output",
4426               "OpStore %v2float_var %used_v2float",
4427             },
4428             /* .dead_consts = */
4429             {
4430               "%dead_float_x = OpConstant %float 3.1415",
4431               "%dead_float_y = OpConstant %float 4.13",
4432               "%dead_v2float = OpConstantComposite %v2float %dead_float_x %dead_float_y",
4433             },
4434             /* .checks = */
4435             {
4436               "; CHECK: [[constx:%\\w+]] = OpConstant %float 3.1415",
4437               "; CHECK: [[consty:%\\w+]] = OpConstant %float 4.13",
4438               "; CHECK: [[const:%\\w+]] = OpConstantComposite %v2float [[constx]] [[consty]]",
4439               "; CHECK-NOT: OpConstant",
4440               "; CHECK: OpStore {{%\\w+}} [[const]]",
4441             },
4442         },
4443         // Tests eliminating dead constant vec3. One dead constant vector and
4444         // one used constant vector. Both built from a same group of scalar
4445         // constants.
4446         {
4447             /* .used_consts = */
4448             {
4449               "%used_float_x = OpConstant %float 3.1415",
4450               "%used_float_y = OpConstant %float 4.25",
4451               "%used_float_z = OpConstant %float 4.75",
4452               "%used_v3float = OpConstantComposite %v3float %used_float_x %used_float_y %used_float_z",
4453             },
4454             /* .main_insts = */
4455             {
4456               "%v3float_var = OpVariable %_pf_v3float Output",
4457               "OpStore %v3float_var %used_v3float",
4458             },
4459             /* .dead_consts = */
4460             {
4461               "%dead_v3float = OpConstantComposite %v3float %used_float_x %used_float_y %used_float_z",
4462             },
4463             /* .checks = */
4464             {
4465               "; CHECK: [[constx:%\\w+]] = OpConstant %float 3.1415",
4466               "; CHECK: [[consty:%\\w+]] = OpConstant %float 4.25",
4467               "; CHECK: [[constz:%\\w+]] = OpConstant %float 4.75",
4468               "; CHECK: [[const:%\\w+]] = OpConstantComposite %v3float [[constx]] [[consty]]",
4469               "; CHECK-NOT: OpConstant",
4470               "; CHECK: OpStore {{%\\w+}} [[const]]",
4471             },
4472         },
4473         // clang-format on
4474     })));
4475 
4476 INSTANTIATE_TEST_SUITE_P(
4477     StructTypeConstants, AggressiveEliminateDeadConstantTest,
4478     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4479         // clang-format off
4480         // A plain struct type dead constants. All of its components are dead
4481         // constants too.
4482         {
4483             /* .used_consts = */ {},
4484             /* .main_insts = */ {},
4485             /* .dead_consts = */
4486             {
4487               "%dead_bool = OpConstantTrue %bool",
4488               "%dead_int = OpConstant %int 1",
4489               "%dead_float = OpConstant %float 2.5",
4490               "%dead_double = OpConstant %double 3.14159265358979",
4491               "%dead_struct = OpConstantComposite %flat_struct %dead_bool %dead_int %dead_float %dead_double",
4492             },
4493             /* .checks = */
4494             {
4495               "; CHECK-NOT: OpConstant",
4496             },
4497         },
4498         // A plain struct type dead constants. Some of its components are dead
4499         // constants while others are not.
4500         {
4501             /* .used_consts = */
4502             {
4503                 "%used_int = OpConstant %int 1",
4504                 "%used_double = OpConstant %double 3.14159265358979",
4505             },
4506             /* .main_insts = */
4507             {
4508                 "%int_var = OpVariable %_pf_int Output",
4509                 "OpStore %int_var %used_int",
4510                 "%double_var = OpVariable %_pf_double Output",
4511                 "OpStore %double_var %used_double",
4512             },
4513             /* .dead_consts = */
4514             {
4515                 "%dead_bool = OpConstantTrue %bool",
4516                 "%dead_float = OpConstant %float 2.5",
4517                 "%dead_struct = OpConstantComposite %flat_struct %dead_bool %used_int %dead_float %used_double",
4518             },
4519             /* .checks = */
4520             {
4521               "; CHECK: [[int:%\\w+]] = OpConstant %int 1",
4522               "; CHECK: [[double:%\\w+]] = OpConstant %double 3.14159265358979",
4523               "; CHECK-NOT: OpConstant",
4524               "; CHECK: OpStore {{%\\w+}} [[int]]",
4525               "; CHECK: OpStore {{%\\w+}} [[double]]",
4526             },
4527         },
4528         // A nesting struct type dead constants. All components of both outer
4529         // and inner structs are dead and should be removed after dead constant
4530         // elimination.
4531         {
4532             /* .used_consts = */ {},
4533             /* .main_insts = */ {},
4534             /* .dead_consts = */
4535             {
4536               "%dead_bool = OpConstantTrue %bool",
4537               "%dead_int = OpConstant %int 1",
4538               "%dead_float = OpConstant %float 2.5",
4539               "%dead_double = OpConstant %double 3.1415926535",
4540               "%dead_inner_struct = OpConstantComposite %inner_struct %dead_bool %dead_int %dead_float %dead_double",
4541               "%dead_int2 = OpConstant %int 2",
4542               "%dead_double2 = OpConstant %double 1.428571428514",
4543               "%dead_outer_struct = OpConstantComposite %outer_struct %dead_inner_struct %dead_int2 %dead_double2",
4544             },
4545             /* .checks = */
4546             {
4547               "; CHECK-NOT: OpConstant",
4548             },
4549         },
4550         // A nesting struct type dead constants. Some of its components are
4551         // dead constants while others are not.
4552         {
4553             /* .used_consts = */
4554             {
4555               "%used_int = OpConstant %int 1",
4556               "%used_double = OpConstant %double 3.14159265358979",
4557             },
4558             /* .main_insts = */
4559             {
4560               "%int_var = OpVariable %_pf_int Output",
4561               "OpStore %int_var %used_int",
4562               "%double_var = OpVariable %_pf_double Output",
4563               "OpStore %double_var %used_double",
4564             },
4565             /* .dead_consts = */
4566             {
4567               "%dead_bool = OpConstantTrue %bool",
4568               "%dead_float = OpConstant %float 2.5",
4569               "%dead_inner_struct = OpConstantComposite %inner_struct %dead_bool %used_int %dead_float %used_double",
4570               "%dead_int = OpConstant %int 2",
4571               "%dead_outer_struct = OpConstantComposite %outer_struct %dead_inner_struct %dead_int %used_double",
4572             },
4573             /* .checks = */
4574             {
4575               "; CHECK: [[int:%\\w+]] = OpConstant %int 1",
4576               "; CHECK: [[double:%\\w+]] = OpConstant %double 3.14159265358979",
4577               "; CHECK-NOT: OpConstant",
4578               "; CHECK: OpStore {{%\\w+}} [[int]]",
4579               "; CHECK: OpStore {{%\\w+}} [[double]]",
4580             },
4581         },
4582         // A nesting struct case. The inner struct is used while the outer struct is not
4583         {
4584           /* .used_const = */
4585           {
4586             "%used_bool = OpConstantTrue %bool",
4587             "%used_int = OpConstant %int 1",
4588             "%used_float = OpConstant %float 1.23",
4589             "%used_double = OpConstant %double 1.2345678901234",
4590             "%used_inner_struct = OpConstantComposite %inner_struct %used_bool %used_int %used_float %used_double",
4591           },
4592           /* .main_insts = */
4593           {
4594             "%bool_var = OpVariable %_pf_bool Output",
4595             "%bool_from_inner_struct = OpCompositeExtract %bool %used_inner_struct 0",
4596             "OpStore %bool_var %bool_from_inner_struct",
4597           },
4598           /* .dead_consts = */
4599           {
4600             "%dead_int = OpConstant %int 2",
4601             "%dead_outer_struct = OpConstantComposite %outer_struct %used_inner_struct %dead_int %used_double"
4602           },
4603           /* .checks = */
4604           {
4605             "; CHECK: [[bool:%\\w+]] = OpConstantTrue",
4606             "; CHECK: [[int:%\\w+]] = OpConstant %int 1",
4607             "; CHECK: [[float:%\\w+]] = OpConstant %float 1.23",
4608             "; CHECK: [[double:%\\w+]] = OpConstant %double 1.2345678901234",
4609             "; CHECK: [[struct:%\\w+]] = OpConstantComposite %inner_struct [[bool]] [[int]] [[float]] [[double]]",
4610             "; CHECK-NOT: OpConstant",
4611             "; CHECK: OpCompositeExtract %bool [[struct]]",
4612           }
4613         },
4614         // A nesting struct case. The outer struct is used, so the inner struct should not
4615         // be removed even though it is not used anywhere.
4616         {
4617           /* .used_const = */
4618           {
4619             "%used_bool = OpConstantTrue %bool",
4620             "%used_int = OpConstant %int 1",
4621             "%used_float = OpConstant %float 1.23",
4622             "%used_double = OpConstant %double 1.2345678901234",
4623             "%used_inner_struct = OpConstantComposite %inner_struct %used_bool %used_int %used_float %used_double",
4624             "%used_outer_struct = OpConstantComposite %outer_struct %used_inner_struct %used_int %used_double"
4625           },
4626           /* .main_insts = */
4627           {
4628             "%int_var = OpVariable %_pf_int Output",
4629             "%int_from_outer_struct = OpCompositeExtract %int %used_outer_struct 1",
4630             "OpStore %int_var %int_from_outer_struct",
4631           },
4632           /* .dead_consts = */ {},
4633           /* .checks = */
4634           {
4635             "; CHECK: [[bool:%\\w+]] = OpConstantTrue %bool",
4636             "; CHECK: [[int:%\\w+]] = OpConstant %int 1",
4637             "; CHECK: [[float:%\\w+]] = OpConstant %float 1.23",
4638             "; CHECK: [[double:%\\w+]] = OpConstant %double 1.2345678901234",
4639             "; CHECK: [[inner_struct:%\\w+]] = OpConstantComposite %inner_struct %used_bool %used_int %used_float %used_double",
4640             "; CHECK: [[outer_struct:%\\w+]] = OpConstantComposite %outer_struct %used_inner_struct %used_int %used_double",
4641             "; CHECK: OpCompositeExtract %int [[outer_struct]]",
4642           },
4643         },
4644         // clang-format on
4645     })));
4646 
4647 INSTANTIATE_TEST_SUITE_P(
4648     ScalarTypeSpecConstants, AggressiveEliminateDeadConstantTest,
4649     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4650         // clang-format off
4651         // All scalar type spec constants.
4652         {
4653             /* .used_consts = */
4654             {
4655               "%used_bool = OpSpecConstantTrue %bool",
4656               "%used_uint = OpSpecConstant %uint 2",
4657               "%used_int = OpSpecConstant %int 2",
4658               "%used_float = OpSpecConstant %float 2.5",
4659               "%used_double = OpSpecConstant %double 1.428571428514",
4660             },
4661             /* .main_insts = */
4662             {
4663               "%bool_var = OpVariable %_pf_bool Output",
4664               "%uint_var = OpVariable %_pf_uint Output",
4665               "%int_var = OpVariable %_pf_int Output",
4666               "%float_var = OpVariable %_pf_float Output",
4667               "%double_var = OpVariable %_pf_double Output",
4668               "OpStore %bool_var %used_bool",
4669               "OpStore %uint_var %used_uint",
4670               "OpStore %int_var %used_int",
4671               "OpStore %float_var %used_float",
4672               "OpStore %double_var %used_double",
4673             },
4674             /* .dead_consts = */
4675             {
4676               "%dead_bool = OpSpecConstantTrue %bool",
4677               "%dead_uint = OpSpecConstant %uint 2",
4678               "%dead_int = OpSpecConstant %int 2",
4679               "%dead_float = OpSpecConstant %float 2.5",
4680               "%dead_double = OpSpecConstant %double 1.428571428514",
4681             },
4682             /* .checks = */
4683             {
4684               "; CHECK: [[bool:%\\w+]] = OpSpecConstantTrue %bool",
4685               "; CHECK: [[uint:%\\w+]] = OpSpecConstant %uint 2",
4686               "; CHECK: [[int:%\\w+]] = OpSpecConstant %int 2",
4687               "; CHECK: [[float:%\\w+]] = OpSpecConstant %float 2.5",
4688               "; CHECK: [[double:%\\w+]] = OpSpecConstant %double 1.428571428514",
4689               "; CHECK-NOT: OpSpecConstant",
4690               "; CHECK: OpStore {{%\\w+}} [[bool]]",
4691               "; CHECK: OpStore {{%\\w+}} [[uint]]",
4692               "; CHECK: OpStore {{%\\w+}} [[int]]",
4693               "; CHECK: OpStore {{%\\w+}} [[float]]",
4694               "; CHECK: OpStore {{%\\w+}} [[double]]",
4695             },
4696         },
4697         // clang-format on
4698     })));
4699 
4700 INSTANTIATE_TEST_SUITE_P(
4701     VectorTypeSpecConstants, AggressiveEliminateDeadConstantTest,
4702     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4703         // clang-format off
4704         // Bool vector type spec constants. One vector has all component dead,
4705         // another vector has one dead boolean and one used boolean.
4706         {
4707             /* .used_consts = */
4708             {
4709               "%used_bool = OpSpecConstantTrue %bool",
4710             },
4711             /* .main_insts = */
4712             {
4713               "%bool_var = OpVariable %_pf_bool Output",
4714               "OpStore %bool_var %used_bool",
4715             },
4716             /* .dead_consts = */
4717             {
4718               "%dead_bool = OpSpecConstantFalse %bool",
4719               "%dead_bool_vec1 = OpSpecConstantComposite %v2bool %dead_bool %dead_bool",
4720               "%dead_bool_vec2 = OpSpecConstantComposite %v2bool %dead_bool %used_bool",
4721             },
4722             /* .checks = */
4723             {
4724               "; CHECK: [[bool:%\\w+]] = OpSpecConstantTrue %bool",
4725               "; CHECK-NOT: OpSpecConstant",
4726               "; CHECK: OpStore {{%\\w+}} [[bool]]",
4727             },
4728         },
4729 
4730         // Uint vector type spec constants. One vector has all component dead,
4731         // another vector has one dead unsigend integer and one used unsigned
4732         // integer.
4733         {
4734             /* .used_consts = */
4735             {
4736               "%used_uint = OpSpecConstant %uint 3",
4737             },
4738             /* .main_insts = */
4739             {
4740               "%uint_var = OpVariable %_pf_uint Output",
4741               "OpStore %uint_var %used_uint",
4742             },
4743             /* .dead_consts = */
4744             {
4745               "%dead_uint = OpSpecConstant %uint 1",
4746               "%dead_uint_vec1 = OpSpecConstantComposite %v2uint %dead_uint %dead_uint",
4747               "%dead_uint_vec2 = OpSpecConstantComposite %v2uint %dead_uint %used_uint",
4748             },
4749             /* .checks = */
4750             {
4751               "; CHECK: [[uint:%\\w+]] = OpSpecConstant %uint 3",
4752               "; CHECK-NOT: OpSpecConstant",
4753               "; CHECK: OpStore {{%\\w+}} [[uint]]",
4754             },
4755         },
4756 
4757         // Int vector type spec constants. One vector has all component dead,
4758         // another vector has one dead integer and one used integer.
4759         {
4760             /* .used_consts = */
4761             {
4762               "%used_int = OpSpecConstant %int 3",
4763             },
4764             /* .main_insts = */
4765             {
4766               "%int_var = OpVariable %_pf_int Output",
4767               "OpStore %int_var %used_int",
4768             },
4769             /* .dead_consts = */
4770             {
4771               "%dead_int = OpSpecConstant %int 1",
4772               "%dead_int_vec1 = OpSpecConstantComposite %v2int %dead_int %dead_int",
4773               "%dead_int_vec2 = OpSpecConstantComposite %v2int %dead_int %used_int",
4774             },
4775             /* .checks = */
4776             {
4777               "; CHECK: [[int:%\\w+]] = OpSpecConstant %int 3",
4778               "; CHECK-NOT: OpSpecConstant",
4779               "; CHECK: OpStore {{%\\w+}} [[int]]",
4780             },
4781         },
4782 
4783         // Int vector type spec constants built with both spec constants and
4784         // front-end constants.
4785         {
4786             /* .used_consts = */
4787             {
4788               "%used_spec_int = OpSpecConstant %int 3",
4789               "%used_front_end_int = OpConstant %int 3",
4790             },
4791             /* .main_insts = */
4792             {
4793               "%int_var1 = OpVariable %_pf_int Output",
4794               "OpStore %int_var1 %used_spec_int",
4795               "%int_var2 = OpVariable %_pf_int Output",
4796               "OpStore %int_var2 %used_front_end_int",
4797             },
4798             /* .dead_consts = */
4799             {
4800               "%dead_spec_int = OpSpecConstant %int 1",
4801               "%dead_front_end_int = OpConstant %int 1",
4802               // Dead front-end and dead spec constants
4803               "%dead_int_vec1 = OpSpecConstantComposite %v2int %dead_spec_int %dead_front_end_int",
4804               // Used front-end and dead spec constants
4805               "%dead_int_vec2 = OpSpecConstantComposite %v2int %dead_spec_int %used_front_end_int",
4806               // Dead front-end and used spec constants
4807               "%dead_int_vec3 = OpSpecConstantComposite %v2int %dead_front_end_int %used_spec_int",
4808             },
4809             /* .checks = */
4810             {
4811               "; CHECK: [[int1:%\\w+]] = OpSpecConstant %int 3",
4812               "; CHECK: [[int2:%\\w+]] = OpConstant %int 3",
4813               "; CHECK-NOT: OpSpecConstant",
4814               "; CHECK-NOT: OpConstant",
4815               "; CHECK: OpStore {{%\\w+}} [[int1]]",
4816               "; CHECK: OpStore {{%\\w+}} [[int2]]",
4817             },
4818         },
4819         // clang-format on
4820     })));
4821 
4822 INSTANTIATE_TEST_SUITE_P(
4823     SpecConstantOp, AggressiveEliminateDeadConstantTest,
4824     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
4825         // clang-format off
4826         // Cast operations: uint <-> int <-> bool
4827         {
4828             /* .used_consts = */ {},
4829             /* .main_insts = */ {},
4830             /* .dead_consts = */
4831             {
4832               // Assistant constants, only used in dead spec constant
4833               // operations.
4834               "%signed_zero = OpConstant %int 0",
4835               "%signed_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
4836               "%unsigned_zero = OpConstant %uint 0",
4837               "%unsigned_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
4838               "%signed_one = OpConstant %int 1",
4839               "%signed_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
4840               "%unsigned_one = OpConstant %uint 1",
4841               "%unsigned_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
4842 
4843               // Spec constants that support casting to each other.
4844               "%dead_bool = OpSpecConstantTrue %bool",
4845               "%dead_uint = OpSpecConstant %uint 1",
4846               "%dead_int = OpSpecConstant %int 2",
4847               "%dead_bool_vec = OpSpecConstantComposite %v2bool %dead_bool %dead_bool",
4848               "%dead_uint_vec = OpSpecConstantComposite %v2uint %dead_uint %dead_uint",
4849               "%dead_int_vec = OpSpecConstantComposite %v2int %dead_int %dead_int",
4850 
4851               // Scalar cast to boolean spec constant.
4852               "%int_to_bool = OpSpecConstantOp %bool INotEqual %dead_int %signed_zero",
4853               "%uint_to_bool = OpSpecConstantOp %bool INotEqual %dead_uint %unsigned_zero",
4854 
4855               // Vector cast to boolean spec constant.
4856               "%int_to_bool_vec = OpSpecConstantOp %v2bool INotEqual %dead_int_vec %signed_zero_vec",
4857               "%uint_to_bool_vec = OpSpecConstantOp %v2bool INotEqual %dead_uint_vec %unsigned_zero_vec",
4858 
4859               // Scalar cast to int spec constant.
4860               "%bool_to_int = OpSpecConstantOp %int Select %dead_bool %signed_one %signed_zero",
4861               "%uint_to_int = OpSpecConstantOp %uint IAdd %dead_uint %unsigned_zero",
4862 
4863               // Vector cast to int spec constant.
4864               "%bool_to_int_vec = OpSpecConstantOp %v2int Select %dead_bool_vec %signed_one_vec %signed_zero_vec",
4865               "%uint_to_int_vec = OpSpecConstantOp %v2uint IAdd %dead_uint_vec %unsigned_zero_vec",
4866 
4867               // Scalar cast to uint spec constant.
4868               "%bool_to_uint = OpSpecConstantOp %uint Select %dead_bool %unsigned_one %unsigned_zero",
4869               "%int_to_uint_vec = OpSpecConstantOp %uint IAdd %dead_int %signed_zero",
4870 
4871               // Vector cast to uint spec constant.
4872               "%bool_to_uint_vec = OpSpecConstantOp %v2uint Select %dead_bool_vec %unsigned_one_vec %unsigned_zero_vec",
4873               "%int_to_uint = OpSpecConstantOp %v2uint IAdd %dead_int_vec %signed_zero_vec",
4874             },
4875             /* .checks = */
4876             {
4877               "; CHECK-NOT: OpConstant",
4878               "; CHECK-NOT: OpSpecConstant",
4879             },
4880         },
4881 
4882         // Add, sub, mul, div, rem.
4883         {
4884             /* .used_consts = */ {},
4885             /* .main_insts = */ {},
4886             /* .dead_consts = */
4887             {
4888               "%dead_spec_int_a = OpSpecConstant %int 1",
4889               "%dead_spec_int_a_vec = OpSpecConstantComposite %v2int %dead_spec_int_a %dead_spec_int_a",
4890 
4891               "%dead_spec_int_b = OpSpecConstant %int 2",
4892               "%dead_spec_int_b_vec = OpSpecConstantComposite %v2int %dead_spec_int_b %dead_spec_int_b",
4893 
4894               "%dead_const_int_c = OpConstant %int 3",
4895               "%dead_const_int_c_vec = OpConstantComposite %v2int %dead_const_int_c %dead_const_int_c",
4896 
4897               // Add
4898               "%add_a_b = OpSpecConstantOp %int IAdd %dead_spec_int_a %dead_spec_int_b",
4899               "%add_a_b_vec = OpSpecConstantOp %v2int IAdd %dead_spec_int_a_vec %dead_spec_int_b_vec",
4900 
4901               // Sub
4902               "%sub_a_b = OpSpecConstantOp %int ISub %dead_spec_int_a %dead_spec_int_b",
4903               "%sub_a_b_vec = OpSpecConstantOp %v2int ISub %dead_spec_int_a_vec %dead_spec_int_b_vec",
4904 
4905               // Mul
4906               "%mul_a_b = OpSpecConstantOp %int IMul %dead_spec_int_a %dead_spec_int_b",
4907               "%mul_a_b_vec = OpSpecConstantOp %v2int IMul %dead_spec_int_a_vec %dead_spec_int_b_vec",
4908 
4909               // Div
4910               "%div_a_b = OpSpecConstantOp %int SDiv %dead_spec_int_a %dead_spec_int_b",
4911               "%div_a_b_vec = OpSpecConstantOp %v2int SDiv %dead_spec_int_a_vec %dead_spec_int_b_vec",
4912 
4913               // Bitwise Xor
4914               "%xor_a_b = OpSpecConstantOp %int BitwiseXor %dead_spec_int_a %dead_spec_int_b",
4915               "%xor_a_b_vec = OpSpecConstantOp %v2int BitwiseXor %dead_spec_int_a_vec %dead_spec_int_b_vec",
4916 
4917               // Scalar Comparison
4918               "%less_a_b = OpSpecConstantOp %bool SLessThan %dead_spec_int_a %dead_spec_int_b",
4919             },
4920             /* .checks = */
4921             {
4922               "; CHECK-NOT: OpConstant",
4923               "; CHECK-NOT: OpSpecConstant",
4924             },
4925         },
4926 
4927         // Vectors without used swizzles should be removed.
4928         {
4929             /* .used_consts = */
4930             {
4931               "%used_int = OpConstant %int 3",
4932             },
4933             /* .main_insts = */
4934             {
4935               "%int_var = OpVariable %_pf_int Output",
4936               "OpStore %int_var %used_int",
4937             },
4938             /* .dead_consts = */
4939             {
4940               "%dead_int = OpConstant %int 3",
4941 
4942               "%dead_spec_int_a = OpSpecConstant %int 1",
4943               "%vec_a = OpSpecConstantComposite %v4int %dead_spec_int_a %dead_spec_int_a %dead_int %dead_int",
4944 
4945               "%dead_spec_int_b = OpSpecConstant %int 2",
4946               "%vec_b = OpSpecConstantComposite %v4int %dead_spec_int_b %dead_spec_int_b %used_int %used_int",
4947 
4948               // Extract scalar
4949               "%a_x = OpSpecConstantOp %int CompositeExtract %vec_a 0",
4950               "%b_x = OpSpecConstantOp %int CompositeExtract %vec_b 0",
4951 
4952               // Extract vector
4953               "%a_xy = OpSpecConstantOp %v2int VectorShuffle %vec_a %vec_a 0 1",
4954               "%b_xy = OpSpecConstantOp %v2int VectorShuffle %vec_b %vec_b 0 1",
4955             },
4956             /* .checks = */
4957             {
4958               "; CHECK: [[int:%\\w+]] = OpConstant %int 3",
4959               "; CHECK-NOT: OpConstant",
4960               "; CHECK-NOT: OpSpecConstant",
4961               "; CHECK: OpStore {{%\\w+}} [[int]]",
4962             },
4963         },
4964         // Vectors with used swizzles should not be removed.
4965         {
4966             /* .used_consts = */
4967             {
4968               "%used_int = OpConstant %int 3",
4969               "%used_spec_int_a = OpSpecConstant %int 1",
4970               "%used_spec_int_b = OpSpecConstant %int 2",
4971               // Create vectors
4972               "%vec_a = OpSpecConstantComposite %v4int %used_spec_int_a %used_spec_int_a %used_int %used_int",
4973               "%vec_b = OpSpecConstantComposite %v4int %used_spec_int_b %used_spec_int_b %used_int %used_int",
4974               // Extract vector
4975               "%a_xy = OpSpecConstantOp %v2int VectorShuffle %vec_a %vec_a 0 1",
4976               "%b_xy = OpSpecConstantOp %v2int VectorShuffle %vec_b %vec_b 0 1",
4977             },
4978             /* .main_insts = */
4979             {
4980               "%v2int_var_a = OpVariable %_pf_v2int Output",
4981               "%v2int_var_b = OpVariable %_pf_v2int Output",
4982               "OpStore %v2int_var_a %a_xy",
4983               "OpStore %v2int_var_b %b_xy",
4984             },
4985             /* .dead_consts = */ {},
4986             /* .checks = */
4987             {
4988               "; CHECK: [[int:%\\w+]] = OpConstant %int 3",
4989               "; CHECK: [[a:%\\w+]] = OpSpecConstant %int 1",
4990               "; CHECK: [[b:%\\w+]] = OpSpecConstant %int 2",
4991               "; CHECK: [[veca:%\\w+]] = OpSpecConstantComposite %v4int [[a]] [[a]] [[int]] [[int]]",
4992               "; CHECK: [[vecb:%\\w+]] = OpSpecConstantComposite %v4int [[b]] [[b]] [[int]] [[int]]",
4993               "; CHECK: [[exa:%\\w+]] = OpSpecConstantOp %v2int VectorShuffle [[veca]] [[veca]] 0 1",
4994               "; CHECK: [[exb:%\\w+]] = OpSpecConstantOp %v2int VectorShuffle [[vecb]] [[vecb]] 0 1",
4995               "; CHECK-NOT: OpConstant",
4996               "; CHECK-NOT: OpSpecConstant",
4997               "; CHECK: OpStore {{%\\w+}} [[exa]]",
4998               "; CHECK: OpStore {{%\\w+}} [[exb]]",
4999             },
5000         },
5001         // clang-format on
5002     })));
5003 
5004 INSTANTIATE_TEST_SUITE_P(
5005     LongDefUseChain, AggressiveEliminateDeadConstantTest,
5006     ::testing::ValuesIn(std::vector<AggressiveEliminateDeadConstantTestCase>({
5007         // clang-format off
5008         // Long Def-Use chain with binary operations.
5009         {
5010             /* .used_consts = */
5011             {
5012               "%array_size = OpConstant %int 4",
5013               "%type_arr_int_4 = OpTypeArray %int %array_size",
5014               "%used_int_0 = OpConstant %int 100",
5015               "%used_int_1 = OpConstant %int 1",
5016               "%used_int_2 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_1",
5017               "%used_int_3 = OpSpecConstantOp %int ISub %used_int_0 %used_int_2",
5018               "%used_int_4 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_3",
5019               "%used_int_5 = OpSpecConstantOp %int ISub %used_int_0 %used_int_4",
5020               "%used_int_6 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_5",
5021               "%used_int_7 = OpSpecConstantOp %int ISub %used_int_0 %used_int_6",
5022               "%used_int_8 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_7",
5023               "%used_int_9 = OpSpecConstantOp %int ISub %used_int_0 %used_int_8",
5024               "%used_int_10 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_9",
5025               "%used_int_11 = OpSpecConstantOp %int ISub %used_int_0 %used_int_10",
5026               "%used_int_12 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_11",
5027               "%used_int_13 = OpSpecConstantOp %int ISub %used_int_0 %used_int_12",
5028               "%used_int_14 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_13",
5029               "%used_int_15 = OpSpecConstantOp %int ISub %used_int_0 %used_int_14",
5030               "%used_int_16 = OpSpecConstantOp %int ISub %used_int_0 %used_int_15",
5031               "%used_int_17 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_16",
5032               "%used_int_18 = OpSpecConstantOp %int ISub %used_int_0 %used_int_17",
5033               "%used_int_19 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_18",
5034               "%used_int_20 = OpSpecConstantOp %int ISub %used_int_0 %used_int_19",
5035               "%used_vec_a = OpSpecConstantComposite %v2int %used_int_18 %used_int_19",
5036               "%used_vec_b = OpSpecConstantOp %v2int IMul %used_vec_a %used_vec_a",
5037               "%used_int_21 = OpSpecConstantOp %int CompositeExtract %used_vec_b 0",
5038               "%used_array = OpConstantComposite %type_arr_int_4 %used_int_20 %used_int_20 %used_int_21 %used_int_21",
5039             },
5040             /* .main_insts = */
5041             {
5042               "%int_var = OpVariable %_pf_int Output",
5043               "%used_array_2 = OpCompositeExtract %int %used_array 2",
5044               "OpStore %int_var %used_array_2",
5045             },
5046             /* .dead_consts = */
5047             {
5048               "%dead_int_1 = OpConstant %int 2",
5049               "%dead_int_2 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_1",
5050               "%dead_int_3 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_2",
5051               "%dead_int_4 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_3",
5052               "%dead_int_5 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_4",
5053               "%dead_int_6 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_5",
5054               "%dead_int_7 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_6",
5055               "%dead_int_8 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_7",
5056               "%dead_int_9 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_8",
5057               "%dead_int_10 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_9",
5058               "%dead_int_11 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_10",
5059               "%dead_int_12 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_11",
5060               "%dead_int_13 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_12",
5061               "%dead_int_14 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_13",
5062               "%dead_int_15 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_14",
5063               "%dead_int_16 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_15",
5064               "%dead_int_17 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_16",
5065               "%dead_int_18 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_17",
5066               "%dead_int_19 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_18",
5067               "%dead_int_20 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_19",
5068               "%dead_vec_a = OpSpecConstantComposite %v2int %dead_int_18 %dead_int_19",
5069               "%dead_vec_b = OpSpecConstantOp %v2int IMul %dead_vec_a %dead_vec_a",
5070               "%dead_int_21 = OpSpecConstantOp %int CompositeExtract %dead_vec_b 0",
5071               "%dead_array = OpConstantComposite %type_arr_int_4 %dead_int_20 %used_int_20 %dead_int_19 %used_int_19",
5072             },
5073             /* .checks = */
5074             {
5075               "; CHECK: OpConstant %int 4",
5076               "; CHECK: [[array:%\\w+]] = OpConstantComposite %type_arr_int_4 %used_int_20 %used_int_20 %used_int_21 %used_int_21",
5077               "; CHECK-NOT: OpConstant",
5078               "; CHECK-NOT: OpSpecConstant",
5079               "; CHECK: OpStore {{%\\w+}} [[array]]",
5080             },
5081         },
5082         // Long Def-Use chain with swizzle
5083         // clang-format on
5084     })));
5085 
TEST_F(AggressiveDCETest,DeadDecorationGroup)5086 TEST_F(AggressiveDCETest, DeadDecorationGroup) {
5087   // The decoration group should be eliminated because the target of group
5088   // decorate is dead.
5089   const std::string text = R"(
5090 ; CHECK-NOT: OpDecorat
5091 ; CHECK-NOT: OpGroupDecorate
5092 OpCapability Shader
5093 OpMemoryModel Logical GLSL450
5094 OpEntryPoint Fragment %main "main"
5095 OpExecutionMode %main OriginUpperLeft
5096 OpDecorate %1 Restrict
5097 OpDecorate %1 Aliased
5098 %1 = OpDecorationGroup
5099 OpGroupDecorate %1 %var
5100 %void = OpTypeVoid
5101 %func = OpTypeFunction %void
5102 %uint = OpTypeInt 32 0
5103 %uint_ptr = OpTypePointer Function %uint
5104 %main = OpFunction %void None %func
5105 %2 = OpLabel
5106 %var = OpVariable %uint_ptr Function
5107 OpReturn
5108 OpFunctionEnd
5109   )";
5110 
5111   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5112 }
5113 
TEST_F(AggressiveDCETest,DeadDecorationGroupAndValidDecorationMgr)5114 TEST_F(AggressiveDCETest, DeadDecorationGroupAndValidDecorationMgr) {
5115   // The decoration group should be eliminated because the target of group
5116   // decorate is dead.
5117   const std::string text = R"(
5118 OpCapability Shader
5119 OpMemoryModel Logical GLSL450
5120 OpEntryPoint Fragment %main "main"
5121 OpExecutionMode %main OriginUpperLeft
5122 OpDecorate %1 Restrict
5123 OpDecorate %1 Aliased
5124 %1 = OpDecorationGroup
5125 OpGroupDecorate %1 %var
5126 %void = OpTypeVoid
5127 %func = OpTypeFunction %void
5128 %uint = OpTypeInt 32 0
5129 %uint_ptr = OpTypePointer Function %uint
5130 %main = OpFunction %void None %func
5131 %2 = OpLabel
5132 %var = OpVariable %uint_ptr Function
5133 OpReturn
5134 OpFunctionEnd
5135   )";
5136 
5137   auto pass = MakeUnique<AggressiveDCEPass>();
5138   auto consumer = [](spv_message_level_t, const char*, const spv_position_t&,
5139                      const char* message) {
5140     std::cerr << message << std::endl;
5141   };
5142   auto context = BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, text);
5143 
5144   // Build the decoration manager before the pass.
5145   context->get_decoration_mgr();
5146 
5147   const auto status = pass->Run(context.get());
5148   EXPECT_EQ(status, Pass::Status::SuccessWithChange);
5149 }
5150 
TEST_F(AggressiveDCETest,ParitallyDeadDecorationGroup)5151 TEST_F(AggressiveDCETest, ParitallyDeadDecorationGroup) {
5152   const std::string text = R"(
5153 ; CHECK: OpDecorate [[grp:%\w+]] Restrict
5154 ; CHECK: [[grp]] = OpDecorationGroup
5155 ; CHECK: OpGroupDecorate [[grp]] [[output:%\w+]]
5156 ; CHECK: [[output]] = OpVariable {{%\w+}} Output
5157 ; CHECK-NOT: OpVariable {{%\w+}} Function
5158 OpCapability Shader
5159 OpMemoryModel Logical GLSL450
5160 OpEntryPoint Fragment %main "main" %output
5161 OpExecutionMode %main OriginUpperLeft
5162 OpDecorate %1 Restrict
5163 %1 = OpDecorationGroup
5164 OpGroupDecorate %1 %var %output
5165 %void = OpTypeVoid
5166 %func = OpTypeFunction %void
5167 %uint = OpTypeInt 32 0
5168 %uint_ptr_Function = OpTypePointer Function %uint
5169 %uint_ptr_Output = OpTypePointer Output %uint
5170 %uint_0 = OpConstant %uint 0
5171 %output = OpVariable %uint_ptr_Output Output
5172 %main = OpFunction %void None %func
5173 %2 = OpLabel
5174 %var = OpVariable %uint_ptr_Function Function
5175 OpStore %output %uint_0
5176 OpReturn
5177 OpFunctionEnd
5178   )";
5179 
5180   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5181 }
5182 
TEST_F(AggressiveDCETest,ParitallyDeadDecorationGroupDifferentGroupDecorate)5183 TEST_F(AggressiveDCETest, ParitallyDeadDecorationGroupDifferentGroupDecorate) {
5184   const std::string text = R"(
5185 ; CHECK: OpDecorate [[grp:%\w+]] Restrict
5186 ; CHECK: [[grp]] = OpDecorationGroup
5187 ; CHECK: OpGroupDecorate [[grp]] [[output:%\w+]]
5188 ; CHECK-NOT: OpGroupDecorate
5189 ; CHECK: [[output]] = OpVariable {{%\w+}} Output
5190 ; CHECK-NOT: OpVariable {{%\w+}} Function
5191 OpCapability Shader
5192 OpMemoryModel Logical GLSL450
5193 OpEntryPoint Fragment %main "main" %output
5194 OpExecutionMode %main OriginUpperLeft
5195 OpDecorate %1 Restrict
5196 %1 = OpDecorationGroup
5197 OpGroupDecorate %1 %output
5198 OpGroupDecorate %1 %var
5199 %void = OpTypeVoid
5200 %func = OpTypeFunction %void
5201 %uint = OpTypeInt 32 0
5202 %uint_ptr_Function = OpTypePointer Function %uint
5203 %uint_ptr_Output = OpTypePointer Output %uint
5204 %uint_0 = OpConstant %uint 0
5205 %output = OpVariable %uint_ptr_Output Output
5206 %main = OpFunction %void None %func
5207 %2 = OpLabel
5208 %var = OpVariable %uint_ptr_Function Function
5209 OpStore %output %uint_0
5210 OpReturn
5211 OpFunctionEnd
5212   )";
5213 
5214   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5215 }
5216 
TEST_F(AggressiveDCETest,DeadGroupMemberDecorate)5217 TEST_F(AggressiveDCETest, DeadGroupMemberDecorate) {
5218   const std::string text = R"(
5219 ; CHECK-NOT: OpDec
5220 ; CHECK-NOT: OpGroup
5221 OpCapability Shader
5222 OpMemoryModel Logical GLSL450
5223 OpEntryPoint Fragment %main "main"
5224 OpExecutionMode %main OriginUpperLeft
5225 OpDecorate %1 Offset 0
5226 OpDecorate %1 Uniform
5227 %1 = OpDecorationGroup
5228 OpGroupMemberDecorate %1 %var 0
5229 %void = OpTypeVoid
5230 %func = OpTypeFunction %void
5231 %uint = OpTypeInt 32 0
5232 %struct = OpTypeStruct %uint %uint
5233 %struct_ptr = OpTypePointer Function %struct
5234 %main = OpFunction %void None %func
5235 %2 = OpLabel
5236 %var = OpVariable %struct_ptr Function
5237 OpReturn
5238 OpFunctionEnd
5239   )";
5240 
5241   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5242 }
5243 
TEST_F(AggressiveDCETest,PartiallyDeadGroupMemberDecorate)5244 TEST_F(AggressiveDCETest, PartiallyDeadGroupMemberDecorate) {
5245   const std::string text = R"(
5246 ; CHECK: OpDecorate [[grp:%\w+]] Offset 0
5247 ; CHECK: OpDecorate [[grp]] RelaxedPrecision
5248 ; CHECK: [[grp]] = OpDecorationGroup
5249 ; CHECK: OpGroupMemberDecorate [[grp]] [[output:%\w+]] 1
5250 ; CHECK: [[output]] = OpTypeStruct
5251 ; CHECK-NOT: OpTypeStruct
5252 OpCapability Shader
5253 OpMemoryModel Logical GLSL450
5254 OpEntryPoint Fragment %main "main" %output
5255 OpExecutionMode %main OriginUpperLeft
5256 OpDecorate %1 Offset 0
5257 OpDecorate %1 RelaxedPrecision
5258 %1 = OpDecorationGroup
5259 OpGroupMemberDecorate %1 %var_struct 0 %output_struct 1
5260 %void = OpTypeVoid
5261 %func = OpTypeFunction %void
5262 %uint = OpTypeInt 32 0
5263 %var_struct = OpTypeStruct %uint %uint
5264 %output_struct = OpTypeStruct %uint %uint
5265 %struct_ptr_Function = OpTypePointer Function %var_struct
5266 %struct_ptr_Output = OpTypePointer Output %output_struct
5267 %uint_ptr_Output = OpTypePointer Output %uint
5268 %output = OpVariable %struct_ptr_Output Output
5269 %uint_0 = OpConstant %uint 0
5270 %main = OpFunction %void None %func
5271 %2 = OpLabel
5272 %var = OpVariable %struct_ptr_Function Function
5273 %3 = OpAccessChain %uint_ptr_Output %output %uint_0
5274 OpStore %3 %uint_0
5275 OpReturn
5276 OpFunctionEnd
5277   )";
5278 
5279   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5280 }
5281 
TEST_F(AggressiveDCETest,PartiallyDeadGroupMemberDecorateDifferentGroupDecorate)5282 TEST_F(AggressiveDCETest,
5283        PartiallyDeadGroupMemberDecorateDifferentGroupDecorate) {
5284   const std::string text = R"(
5285 ; CHECK: OpDecorate [[grp:%\w+]] Offset 0
5286 ; CHECK: OpDecorate [[grp]] RelaxedPrecision
5287 ; CHECK: [[grp]] = OpDecorationGroup
5288 ; CHECK: OpGroupMemberDecorate [[grp]] [[output:%\w+]] 1
5289 ; CHECK-NOT: OpGroupMemberDecorate
5290 ; CHECK: [[output]] = OpTypeStruct
5291 ; CHECK-NOT: OpTypeStruct
5292 OpCapability Shader
5293 OpMemoryModel Logical GLSL450
5294 OpEntryPoint Fragment %main "main" %output
5295 OpExecutionMode %main OriginUpperLeft
5296 OpDecorate %1 Offset 0
5297 OpDecorate %1 RelaxedPrecision
5298 %1 = OpDecorationGroup
5299 OpGroupMemberDecorate %1 %var_struct 0
5300 OpGroupMemberDecorate %1 %output_struct 1
5301 %void = OpTypeVoid
5302 %func = OpTypeFunction %void
5303 %uint = OpTypeInt 32 0
5304 %var_struct = OpTypeStruct %uint %uint
5305 %output_struct = OpTypeStruct %uint %uint
5306 %struct_ptr_Function = OpTypePointer Function %var_struct
5307 %struct_ptr_Output = OpTypePointer Output %output_struct
5308 %uint_ptr_Output = OpTypePointer Output %uint
5309 %output = OpVariable %struct_ptr_Output Output
5310 %uint_0 = OpConstant %uint 0
5311 %main = OpFunction %void None %func
5312 %2 = OpLabel
5313 %var = OpVariable %struct_ptr_Function Function
5314 %3 = OpAccessChain %uint_ptr_Output %output %uint_0
5315 OpStore %3 %uint_0
5316 OpReturn
5317 OpFunctionEnd
5318   )";
5319 
5320   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5321 }
5322 
5323 // Test for #1404
TEST_F(AggressiveDCETest,DontRemoveWorkgroupSize)5324 TEST_F(AggressiveDCETest, DontRemoveWorkgroupSize) {
5325   const std::string text = R"(
5326 ; CHECK: OpDecorate [[wgs:%\w+]] BuiltIn WorkgroupSize
5327 ; CHECK: [[wgs]] = OpSpecConstantComposite
5328 OpCapability Shader
5329 OpMemoryModel Logical GLSL450
5330 OpEntryPoint GLCompute %func "func"
5331 OpExecutionMode %func LocalSize 1 1 1
5332 OpDecorate %1 BuiltIn WorkgroupSize
5333 %void = OpTypeVoid
5334 %int = OpTypeInt 32 0
5335 %functy = OpTypeFunction %void
5336 %v3int = OpTypeVector %int 3
5337 %2 = OpSpecConstant %int 1
5338 %1 = OpSpecConstantComposite %v3int %2 %2 %2
5339 %func = OpFunction %void None %functy
5340 %3 = OpLabel
5341 OpReturn
5342 OpFunctionEnd
5343 )";
5344 
5345   SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
5346 }
5347 
5348 // Test for #1214
TEST_F(AggressiveDCETest,LoopHeaderIsAlsoAnotherLoopMerge)5349 TEST_F(AggressiveDCETest, LoopHeaderIsAlsoAnotherLoopMerge) {
5350   const std::string text = R"(OpCapability Shader
5351 OpMemoryModel Logical GLSL450
5352 OpEntryPoint Fragment %1 "func" %2
5353 OpExecutionMode %1 OriginUpperLeft
5354 %void = OpTypeVoid
5355 %bool = OpTypeBool
5356 %true = OpConstantTrue %bool
5357 %uint = OpTypeInt 32 0
5358 %_ptr_Output_uint = OpTypePointer Output %uint
5359 %2 = OpVariable %_ptr_Output_uint Output
5360 %uint_0 = OpConstant %uint 0
5361 %9 = OpTypeFunction %void
5362 %1 = OpFunction %void None %9
5363 %10 = OpLabel
5364 OpBranch %11
5365 %11 = OpLabel
5366 OpLoopMerge %12 %13 None
5367 OpBranchConditional %true %14 %13
5368 %14 = OpLabel
5369 OpStore %2 %uint_0
5370 OpLoopMerge %15 %16 None
5371 OpBranchConditional %true %15 %16
5372 %16 = OpLabel
5373 OpBranch %14
5374 %15 = OpLabel
5375 OpBranchConditional %true %12 %13
5376 %13 = OpLabel
5377 OpBranch %11
5378 %12 = OpLabel
5379 %17 = OpPhi %uint %uint_0 %15 %uint_0 %18
5380 OpStore %2 %17
5381 OpLoopMerge %19 %18 None
5382 OpBranchConditional %true %19 %18
5383 %18 = OpLabel
5384 OpBranch %12
5385 %19 = OpLabel
5386 OpReturn
5387 OpFunctionEnd
5388 )";
5389 
5390   SinglePassRunAndCheck<AggressiveDCEPass>(text, text, true, true);
5391 }
5392 
TEST_F(AggressiveDCETest,BreaksDontVisitPhis)5393 TEST_F(AggressiveDCETest, BreaksDontVisitPhis) {
5394   const std::string text = R"(
5395 OpCapability Shader
5396 OpMemoryModel Logical GLSL450
5397 OpEntryPoint Fragment %func "func" %var
5398 OpExecutionMode %func OriginUpperLeft
5399 %void = OpTypeVoid
5400 %bool = OpTypeBool
5401 %true = OpConstantTrue %bool
5402 %int = OpTypeInt 32 0
5403 %int_ptr_Output = OpTypePointer Output %int
5404 %var = OpVariable %int_ptr_Output Output
5405 %int0 = OpConstant %int 0
5406 %functy = OpTypeFunction %void
5407 %func = OpFunction %void None %functy
5408 %entry = OpLabel
5409 OpBranch %outer_header
5410 %outer_header = OpLabel
5411 OpLoopMerge %outer_merge %outer_continue None
5412 OpBranchConditional %true %inner_header %outer_continue
5413 %inner_header = OpLabel
5414 %phi = OpPhi %int %int0 %outer_header %int0 %inner_continue
5415 OpStore %var %phi
5416 OpLoopMerge %inner_merge %inner_continue None
5417 OpBranchConditional %true %inner_merge %inner_continue
5418 %inner_continue = OpLabel
5419 OpBranch %inner_header
5420 %inner_merge = OpLabel
5421 OpBranch %outer_continue
5422 %outer_continue = OpLabel
5423 %p = OpPhi %int %int0 %outer_header %int0 %inner_merge
5424 OpStore %var %p
5425 OpBranch %outer_header
5426 %outer_merge = OpLabel
5427 OpReturn
5428 OpFunctionEnd
5429 )";
5430 
5431   EXPECT_EQ(Pass::Status::SuccessWithoutChange,
5432             std::get<1>(SinglePassRunAndDisassemble<AggressiveDCEPass>(
5433                 text, false, true)));
5434 }
5435 
5436 // Test for #1212
TEST_F(AggressiveDCETest,ConstStoreInnerLoop)5437 TEST_F(AggressiveDCETest, ConstStoreInnerLoop) {
5438   const std::string text = R"(OpCapability Shader
5439 OpMemoryModel Logical GLSL450
5440 OpEntryPoint Vertex %1 "main" %2
5441 %void = OpTypeVoid
5442 %4 = OpTypeFunction %void
5443 %float = OpTypeFloat 32
5444 %bool = OpTypeBool
5445 %true = OpConstantTrue %bool
5446 %_ptr_Output_float = OpTypePointer Output %float
5447 %2 = OpVariable %_ptr_Output_float Output
5448 %float_3 = OpConstant %float 3
5449 %1 = OpFunction %void None %4
5450 %13 = OpLabel
5451 OpBranch %14
5452 %14 = OpLabel
5453 OpLoopMerge %15 %16 None
5454 OpBranchConditional %true %17 %15
5455 %17 = OpLabel
5456 OpStore %2 %float_3
5457 OpLoopMerge %18 %17 None
5458 OpBranchConditional %true %18 %17
5459 %18 = OpLabel
5460 OpBranch %15
5461 %16 = OpLabel
5462 OpBranch %14
5463 %15 = OpLabel
5464 OpBranch %20
5465 %20 = OpLabel
5466 OpReturn
5467 OpFunctionEnd
5468 )";
5469 
5470   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5471   SinglePassRunAndCheck<AggressiveDCEPass>(text, text, true, true);
5472 }
5473 
5474 // Test for #1212
TEST_F(AggressiveDCETest,InnerLoopCopy)5475 TEST_F(AggressiveDCETest, InnerLoopCopy) {
5476   const std::string text = R"(OpCapability Shader
5477 OpMemoryModel Logical GLSL450
5478 OpEntryPoint Vertex %1 "main" %2 %3
5479 %void = OpTypeVoid
5480 %5 = OpTypeFunction %void
5481 %float = OpTypeFloat 32
5482 %bool = OpTypeBool
5483 %true = OpConstantTrue %bool
5484 %_ptr_Output_float = OpTypePointer Output %float
5485 %_ptr_Input_float = OpTypePointer Input %float
5486 %2 = OpVariable %_ptr_Output_float Output
5487 %3 = OpVariable %_ptr_Input_float Input
5488 %1 = OpFunction %void None %5
5489 %14 = OpLabel
5490 OpBranch %15
5491 %15 = OpLabel
5492 OpLoopMerge %16 %17 None
5493 OpBranchConditional %true %18 %16
5494 %18 = OpLabel
5495 %19 = OpLoad %float %3
5496 OpStore %2 %19
5497 OpLoopMerge %20 %18 None
5498 OpBranchConditional %true %20 %18
5499 %20 = OpLabel
5500 OpBranch %16
5501 %17 = OpLabel
5502 OpBranch %15
5503 %16 = OpLabel
5504 OpBranch %22
5505 %22 = OpLabel
5506 OpReturn
5507 OpFunctionEnd
5508 )";
5509 
5510   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5511   SinglePassRunAndCheck<AggressiveDCEPass>(text, text, true, true);
5512 }
5513 
TEST_F(AggressiveDCETest,AtomicAdd)5514 TEST_F(AggressiveDCETest, AtomicAdd) {
5515   const std::string text = R"(OpCapability SampledBuffer
5516 OpCapability StorageImageExtendedFormats
5517 OpCapability ImageBuffer
5518 OpCapability Shader
5519 %1 = OpExtInstImport "GLSL.std.450"
5520 OpMemoryModel Logical GLSL450
5521 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
5522 OpExecutionMode %2 LocalSize 64 1 1
5523 OpSource HLSL 600
5524 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
5525 OpDecorate %4 DescriptorSet 4
5526 OpDecorate %4 Binding 70
5527 %uint = OpTypeInt 32 0
5528 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
5529 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
5530 %_ptr_Private_6 = OpTypePointer Private %6
5531 %void = OpTypeVoid
5532 %10 = OpTypeFunction %void
5533 %uint_0 = OpConstant %uint 0
5534 %uint_1 = OpConstant %uint 1
5535 %v3uint = OpTypeVector %uint 3
5536 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
5537 %_ptr_Image_uint = OpTypePointer Image %uint
5538 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
5539 %16 = OpVariable %_ptr_Private_6 Private
5540 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
5541 %2 = OpFunction %void None %10
5542 %17 = OpLabel
5543 %18 = OpLoad %6 %4
5544 OpStore %16 %18
5545 %19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0
5546 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
5547 OpReturn
5548 OpFunctionEnd
5549 )";
5550 
5551   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5552   SinglePassRunAndCheck<AggressiveDCEPass>(text, text, true, true);
5553 }
5554 
TEST_F(AggressiveDCETest,SafelyRemoveDecorateString)5555 TEST_F(AggressiveDCETest, SafelyRemoveDecorateString) {
5556   const std::string preamble = R"(OpCapability Shader
5557 OpExtension "SPV_GOOGLE_hlsl_functionality1"
5558 OpMemoryModel Logical GLSL450
5559 OpEntryPoint Fragment %1 "main"
5560 OpExecutionMode %1 OriginUpperLeft
5561 )";
5562 
5563   const std::string body_before =
5564       R"(OpDecorateStringGOOGLE %2 HlslSemanticGOOGLE "FOOBAR"
5565 %void = OpTypeVoid
5566 %4 = OpTypeFunction %void
5567 %uint = OpTypeInt 32 0
5568 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
5569 %2 = OpVariable %_ptr_StorageBuffer_uint StorageBuffer
5570 %1 = OpFunction %void None %4
5571 %7 = OpLabel
5572 OpReturn
5573 OpFunctionEnd
5574 )";
5575 
5576   const std::string body_after = R"(%void = OpTypeVoid
5577 %4 = OpTypeFunction %void
5578 %1 = OpFunction %void None %4
5579 %7 = OpLabel
5580 OpReturn
5581 OpFunctionEnd
5582 )";
5583 
5584   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5585   SinglePassRunAndCheck<AggressiveDCEPass>(preamble + body_before,
5586                                            preamble + body_after, true, true);
5587 }
5588 
TEST_F(AggressiveDCETest,CopyMemoryToGlobal)5589 TEST_F(AggressiveDCETest, CopyMemoryToGlobal) {
5590   // |local| is loaded in an OpCopyMemory instruction.  So the store must be
5591   // kept alive.
5592   const std::string test =
5593       R"(OpCapability Geometry
5594 %1 = OpExtInstImport "GLSL.std.450"
5595 OpMemoryModel Logical GLSL450
5596 OpEntryPoint Geometry %main "main" %global
5597 OpExecutionMode %main Triangles
5598 OpExecutionMode %main Invocations 1
5599 OpExecutionMode %main OutputTriangleStrip
5600 OpExecutionMode %main OutputVertices 5
5601 OpSource GLSL 440
5602 OpName %main "main"
5603 OpName %local "local"
5604 OpName %global "global"
5605 %void = OpTypeVoid
5606 %7 = OpTypeFunction %void
5607 %float = OpTypeFloat 32
5608 %v4float = OpTypeVector %float 4
5609 %12 = OpConstantNull %v4float
5610 %_ptr_Function_v4float = OpTypePointer Function %v4float
5611 %_ptr_Output_v4float = OpTypePointer Output %v4float
5612 %global = OpVariable %_ptr_Output_v4float Output
5613 %main = OpFunction %void None %7
5614 %19 = OpLabel
5615 %local = OpVariable %_ptr_Function_v4float Function
5616 OpStore %local %12
5617 OpCopyMemory %global %local
5618 OpEndPrimitive
5619 OpReturn
5620 OpFunctionEnd
5621 )";
5622 
5623   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5624   SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
5625 }
5626 
TEST_F(AggressiveDCETest,CopyMemoryToLocal)5627 TEST_F(AggressiveDCETest, CopyMemoryToLocal) {
5628   // Make sure the store to |local2| using OpCopyMemory is kept and keeps
5629   // |local1| alive.
5630   const std::string test =
5631       R"(OpCapability Geometry
5632 %1 = OpExtInstImport "GLSL.std.450"
5633 OpMemoryModel Logical GLSL450
5634 OpEntryPoint Geometry %main "main" %global
5635 OpExecutionMode %main Triangles
5636 OpExecutionMode %main Invocations 1
5637 OpExecutionMode %main OutputTriangleStrip
5638 OpExecutionMode %main OutputVertices 5
5639 OpSource GLSL 440
5640 OpName %main "main"
5641 OpName %local1 "local1"
5642 OpName %local2 "local2"
5643 OpName %global "global"
5644 %void = OpTypeVoid
5645 %7 = OpTypeFunction %void
5646 %float = OpTypeFloat 32
5647 %v4float = OpTypeVector %float 4
5648 %12 = OpConstantNull %v4float
5649 %_ptr_Function_v4float = OpTypePointer Function %v4float
5650 %_ptr_Output_v4float = OpTypePointer Output %v4float
5651 %global = OpVariable %_ptr_Output_v4float Output
5652 %main = OpFunction %void None %7
5653 %19 = OpLabel
5654 %local1 = OpVariable %_ptr_Function_v4float Function
5655 %local2 = OpVariable %_ptr_Function_v4float Function
5656 OpStore %local1 %12
5657 OpCopyMemory %local2 %local1
5658 OpCopyMemory %global %local2
5659 OpEndPrimitive
5660 OpReturn
5661 OpFunctionEnd
5662 )";
5663 
5664   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5665   SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
5666 }
5667 
TEST_F(AggressiveDCETest,RemoveCopyMemoryToLocal)5668 TEST_F(AggressiveDCETest, RemoveCopyMemoryToLocal) {
5669   // Test that we remove function scope variables that are stored to using
5670   // OpCopyMemory, but are never loaded.  We can remove both |local1| and
5671   // |local2|.
5672   const std::string test =
5673       R"(OpCapability Geometry
5674 %1 = OpExtInstImport "GLSL.std.450"
5675 OpMemoryModel Logical GLSL450
5676 OpEntryPoint Geometry %main "main" %global
5677 OpExecutionMode %main Triangles
5678 OpExecutionMode %main Invocations 1
5679 OpExecutionMode %main OutputTriangleStrip
5680 OpExecutionMode %main OutputVertices 5
5681 OpSource GLSL 440
5682 OpName %main "main"
5683 OpName %local1 "local1"
5684 OpName %local2 "local2"
5685 OpName %global "global"
5686 %void = OpTypeVoid
5687 %7 = OpTypeFunction %void
5688 %float = OpTypeFloat 32
5689 %v4float = OpTypeVector %float 4
5690 %12 = OpConstantNull %v4float
5691 %_ptr_Function_v4float = OpTypePointer Function %v4float
5692 %_ptr_Output_v4float = OpTypePointer Output %v4float
5693 %global = OpVariable %_ptr_Output_v4float Output
5694 %main = OpFunction %void None %7
5695 %19 = OpLabel
5696 %local1 = OpVariable %_ptr_Function_v4float Function
5697 %local2 = OpVariable %_ptr_Function_v4float Function
5698 OpStore %local1 %12
5699 OpCopyMemory %local2 %local1
5700 OpEndPrimitive
5701 OpReturn
5702 OpFunctionEnd
5703 )";
5704 
5705   const std::string result =
5706       R"(OpCapability Geometry
5707 %1 = OpExtInstImport "GLSL.std.450"
5708 OpMemoryModel Logical GLSL450
5709 OpEntryPoint Geometry %main "main" %global
5710 OpExecutionMode %main Triangles
5711 OpExecutionMode %main Invocations 1
5712 OpExecutionMode %main OutputTriangleStrip
5713 OpExecutionMode %main OutputVertices 5
5714 OpSource GLSL 440
5715 OpName %main "main"
5716 OpName %global "global"
5717 %void = OpTypeVoid
5718 %7 = OpTypeFunction %void
5719 %float = OpTypeFloat 32
5720 %v4float = OpTypeVector %float 4
5721 %_ptr_Output_v4float = OpTypePointer Output %v4float
5722 %global = OpVariable %_ptr_Output_v4float Output
5723 %main = OpFunction %void None %7
5724 %19 = OpLabel
5725 OpEndPrimitive
5726 OpReturn
5727 OpFunctionEnd
5728 )";
5729 
5730   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5731   SinglePassRunAndCheck<AggressiveDCEPass>(test, result, true, true);
5732 }
5733 
TEST_F(AggressiveDCETest,RemoveCopyMemoryToLocal2)5734 TEST_F(AggressiveDCETest, RemoveCopyMemoryToLocal2) {
5735   // We are able to remove "local2" because it is not loaded, but have to keep
5736   // the stores to "local1".
5737   const std::string test =
5738       R"(OpCapability Geometry
5739 %1 = OpExtInstImport "GLSL.std.450"
5740 OpMemoryModel Logical GLSL450
5741 OpEntryPoint Geometry %main "main" %global
5742 OpExecutionMode %main Triangles
5743 OpExecutionMode %main Invocations 1
5744 OpExecutionMode %main OutputTriangleStrip
5745 OpExecutionMode %main OutputVertices 5
5746 OpSource GLSL 440
5747 OpName %main "main"
5748 OpName %local1 "local1"
5749 OpName %local2 "local2"
5750 OpName %global "global"
5751 %void = OpTypeVoid
5752 %7 = OpTypeFunction %void
5753 %float = OpTypeFloat 32
5754 %v4float = OpTypeVector %float 4
5755 %12 = OpConstantNull %v4float
5756 %_ptr_Function_v4float = OpTypePointer Function %v4float
5757 %_ptr_Output_v4float = OpTypePointer Output %v4float
5758 %global = OpVariable %_ptr_Output_v4float Output
5759 %main = OpFunction %void None %7
5760 %19 = OpLabel
5761 %local1 = OpVariable %_ptr_Function_v4float Function
5762 %local2 = OpVariable %_ptr_Function_v4float Function
5763 OpStore %local1 %12
5764 OpCopyMemory %local2 %local1
5765 OpCopyMemory %global %local1
5766 OpEndPrimitive
5767 OpReturn
5768 OpFunctionEnd
5769 )";
5770 
5771   const std::string result =
5772       R"(OpCapability Geometry
5773 %1 = OpExtInstImport "GLSL.std.450"
5774 OpMemoryModel Logical GLSL450
5775 OpEntryPoint Geometry %main "main" %global
5776 OpExecutionMode %main Triangles
5777 OpExecutionMode %main Invocations 1
5778 OpExecutionMode %main OutputTriangleStrip
5779 OpExecutionMode %main OutputVertices 5
5780 OpSource GLSL 440
5781 OpName %main "main"
5782 OpName %local1 "local1"
5783 OpName %global "global"
5784 %void = OpTypeVoid
5785 %7 = OpTypeFunction %void
5786 %float = OpTypeFloat 32
5787 %v4float = OpTypeVector %float 4
5788 %12 = OpConstantNull %v4float
5789 %_ptr_Function_v4float = OpTypePointer Function %v4float
5790 %_ptr_Output_v4float = OpTypePointer Output %v4float
5791 %global = OpVariable %_ptr_Output_v4float Output
5792 %main = OpFunction %void None %7
5793 %19 = OpLabel
5794 %local1 = OpVariable %_ptr_Function_v4float Function
5795 OpStore %local1 %12
5796 OpCopyMemory %global %local1
5797 OpEndPrimitive
5798 OpReturn
5799 OpFunctionEnd
5800 )";
5801 
5802   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5803   SinglePassRunAndCheck<AggressiveDCEPass>(test, result, true, true);
5804 }
5805 
TEST_F(AggressiveDCETest,StructuredIfWithConditionalExit)5806 TEST_F(AggressiveDCETest, StructuredIfWithConditionalExit) {
5807   // We are able to remove "local2" because it is not loaded, but have to keep
5808   // the stores to "local1".
5809   const std::string test =
5810       R"(OpCapability Shader
5811 %1 = OpExtInstImport "GLSL.std.450"
5812 OpMemoryModel Logical GLSL450
5813 OpEntryPoint Fragment %main "main"
5814 OpExecutionMode %main OriginUpperLeft
5815 OpSource GLSL 140
5816 OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
5817 OpSourceExtension "GL_GOOGLE_include_directive"
5818 OpName %main "main"
5819 OpName %a "a"
5820 %void = OpTypeVoid
5821 %5 = OpTypeFunction %void
5822 %int = OpTypeInt 32 1
5823 %_ptr_Uniform_int = OpTypePointer Uniform %int
5824 %int_0 = OpConstant %int 0
5825 %bool = OpTypeBool
5826 %int_100 = OpConstant %int 100
5827 %int_1 = OpConstant %int 1
5828 %a = OpVariable %_ptr_Uniform_int Uniform
5829 %main = OpFunction %void None %5
5830 %12 = OpLabel
5831 %13 = OpLoad %int %a
5832 %14 = OpSGreaterThan %bool %13 %int_0
5833 OpSelectionMerge %15 None
5834 OpBranchConditional %14 %16 %15
5835 %16 = OpLabel
5836 %17 = OpLoad %int %a
5837 %18 = OpSLessThan %bool %17 %int_100
5838 OpBranchConditional %18 %19 %15
5839 %19 = OpLabel
5840 OpStore %a %int_1
5841 OpBranch %15
5842 %15 = OpLabel
5843 OpReturn
5844 OpFunctionEnd
5845 )";
5846 
5847   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5848   SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
5849 }
5850 
TEST_F(AggressiveDCETest,CountingLoopNotEliminated)5851 TEST_F(AggressiveDCETest, CountingLoopNotEliminated) {
5852   // #version 310 es
5853   //
5854   // precision highp float;
5855   // precision highp int;
5856   //
5857   // layout(location = 0) out vec4 _GLF_color;
5858   //
5859   // void main()
5860   // {
5861   //   float data[1];
5862   //   for (int c = 0; c < 1; c++) {
5863   //     if (true) {
5864   //       do {
5865   //         for (int i = 0; i < 1; i++) {
5866   //           data[i] = 1.0;
5867   //         }
5868   //       } while (false);
5869   //     }
5870   //   }
5871   //   _GLF_color = vec4(data[0], 0.0, 0.0, 1.0);
5872   // }
5873   const std::string test =
5874       R"(OpCapability Shader
5875 %1 = OpExtInstImport "GLSL.std.450"
5876 OpMemoryModel Logical GLSL450
5877 OpEntryPoint Fragment %main "main" %_GLF_color
5878 OpExecutionMode %main OriginUpperLeft
5879 OpSource ESSL 310
5880 OpName %main "main"
5881 OpName %c "c"
5882 OpName %i "i"
5883 OpName %data "data"
5884 OpName %_GLF_color "_GLF_color"
5885 OpDecorate %_GLF_color Location 0
5886 %void = OpTypeVoid
5887 %8 = OpTypeFunction %void
5888 %int = OpTypeInt 32 1
5889 %_ptr_Function_int = OpTypePointer Function %int
5890 %int_0 = OpConstant %int 0
5891 %int_1 = OpConstant %int 1
5892 %bool = OpTypeBool
5893 %float = OpTypeFloat 32
5894 %uint = OpTypeInt 32 0
5895 %uint_1 = OpConstant %uint 1
5896 %_arr_float_uint_1 = OpTypeArray %float %uint_1
5897 %_ptr_Function__arr_float_uint_1 = OpTypePointer Function %_arr_float_uint_1
5898 %float_1 = OpConstant %float 1
5899 %_ptr_Function_float = OpTypePointer Function %float
5900 %false = OpConstantFalse %bool
5901 %v4float = OpTypeVector %float 4
5902 %_ptr_Output_v4float = OpTypePointer Output %v4float
5903 %_GLF_color = OpVariable %_ptr_Output_v4float Output
5904 %float_0 = OpConstant %float 0
5905 %main = OpFunction %void None %8
5906 %26 = OpLabel
5907 %c = OpVariable %_ptr_Function_int Function
5908 %i = OpVariable %_ptr_Function_int Function
5909 %data = OpVariable %_ptr_Function__arr_float_uint_1 Function
5910 OpStore %c %int_0
5911 OpBranch %27
5912 %27 = OpLabel
5913 OpLoopMerge %28 %29 None
5914 OpBranch %30
5915 %30 = OpLabel
5916 %31 = OpLoad %int %c
5917 %32 = OpSLessThan %bool %31 %int_1
5918 OpBranchConditional %32 %33 %28
5919 %33 = OpLabel
5920 OpBranch %34
5921 %34 = OpLabel
5922 OpBranch %35
5923 %35 = OpLabel
5924 OpLoopMerge %36 %37 None
5925 OpBranch %38
5926 %38 = OpLabel
5927 OpStore %i %int_0
5928 OpBranch %39
5929 %39 = OpLabel
5930 OpLoopMerge %40 %41 None
5931 OpBranch %42
5932 %42 = OpLabel
5933 %43 = OpLoad %int %i
5934 %44 = OpSLessThan %bool %43 %int_1
5935 OpSelectionMerge %45 None
5936 OpBranchConditional %44 %46 %40
5937 %46 = OpLabel
5938 %47 = OpLoad %int %i
5939 %48 = OpAccessChain %_ptr_Function_float %data %47
5940 OpStore %48 %float_1
5941 OpBranch %41
5942 %41 = OpLabel
5943 %49 = OpLoad %int %i
5944 %50 = OpIAdd %int %49 %int_1
5945 OpStore %i %50
5946 OpBranch %39
5947 %40 = OpLabel
5948 OpBranch %37
5949 %37 = OpLabel
5950 OpBranchConditional %false %35 %36
5951 %36 = OpLabel
5952 OpBranch %45
5953 %45 = OpLabel
5954 OpBranch %29
5955 %29 = OpLabel
5956 %51 = OpLoad %int %c
5957 %52 = OpIAdd %int %51 %int_1
5958 OpStore %c %52
5959 OpBranch %27
5960 %28 = OpLabel
5961 %53 = OpAccessChain %_ptr_Function_float %data %int_0
5962 %54 = OpLoad %float %53
5963 %55 = OpCompositeConstruct %v4float %54 %float_0 %float_0 %float_1
5964 OpStore %_GLF_color %55
5965 OpReturn
5966 OpFunctionEnd
5967 )";
5968 
5969   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5970   SinglePassRunAndCheck<AggressiveDCEPass>(test, test, true, true);
5971 }
5972 
TEST_F(AggressiveDCETest,EliminateLoopWithUnreachable)5973 TEST_F(AggressiveDCETest, EliminateLoopWithUnreachable) {
5974   // #version 430
5975   //
5976   // layout(std430) buffer U_t
5977   // {
5978   //   float g_F[10];
5979   //   float g_S;
5980   // };
5981   //
5982   // layout(location = 0)out float o;
5983   //
5984   // void main(void)
5985   // {
5986   //   // Useless loop
5987   //   for (int i = 0; i<10; i++) {
5988   //     if (g_F[i] == 0.0)
5989   //       break;
5990   //     else
5991   //       break;
5992   //     // Unreachable merge block created here.
5993   //     // Need to edit SPIR-V to change to OpUnreachable
5994   //   }
5995   //   o = g_S;
5996   // }
5997 
5998   const std::string before =
5999       R"(OpCapability Shader
6000 %1 = OpExtInstImport "GLSL.std.450"
6001 OpMemoryModel Logical GLSL450
6002 OpEntryPoint Fragment %main "main" %o
6003 OpExecutionMode %main OriginUpperLeft
6004 OpSource GLSL 430
6005 OpName %main "main"
6006 OpName %i "i"
6007 OpName %U_t "U_t"
6008 OpMemberName %U_t 0 "g_F"
6009 OpMemberName %U_t 1 "g_S"
6010 OpName %_ ""
6011 OpName %o "o"
6012 OpDecorate %_arr_float_uint_10 ArrayStride 4
6013 OpMemberDecorate %U_t 0 Offset 0
6014 OpMemberDecorate %U_t 1 Offset 40
6015 OpDecorate %U_t BufferBlock
6016 OpDecorate %_ DescriptorSet 0
6017 OpDecorate %o Location 0
6018 %void = OpTypeVoid
6019 %9 = OpTypeFunction %void
6020 %int = OpTypeInt 32 1
6021 %_ptr_Function_int = OpTypePointer Function %int
6022 %int_0 = OpConstant %int 0
6023 %int_10 = OpConstant %int 10
6024 %bool = OpTypeBool
6025 %float = OpTypeFloat 32
6026 %uint = OpTypeInt 32 0
6027 %uint_10 = OpConstant %uint 10
6028 %_arr_float_uint_10 = OpTypeArray %float %uint_10
6029 %U_t = OpTypeStruct %_arr_float_uint_10 %float
6030 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
6031 %_ = OpVariable %_ptr_Uniform_U_t Uniform
6032 %_ptr_Uniform_float = OpTypePointer Uniform %float
6033 %float_0 = OpConstant %float 0
6034 %int_1 = OpConstant %int 1
6035 %_ptr_Output_float = OpTypePointer Output %float
6036 %o = OpVariable %_ptr_Output_float Output
6037 %main = OpFunction %void None %9
6038 %23 = OpLabel
6039 %i = OpVariable %_ptr_Function_int Function
6040 OpStore %i %int_0
6041 OpBranch %24
6042 %24 = OpLabel
6043 OpLoopMerge %25 %26 None
6044 OpBranch %27
6045 %27 = OpLabel
6046 %28 = OpLoad %int %i
6047 %29 = OpSLessThan %bool %28 %int_10
6048 OpBranchConditional %29 %30 %25
6049 %30 = OpLabel
6050 %31 = OpLoad %int %i
6051 %32 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %31
6052 %33 = OpLoad %float %32
6053 %34 = OpFOrdEqual %bool %33 %float_0
6054 OpSelectionMerge %35 None
6055 OpBranchConditional %34 %36 %37
6056 %36 = OpLabel
6057 OpBranch %25
6058 %37 = OpLabel
6059 OpBranch %25
6060 %35 = OpLabel
6061 OpUnreachable
6062 %26 = OpLabel
6063 %38 = OpLoad %int %i
6064 %39 = OpIAdd %int %38 %int_1
6065 OpStore %i %39
6066 OpBranch %24
6067 %25 = OpLabel
6068 %40 = OpAccessChain %_ptr_Uniform_float %_ %int_1
6069 %41 = OpLoad %float %40
6070 OpStore %o %41
6071 OpReturn
6072 OpFunctionEnd
6073 )";
6074 
6075   const std::string after =
6076       R"(OpCapability Shader
6077 %1 = OpExtInstImport "GLSL.std.450"
6078 OpMemoryModel Logical GLSL450
6079 OpEntryPoint Fragment %main "main" %o
6080 OpExecutionMode %main OriginUpperLeft
6081 OpSource GLSL 430
6082 OpName %main "main"
6083 OpName %U_t "U_t"
6084 OpMemberName %U_t 0 "g_F"
6085 OpMemberName %U_t 1 "g_S"
6086 OpName %_ ""
6087 OpName %o "o"
6088 OpDecorate %_arr_float_uint_10 ArrayStride 4
6089 OpMemberDecorate %U_t 0 Offset 0
6090 OpMemberDecorate %U_t 1 Offset 40
6091 OpDecorate %U_t BufferBlock
6092 OpDecorate %_ DescriptorSet 0
6093 OpDecorate %o Location 0
6094 %void = OpTypeVoid
6095 %9 = OpTypeFunction %void
6096 %int = OpTypeInt 32 1
6097 %float = OpTypeFloat 32
6098 %uint = OpTypeInt 32 0
6099 %uint_10 = OpConstant %uint 10
6100 %_arr_float_uint_10 = OpTypeArray %float %uint_10
6101 %U_t = OpTypeStruct %_arr_float_uint_10 %float
6102 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
6103 %_ = OpVariable %_ptr_Uniform_U_t Uniform
6104 %_ptr_Uniform_float = OpTypePointer Uniform %float
6105 %int_1 = OpConstant %int 1
6106 %_ptr_Output_float = OpTypePointer Output %float
6107 %o = OpVariable %_ptr_Output_float Output
6108 %main = OpFunction %void None %9
6109 %23 = OpLabel
6110 OpBranch %24
6111 %24 = OpLabel
6112 OpBranch %25
6113 %25 = OpLabel
6114 %40 = OpAccessChain %_ptr_Uniform_float %_ %int_1
6115 %41 = OpLoad %float %40
6116 OpStore %o %41
6117 OpReturn
6118 OpFunctionEnd
6119 )";
6120 
6121   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6122   SinglePassRunAndCheck<AggressiveDCEPass>(before, after, true, true);
6123 }
6124 
TEST_F(AggressiveDCETest,DeadHlslCounterBufferGOOGLE)6125 TEST_F(AggressiveDCETest, DeadHlslCounterBufferGOOGLE) {
6126   // We are able to remove "local2" because it is not loaded, but have to keep
6127   // the stores to "local1".
6128   const std::string test =
6129       R"(
6130 ; CHECK-NOT: OpDecorateId
6131 ; CHECK: [[var:%\w+]] = OpVariable
6132 ; CHECK-NOT: OpVariable
6133 ; CHECK: [[ac:%\w+]] = OpAccessChain {{%\w+}} [[var]]
6134 ; CHECK: OpStore [[ac]]
6135                OpCapability Shader
6136                OpExtension "SPV_GOOGLE_hlsl_functionality1"
6137                OpMemoryModel Logical GLSL450
6138                OpEntryPoint GLCompute %1 "main"
6139                OpExecutionMode %1 LocalSize 32 1 1
6140                OpSource HLSL 600
6141                OpDecorate %_runtimearr_v2float ArrayStride 8
6142                OpMemberDecorate %_struct_3 0 Offset 0
6143                OpDecorate %_struct_3 BufferBlock
6144                OpMemberDecorate %_struct_4 0 Offset 0
6145                OpDecorate %_struct_4 BufferBlock
6146                OpDecorateId %5 HlslCounterBufferGOOGLE %6
6147                OpDecorate %5 DescriptorSet 0
6148                OpDecorate %5 Binding 0
6149                OpDecorate %6 DescriptorSet 0
6150                OpDecorate %6 Binding 1
6151       %float = OpTypeFloat 32
6152     %v2float = OpTypeVector %float 2
6153 %_runtimearr_v2float = OpTypeRuntimeArray %v2float
6154   %_struct_3 = OpTypeStruct %_runtimearr_v2float
6155 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
6156         %int = OpTypeInt 32 1
6157   %_struct_4 = OpTypeStruct %int
6158 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
6159        %void = OpTypeVoid
6160          %13 = OpTypeFunction %void
6161          %19 = OpConstantNull %v2float
6162       %int_0 = OpConstant %int 0
6163 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
6164           %5 = OpVariable %_ptr_Uniform__struct_3 Uniform
6165           %6 = OpVariable %_ptr_Uniform__struct_4 Uniform
6166           %1 = OpFunction %void None %13
6167          %22 = OpLabel
6168          %23 = OpAccessChain %_ptr_Uniform_v2float %5 %int_0 %int_0
6169                OpStore %23 %19
6170                OpReturn
6171                OpFunctionEnd
6172 )";
6173 
6174   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6175   SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
6176 }
6177 
TEST_F(AggressiveDCETest,Dead)6178 TEST_F(AggressiveDCETest, Dead) {
6179   // We are able to remove "local2" because it is not loaded, but have to keep
6180   // the stores to "local1".
6181   const std::string test =
6182       R"(
6183 ; CHECK: OpCapability
6184 ; CHECK-NOT: OpMemberDecorateStringGOOGLE
6185 ; CHECK: OpFunctionEnd
6186            OpCapability Shader
6187            OpExtension "SPV_GOOGLE_hlsl_functionality1"
6188       %1 = OpExtInstImport "GLSL.std.450"
6189            OpMemoryModel Logical GLSL450
6190            OpEntryPoint Vertex %VSMain "VSMain"
6191            OpSource HLSL 500
6192            OpName %VSMain "VSMain"
6193            OpName %PSInput "PSInput"
6194            OpMemberName %PSInput 0 "Pos"
6195            OpMemberName %PSInput 1 "uv"
6196            OpMemberDecorateStringGOOGLE %PSInput 0 HlslSemanticGOOGLE "SV_POSITION"
6197            OpMemberDecorateStringGOOGLE %PSInput 1 HlslSemanticGOOGLE "TEX_COORD"
6198    %void = OpTypeVoid
6199       %5 = OpTypeFunction %void
6200   %float = OpTypeFloat 32
6201 %v2float = OpTypeVector %float 2
6202 %v4float = OpTypeVector %float 4
6203 %PSInput = OpTypeStruct %v4float %v2float
6204  %VSMain = OpFunction %void None %5
6205       %9 = OpLabel
6206            OpReturn
6207            OpFunctionEnd
6208 )";
6209 
6210   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6211   SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
6212 }
6213 
TEST_F(AggressiveDCETest,DeadInfiniteLoop)6214 TEST_F(AggressiveDCETest, DeadInfiniteLoop) {
6215   const std::string test = R"(
6216 ; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]]
6217 ; CHECK: [[block]] = OpLabel
6218 ; CHECK-NEXT: OpBranch [[block:%\w+]]
6219 ; CHECK: [[block]] = OpLabel
6220 ; CHECK-NEXT: OpBranch [[block:%\w+]]
6221 ; CHECK: [[block]] = OpLabel
6222 ; CHECK-NEXT: OpReturn
6223                OpCapability Shader
6224                OpMemoryModel Logical GLSL450
6225                OpEntryPoint Fragment %2 "main"
6226                OpExecutionMode %2 OriginUpperLeft
6227           %6 = OpTypeVoid
6228           %7 = OpTypeFunction %6
6229           %8 = OpTypeFloat 32
6230           %9 = OpTypeVector %8 3
6231          %10 = OpTypeFunction %9
6232          %11 = OpConstant %8 1
6233          %12 = OpConstantComposite %9 %11 %11 %11
6234          %13 = OpTypeInt 32 1
6235          %32 = OpUndef %13
6236           %2 = OpFunction %6 None %7
6237          %33 = OpLabel
6238                OpBranch %34
6239          %34 = OpLabel
6240                OpLoopMerge %35 %36 None
6241                OpBranch %37
6242          %37 = OpLabel
6243          %38 = OpFunctionCall %9 %39
6244                OpSelectionMerge %40 None
6245                OpSwitch %32 %40 14 %41 58 %42
6246          %42 = OpLabel
6247                OpBranch %43
6248          %43 = OpLabel
6249                OpLoopMerge %44 %45 None
6250                OpBranch %45
6251          %45 = OpLabel
6252                OpBranch %43
6253          %44 = OpLabel
6254                OpUnreachable
6255          %41 = OpLabel
6256                OpBranch %36
6257          %40 = OpLabel
6258                OpBranch %36
6259          %36 = OpLabel
6260                OpBranch %34
6261          %35 = OpLabel
6262                OpReturn
6263                OpFunctionEnd
6264          %39 = OpFunction %9 None %10
6265          %46 = OpLabel
6266                OpReturnValue %12
6267                OpFunctionEnd
6268 )";
6269 
6270   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6271   SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
6272 }
6273 
TEST_F(AggressiveDCETest,DeadInfiniteLoopReturnValue)6274 TEST_F(AggressiveDCETest, DeadInfiniteLoopReturnValue) {
6275   const std::string test = R"(
6276 ; CHECK: [[vec3:%\w+]] = OpTypeVector
6277 ; CHECK: [[undef:%\w+]] = OpUndef [[vec3]]
6278 ; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]]
6279 ; CHECK: [[block]] = OpLabel
6280 ; CHECK-NEXT: OpBranch [[block:%\w+]]
6281 ; CHECK: [[block]] = OpLabel
6282 ; CHECK-NEXT: OpBranch [[block:%\w+]]
6283 ; CHECK: [[block]] = OpLabel
6284 ; CHECK-NEXT: OpReturnValue [[undef]]
6285                OpCapability Shader
6286                OpMemoryModel Logical GLSL450
6287                OpEntryPoint Fragment %2 "main"
6288                OpExecutionMode %2 OriginUpperLeft
6289           %6 = OpTypeVoid
6290           %7 = OpTypeFunction %6
6291           %8 = OpTypeFloat 32
6292           %9 = OpTypeVector %8 3
6293          %10 = OpTypeFunction %9
6294          %11 = OpConstant %8 1
6295          %12 = OpConstantComposite %9 %11 %11 %11
6296          %13 = OpTypeInt 32 1
6297          %32 = OpUndef %13
6298           %2 = OpFunction %6 None %7
6299       %entry = OpLabel
6300        %call = OpFunctionCall %9 %func
6301                OpReturn
6302                OpFunctionEnd
6303        %func = OpFunction %9 None %10
6304          %33 = OpLabel
6305                OpBranch %34
6306          %34 = OpLabel
6307                OpLoopMerge %35 %36 None
6308                OpBranch %37
6309          %37 = OpLabel
6310          %38 = OpFunctionCall %9 %39
6311                OpSelectionMerge %40 None
6312                OpSwitch %32 %40 14 %41 58 %42
6313          %42 = OpLabel
6314                OpBranch %43
6315          %43 = OpLabel
6316                OpLoopMerge %44 %45 None
6317                OpBranch %45
6318          %45 = OpLabel
6319                OpBranch %43
6320          %44 = OpLabel
6321                OpUnreachable
6322          %41 = OpLabel
6323                OpBranch %36
6324          %40 = OpLabel
6325                OpBranch %36
6326          %36 = OpLabel
6327                OpBranch %34
6328          %35 = OpLabel
6329                OpReturnValue %12
6330                OpFunctionEnd
6331          %39 = OpFunction %9 None %10
6332          %46 = OpLabel
6333                OpReturnValue %12
6334                OpFunctionEnd
6335 )";
6336 
6337   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6338   SinglePassRunAndMatch<AggressiveDCEPass>(test, true);
6339 }
6340 
TEST_F(AggressiveDCETest,TestVariablePointer)6341 TEST_F(AggressiveDCETest, TestVariablePointer) {
6342   const std::string before =
6343       R"(OpCapability Shader
6344 OpCapability VariablePointers
6345 %1 = OpExtInstImport "GLSL.std.450"
6346 OpMemoryModel Logical GLSL450
6347 OpEntryPoint GLCompute %2 "main"
6348 OpExecutionMode %2 LocalSize 1 1 1
6349 OpSource GLSL 450
6350 OpMemberDecorate %_struct_3 0 Offset 0
6351 OpDecorate %_struct_3 Block
6352 OpDecorate %4 DescriptorSet 0
6353 OpDecorate %4 Binding 0
6354 OpDecorate %_ptr_StorageBuffer_int ArrayStride 4
6355 OpDecorate %_arr_int_int_128 ArrayStride 4
6356 %void = OpTypeVoid
6357 %8 = OpTypeFunction %void
6358 %int = OpTypeInt 32 1
6359 %int_128 = OpConstant %int 128
6360 %_arr_int_int_128 = OpTypeArray %int %int_128
6361 %_struct_3 = OpTypeStruct %_arr_int_int_128
6362 %_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
6363 %4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer
6364 %bool = OpTypeBool
6365 %true = OpConstantTrue %bool
6366 %int_0 = OpConstant %int 0
6367 %int_1 = OpConstant %int 1
6368 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
6369 %2 = OpFunction %void None %8
6370 %16 = OpLabel
6371 %17 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0
6372 OpBranch %18
6373 %18 = OpLabel
6374 %19 = OpPhi %_ptr_StorageBuffer_int %17 %16 %20 %21
6375 OpLoopMerge %22 %21 None
6376 OpBranchConditional %true %23 %22
6377 %23 = OpLabel
6378 OpStore %19 %int_0
6379 OpBranch %21
6380 %21 = OpLabel
6381 %20 = OpPtrAccessChain %_ptr_StorageBuffer_int %19 %int_1
6382 OpBranch %18
6383 %22 = OpLabel
6384 OpReturn
6385 OpFunctionEnd
6386 )";
6387 
6388   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
6389   SinglePassRunAndCheck<AggressiveDCEPass>(before, before, true, true);
6390 }
6391 
TEST_F(AggressiveDCETest,DeadInputInterfaceV13)6392 TEST_F(AggressiveDCETest, DeadInputInterfaceV13) {
6393   const std::string spirv = R"(
6394 ; CHECK: OpEntryPoint GLCompute %main "main" [[var:%\w+]]
6395 ; CHECK: [[var]] = OpVariable
6396 OpCapability Shader
6397 OpMemoryModel Logical GLSL450
6398 OpEntryPoint GLCompute %main "main" %dead
6399 OpExecutionMode %main LocalSize 1 1 1
6400 OpName %main "main"
6401 %void = OpTypeVoid
6402 %int = OpTypeInt 32 0
6403 %ptr_input_int = OpTypePointer Input %int
6404 %dead = OpVariable %ptr_input_int Input
6405 %void_fn = OpTypeFunction %void
6406 %main = OpFunction %void None %void_fn
6407 %entry = OpLabel
6408 OpReturn
6409 OpFunctionEnd
6410 )";
6411 
6412   SetTargetEnv(SPV_ENV_UNIVERSAL_1_3);
6413   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6414 }
6415 
TEST_F(AggressiveDCETest,DeadInputInterfaceV14)6416 TEST_F(AggressiveDCETest, DeadInputInterfaceV14) {
6417   const std::string spirv = R"(
6418 ; CHECK: OpEntryPoint GLCompute %main "main" [[var:%\w+]]
6419 ; CHECK: [[var]] = OpVariable
6420 OpCapability Shader
6421 OpMemoryModel Logical GLSL450
6422 OpEntryPoint GLCompute %main "main" %dead
6423 OpExecutionMode %main LocalSize 1 1 1
6424 OpName %main "main"
6425 %void = OpTypeVoid
6426 %int = OpTypeInt 32 0
6427 %ptr_input_int = OpTypePointer Input %int
6428 %dead = OpVariable %ptr_input_int Input
6429 %void_fn = OpTypeFunction %void
6430 %main = OpFunction %void None %void_fn
6431 %entry = OpLabel
6432 OpReturn
6433 OpFunctionEnd
6434 )";
6435 
6436   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6437   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6438 }
6439 
TEST_F(AggressiveDCETest,DeadInterfaceV14)6440 TEST_F(AggressiveDCETest, DeadInterfaceV14) {
6441   const std::string spirv = R"(
6442 ; CHECK-NOT: OpEntryPoint GLCompute %main "main" %
6443 ; CHECK: OpEntryPoint GLCompute %main "main"
6444 ; CHECK-NOT: OpVariable
6445 OpCapability Shader
6446 OpMemoryModel Logical GLSL450
6447 OpEntryPoint GLCompute %main "main" %dead
6448 OpExecutionMode %main LocalSize 1 1 1
6449 OpName %main "main"
6450 %void = OpTypeVoid
6451 %int = OpTypeInt 32 0
6452 %ptr_private_int = OpTypePointer Private %int
6453 %dead = OpVariable %ptr_private_int Private
6454 %void_fn = OpTypeFunction %void
6455 %main = OpFunction %void None %void_fn
6456 %entry = OpLabel
6457 OpReturn
6458 OpFunctionEnd
6459 )";
6460 
6461   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6462   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6463 }
6464 
TEST_F(AggressiveDCETest,DeadInterfacesV14)6465 TEST_F(AggressiveDCETest, DeadInterfacesV14) {
6466   const std::string spirv = R"(
6467 ; CHECK: OpEntryPoint GLCompute %main "main" %live1 %live2
6468 ; CHECK-NOT: %dead
6469 OpCapability Shader
6470 OpMemoryModel Logical GLSL450
6471 OpEntryPoint GLCompute %main "main" %live1 %dead1 %dead2 %live2
6472 OpExecutionMode %main LocalSize 1 1 1
6473 OpName %main "main"
6474 OpName %live1 "live1"
6475 OpName %live2 "live2"
6476 OpName %dead1 "dead1"
6477 OpName %dead2 "dead2"
6478 %void = OpTypeVoid
6479 %int = OpTypeInt 32 0
6480 %int0 = OpConstant %int 0
6481 %ptr_ssbo_int = OpTypePointer StorageBuffer %int
6482 %live1 = OpVariable %ptr_ssbo_int StorageBuffer
6483 %live2 = OpVariable %ptr_ssbo_int StorageBuffer
6484 %dead1 = OpVariable %ptr_ssbo_int StorageBuffer
6485 %dead2 = OpVariable %ptr_ssbo_int StorageBuffer
6486 %void_fn = OpTypeFunction %void
6487 %main = OpFunction %void None %void_fn
6488 %entry = OpLabel
6489 OpStore %live1 %int0
6490 OpStore %live2 %int0
6491 OpReturn
6492 OpFunctionEnd
6493 )";
6494 
6495   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6496   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6497 }
6498 
TEST_F(AggressiveDCETest,PreserveBindings)6499 TEST_F(AggressiveDCETest, PreserveBindings) {
6500   const std::string spirv = R"(
6501 ; CHECK: OpDecorate %unusedSampler DescriptorSet 0
6502 ; CHECK: OpDecorate %unusedSampler Binding 0
6503 OpCapability Shader
6504 %1 = OpExtInstImport "GLSL.std.450"
6505 OpMemoryModel Logical GLSL450
6506 OpEntryPoint Fragment %main "main"
6507 OpExecutionMode %main OriginUpperLeft
6508 OpSource GLSL 430
6509 OpName %main "main"
6510 OpName %unusedSampler "unusedSampler"
6511 OpDecorate %unusedSampler DescriptorSet 0
6512 OpDecorate %unusedSampler Binding 0
6513 %void = OpTypeVoid
6514 %5 = OpTypeFunction %void
6515 %float = OpTypeFloat 32
6516 %7 = OpTypeImage %float 2D 0 0 0 1 Unknown
6517 %8 = OpTypeSampledImage %7
6518 %_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8
6519 %unusedSampler = OpVariable %_ptr_UniformConstant_8 UniformConstant
6520 %main = OpFunction %void None %5
6521 %10 = OpLabel
6522 OpReturn
6523 OpFunctionEnd
6524 )";
6525 
6526   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6527 
6528   OptimizerOptions()->preserve_bindings_ = true;
6529 
6530   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6531 }
6532 
TEST_F(AggressiveDCETest,PreserveSpecConstants)6533 TEST_F(AggressiveDCETest, PreserveSpecConstants) {
6534   const std::string spirv = R"(
6535 ; CHECK: OpName %specConstant "specConstant"
6536 ; CHECK: %specConstant = OpSpecConstant %int 0
6537 OpCapability Shader
6538 %1 = OpExtInstImport "GLSL.std.450"
6539 OpMemoryModel Logical GLSL450
6540 OpEntryPoint Fragment %main "main"
6541 OpExecutionMode %main OriginUpperLeft
6542 OpSource GLSL 430
6543 OpName %main "main"
6544 OpName %specConstant "specConstant"
6545 OpDecorate %specConstant SpecId 0
6546 %void = OpTypeVoid
6547 %3 = OpTypeFunction %void
6548 %int = OpTypeInt 32 1
6549 %specConstant = OpSpecConstant %int 0
6550 %main = OpFunction %void None %3
6551 %5 = OpLabel
6552 OpReturn
6553 OpFunctionEnd
6554 )";
6555 
6556   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6557 
6558   OptimizerOptions()->preserve_spec_constants_ = true;
6559 
6560   SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
6561 }
6562 
TEST_F(AggressiveDCETest,LiveDecorateId)6563 TEST_F(AggressiveDCETest, LiveDecorateId) {
6564   const std::string spirv = R"(OpCapability Shader
6565 OpMemoryModel Logical GLSL450
6566 OpEntryPoint GLCompute %1 "main" %2
6567 OpExecutionMode %1 LocalSize 8 1 1
6568 OpDecorate %2 DescriptorSet 0
6569 OpDecorate %2 Binding 0
6570 OpDecorateId %3 UniformId %uint_2
6571 %void = OpTypeVoid
6572 %uint = OpTypeInt 32 0
6573 %uint_2 = OpConstant %uint 2
6574 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
6575 %2 = OpVariable %_ptr_StorageBuffer_uint StorageBuffer
6576 %8 = OpTypeFunction %void
6577 %1 = OpFunction %void None %8
6578 %9 = OpLabel
6579 %3 = OpLoad %uint %2
6580 OpStore %2 %3
6581 OpReturn
6582 OpFunctionEnd
6583 )";
6584 
6585   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6586   OptimizerOptions()->preserve_spec_constants_ = true;
6587   SinglePassRunAndCheck<AggressiveDCEPass>(spirv, spirv, true);
6588 }
6589 
TEST_F(AggressiveDCETest,LiveDecorateIdOnGroup)6590 TEST_F(AggressiveDCETest, LiveDecorateIdOnGroup) {
6591   const std::string spirv = R"(OpCapability Shader
6592 OpMemoryModel Logical GLSL450
6593 OpEntryPoint GLCompute %1 "main" %2
6594 OpExecutionMode %1 LocalSize 8 1 1
6595 OpDecorate %2 DescriptorSet 0
6596 OpDecorate %2 Binding 0
6597 OpDecorateId %3 UniformId %uint_2
6598 %3 = OpDecorationGroup
6599 OpGroupDecorate %3 %5
6600 %void = OpTypeVoid
6601 %uint = OpTypeInt 32 0
6602 %uint_2 = OpConstant %uint 2
6603 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
6604 %2 = OpVariable %_ptr_StorageBuffer_uint StorageBuffer
6605 %9 = OpTypeFunction %void
6606 %1 = OpFunction %void None %9
6607 %10 = OpLabel
6608 %5 = OpLoad %uint %2
6609 OpStore %2 %5
6610 OpReturn
6611 OpFunctionEnd
6612 )";
6613 
6614   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
6615   OptimizerOptions()->preserve_spec_constants_ = true;
6616   SinglePassRunAndCheck<AggressiveDCEPass>(spirv, spirv, true);
6617 }
6618 
TEST_F(AggressiveDCETest,NoEliminateForwardPointer)6619 TEST_F(AggressiveDCETest, NoEliminateForwardPointer) {
6620   // clang-format off
6621   //
6622   //  #version 450
6623   //  #extension GL_EXT_buffer_reference : enable
6624   //
6625   //    // forward reference
6626   //    layout(buffer_reference) buffer blockType;
6627   //
6628   //  layout(buffer_reference, std430, buffer_reference_align = 16) buffer blockType {
6629   //    int x;
6630   //    blockType next;
6631   //  };
6632   //
6633   //  layout(std430) buffer rootBlock {
6634   //    blockType root;
6635   //  } r;
6636   //
6637   //  void main()
6638   //  {
6639   //    blockType b = r.root;
6640   //    b = b.next;
6641   //    b.x = 531;
6642   //  }
6643   //
6644   // clang-format on
6645 
6646   const std::string predefs1 =
6647       R"(OpCapability Shader
6648 OpCapability PhysicalStorageBufferAddresses
6649 OpExtension "SPV_EXT_physical_storage_buffer"
6650 OpExtension "SPV_KHR_storage_buffer_storage_class"
6651 %1 = OpExtInstImport "GLSL.std.450"
6652 OpMemoryModel PhysicalStorageBuffer64 GLSL450
6653 OpEntryPoint GLCompute %main "main"
6654 OpExecutionMode %main LocalSize 1 1 1
6655 OpSource GLSL 450
6656 OpSourceExtension "GL_EXT_buffer_reference"
6657 )";
6658 
6659   const std::string names_before =
6660       R"(OpName %main "main"
6661 OpName %blockType "blockType"
6662 OpMemberName %blockType 0 "x"
6663 OpMemberName %blockType 1 "next"
6664 OpName %b "b"
6665 OpName %rootBlock "rootBlock"
6666 OpMemberName %rootBlock 0 "root"
6667 OpName %r "r"
6668 OpMemberDecorate %blockType 0 Offset 0
6669 OpMemberDecorate %blockType 1 Offset 8
6670 OpDecorate %blockType Block
6671 OpDecorate %b AliasedPointer
6672 OpMemberDecorate %rootBlock 0 Offset 0
6673 OpDecorate %rootBlock Block
6674 OpDecorate %r DescriptorSet 0
6675 OpDecorate %r Binding 0
6676 )";
6677 
6678   const std::string names_after =
6679       R"(OpName %main "main"
6680 OpName %blockType "blockType"
6681 OpMemberName %blockType 0 "x"
6682 OpMemberName %blockType 1 "next"
6683 OpName %rootBlock "rootBlock"
6684 OpMemberName %rootBlock 0 "root"
6685 OpName %r "r"
6686 OpMemberDecorate %blockType 0 Offset 0
6687 OpMemberDecorate %blockType 1 Offset 8
6688 OpDecorate %blockType Block
6689 OpMemberDecorate %rootBlock 0 Offset 0
6690 OpDecorate %rootBlock Block
6691 OpDecorate %r DescriptorSet 0
6692 OpDecorate %r Binding 0
6693 )";
6694 
6695   const std::string predefs2_before =
6696       R"(%void = OpTypeVoid
6697 %3 = OpTypeFunction %void
6698 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
6699 %int = OpTypeInt 32 1
6700 %blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
6701 %_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
6702 %_ptr_Function__ptr_PhysicalStorageBuffer_blockType = OpTypePointer Function %_ptr_PhysicalStorageBuffer_blockType
6703 %rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
6704 %_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
6705 %r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
6706 %int_0 = OpConstant %int 0
6707 %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
6708 %int_1 = OpConstant %int 1
6709 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
6710 %int_531 = OpConstant %int 531
6711 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
6712 )";
6713 
6714   const std::string predefs2_after =
6715       R"(%void = OpTypeVoid
6716 %8 = OpTypeFunction %void
6717 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
6718 %int = OpTypeInt 32 1
6719 %blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
6720 %_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
6721 %rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
6722 %_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
6723 %r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
6724 %int_0 = OpConstant %int 0
6725 %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
6726 %int_1 = OpConstant %int 1
6727 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
6728 %int_531 = OpConstant %int 531
6729 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
6730 )";
6731 
6732   const std::string func_before =
6733       R"(%main = OpFunction %void None %3
6734 %5 = OpLabel
6735 %b = OpVariable %_ptr_Function__ptr_PhysicalStorageBuffer_blockType Function
6736 %16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
6737 %17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
6738 %21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
6739 %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
6740 OpStore %b %22
6741 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
6742 OpStore %26 %int_531 Aligned 16
6743 OpReturn
6744 OpFunctionEnd
6745 )";
6746 
6747   const std::string func_after =
6748       R"(%main = OpFunction %void None %8
6749 %19 = OpLabel
6750 %20 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
6751 %21 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %20
6752 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %21 %int_1
6753 %23 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %22 Aligned 8
6754 %24 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %23 %int_0
6755 OpStore %24 %int_531 Aligned 16
6756 OpReturn
6757 OpFunctionEnd
6758 )";
6759 
6760   SinglePassRunAndCheck<AggressiveDCEPass>(
6761       predefs1 + names_before + predefs2_before + func_before,
6762       predefs1 + names_after + predefs2_after + func_after, true, true);
6763 }
6764 
6765 // TODO(greg-lunarg): Add tests to verify handling of these cases:
6766 //
6767 //    Check that logical addressing required
6768 //    Check that function calls inhibit optimization
6769 //    Others?
6770 
6771 }  // namespace
6772 }  // namespace opt
6773 }  // namespace spvtools
6774