• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <cstdarg>
17 #include <iostream>
18 #include <sstream>
19 #include <string>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "test/opt/assembly_builder.h"
24 #include "test/opt/pass_fixture.h"
25 #include "test/opt/pass_utils.h"
26 
27 namespace spvtools {
28 namespace opt {
29 namespace {
30 
31 using EliminateDeadConstantBasicTest = PassTest<::testing::Test>;
32 
TEST_F(EliminateDeadConstantBasicTest,BasicAllDeadConstants)33 TEST_F(EliminateDeadConstantBasicTest, BasicAllDeadConstants) {
34   const std::vector<const char*> text = {
35       // clang-format off
36                "OpCapability Shader",
37                "OpCapability Float64",
38           "%1 = OpExtInstImport \"GLSL.std.450\"",
39                "OpMemoryModel Logical GLSL450",
40                "OpEntryPoint Vertex %main \"main\"",
41                "OpName %main \"main\"",
42        "%void = OpTypeVoid",
43           "%4 = OpTypeFunction %void",
44        "%bool = OpTypeBool",
45        "%true = OpConstantTrue %bool",
46       "%false = OpConstantFalse %bool",
47         "%int = OpTypeInt 32 1",
48           "%9 = OpConstant %int 1",
49        "%uint = OpTypeInt 32 0",
50          "%11 = OpConstant %uint 2",
51       "%float = OpTypeFloat 32",
52          "%13 = OpConstant %float 3.1415",
53      "%double = OpTypeFloat 64",
54          "%15 = OpConstant %double 3.14159265358979",
55        "%main = OpFunction %void None %4",
56          "%16 = OpLabel",
57                "OpReturn",
58                "OpFunctionEnd",
59       // clang-format on
60   };
61   // None of the above constants is ever used, so all of them should be
62   // eliminated.
63   const char* const_decl_opcodes[] = {
64       " OpConstantTrue ",
65       " OpConstantFalse ",
66       " OpConstant ",
67   };
68   // Skip lines that have any one of const_decl_opcodes.
69   const std::string expected_disassembly =
70       SelectiveJoin(text, [&const_decl_opcodes](const char* line) {
71         return std::any_of(
72             std::begin(const_decl_opcodes), std::end(const_decl_opcodes),
73             [&line](const char* const_decl_op) {
74               return std::string(line).find(const_decl_op) != std::string::npos;
75             });
76       });
77 
78   SinglePassRunAndCheck<EliminateDeadConstantPass>(
79       JoinAllInsts(text), expected_disassembly, /* skip_nop = */ true);
80 }
81 
TEST_F(EliminateDeadConstantBasicTest,BasicNoneDeadConstants)82 TEST_F(EliminateDeadConstantBasicTest, BasicNoneDeadConstants) {
83   const std::vector<const char*> text = {
84       // clang-format off
85                 "OpCapability Shader",
86                 "OpCapability Float64",
87            "%1 = OpExtInstImport \"GLSL.std.450\"",
88                 "OpMemoryModel Logical GLSL450",
89                 "OpEntryPoint Vertex %main \"main\"",
90                 "OpName %main \"main\"",
91                 "OpName %btv \"btv\"",
92                 "OpName %bfv \"bfv\"",
93                 "OpName %iv \"iv\"",
94                 "OpName %uv \"uv\"",
95                 "OpName %fv \"fv\"",
96                 "OpName %dv \"dv\"",
97         "%void = OpTypeVoid",
98           "%10 = OpTypeFunction %void",
99         "%bool = OpTypeBool",
100  "%_ptr_Function_bool = OpTypePointer Function %bool",
101         "%true = OpConstantTrue %bool",
102        "%false = OpConstantFalse %bool",
103          "%int = OpTypeInt 32 1",
104  "%_ptr_Function_int = OpTypePointer Function %int",
105        "%int_1 = OpConstant %int 1",
106         "%uint = OpTypeInt 32 0",
107  "%_ptr_Function_uint = OpTypePointer Function %uint",
108       "%uint_2 = OpConstant %uint 2",
109        "%float = OpTypeFloat 32",
110  "%_ptr_Function_float = OpTypePointer Function %float",
111   "%float_3_1415 = OpConstant %float 3.1415",
112       "%double = OpTypeFloat 64",
113  "%_ptr_Function_double = OpTypePointer Function %double",
114  "%double_3_14159265358979 = OpConstant %double 3.14159265358979",
115         "%main = OpFunction %void None %10",
116           "%27 = OpLabel",
117          "%btv = OpVariable %_ptr_Function_bool Function",
118          "%bfv = OpVariable %_ptr_Function_bool Function",
119           "%iv = OpVariable %_ptr_Function_int Function",
120           "%uv = OpVariable %_ptr_Function_uint Function",
121           "%fv = OpVariable %_ptr_Function_float Function",
122           "%dv = OpVariable %_ptr_Function_double Function",
123                 "OpStore %btv %true",
124                 "OpStore %bfv %false",
125                 "OpStore %iv %int_1",
126                 "OpStore %uv %uint_2",
127                 "OpStore %fv %float_3_1415",
128                 "OpStore %dv %double_3_14159265358979",
129                 "OpReturn",
130                 "OpFunctionEnd",
131       // clang-format on
132   };
133   // All constants are used, so none of them should be eliminated.
134   SinglePassRunAndCheck<EliminateDeadConstantPass>(
135       JoinAllInsts(text), JoinAllInsts(text), /* skip_nop = */ true);
136 }
137 
138 struct EliminateDeadConstantTestCase {
139   // Type declarations and constants that should be kept.
140   std::vector<std::string> used_consts;
141   // Instructions that refer to constants, this is added to create uses for
142   // some constants so they won't be treated as dead constants.
143   std::vector<std::string> main_insts;
144   // Dead constants that should be removed.
145   std::vector<std::string> dead_consts;
146 };
147 
148 // All types that are potentially required in EliminateDeadConstantTest.
149 const std::vector<std::string> CommonTypes = {
150     // clang-format off
151     // scalar types
152     "%bool = OpTypeBool",
153     "%uint = OpTypeInt 32 0",
154     "%int = OpTypeInt 32 1",
155     "%float = OpTypeFloat 32",
156     "%double = OpTypeFloat 64",
157     // vector types
158     "%v2bool = OpTypeVector %bool 2",
159     "%v2uint = OpTypeVector %uint 2",
160     "%v2int = OpTypeVector %int 2",
161     "%v3int = OpTypeVector %int 3",
162     "%v4int = OpTypeVector %int 4",
163     "%v2float = OpTypeVector %float 2",
164     "%v3float = OpTypeVector %float 3",
165     "%v2double = OpTypeVector %double 2",
166     // variable pointer types
167     "%_pf_bool = OpTypePointer Function %bool",
168     "%_pf_uint = OpTypePointer Function %uint",
169     "%_pf_int = OpTypePointer Function %int",
170     "%_pf_float = OpTypePointer Function %float",
171     "%_pf_double = OpTypePointer Function %double",
172     "%_pf_v2int = OpTypePointer Function %v2int",
173     "%_pf_v3int = OpTypePointer Function %v3int",
174     "%_pf_v2float = OpTypePointer Function %v2float",
175     "%_pf_v3float = OpTypePointer Function %v3float",
176     "%_pf_v2double = OpTypePointer Function %v2double",
177     // struct types
178     "%inner_struct = OpTypeStruct %bool %int %float %double",
179     "%outer_struct = OpTypeStruct %inner_struct %int %double",
180     "%flat_struct = OpTypeStruct %bool %int %float %double",
181     // clang-format on
182 };
183 
184 using EliminateDeadConstantTest =
185     PassTest<::testing::TestWithParam<EliminateDeadConstantTestCase>>;
186 
TEST_P(EliminateDeadConstantTest,Custom)187 TEST_P(EliminateDeadConstantTest, Custom) {
188   auto& tc = GetParam();
189   AssemblyBuilder builder;
190   builder.AppendTypesConstantsGlobals(CommonTypes)
191       .AppendTypesConstantsGlobals(tc.used_consts)
192       .AppendInMain(tc.main_insts);
193   const std::string expected = builder.GetCode();
194   builder.AppendTypesConstantsGlobals(tc.dead_consts);
195   const std::string assembly_with_dead_const = builder.GetCode();
196   SinglePassRunAndCheck<EliminateDeadConstantPass>(
197       assembly_with_dead_const, expected, /*  skip_nop = */ true);
198 }
199 
200 INSTANTIATE_TEST_SUITE_P(
201     ScalarTypeConstants, EliminateDeadConstantTest,
202     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
203         // clang-format off
204         // Scalar type constants, one dead constant and one used constant.
205         {
206             /* .used_consts = */
207             {
208                 "%used_const_int = OpConstant %int 1",
209             },
210             /* .main_insts = */
211             {
212                 "%int_var = OpVariable %_pf_int Function",
213                 "OpStore %int_var %used_const_int",
214             },
215             /* .dead_consts = */
216             {
217                 "%dead_const_int = OpConstant %int 1",
218             },
219         },
220         {
221             /* .used_consts = */
222             {
223                 "%used_const_uint = OpConstant %uint 1",
224             },
225             /* .main_insts = */
226             {
227                 "%uint_var = OpVariable %_pf_uint Function",
228                 "OpStore %uint_var %used_const_uint",
229             },
230             /* .dead_consts = */
231             {
232                 "%dead_const_uint = OpConstant %uint 1",
233             },
234         },
235         {
236             /* .used_consts = */
237             {
238                 "%used_const_float = OpConstant %float 3.1415",
239             },
240             /* .main_insts = */
241             {
242                 "%float_var = OpVariable %_pf_float Function",
243                 "OpStore %float_var %used_const_float",
244             },
245             /* .dead_consts = */
246             {
247                 "%dead_const_float = OpConstant %float 3.1415",
248             },
249         },
250         {
251             /* .used_consts = */
252             {
253                 "%used_const_double = OpConstant %double 3.141592653",
254             },
255             /* .main_insts = */
256             {
257                 "%double_var = OpVariable %_pf_double Function",
258                 "OpStore %double_var %used_const_double",
259             },
260             /* .dead_consts = */
261             {
262                 "%dead_const_double = OpConstant %double 3.141592653",
263             },
264         },
265         // clang-format on
266     })));
267 
268 INSTANTIATE_TEST_SUITE_P(
269     VectorTypeConstants, EliminateDeadConstantTest,
270     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
271         // clang-format off
272         // Tests eliminating dead constant type ivec2. One dead constant vector
273         // and one used constant vector, each built from its own group of
274         // scalar constants.
275         {
276             /* .used_consts = */
277             {
278                 "%used_int_x = OpConstant %int 1",
279                 "%used_int_y = OpConstant %int 2",
280                 "%used_v2int = OpConstantComposite %v2int %used_int_x %used_int_y",
281             },
282             /* .main_insts = */
283             {
284                 "%v2int_var = OpVariable %_pf_v2int Function",
285                 "OpStore %v2int_var %used_v2int",
286             },
287             /* .dead_consts = */
288             {
289                 "%dead_int_x = OpConstant %int 1",
290                 "%dead_int_y = OpConstant %int 2",
291                 "%dead_v2int = OpConstantComposite %v2int %dead_int_x %dead_int_y",
292             },
293         },
294         // Tests eliminating dead constant ivec2. One dead constant vector and
295         // one used constant vector. But both built from a same group of
296         // scalar constants.
297         {
298             /* .used_consts = */
299             {
300                 "%used_int_x = OpConstant %int 1",
301                 "%used_int_y = OpConstant %int 2",
302                 "%used_int_z = OpConstant %int 3",
303                 "%used_v3int = OpConstantComposite %v3int %used_int_x %used_int_y %used_int_z",
304             },
305             /* .main_insts = */
306             {
307                 "%v3int_var = OpVariable %_pf_v3int Function",
308                 "OpStore %v3int_var %used_v3int",
309             },
310             /* .dead_consts = */
311             {
312                 "%dead_v3int = OpConstantComposite %v3int %used_int_x %used_int_y %used_int_z",
313             },
314         },
315         // Tests eliminating dead cosntant vec2. One dead constant vector and
316         // one used constant vector. Each built from its own group of scalar
317         // constants.
318         {
319             /* .used_consts = */
320             {
321                 "%used_float_x = OpConstant %float 3.1415",
322                 "%used_float_y = OpConstant %float 4.25",
323                 "%used_v2float = OpConstantComposite %v2float %used_float_x %used_float_y",
324             },
325             /* .main_insts = */
326             {
327                 "%v2float_var = OpVariable %_pf_v2float Function",
328                 "OpStore %v2float_var %used_v2float",
329             },
330             /* .dead_consts = */
331             {
332                 "%dead_float_x = OpConstant %float 3.1415",
333                 "%dead_float_y = OpConstant %float 4.25",
334                 "%dead_v2float = OpConstantComposite %v2float %dead_float_x %dead_float_y",
335             },
336         },
337         // Tests eliminating dead cosntant vec2. One dead constant vector and
338         // one used constant vector. Both built from a same group of scalar
339         // constants.
340         {
341             /* .used_consts = */
342             {
343                 "%used_float_x = OpConstant %float 3.1415",
344                 "%used_float_y = OpConstant %float 4.25",
345                 "%used_float_z = OpConstant %float 4.75",
346                 "%used_v3float = OpConstantComposite %v3float %used_float_x %used_float_y %used_float_z",
347             },
348             /* .main_insts = */
349             {
350                 "%v3float_var = OpVariable %_pf_v3float Function",
351                 "OpStore %v3float_var %used_v3float",
352             },
353             /* .dead_consts = */
354             {
355                 "%dead_v3float = OpConstantComposite %v3float %used_float_x %used_float_y %used_float_z",
356             },
357         },
358         // clang-format on
359     })));
360 
361 INSTANTIATE_TEST_SUITE_P(
362     StructTypeConstants, EliminateDeadConstantTest,
363     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
364         // clang-format off
365         // A plain struct type dead constants. All of its components are dead
366         // constants too.
367         {
368             /* .used_consts = */ {},
369             /* .main_insts = */ {},
370             /* .dead_consts = */
371             {
372                 "%dead_bool = OpConstantTrue %bool",
373                 "%dead_int = OpConstant %int 1",
374                 "%dead_float = OpConstant %float 2.5",
375                 "%dead_double = OpConstant %double 3.14159265358979",
376                 "%dead_struct = OpConstantComposite %flat_struct %dead_bool %dead_int %dead_float %dead_double",
377             },
378         },
379         // A plain struct type dead constants. Some of its components are dead
380         // constants while others are not.
381         {
382             /* .used_consts = */
383             {
384                 "%used_int = OpConstant %int 1",
385                 "%used_double = OpConstant %double 3.14159265358979",
386             },
387             /* .main_insts = */
388             {
389                 "%int_var = OpVariable %_pf_int Function",
390                 "OpStore %int_var %used_int",
391                 "%double_var = OpVariable %_pf_double Function",
392                 "OpStore %double_var %used_double",
393             },
394             /* .dead_consts = */
395             {
396                 "%dead_bool = OpConstantTrue %bool",
397                 "%dead_float = OpConstant %float 2.5",
398                 "%dead_struct = OpConstantComposite %flat_struct %dead_bool %used_int %dead_float %used_double",
399             },
400         },
401         // A nesting struct type dead constants. All components of both outer
402         // and inner structs are dead and should be removed after dead constant
403         // elimination.
404         {
405             /* .used_consts = */ {},
406             /* .main_insts = */ {},
407             /* .dead_consts = */
408             {
409                 "%dead_bool = OpConstantTrue %bool",
410                 "%dead_int = OpConstant %int 1",
411                 "%dead_float = OpConstant %float 2.5",
412                 "%dead_double = OpConstant %double 3.1415926535",
413                 "%dead_inner_struct = OpConstantComposite %inner_struct %dead_bool %dead_int %dead_float %dead_double",
414                 "%dead_int2 = OpConstant %int 2",
415                 "%dead_double2 = OpConstant %double 1.428571428514",
416                 "%dead_outer_struct = OpConstantComposite %outer_struct %dead_inner_struct %dead_int2 %dead_double2",
417             },
418         },
419         // A nesting struct type dead constants. Some of its components are
420         // dead constants while others are not.
421         {
422             /* .used_consts = */
423             {
424                 "%used_int = OpConstant %int 1",
425                 "%used_double = OpConstant %double 3.14159265358979",
426             },
427             /* .main_insts = */
428             {
429                 "%int_var = OpVariable %_pf_int Function",
430                 "OpStore %int_var %used_int",
431                 "%double_var = OpVariable %_pf_double Function",
432                 "OpStore %double_var %used_double",
433             },
434             /* .dead_consts = */
435             {
436                 "%dead_bool = OpConstantTrue %bool",
437                 "%dead_float = OpConstant %float 2.5",
438                 "%dead_inner_struct = OpConstantComposite %inner_struct %dead_bool %used_int %dead_float %used_double",
439                 "%dead_int = OpConstant %int 2",
440                 "%dead_outer_struct = OpConstantComposite %outer_struct %dead_inner_struct %dead_int %used_double",
441             },
442         },
443         // A nesting struct case. The inner struct is used while the outer struct is not
444         {
445           /* .used_const = */
446           {
447             "%used_bool = OpConstantTrue %bool",
448             "%used_int = OpConstant %int 1",
449             "%used_float = OpConstant %float 1.25",
450             "%used_double = OpConstant %double 1.23456789012345",
451             "%used_inner_struct = OpConstantComposite %inner_struct %used_bool %used_int %used_float %used_double",
452           },
453           /* .main_insts = */
454           {
455             "%bool_var = OpVariable %_pf_bool Function",
456             "%bool_from_inner_struct = OpCompositeExtract %bool %used_inner_struct 0",
457             "OpStore %bool_var %bool_from_inner_struct",
458           },
459           /* .dead_consts = */
460           {
461             "%dead_int = OpConstant %int 2",
462             "%dead_outer_struct = OpConstantComposite %outer_struct %used_inner_struct %dead_int %used_double"
463           },
464         },
465         // A nesting struct case. The outer struct is used, so the inner struct should not
466         // be removed even though it is not used anywhere.
467         {
468           /* .used_const = */
469           {
470             "%used_bool = OpConstantTrue %bool",
471             "%used_int = OpConstant %int 1",
472             "%used_float = OpConstant %float 1.25",
473             "%used_double = OpConstant %double 1.23456789012345",
474             "%used_inner_struct = OpConstantComposite %inner_struct %used_bool %used_int %used_float %used_double",
475             "%used_outer_struct = OpConstantComposite %outer_struct %used_inner_struct %used_int %used_double"
476           },
477           /* .main_insts = */
478           {
479             "%int_var = OpVariable %_pf_int Function",
480             "%int_from_outer_struct = OpCompositeExtract %int %used_outer_struct 1",
481             "OpStore %int_var %int_from_outer_struct",
482           },
483           /* .dead_consts = */ {},
484         },
485         // clang-format on
486     })));
487 
488 INSTANTIATE_TEST_SUITE_P(
489     ScalarTypeSpecConstants, EliminateDeadConstantTest,
490     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
491         // clang-format off
492         // All scalar type spec constants.
493         {
494             /* .used_consts = */
495             {
496                 "%used_bool = OpSpecConstantTrue %bool",
497                 "%used_uint = OpSpecConstant %uint 2",
498                 "%used_int = OpSpecConstant %int 2",
499                 "%used_float = OpSpecConstant %float 2.5",
500                 "%used_double = OpSpecConstant %double 1.42857142851",
501             },
502             /* .main_insts = */
503             {
504                 "%bool_var = OpVariable %_pf_bool Function",
505                 "%uint_var = OpVariable %_pf_uint Function",
506                 "%int_var = OpVariable %_pf_int Function",
507                 "%float_var = OpVariable %_pf_float Function",
508                 "%double_var = OpVariable %_pf_double Function",
509                 "OpStore %bool_var %used_bool", "OpStore %uint_var %used_uint",
510                 "OpStore %int_var %used_int", "OpStore %float_var %used_float",
511                 "OpStore %double_var %used_double",
512             },
513             /* .dead_consts = */
514             {
515                 "%dead_bool = OpSpecConstantTrue %bool",
516                 "%dead_uint = OpSpecConstant %uint 2",
517                 "%dead_int = OpSpecConstant %int 2",
518                 "%dead_float = OpSpecConstant %float 2.5",
519                 "%dead_double = OpSpecConstant %double 1.42857142851",
520             },
521         },
522         // clang-format on
523     })));
524 
525 INSTANTIATE_TEST_SUITE_P(
526     VectorTypeSpecConstants, EliminateDeadConstantTest,
527     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
528         // clang-format off
529         // Bool vector type spec constants. One vector has all component dead,
530         // another vector has one dead boolean and one used boolean.
531         {
532             /* .used_consts = */
533             {
534                 "%used_bool = OpSpecConstantTrue %bool",
535             },
536             /* .main_insts = */
537             {
538                 "%bool_var = OpVariable %_pf_bool Function",
539                 "OpStore %bool_var %used_bool",
540             },
541             /* .dead_consts = */
542             {
543                 "%dead_bool = OpSpecConstantFalse %bool",
544                 "%dead_bool_vec1 = OpSpecConstantComposite %v2bool %dead_bool %dead_bool",
545                 "%dead_bool_vec2 = OpSpecConstantComposite %v2bool %dead_bool %used_bool",
546             },
547         },
548 
549         // Uint vector type spec constants. One vector has all component dead,
550         // another vector has one dead unsigned integer and one used unsigned
551         // integer.
552         {
553             /* .used_consts = */
554             {
555                 "%used_uint = OpSpecConstant %uint 3",
556             },
557             /* .main_insts = */
558             {
559                 "%uint_var = OpVariable %_pf_uint Function",
560                 "OpStore %uint_var %used_uint",
561             },
562             /* .dead_consts = */
563             {
564                 "%dead_uint = OpSpecConstant %uint 1",
565                 "%dead_uint_vec1 = OpSpecConstantComposite %v2uint %dead_uint %dead_uint",
566                 "%dead_uint_vec2 = OpSpecConstantComposite %v2uint %dead_uint %used_uint",
567             },
568         },
569 
570         // Int vector type spec constants. One vector has all component dead,
571         // another vector has one dead integer and one used integer.
572         {
573             /* .used_consts = */
574             {
575                 "%used_int = OpSpecConstant %int 3",
576             },
577             /* .main_insts = */
578             {
579                 "%int_var = OpVariable %_pf_int Function",
580                 "OpStore %int_var %used_int",
581             },
582             /* .dead_consts = */
583             {
584                 "%dead_int = OpSpecConstant %int 1",
585                 "%dead_int_vec1 = OpSpecConstantComposite %v2int %dead_int %dead_int",
586                 "%dead_int_vec2 = OpSpecConstantComposite %v2int %dead_int %used_int",
587             },
588         },
589 
590         // Int vector type spec constants built with both spec constants and
591         // front-end constants.
592         {
593             /* .used_consts = */
594             {
595                 "%used_spec_int = OpSpecConstant %int 3",
596                 "%used_front_end_int = OpConstant %int 3",
597             },
598             /* .main_insts = */
599             {
600                 "%int_var1 = OpVariable %_pf_int Function",
601                 "OpStore %int_var1 %used_spec_int",
602                 "%int_var2 = OpVariable %_pf_int Function",
603                 "OpStore %int_var2 %used_front_end_int",
604             },
605             /* .dead_consts = */
606             {
607                 "%dead_spec_int = OpSpecConstant %int 1",
608                 "%dead_front_end_int = OpConstant %int 1",
609                 // Dead front-end and dead spec constants
610                 "%dead_int_vec1 = OpSpecConstantComposite %v2int %dead_spec_int %dead_front_end_int",
611                 // Used front-end and dead spec constants
612                 "%dead_int_vec2 = OpSpecConstantComposite %v2int %dead_spec_int %used_front_end_int",
613                 // Dead front-end and used spec constants
614                 "%dead_int_vec3 = OpSpecConstantComposite %v2int %dead_front_end_int %used_spec_int",
615             },
616         },
617         // clang-format on
618     })));
619 
620 INSTANTIATE_TEST_SUITE_P(
621     SpecConstantOp, EliminateDeadConstantTest,
622     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
623         // clang-format off
624         // Cast operations: uint <-> int <-> bool
625         {
626             /* .used_consts = */ {},
627             /* .main_insts = */ {},
628             /* .dead_consts = */
629             {
630                 // Assistant constants, only used in dead spec constant
631                 // operations.
632                 "%signed_zero = OpConstant %int 0",
633                 "%signed_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
634                 "%unsigned_zero = OpConstant %uint 0",
635                 "%unsigned_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
636                 "%signed_one = OpConstant %int 1",
637                 "%signed_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
638                 "%unsigned_one = OpConstant %uint 1",
639                 "%unsigned_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
640 
641                 // Spec constants that support casting to each other.
642                 "%dead_bool = OpSpecConstantTrue %bool",
643                 "%dead_uint = OpSpecConstant %uint 1",
644                 "%dead_int = OpSpecConstant %int 2",
645                 "%dead_bool_vec = OpSpecConstantComposite %v2bool %dead_bool %dead_bool",
646                 "%dead_uint_vec = OpSpecConstantComposite %v2uint %dead_uint %dead_uint",
647                 "%dead_int_vec = OpSpecConstantComposite %v2int %dead_int %dead_int",
648 
649                 // Scalar cast to boolean spec constant.
650                 "%int_to_bool = OpSpecConstantOp %bool INotEqual %dead_int %signed_zero",
651                 "%uint_to_bool = OpSpecConstantOp %bool INotEqual %dead_uint %unsigned_zero",
652 
653                 // Vector cast to boolean spec constant.
654                 "%int_to_bool_vec = OpSpecConstantOp %v2bool INotEqual %dead_int_vec %signed_zero_vec",
655                 "%uint_to_bool_vec = OpSpecConstantOp %v2bool INotEqual %dead_uint_vec %unsigned_zero_vec",
656 
657                 // Scalar cast to int spec constant.
658                 "%bool_to_int = OpSpecConstantOp %int Select %dead_bool %signed_one %signed_zero",
659                 "%uint_to_int = OpSpecConstantOp %uint IAdd %dead_uint %unsigned_zero",
660 
661                 // Vector cast to int spec constant.
662                 "%bool_to_int_vec = OpSpecConstantOp %v2int Select %dead_bool_vec %signed_one_vec %signed_zero_vec",
663                 "%uint_to_int_vec = OpSpecConstantOp %v2uint IAdd %dead_uint_vec %unsigned_zero_vec",
664 
665                 // Scalar cast to uint spec constant.
666                 "%bool_to_uint = OpSpecConstantOp %uint Select %dead_bool %unsigned_one %unsigned_zero",
667                 "%int_to_uint_vec = OpSpecConstantOp %uint IAdd %dead_int %signed_zero",
668 
669                 // Vector cast to uint spec constant.
670                 "%bool_to_uint_vec = OpSpecConstantOp %v2uint Select %dead_bool_vec %unsigned_one_vec %unsigned_zero_vec",
671                 "%int_to_uint = OpSpecConstantOp %v2uint IAdd %dead_int_vec %signed_zero_vec",
672             },
673         },
674 
675         // Add, sub, mul, div, rem.
676         {
677             /* .used_consts = */ {},
678             /* .main_insts = */ {},
679             /* .dead_consts = */
680             {
681                 "%dead_spec_int_a = OpSpecConstant %int 1",
682                 "%dead_spec_int_a_vec = OpSpecConstantComposite %v2int %dead_spec_int_a %dead_spec_int_a",
683 
684                 "%dead_spec_int_b = OpSpecConstant %int 2",
685                 "%dead_spec_int_b_vec = OpSpecConstantComposite %v2int %dead_spec_int_b %dead_spec_int_b",
686 
687                 "%dead_const_int_c = OpConstant %int 3",
688                 "%dead_const_int_c_vec = OpConstantComposite %v2int %dead_const_int_c %dead_const_int_c",
689 
690                 // Add
691                 "%add_a_b = OpSpecConstantOp %int IAdd %dead_spec_int_a %dead_spec_int_b",
692                 "%add_a_b_vec = OpSpecConstantOp %v2int IAdd %dead_spec_int_a_vec %dead_spec_int_b_vec",
693 
694                 // Sub
695                 "%sub_a_b = OpSpecConstantOp %int ISub %dead_spec_int_a %dead_spec_int_b",
696                 "%sub_a_b_vec = OpSpecConstantOp %v2int ISub %dead_spec_int_a_vec %dead_spec_int_b_vec",
697 
698                 // Mul
699                 "%mul_a_b = OpSpecConstantOp %int IMul %dead_spec_int_a %dead_spec_int_b",
700                 "%mul_a_b_vec = OpSpecConstantOp %v2int IMul %dead_spec_int_a_vec %dead_spec_int_b_vec",
701 
702                 // Div
703                 "%div_a_b = OpSpecConstantOp %int SDiv %dead_spec_int_a %dead_spec_int_b",
704                 "%div_a_b_vec = OpSpecConstantOp %v2int SDiv %dead_spec_int_a_vec %dead_spec_int_b_vec",
705 
706                 // Bitwise Xor
707                 "%xor_a_b = OpSpecConstantOp %int BitwiseXor %dead_spec_int_a %dead_spec_int_b",
708                 "%xor_a_b_vec = OpSpecConstantOp %v2int BitwiseXor %dead_spec_int_a_vec %dead_spec_int_b_vec",
709 
710                 // Scalar Comparison
711                 "%less_a_b = OpSpecConstantOp %bool SLessThan %dead_spec_int_a %dead_spec_int_b",
712             },
713         },
714 
715         // Vectors without used swizzles should be removed.
716         {
717             /* .used_consts = */
718             {
719                 "%used_int = OpConstant %int 3",
720             },
721             /* .main_insts = */
722             {
723                 "%int_var = OpVariable %_pf_int Function",
724                 "OpStore %int_var %used_int",
725             },
726             /* .dead_consts = */
727             {
728                 "%dead_int = OpConstant %int 3",
729 
730                 "%dead_spec_int_a = OpSpecConstant %int 1",
731                 "%vec_a = OpSpecConstantComposite %v4int %dead_spec_int_a %dead_spec_int_a %dead_int %dead_int",
732 
733                 "%dead_spec_int_b = OpSpecConstant %int 2",
734                 "%vec_b = OpSpecConstantComposite %v4int %dead_spec_int_b %dead_spec_int_b %used_int %used_int",
735 
736                 // Extract scalar
737                 "%a_x = OpSpecConstantOp %int CompositeExtract %vec_a 0",
738                 "%b_x = OpSpecConstantOp %int CompositeExtract %vec_b 0",
739 
740                 // Extract vector
741                 "%a_xy = OpSpecConstantOp %v2int VectorShuffle %vec_a %vec_a 0 1",
742                 "%b_xy = OpSpecConstantOp %v2int VectorShuffle %vec_b %vec_b 0 1",
743             },
744         },
745         // Vectors with used swizzles should not be removed.
746         {
747             /* .used_consts = */
748             {
749                 "%used_int = OpConstant %int 3",
750                 "%used_spec_int_a = OpSpecConstant %int 1",
751                 "%used_spec_int_b = OpSpecConstant %int 2",
752                 // Create vectors
753                 "%vec_a = OpSpecConstantComposite %v4int %used_spec_int_a %used_spec_int_a %used_int %used_int",
754                 "%vec_b = OpSpecConstantComposite %v4int %used_spec_int_b %used_spec_int_b %used_int %used_int",
755                 // Extract vector
756                 "%a_xy = OpSpecConstantOp %v2int VectorShuffle %vec_a %vec_a 0 1",
757                 "%b_xy = OpSpecConstantOp %v2int VectorShuffle %vec_b %vec_b 0 1",
758             },
759             /* .main_insts = */
760             {
761                 "%v2int_var_a = OpVariable %_pf_v2int Function",
762                 "%v2int_var_b = OpVariable %_pf_v2int Function",
763                 "OpStore %v2int_var_a %a_xy",
764                 "OpStore %v2int_var_b %b_xy",
765             },
766             /* .dead_consts = */ {},
767         },
768         // clang-format on
769     })));
770 
771 INSTANTIATE_TEST_SUITE_P(
772     LongDefUseChain, EliminateDeadConstantTest,
773     ::testing::ValuesIn(std::vector<EliminateDeadConstantTestCase>({
774         // clang-format off
775         // Long Def-Use chain with binary operations.
776         {
777             /* .used_consts = */
778             {
779               "%array_size = OpConstant %int 4",
780               "%type_arr_int_4 = OpTypeArray %int %array_size",
781               "%used_int_0 = OpConstant %int 100",
782               "%used_int_1 = OpConstant %int 1",
783               "%used_int_2 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_1",
784               "%used_int_3 = OpSpecConstantOp %int ISub %used_int_0 %used_int_2",
785               "%used_int_4 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_3",
786               "%used_int_5 = OpSpecConstantOp %int ISub %used_int_0 %used_int_4",
787               "%used_int_6 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_5",
788               "%used_int_7 = OpSpecConstantOp %int ISub %used_int_0 %used_int_6",
789               "%used_int_8 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_7",
790               "%used_int_9 = OpSpecConstantOp %int ISub %used_int_0 %used_int_8",
791               "%used_int_10 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_9",
792               "%used_int_11 = OpSpecConstantOp %int ISub %used_int_0 %used_int_10",
793               "%used_int_12 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_11",
794               "%used_int_13 = OpSpecConstantOp %int ISub %used_int_0 %used_int_12",
795               "%used_int_14 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_13",
796               "%used_int_15 = OpSpecConstantOp %int ISub %used_int_0 %used_int_14",
797               "%used_int_16 = OpSpecConstantOp %int ISub %used_int_0 %used_int_15",
798               "%used_int_17 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_16",
799               "%used_int_18 = OpSpecConstantOp %int ISub %used_int_0 %used_int_17",
800               "%used_int_19 = OpSpecConstantOp %int IAdd %used_int_0 %used_int_18",
801               "%used_int_20 = OpSpecConstantOp %int ISub %used_int_0 %used_int_19",
802               "%used_vec_a = OpSpecConstantComposite %v2int %used_int_18 %used_int_19",
803               "%used_vec_b = OpSpecConstantOp %v2int IMul %used_vec_a %used_vec_a",
804               "%used_int_21 = OpSpecConstantOp %int CompositeExtract %used_vec_b 0",
805               "%used_array = OpConstantComposite %type_arr_int_4 %used_int_20 %used_int_20 %used_int_21 %used_int_21",
806             },
807             /* .main_insts = */
808             {
809               "%int_var = OpVariable %_pf_int Function",
810               "%used_array_2 = OpCompositeExtract %int %used_array 2",
811               "OpStore %int_var %used_array_2",
812             },
813             /* .dead_consts = */
814             {
815               "%dead_int_1 = OpConstant %int 2",
816               "%dead_int_2 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_1",
817               "%dead_int_3 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_2",
818               "%dead_int_4 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_3",
819               "%dead_int_5 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_4",
820               "%dead_int_6 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_5",
821               "%dead_int_7 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_6",
822               "%dead_int_8 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_7",
823               "%dead_int_9 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_8",
824               "%dead_int_10 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_9",
825               "%dead_int_11 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_10",
826               "%dead_int_12 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_11",
827               "%dead_int_13 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_12",
828               "%dead_int_14 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_13",
829               "%dead_int_15 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_14",
830               "%dead_int_16 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_15",
831               "%dead_int_17 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_16",
832               "%dead_int_18 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_17",
833               "%dead_int_19 = OpSpecConstantOp %int IAdd %used_int_0 %dead_int_18",
834               "%dead_int_20 = OpSpecConstantOp %int ISub %used_int_0 %dead_int_19",
835               "%dead_vec_a = OpSpecConstantComposite %v2int %dead_int_18 %dead_int_19",
836               "%dead_vec_b = OpSpecConstantOp %v2int IMul %dead_vec_a %dead_vec_a",
837               "%dead_int_21 = OpSpecConstantOp %int CompositeExtract %dead_vec_b 0",
838               "%dead_array = OpConstantComposite %type_arr_int_4 %dead_int_20 %used_int_20 %dead_int_19 %used_int_19",
839             },
840         },
841         // Long Def-Use chain with swizzle
842         // clang-format on
843     })));
844 
845 }  // namespace
846 }  // namespace opt
847 }  // namespace spvtools
848