• 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 <string>
16 #include <tuple>
17 #include <unordered_set>
18 #include <utility>
19 #include <vector>
20 
21 #include "test/opt/assembly_builder.h"
22 #include "test/opt/pass_fixture.h"
23 #include "test/opt/pass_utils.h"
24 
25 namespace spvtools {
26 namespace opt {
27 namespace {
28 
29 // Returns the types defining instructions commonly used in many tests.
CommonTypes()30 std::vector<std::string> CommonTypes() {
31   return std::vector<std::string>{
32       // clang-format off
33     // scalar types
34     "%bool = OpTypeBool",
35     "%uint = OpTypeInt 32 0",
36     "%int = OpTypeInt 32 1",
37     "%uint64 = OpTypeInt 64 0",
38     "%int64 = OpTypeInt 64 1",
39     "%float = OpTypeFloat 32",
40     "%double = OpTypeFloat 64",
41     // vector types
42     "%v2bool = OpTypeVector %bool 2",
43     "%v2uint = OpTypeVector %uint 2",
44     "%v2int = OpTypeVector %int 2",
45     "%v3int = OpTypeVector %int 3",
46     "%v4int = OpTypeVector %int 4",
47     "%v2float = OpTypeVector %float 2",
48     "%v3float = OpTypeVector %float 3",
49     "%v2double = OpTypeVector %double 2",
50     // struct types
51     "%inner_struct = OpTypeStruct %bool %float",
52     "%outer_struct = OpTypeStruct %inner_struct %int %double",
53     "%flat_struct = OpTypeStruct %bool %int %float %double",
54     // variable pointer types
55     "%_pf_bool = OpTypePointer Function %bool",
56     "%_pf_uint = OpTypePointer Function %uint",
57     "%_pf_int = OpTypePointer Function %int",
58     "%_pf_uint64 = OpTypePointer Function %uint64",
59     "%_pf_int64 = OpTypePointer Function %int64",
60     "%_pf_float = OpTypePointer Function %float",
61     "%_pf_double = OpTypePointer Function %double",
62     "%_pf_v2int = OpTypePointer Function %v2int",
63     "%_pf_v3int = OpTypePointer Function %v3int",
64     "%_pf_v4int = OpTypePointer Function %v4int",
65     "%_pf_v2float = OpTypePointer Function %v2float",
66     "%_pf_v3float = OpTypePointer Function %v3float",
67     "%_pf_v2double = OpTypePointer Function %v2double",
68     "%_pf_inner_struct = OpTypePointer Function %inner_struct",
69     "%_pf_outer_struct = OpTypePointer Function %outer_struct",
70     "%_pf_flat_struct = OpTypePointer Function %flat_struct",
71       // clang-format on
72   };
73 }
74 
75 // A helper function to strip OpName instructions from the given string of
76 // disassembly code and put those debug instructions to a set. Returns the
77 // string with all OpName instruction stripped and a set of OpName
78 // instructions.
79 std::tuple<std::string, std::unordered_set<std::string>>
StripOpNameInstructionsToSet(const std::string & str)80 StripOpNameInstructionsToSet(const std::string& str) {
81   std::stringstream ss(str);
82   std::ostringstream oss;
83   std::string inst_str;
84   std::unordered_set<std::string> opname_instructions;
85   while (std::getline(ss, inst_str, '\n')) {
86     if (inst_str.find("OpName %") == std::string::npos) {
87       oss << inst_str << '\n';
88     } else {
89       opname_instructions.insert(inst_str);
90     }
91   }
92   return std::make_tuple(oss.str(), std::move(opname_instructions));
93 }
94 
95 // The test fixture for all tests of UnifyConstantPass. This fixture defines
96 // the rule of checking: all the optimized code should be exactly the same as
97 // the expected code, except the OpName instructions, which can be different in
98 // order.
99 template <typename T>
100 class UnifyConstantTest : public PassTest<T> {
101  protected:
102   // Runs UnifyConstantPass on the code built from the given |test_builder|,
103   // and checks whether the optimization result matches with the code built
104   // from |expected_builder|.
Check(const AssemblyBuilder & expected_builder,const AssemblyBuilder & test_builder)105   void Check(const AssemblyBuilder& expected_builder,
106              const AssemblyBuilder& test_builder) {
107     // unoptimized code
108     const std::string original_before_strip = test_builder.GetCode();
109     std::string original_without_opnames;
110     std::unordered_set<std::string> original_opnames;
111     std::tie(original_without_opnames, original_opnames) =
112         StripOpNameInstructionsToSet(original_before_strip);
113 
114     // expected code
115     std::string expected_without_opnames;
116     std::unordered_set<std::string> expected_opnames;
117     std::tie(expected_without_opnames, expected_opnames) =
118         StripOpNameInstructionsToSet(expected_builder.GetCode());
119 
120     // optimized code
121     std::string optimized_before_strip;
122     auto status = Pass::Status::SuccessWithoutChange;
123     std::tie(optimized_before_strip, status) =
124         this->template SinglePassRunAndDisassemble<UnifyConstantPass>(
125             test_builder.GetCode(),
126             /* skip_nop = */ true, /* do_validation = */ false);
127     std::string optimized_without_opnames;
128     std::unordered_set<std::string> optimized_opnames;
129     std::tie(optimized_without_opnames, optimized_opnames) =
130         StripOpNameInstructionsToSet(optimized_before_strip);
131 
132     // Flag "status" should be returned correctly.
133     EXPECT_NE(Pass::Status::Failure, status);
134     EXPECT_EQ(expected_without_opnames == original_without_opnames,
135               status == Pass::Status::SuccessWithoutChange);
136     // Code except OpName instructions should be exactly the same.
137     EXPECT_EQ(expected_without_opnames, optimized_without_opnames);
138     // OpName instructions can be in different order, but the content must be
139     // the same.
140     EXPECT_EQ(expected_opnames, optimized_opnames);
141   }
142 };
143 
144 using UnifyFrontEndConstantSingleTest =
145     UnifyConstantTest<PassTest<::testing::Test>>;
146 
TEST_F(UnifyFrontEndConstantSingleTest,Basic)147 TEST_F(UnifyFrontEndConstantSingleTest, Basic) {
148   AssemblyBuilder test_builder;
149   AssemblyBuilder expected_builder;
150 
151   test_builder
152       .AppendTypesConstantsGlobals({
153           "%uint = OpTypeInt 32 0", "%_pf_uint = OpTypePointer Function %uint",
154           "%unsigned_1 = OpConstant %uint 1",
155           "%unsigned_1_duplicate = OpConstant %uint 1",  // duplicated constant
156       })
157       .AppendInMain({
158           "%uint_var = OpVariable %_pf_uint Function",
159           "OpStore %uint_var %unsigned_1_duplicate",
160       });
161 
162   expected_builder
163       .AppendTypesConstantsGlobals({
164           "%uint = OpTypeInt 32 0",
165           "%_pf_uint = OpTypePointer Function %uint",
166           "%unsigned_1 = OpConstant %uint 1",
167       })
168       .AppendInMain({
169           "%uint_var = OpVariable %_pf_uint Function",
170           "OpStore %uint_var %unsigned_1",
171       })
172       .AppendNames({
173           "OpName %unsigned_1 \"unsigned_1_duplicate\"",  // the OpName
174                                                           // instruction of the
175                                                           // removed duplicated
176                                                           // constant won't be
177                                                           // erased.
178       });
179   Check(expected_builder, test_builder);
180 }
181 
TEST_F(UnifyFrontEndConstantSingleTest,SkipWhenResultIdHasDecorations)182 TEST_F(UnifyFrontEndConstantSingleTest, SkipWhenResultIdHasDecorations) {
183   AssemblyBuilder test_builder;
184   AssemblyBuilder expected_builder;
185 
186   test_builder
187       .AppendAnnotations({
188           // So far we don't have valid decorations for constants. This is
189           // preparing for the future updates of SPIR-V.
190           // TODO(qining): change to a valid decoration once they are available.
191           "OpDecorate %f_1 RelaxedPrecision",
192           "OpDecorate %f_2_dup RelaxedPrecision",
193       })
194       .AppendTypesConstantsGlobals({
195           // clang-format off
196           "%float = OpTypeFloat 32",
197           "%_pf_float = OpTypePointer Function %float",
198           "%f_1 = OpConstant %float 1",
199           // %f_1 has decoration, so %f_1 will not be used to replace %f_1_dup.
200           "%f_1_dup = OpConstant %float 1",
201           "%f_2 = OpConstant %float 2",
202           // %_2_dup has decoration, so %f_2 will not replace %f_2_dup.
203           "%f_2_dup = OpConstant %float 2",
204           // no decoration for %f_3 or %f_3_dup, %f_3_dup should be replaced.
205           "%f_3 = OpConstant %float 3",
206           "%f_3_dup = OpConstant %float 3",
207           // clang-format on
208       })
209       .AppendInMain({
210           // clang-format off
211           "%f_var = OpVariable %_pf_float Function",
212           "OpStore %f_var %f_1_dup",
213           "OpStore %f_var %f_2_dup",
214           "OpStore %f_var %f_3_dup",
215           // clang-format on
216       });
217 
218   expected_builder
219       .AppendAnnotations({
220           "OpDecorate %f_1 RelaxedPrecision",
221           "OpDecorate %f_2_dup RelaxedPrecision",
222       })
223       .AppendTypesConstantsGlobals({
224           // clang-format off
225           "%float = OpTypeFloat 32",
226           "%_pf_float = OpTypePointer Function %float",
227           "%f_1 = OpConstant %float 1",
228           "%f_1_dup = OpConstant %float 1",
229           "%f_2 = OpConstant %float 2",
230           "%f_2_dup = OpConstant %float 2",
231           "%f_3 = OpConstant %float 3",
232           // clang-format on
233       })
234       .AppendInMain({
235           // clang-format off
236           "%f_var = OpVariable %_pf_float Function",
237           "OpStore %f_var %f_1_dup",
238           "OpStore %f_var %f_2_dup",
239           "OpStore %f_var %f_3",
240           // clang-format on
241       })
242       .AppendNames({
243           "OpName %f_3 \"f_3_dup\"",
244       });
245 
246   Check(expected_builder, test_builder);
247 }
248 
TEST_F(UnifyFrontEndConstantSingleTest,UnifyWithDecorationOnTypes)249 TEST_F(UnifyFrontEndConstantSingleTest, UnifyWithDecorationOnTypes) {
250   AssemblyBuilder test_builder;
251   AssemblyBuilder expected_builder;
252 
253   test_builder
254       .AppendAnnotations({
255           "OpMemberDecorate %flat_d 1 RelaxedPrecision",
256       })
257       .AppendTypesConstantsGlobals({
258           // clang-format off
259           "%int = OpTypeInt 32 1",
260           "%float = OpTypeFloat 32",
261           "%flat = OpTypeStruct %int %float",
262           "%_pf_flat = OpTypePointer Function %flat",
263           // decorated flat struct
264           "%flat_d = OpTypeStruct %int %float",
265           "%_pf_flat_d = OpTypePointer Function %flat_d",
266           // perserved contants. %flat_1 and %flat_d has same members, but
267           // their type are different in decorations, so they should not be
268           // used to replace each other.
269           "%int_1 = OpConstant %int 1",
270           "%float_1 = OpConstant %float 1",
271           "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
272           "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
273           // duplicated constants.
274           "%flat_1_dup = OpConstantComposite %flat %int_1 %float_1",
275           "%flat_d_1_dup = OpConstantComposite %flat_d %int_1 %float_1",
276           // clang-format on
277       })
278       .AppendInMain({
279           "%flat_var = OpVariable %_pf_flat Function",
280           "OpStore %flat_var %flat_1_dup",
281           "%flat_d_var = OpVariable %_pf_flat_d Function",
282           "OpStore %flat_d_var %flat_d_1_dup",
283       });
284 
285   expected_builder
286       .AppendAnnotations({
287           "OpMemberDecorate %flat_d 1 RelaxedPrecision",
288       })
289       .AppendTypesConstantsGlobals({
290           // clang-format off
291           "%int = OpTypeInt 32 1",
292           "%float = OpTypeFloat 32",
293           "%flat = OpTypeStruct %int %float",
294           "%_pf_flat = OpTypePointer Function %flat",
295           // decorated flat struct
296           "%flat_d = OpTypeStruct %int %float",
297           "%_pf_flat_d = OpTypePointer Function %flat_d",
298           "%int_1 = OpConstant %int 1",
299           "%float_1 = OpConstant %float 1",
300           "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
301           "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
302           // clang-format on
303       })
304       .AppendInMain({
305           "%flat_var = OpVariable %_pf_flat Function",
306           "OpStore %flat_var %flat_1",
307           "%flat_d_var = OpVariable %_pf_flat_d Function",
308           "OpStore %flat_d_var %flat_d_1",
309       })
310       .AppendNames({
311           "OpName %flat_1 \"flat_1_dup\"",
312           "OpName %flat_d_1 \"flat_d_1_dup\"",
313       });
314 
315   Check(expected_builder, test_builder);
316 }
317 
318 struct UnifyConstantTestCase {
319   // preserved constants.
320   std::vector<std::string> preserved_consts;
321   // expected uses of the preserved constants.
322   std::vector<std::string> use_preserved_consts;
323   // duplicated constants of the preserved constants.
324   std::vector<std::string> duplicate_consts;
325   // uses of the duplicated constants, expected to be updated to use the
326   // preserved constants.
327   std::vector<std::string> use_duplicate_consts;
328   // The updated OpName instructions that originally refer to duplicated
329   // constants.
330   std::vector<std::string> remapped_names;
331 };
332 
333 using UnifyFrontEndConstantParamTest = UnifyConstantTest<
334     PassTest<::testing::TestWithParam<UnifyConstantTestCase>>>;
335 
TEST_P(UnifyFrontEndConstantParamTest,TestCase)336 TEST_P(UnifyFrontEndConstantParamTest, TestCase) {
337   auto& tc = GetParam();
338   AssemblyBuilder test_builder;
339   AssemblyBuilder expected_builder;
340   test_builder.AppendTypesConstantsGlobals(CommonTypes());
341   expected_builder.AppendTypesConstantsGlobals(CommonTypes());
342 
343   test_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
344       .AppendTypesConstantsGlobals(tc.duplicate_consts)
345       .AppendInMain(tc.use_duplicate_consts);
346 
347   // Duplicated constants are killed in the expected output, and the debug
348   // instructions attached to those duplicated instructions will be migrated to
349   // the corresponding preserved constants.
350   expected_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
351       .AppendInMain(tc.use_preserved_consts)
352       .AppendNames(tc.remapped_names);
353 
354   Check(expected_builder, test_builder);
355 }
356 
357 INSTANTIATE_TEST_SUITE_P(
358     Case, UnifyFrontEndConstantParamTest,
359     ::
360         testing::
361             ValuesIn(
362                 std::
363                     vector<UnifyConstantTestCase>(
364                         {
365                             // clang-format off
366         // basic tests for scalar constants
367         {
368           // preserved constants
369           {
370             "%bool_true = OpConstantTrue %bool",
371             "%signed_1 = OpConstant %int 1",
372             "%signed_minus_1 = OpConstant %int64 -1",
373             "%unsigned_max = OpConstant %uint64 18446744073709551615",
374             "%float_1 = OpConstant %float 1",
375             "%double_1 = OpConstant %double 1",
376           },
377           // use preserved constants in main
378           {
379             "%bool_var = OpVariable %_pf_bool Function",
380             "OpStore %bool_var %bool_true",
381             "%int_var = OpVariable %_pf_int Function",
382             "OpStore %int_var %signed_1",
383             "%int64_var = OpVariable %_pf_int64 Function",
384             "OpStore %int64_var %signed_minus_1",
385             "%uint64_var = OpVariable %_pf_uint64 Function",
386             "OpStore %uint64_var %unsigned_max",
387             "%float_var = OpVariable %_pf_float Function",
388             "OpStore %float_var %float_1",
389             "%double_var = OpVariable %_pf_double Function",
390             "OpStore %double_var %double_1",
391           },
392           // duplicated constants
393           {
394             "%bool_true_duplicate = OpConstantTrue %bool",
395             "%signed_1_duplicate = OpConstant %int 1",
396             "%signed_minus_1_duplicate = OpConstant %int64 -1",
397             "%unsigned_max_duplicate = OpConstant %uint64 18446744073709551615",
398             "%float_1_duplicate = OpConstant %float 1",
399             "%double_1_duplicate = OpConstant %double 1",
400           },
401           // use duplicated constants in main
402           {
403             "%bool_var = OpVariable %_pf_bool Function",
404             "OpStore %bool_var %bool_true_duplicate",
405             "%int_var = OpVariable %_pf_int Function",
406             "OpStore %int_var %signed_1_duplicate",
407             "%int64_var = OpVariable %_pf_int64 Function",
408             "OpStore %int64_var %signed_minus_1_duplicate",
409             "%uint64_var = OpVariable %_pf_uint64 Function",
410             "OpStore %uint64_var %unsigned_max_duplicate",
411             "%float_var = OpVariable %_pf_float Function",
412             "OpStore %float_var %float_1_duplicate",
413             "%double_var = OpVariable %_pf_double Function",
414             "OpStore %double_var %double_1_duplicate",
415           },
416           // remapped names
417           {
418             "OpName %bool_true \"bool_true_duplicate\"",
419             "OpName %signed_1 \"signed_1_duplicate\"",
420             "OpName %signed_minus_1 \"signed_minus_1_duplicate\"",
421             "OpName %unsigned_max \"unsigned_max_duplicate\"",
422             "OpName %float_1 \"float_1_duplicate\"",
423             "OpName %double_1 \"double_1_duplicate\"",
424           },
425         },
426         // NaN in different bit patterns should not be unified, but the ones
427         // using same bit pattern should be unified.
428         {
429           // preserved constants
430           {
431             "%float_nan_1 = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
432             "%float_nan_2 = OpConstant %float 0x1.800002p+128",// !2143289345 7FC00001
433           },
434           // use preserved constants in main
435           {
436             "%float_var = OpVariable %_pf_float Function",
437             "OpStore %float_var %float_nan_1",
438             "OpStore %float_var %float_nan_2",
439           },
440           // duplicated constants
441           {
442             "%float_nan_1_duplicate = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
443             "%float_nan_2_duplicate = OpConstant %float 0x1.800002p+128",// !2143289345, 7FC00001
444           },
445           // use duplicated constants in main
446           {
447             "%float_var = OpVariable %_pf_float Function",
448             "OpStore %float_var %float_nan_1_duplicate",
449             "OpStore %float_var %float_nan_2_duplicate",
450           },
451           // remapped names
452           {
453             "OpName %float_nan_1 \"float_nan_1_duplicate\"",
454             "OpName %float_nan_2 \"float_nan_2_duplicate\"",
455           },
456         },
457         // null values
458         {
459           // preserved constants
460           {
461             "%bool_null = OpConstantNull %bool",
462             "%signed_null = OpConstantNull %int",
463             "%signed_64_null = OpConstantNull %int64",
464             "%float_null = OpConstantNull %float",
465             "%double_null = OpConstantNull %double",
466             // zero-valued constants will not be unified with the equivalent
467             // null constants.
468             "%signed_zero = OpConstant %int 0",
469           },
470           // use preserved constants in main
471           {
472             "%bool_var = OpVariable %_pf_bool Function",
473             "OpStore %bool_var %bool_null",
474             "%int_var = OpVariable %_pf_int Function",
475             "OpStore %int_var %signed_null",
476             "%int64_var = OpVariable %_pf_int64 Function",
477             "OpStore %int64_var %signed_64_null",
478             "%float_var = OpVariable %_pf_float Function",
479             "OpStore %float_var %float_null",
480             "%double_var = OpVariable %_pf_double Function",
481             "OpStore %double_var %double_null",
482           },
483           // duplicated constants
484           {
485             "%bool_null_duplicate = OpConstantNull %bool",
486             "%signed_null_duplicate = OpConstantNull %int",
487             "%signed_64_null_duplicate = OpConstantNull %int64",
488             "%float_null_duplicate = OpConstantNull %float",
489             "%double_null_duplicate = OpConstantNull %double",
490           },
491           // use duplicated constants in main
492           {
493             "%bool_var = OpVariable %_pf_bool Function",
494             "OpStore %bool_var %bool_null_duplicate",
495             "%int_var = OpVariable %_pf_int Function",
496             "OpStore %int_var %signed_null_duplicate",
497             "%int64_var = OpVariable %_pf_int64 Function",
498             "OpStore %int64_var %signed_64_null_duplicate",
499             "%float_var = OpVariable %_pf_float Function",
500             "OpStore %float_var %float_null_duplicate",
501             "%double_var = OpVariable %_pf_double Function",
502             "OpStore %double_var %double_null_duplicate",
503           },
504           // remapped names
505           {
506             "OpName %bool_null \"bool_null_duplicate\"",
507             "OpName %signed_null \"signed_null_duplicate\"",
508             "OpName %signed_64_null \"signed_64_null_duplicate\"",
509             "OpName %float_null \"float_null_duplicate\"",
510             "OpName %double_null \"double_null_duplicate\"",
511           },
512         },
513         // constant sampler
514         {
515           // preserved constants
516           {
517             "%sampler = OpTypeSampler",
518             "%_pf_sampler = OpTypePointer Function %sampler",
519             "%sampler_1 = OpConstantSampler %sampler Repeat 0 Linear",
520           },
521           // use preserved constants in main
522           {
523             "%sampler_var = OpVariable %_pf_sampler Function",
524             "OpStore %sampler_var %sampler_1",
525           },
526           // duplicated constants
527           {
528             "%sampler_1_duplicate = OpConstantSampler %sampler Repeat 0 Linear",
529           },
530           // use duplicated constants in main
531           {
532             "%sampler_var = OpVariable %_pf_sampler Function",
533             "OpStore %sampler_var %sampler_1_duplicate",
534           },
535           // remapped names
536           {
537             "OpName %sampler_1 \"sampler_1_duplicate\"",
538           },
539         },
540         // duplicate vector built from same ids.
541         {
542           // preserved constants
543           {
544             "%signed_1 = OpConstant %int 1",
545             "%signed_2 = OpConstant %int 2",
546             "%signed_3 = OpConstant %int 3",
547             "%signed_4 = OpConstant %int 4",
548             "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
549           },
550           // use preserved constants in main
551           {
552             "%vec_var = OpVariable %_pf_v4int Function",
553             "OpStore %vec_var %vec",
554           },
555           // duplicated constants
556           {
557             "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
558           },
559           // use duplicated constants in main
560           {
561             "%vec_var = OpVariable %_pf_v4int Function",
562             "OpStore %vec_var %vec_duplicate",
563           },
564           // remapped names
565           {
566             "OpName %vec \"vec_duplicate\"",
567           }
568         },
569         // duplicate vector built from duplicated ids.
570         {
571           // preserved constants
572           {
573             "%signed_1 = OpConstant %int 1",
574             "%signed_2 = OpConstant %int 2",
575             "%signed_3 = OpConstant %int 3",
576             "%signed_4 = OpConstant %int 4",
577             "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
578           },
579           // use preserved constants in main
580           {
581             "%vec_var = OpVariable %_pf_v4int Function",
582             "OpStore %vec_var %vec",
583           },
584           // duplicated constants
585           {
586             "%signed_3_duplicate = OpConstant %int 3",
587             "%signed_4_duplicate = OpConstant %int 4",
588             "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3_duplicate %signed_4_duplicate",
589           },
590           // use duplicated constants in main
591           {
592             "%vec_var = OpVariable %_pf_v4int Function",
593             "OpStore %vec_var %vec_duplicate",
594           },
595           // remapped names
596           {
597             "OpName %signed_3 \"signed_3_duplicate\"",
598             "OpName %signed_4 \"signed_4_duplicate\"",
599             "OpName %vec \"vec_duplicate\"",
600           },
601         },
602         // flat struct
603         {
604           // preserved constants
605           {
606             "%bool_true = OpConstantTrue %bool",
607             "%signed_1 = OpConstant %int 1",
608             "%float_1 = OpConstant %float 1",
609             "%double_1 = OpConstant %double 1",
610             "%s = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1 %double_1",
611           },
612           // use preserved constants in main
613           {
614             "%s_var = OpVariable %_pf_flat_struct Function",
615             "OpStore %s_var %s",
616           },
617           // duplicated constants
618           {
619             "%float_1_duplicate = OpConstant %float 1",
620             "%double_1_duplicate = OpConstant %double 1",
621             "%s_duplicate = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1_duplicate %double_1_duplicate",
622           },
623           // use duplicated constants in main
624           {
625             "%s_var = OpVariable %_pf_flat_struct Function",
626             "OpStore %s_var %s_duplicate",
627           },
628           // remapped names
629           {
630             "OpName %float_1 \"float_1_duplicate\"",
631             "OpName %double_1 \"double_1_duplicate\"",
632             "OpName %s \"s_duplicate\"",
633           },
634         },
635         // nested struct
636         {
637           // preserved constants
638           {
639             "%bool_true = OpConstantTrue %bool",
640             "%signed_1 = OpConstant %int 1",
641             "%float_1 = OpConstant %float 1",
642             "%double_1 = OpConstant %double 1",
643             "%inner = OpConstantComposite %inner_struct %bool_true %float_1",
644             "%outer = OpConstantComposite %outer_struct %inner %signed_1 %double_1",
645           },
646           // use preserved constants in main
647           {
648             "%outer_var = OpVariable %_pf_outer_struct Function",
649             "OpStore %outer_var %outer",
650           },
651           // duplicated constants
652           {
653             "%float_1_duplicate = OpConstant %float 1",
654             "%double_1_duplicate = OpConstant %double 1",
655             "%inner_duplicate = OpConstantComposite %inner_struct %bool_true %float_1_duplicate",
656             "%outer_duplicate = OpConstantComposite %outer_struct %inner_duplicate %signed_1 %double_1_duplicate",
657           },
658           // use duplicated constants in main
659           {
660             "%outer_var = OpVariable %_pf_outer_struct Function",
661             "OpStore %outer_var %outer_duplicate",
662           },
663           // remapped names
664           {
665             "OpName %float_1 \"float_1_duplicate\"",
666             "OpName %double_1 \"double_1_duplicate\"",
667             "OpName %inner \"inner_duplicate\"",
668             "OpName %outer \"outer_duplicate\"",
669           },
670         },
671         // composite type null constants. Null constants and zero-valued
672         // constants should not be used to replace each other.
673         {
674           // preserved constants
675           {
676             "%bool_zero = OpConstantFalse %bool",
677             "%float_zero = OpConstant %float 0",
678             "%int_null = OpConstantNull %int",
679             "%double_null = OpConstantNull %double",
680             // inner_struct type null constant.
681             "%null_inner = OpConstantNull %inner_struct",
682             // zero-valued composite constant built from zero-valued constant
683             // component. inner_zero should not be replace by null_inner.
684             "%inner_zero = OpConstantComposite %inner_struct %bool_zero %float_zero",
685             // zero-valued composite contant built from zero-valued constants
686             // and null constants.
687             "%outer_zero = OpConstantComposite %outer_struct %inner_zero %int_null %double_null",
688             // outer_struct type null constant, it should not be replaced by
689             // outer_zero.
690             "%null_outer = OpConstantNull %outer_struct",
691           },
692           // use preserved constants in main
693           {
694             "%inner_var = OpVariable %_pf_inner_struct Function",
695             "OpStore %inner_var %inner_zero",
696             "OpStore %inner_var %null_inner",
697             "%outer_var = OpVariable %_pf_outer_struct Function",
698             "OpStore %outer_var %outer_zero",
699             "OpStore %outer_var %null_outer",
700           },
701           // duplicated constants
702           {
703             "%null_inner_dup = OpConstantNull %inner_struct",
704             "%null_outer_dup = OpConstantNull %outer_struct",
705             "%inner_zero_dup = OpConstantComposite %inner_struct %bool_zero %float_zero",
706             "%outer_zero_dup = OpConstantComposite %outer_struct %inner_zero_dup %int_null %double_null",
707           },
708           // use duplicated constants in main
709           {
710             "%inner_var = OpVariable %_pf_inner_struct Function",
711             "OpStore %inner_var %inner_zero_dup",
712             "OpStore %inner_var %null_inner_dup",
713             "%outer_var = OpVariable %_pf_outer_struct Function",
714             "OpStore %outer_var %outer_zero_dup",
715             "OpStore %outer_var %null_outer_dup",
716           },
717           // remapped names
718           {
719             "OpName %null_inner \"null_inner_dup\"",
720             "OpName %null_outer \"null_outer_dup\"",
721             "OpName %inner_zero \"inner_zero_dup\"",
722             "OpName %outer_zero \"outer_zero_dup\"",
723           },
724         },
725         // Spec Constants with SpecId decoration should be skipped.
726         {
727           // preserved constants
728           {
729             // Assembly builder will add OpDecorate SpecId instruction for the
730             // following spec constant instructions automatically.
731             "%spec_bool_1 = OpSpecConstantTrue %bool",
732             "%spec_bool_2 = OpSpecConstantTrue %bool",
733             "%spec_int_1 = OpSpecConstant %int 1",
734             "%spec_int_2 = OpSpecConstant %int 1",
735           },
736           // use preserved constants in main
737           {
738             "%bool_var = OpVariable %_pf_bool Function",
739             "OpStore %bool_var %spec_bool_1",
740             "OpStore %bool_var %spec_bool_2",
741             "%int_var = OpVariable %_pf_int Function",
742             "OpStore %int_var %spec_int_1",
743             "OpStore %int_var %spec_int_2",
744           },
745           // duplicated constants. No duplicated instruction to remove in this
746           // case.
747           {},
748           // use duplicated constants in main. Same as the above 'use preserved
749           // constants in main' defined above, as no instruction should be
750           // removed in this case.
751           {
752             "%bool_var = OpVariable %_pf_bool Function",
753             "OpStore %bool_var %spec_bool_1",
754             "OpStore %bool_var %spec_bool_2",
755             "%int_var = OpVariable %_pf_int Function",
756             "OpStore %int_var %spec_int_1",
757             "OpStore %int_var %spec_int_2",
758           },
759           // remapped names. No duplicated instruction removed, so this is
760           // empty.
761           {}
762         },
763         // spec constant composite
764         {
765           // preserved constants
766           {
767             "%spec_bool_true = OpSpecConstantTrue %bool",
768             "%spec_signed_1 = OpSpecConstant %int 1",
769             "%float_1 = OpConstant %float 1",
770             "%double_1 = OpConstant %double 1",
771             "%spec_inner = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1",
772             "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %spec_signed_1 %double_1",
773             "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
774           },
775           // use preserved constants in main
776           {
777             "%outer_var = OpVariable %_pf_outer_struct Function",
778             "OpStore %outer_var %spec_outer",
779             "%v2float_var = OpVariable %_pf_v2float Function",
780             "OpStore %v2float_var %spec_vec2",
781           },
782           // duplicated constants
783           {
784             "%float_1_duplicate = OpConstant %float 1",
785             "%double_1_duplicate = OpConstant %double 1",
786             "%spec_inner_duplicate = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1_duplicate",
787             "%spec_outer_duplicate = OpSpecConstantComposite %outer_struct %spec_inner_duplicate %spec_signed_1 %double_1_duplicate",
788             "%spec_vec2_duplicate = OpSpecConstantComposite %v2float %float_1 %float_1_duplicate",
789           },
790           // use duplicated constants in main
791           {
792             "%outer_var = OpVariable %_pf_outer_struct Function",
793             "OpStore %outer_var %spec_outer_duplicate",
794             "%v2float_var = OpVariable %_pf_v2float Function",
795             "OpStore %v2float_var %spec_vec2_duplicate",
796           },
797           // remapped names
798           {
799             "OpName %float_1 \"float_1_duplicate\"",
800             "OpName %double_1 \"double_1_duplicate\"",
801             "OpName %spec_inner \"spec_inner_duplicate\"",
802             "OpName %spec_outer \"spec_outer_duplicate\"",
803             "OpName %spec_vec2 \"spec_vec2_duplicate\"",
804           },
805         },
806         // spec constant op with int scalar
807         {
808           // preserved constants
809           {
810             "%spec_signed_1 = OpSpecConstant %int 1",
811             "%spec_signed_2 = OpSpecConstant %int 2",
812             "%spec_signed_add = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
813           },
814           // use preserved constants in main
815           {
816             "%int_var = OpVariable %_pf_int Function",
817             "OpStore %int_var %spec_signed_add",
818           },
819           // duplicated constants
820           {
821             "%spec_signed_add_duplicate = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
822           },
823           // use duplicated contants in main
824           {
825             "%int_var = OpVariable %_pf_int Function",
826             "OpStore %int_var %spec_signed_add_duplicate",
827           },
828           // remapped names
829           {
830             "OpName %spec_signed_add \"spec_signed_add_duplicate\"",
831           },
832         },
833         // spec constant op composite extract
834         {
835           // preserved constants
836           {
837             "%float_1 = OpConstant %float 1",
838             "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
839             "%spec_extract = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
840           },
841           // use preserved constants in main
842           {
843             "%float_var = OpVariable %_pf_float Function",
844             "OpStore %float_var %spec_extract",
845           },
846           // duplicated constants
847           {
848             "%spec_extract_duplicate = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
849           },
850           // use duplicated constants in main
851           {
852             "%float_var = OpVariable %_pf_float Function",
853             "OpStore %float_var %spec_extract_duplicate",
854           },
855           // remapped names
856           {
857             "OpName %spec_extract \"spec_extract_duplicate\"",
858           },
859         },
860         // spec constant op vector shuffle
861         {
862           // preserved constants
863           {
864             "%float_1 = OpConstant %float 1",
865             "%float_2 = OpConstant %float 2",
866             "%spec_vec2_1 = OpSpecConstantComposite %v2float %float_1 %float_1",
867             "%spec_vec2_2 = OpSpecConstantComposite %v2float %float_2 %float_2",
868             "%spec_vector_shuffle = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
869           },
870           // use preserved constants in main
871           {
872             "%v2float_var = OpVariable %_pf_v2float Function",
873             "OpStore %v2float_var %spec_vector_shuffle",
874           },
875           // duplicated constants
876           {
877             "%spec_vector_shuffle_duplicate = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
878           },
879           // use duplicated constants in main
880           {
881             "%v2float_var = OpVariable %_pf_v2float Function",
882             "OpStore %v2float_var %spec_vector_shuffle_duplicate",
883           },
884           // remapped names
885           {
886             "OpName %spec_vector_shuffle \"spec_vector_shuffle_duplicate\"",
887           },
888         },
889         // long dependency chain
890         {
891           // preserved constants
892           {
893             "%array_size = OpConstant %int 4",
894             "%type_arr_int_4 = OpTypeArray %int %array_size",
895             "%signed_0 = OpConstant %int 100",
896             "%signed_1 = OpConstant %int 1",
897             "%signed_2 = OpSpecConstantOp %int IAdd %signed_0 %signed_1",
898             "%signed_3 = OpSpecConstantOp %int ISub %signed_0 %signed_2",
899             "%signed_4 = OpSpecConstantOp %int IAdd %signed_0 %signed_3",
900             "%signed_5 = OpSpecConstantOp %int ISub %signed_0 %signed_4",
901             "%signed_6 = OpSpecConstantOp %int IAdd %signed_0 %signed_5",
902             "%signed_7 = OpSpecConstantOp %int ISub %signed_0 %signed_6",
903             "%signed_8 = OpSpecConstantOp %int IAdd %signed_0 %signed_7",
904             "%signed_9 = OpSpecConstantOp %int ISub %signed_0 %signed_8",
905             "%signed_10 = OpSpecConstantOp %int IAdd %signed_0 %signed_9",
906             "%signed_11 = OpSpecConstantOp %int ISub %signed_0 %signed_10",
907             "%signed_12 = OpSpecConstantOp %int IAdd %signed_0 %signed_11",
908             "%signed_13 = OpSpecConstantOp %int ISub %signed_0 %signed_12",
909             "%signed_14 = OpSpecConstantOp %int IAdd %signed_0 %signed_13",
910             "%signed_15 = OpSpecConstantOp %int ISub %signed_0 %signed_14",
911             "%signed_16 = OpSpecConstantOp %int ISub %signed_0 %signed_15",
912             "%signed_17 = OpSpecConstantOp %int IAdd %signed_0 %signed_16",
913             "%signed_18 = OpSpecConstantOp %int ISub %signed_0 %signed_17",
914             "%signed_19 = OpSpecConstantOp %int IAdd %signed_0 %signed_18",
915             "%signed_20 = OpSpecConstantOp %int ISub %signed_0 %signed_19",
916             "%signed_vec_a = OpSpecConstantComposite %v2int %signed_18 %signed_19",
917             "%signed_vec_b = OpSpecConstantOp %v2int IMul %signed_vec_a %signed_vec_a",
918             "%signed_21 = OpSpecConstantOp %int CompositeExtract %signed_vec_b 0",
919             "%signed_array = OpConstantComposite %type_arr_int_4 %signed_20 %signed_20 %signed_21 %signed_21",
920             "%signed_22 = OpSpecConstantOp %int CompositeExtract %signed_array 0",
921           },
922           // use preserved constants in main
923           {
924             "%int_var = OpVariable %_pf_int Function",
925             "OpStore %int_var %signed_22",
926           },
927           // duplicated constants
928           {
929             "%signed_0_dup = OpConstant %int 100",
930             "%signed_1_dup = OpConstant %int 1",
931             "%signed_2_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_1_dup",
932             "%signed_3_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_2_dup",
933             "%signed_4_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_3_dup",
934             "%signed_5_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_4_dup",
935             "%signed_6_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_5_dup",
936             "%signed_7_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_6_dup",
937             "%signed_8_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_7_dup",
938             "%signed_9_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_8_dup",
939             "%signed_10_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_9_dup",
940             "%signed_11_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_10_dup",
941             "%signed_12_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_11_dup",
942             "%signed_13_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_12_dup",
943             "%signed_14_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_13_dup",
944             "%signed_15_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_14_dup",
945             "%signed_16_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_15_dup",
946             "%signed_17_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_16_dup",
947             "%signed_18_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_17_dup",
948             "%signed_19_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_18_dup",
949             "%signed_20_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_19_dup",
950             "%signed_vec_a_dup = OpSpecConstantComposite %v2int %signed_18_dup %signed_19_dup",
951             "%signed_vec_b_dup = OpSpecConstantOp %v2int IMul %signed_vec_a_dup %signed_vec_a_dup",
952             "%signed_21_dup = OpSpecConstantOp %int CompositeExtract %signed_vec_b_dup 0",
953             "%signed_array_dup = OpConstantComposite %type_arr_int_4 %signed_20_dup %signed_20_dup %signed_21_dup %signed_21_dup",
954             "%signed_22_dup = OpSpecConstantOp %int CompositeExtract %signed_array_dup 0",
955           },
956           // use duplicated constants in main
957           {
958             "%int_var = OpVariable %_pf_int Function",
959             "OpStore %int_var %signed_22_dup",
960           },
961           // remapped names
962           {
963             "OpName %signed_0 \"signed_0_dup\"",
964             "OpName %signed_1 \"signed_1_dup\"",
965             "OpName %signed_2 \"signed_2_dup\"",
966             "OpName %signed_3 \"signed_3_dup\"",
967             "OpName %signed_4 \"signed_4_dup\"",
968             "OpName %signed_5 \"signed_5_dup\"",
969             "OpName %signed_6 \"signed_6_dup\"",
970             "OpName %signed_7 \"signed_7_dup\"",
971             "OpName %signed_8 \"signed_8_dup\"",
972             "OpName %signed_9 \"signed_9_dup\"",
973             "OpName %signed_10 \"signed_10_dup\"",
974             "OpName %signed_11 \"signed_11_dup\"",
975             "OpName %signed_12 \"signed_12_dup\"",
976             "OpName %signed_13 \"signed_13_dup\"",
977             "OpName %signed_14 \"signed_14_dup\"",
978             "OpName %signed_15 \"signed_15_dup\"",
979             "OpName %signed_16 \"signed_16_dup\"",
980             "OpName %signed_17 \"signed_17_dup\"",
981             "OpName %signed_18 \"signed_18_dup\"",
982             "OpName %signed_19 \"signed_19_dup\"",
983             "OpName %signed_20 \"signed_20_dup\"",
984             "OpName %signed_vec_a \"signed_vec_a_dup\"",
985             "OpName %signed_vec_b \"signed_vec_b_dup\"",
986             "OpName %signed_21 \"signed_21_dup\"",
987             "OpName %signed_array \"signed_array_dup\"",
988             "OpName %signed_22 \"signed_22_dup\"",
989           },
990         },
991                             // clang-format on
992                         })));
993 
994 }  // namespace
995 }  // namespace opt
996 }  // namespace spvtools
997