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