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 <sstream>
16 #include <string>
17 #include <vector>
18 
19 #include "test/opt/assembly_builder.h"
20 #include "test/opt/pass_fixture.h"
21 #include "test/opt/pass_utils.h"
22 
23 namespace spvtools {
24 namespace opt {
25 namespace {
26 
27 using FoldSpecConstantOpAndCompositePassBasicTest = PassTest<::testing::Test>;
28 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, Empty)29 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, Empty) {
30   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
31       "", "", /* skip_nop = */ true);
32 }
33 
34 // A test of the basic functionality of FoldSpecConstantOpAndCompositePass.
35 // A spec constant defined with an integer addition operation should be folded
36 // to a normal constant with fixed value.
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, Basic)37 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, Basic) {
38   AssemblyBuilder builder;
39   builder.AppendTypesConstantsGlobals({
40       // clang-format off
41         "%int = OpTypeInt 32 1",
42         "%frozen_spec_const_int = OpConstant %int 1",
43         "%const_int = OpConstant %int 2",
44         // Folding target:
45         "%spec_add = OpSpecConstantOp %int IAdd %frozen_spec_const_int %const_int",
46       // clang-format on
47   });
48 
49   std::vector<const char*> expected = {
50       // clang-format off
51                     "OpCapability Shader",
52                     "OpCapability Float64",
53                "%1 = OpExtInstImport \"GLSL.std.450\"",
54                     "OpMemoryModel Logical GLSL450",
55                     "OpEntryPoint Vertex %main \"main\"",
56                     "OpName %void \"void\"",
57                     "OpName %main_func_type \"main_func_type\"",
58                     "OpName %main \"main\"",
59                     "OpName %main_func_entry_block \"main_func_entry_block\"",
60                     "OpName %int \"int\"",
61                     "OpName %frozen_spec_const_int \"frozen_spec_const_int\"",
62                     "OpName %const_int \"const_int\"",
63                     "OpName %spec_add \"spec_add\"",
64             "%void = OpTypeVoid",
65   "%main_func_type = OpTypeFunction %void",
66              "%int = OpTypeInt 32 1",
67 "%frozen_spec_const_int = OpConstant %int 1",
68        "%const_int = OpConstant %int 2",
69         // The SpecConstantOp IAdd instruction should be replace by OpConstant
70         // instruction:
71         "%spec_add = OpConstant %int 3",
72             "%main = OpFunction %void None %main_func_type",
73 "%main_func_entry_block = OpLabel",
74                     "OpReturn",
75                     "OpFunctionEnd",
76       // clang-format on
77   };
78   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
79       builder.GetCode(), JoinAllInsts(expected), /* skip_nop = */ true);
80 }
81 
82 // A test of skipping folding an instruction when the instruction result type
83 // has decorations.
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, SkipWhenTypeHasDecorations)84 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
85        SkipWhenTypeHasDecorations) {
86   AssemblyBuilder builder;
87   builder
88       .AppendAnnotations({
89           // clang-format off
90           "OpDecorate %int RelaxedPrecision",
91           // clang-format on
92       })
93       .AppendTypesConstantsGlobals({
94           // clang-format off
95           "%int = OpTypeInt 32 1",
96           "%frozen_spec_const_int = OpConstant %int 1",
97           "%const_int = OpConstant %int 2",
98           // The following spec constant should not be folded as the result type
99           // has relaxed precision decoration.
100           "%spec_add = OpSpecConstantOp %int IAdd %frozen_spec_const_int %const_int",
101           // clang-format on
102       });
103 
104   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
105       builder.GetCode(), builder.GetCode(), /* skip_nop = */ true);
106 }
107 
108 // Test where OpSpecConstantOp depends on another OpSpecConstantOp with
109 // CompositeExtract
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, StackedCompositeExtract)110 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, StackedCompositeExtract) {
111   AssemblyBuilder builder;
112   builder.AppendTypesConstantsGlobals({
113       // clang-format off
114     "%uint = OpTypeInt 32 0",
115     "%v3uint = OpTypeVector %uint 3",
116     "%uint_2 = OpConstant %uint 2",
117     "%uint_3 = OpConstant %uint 3",
118     // Folding target:
119     "%composite_0 = OpSpecConstantComposite %v3uint %uint_2 %uint_3 %uint_2",
120     "%op_0 = OpSpecConstantOp %uint CompositeExtract %composite_0 0",
121     "%op_1 = OpSpecConstantOp %uint CompositeExtract %composite_0 1",
122     "%op_2 = OpSpecConstantOp %uint IMul %op_0 %op_1",
123     "%composite_1 = OpSpecConstantComposite %v3uint %op_0 %op_1 %op_2",
124     "%op_3 = OpSpecConstantOp %uint CompositeExtract %composite_1 0",
125     "%op_4 = OpSpecConstantOp %uint IMul %op_2 %op_3",
126       // clang-format on
127   });
128 
129   std::vector<const char*> expected = {
130       // clang-format off
131         "OpCapability Shader",
132         "OpCapability Float64",
133     "%1 = OpExtInstImport \"GLSL.std.450\"",
134         "OpMemoryModel Logical GLSL450",
135         "OpEntryPoint Vertex %main \"main\"",
136         "OpName %void \"void\"",
137         "OpName %main_func_type \"main_func_type\"",
138         "OpName %main \"main\"",
139         "OpName %main_func_entry_block \"main_func_entry_block\"",
140         "OpName %uint \"uint\"",
141         "OpName %v3uint \"v3uint\"",
142         "OpName %uint_2 \"uint_2\"",
143         "OpName %uint_3 \"uint_3\"",
144         "OpName %composite_0 \"composite_0\"",
145         "OpName %op_0 \"op_0\"",
146         "OpName %op_1 \"op_1\"",
147         "OpName %op_2 \"op_2\"",
148         "OpName %composite_1 \"composite_1\"",
149         "OpName %op_3 \"op_3\"",
150         "OpName %op_4 \"op_4\"",
151     "%void = OpTypeVoid",
152 "%main_func_type = OpTypeFunction %void",
153     "%uint = OpTypeInt 32 0",
154   "%v3uint = OpTypeVector %uint 3",
155   "%uint_2 = OpConstant %uint 2",
156   "%uint_3 = OpConstant %uint 3",
157 "%composite_0 = OpConstantComposite %v3uint %uint_2 %uint_3 %uint_2",
158     "%op_0 = OpConstant %uint 2",
159     "%op_1 = OpConstant %uint 3",
160     "%op_2 = OpConstant %uint 6",
161 "%composite_1 = OpConstantComposite %v3uint %op_0 %op_1 %op_2",
162 "%op_3 = OpConstant %uint 2",
163  "%op_4 = OpConstant %uint 12",
164     "%main = OpFunction %void None %main_func_type",
165 "%main_func_entry_block = OpLabel",
166             "OpReturn",
167             "OpFunctionEnd",
168       // clang-format on
169   };
170   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
171       builder.GetCode(), JoinAllInsts(expected), /* skip_nop = */ true);
172 }
173 
174 // Test where OpSpecConstantOp depends on another OpSpecConstantOp with
175 // VectorShuffle
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, StackedVectorShuffle)176 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, StackedVectorShuffle) {
177   AssemblyBuilder builder;
178   builder.AppendTypesConstantsGlobals({
179       // clang-format off
180     "%uint = OpTypeInt 32 0",
181     "%v3uint = OpTypeVector %uint 3",
182     "%uint_1 = OpConstant %uint 1",
183     "%uint_2 = OpConstant %uint 2",
184     "%uint_3 = OpConstant %uint 3",
185     "%uint_4 = OpConstant %uint 4",
186     "%uint_5 = OpConstant %uint 5",
187     "%uint_6 = OpConstant %uint 6",
188     // Folding target:
189     "%composite_0 = OpSpecConstantComposite %v3uint %uint_1 %uint_2 %uint_3",
190     "%composite_1 = OpSpecConstantComposite %v3uint %uint_4 %uint_5 %uint_6",
191     "%vecshuffle = OpSpecConstantOp %v3uint VectorShuffle %composite_0 %composite_1 0 5 3",
192     "%op = OpSpecConstantOp %uint CompositeExtract %vecshuffle 1",
193       // clang-format on
194   });
195 
196   std::vector<const char*> expected = {
197       // clang-format off
198         "OpCapability Shader",
199         "OpCapability Float64",
200         "%1 = OpExtInstImport \"GLSL.std.450\"",
201         "OpMemoryModel Logical GLSL450",
202         "OpEntryPoint Vertex %main \"main\"",
203         "OpName %void \"void\"",
204         "OpName %main_func_type \"main_func_type\"",
205         "OpName %main \"main\"",
206         "OpName %main_func_entry_block \"main_func_entry_block\"",
207         "OpName %uint \"uint\"",
208         "OpName %v3uint \"v3uint\"",
209         "OpName %uint_1 \"uint_1\"",
210         "OpName %uint_2 \"uint_2\"",
211         "OpName %uint_3 \"uint_3\"",
212         "OpName %uint_4 \"uint_4\"",
213         "OpName %uint_5 \"uint_5\"",
214         "OpName %uint_6 \"uint_6\"",
215         "OpName %composite_0 \"composite_0\"",
216         "OpName %composite_1 \"composite_1\"",
217         "OpName %vecshuffle \"vecshuffle\"",
218         "OpName %op \"op\"",
219     "%void = OpTypeVoid",
220 "%main_func_type = OpTypeFunction %void",
221     "%uint = OpTypeInt 32 0",
222   "%v3uint = OpTypeVector %uint 3",
223   "%uint_1 = OpConstant %uint 1",
224   "%uint_2 = OpConstant %uint 2",
225   "%uint_3 = OpConstant %uint 3",
226   "%uint_4 = OpConstant %uint 4",
227   "%uint_5 = OpConstant %uint 5",
228   "%uint_6 = OpConstant %uint 6",
229 "%composite_0 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3",
230 "%composite_1 = OpConstantComposite %v3uint %uint_4 %uint_5 %uint_6",
231 "%vecshuffle = OpConstantComposite %v3uint %uint_1 %uint_6 %uint_4",
232       "%op = OpConstant %uint 6",
233     "%main = OpFunction %void None %main_func_type",
234 "%main_func_entry_block = OpLabel",
235         "OpReturn",
236         "OpFunctionEnd",
237       // clang-format on
238   };
239   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
240       builder.GetCode(), JoinAllInsts(expected), /* skip_nop = */ true);
241 }
242 
243 // Test CompositeExtract with matrix
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeExtractMaxtrix)244 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeExtractMaxtrix) {
245   AssemblyBuilder builder;
246   builder.AppendTypesConstantsGlobals({
247       // clang-format off
248     "%uint = OpTypeInt 32 0",
249     "%v3uint = OpTypeVector %uint 3",
250     "%mat3x3 = OpTypeMatrix %v3uint 3",
251     "%uint_1 = OpConstant %uint 1",
252     "%uint_2 = OpConstant %uint 2",
253     "%uint_3 = OpConstant %uint 3",
254     // Folding target:
255     "%a = OpSpecConstantComposite %v3uint %uint_1 %uint_1 %uint_1",
256     "%b = OpSpecConstantComposite %v3uint %uint_1 %uint_1 %uint_3",
257     "%c = OpSpecConstantComposite %v3uint %uint_1 %uint_2 %uint_1",
258     "%op = OpSpecConstantComposite %mat3x3 %a %b %c",
259     "%x = OpSpecConstantOp %uint CompositeExtract %op 2 1",
260     "%y = OpSpecConstantOp %uint CompositeExtract %op 1 2",
261       // clang-format on
262   });
263 
264   std::vector<const char*> expected = {
265       // clang-format off
266         "OpCapability Shader",
267         "OpCapability Float64",
268    "%1 = OpExtInstImport \"GLSL.std.450\"",
269         "OpMemoryModel Logical GLSL450",
270         "OpEntryPoint Vertex %main \"main\"",
271         "OpName %void \"void\"",
272         "OpName %main_func_type \"main_func_type\"",
273         "OpName %main \"main\"",
274         "OpName %main_func_entry_block \"main_func_entry_block\"",
275         "OpName %uint \"uint\"",
276         "OpName %v3uint \"v3uint\"",
277         "OpName %mat3x3 \"mat3x3\"",
278         "OpName %uint_1 \"uint_1\"",
279         "OpName %uint_2 \"uint_2\"",
280         "OpName %uint_3 \"uint_3\"",
281         "OpName %a \"a\"",
282         "OpName %b \"b\"",
283         "OpName %c \"c\"",
284         "OpName %op \"op\"",
285         "OpName %x \"x\"",
286         "OpName %y \"y\"",
287     "%void = OpTypeVoid",
288 "%main_func_type = OpTypeFunction %void",
289     "%uint = OpTypeInt 32 0",
290   "%v3uint = OpTypeVector %uint 3",
291   "%mat3x3 = OpTypeMatrix %v3uint 3",
292   "%uint_1 = OpConstant %uint 1",
293   "%uint_2 = OpConstant %uint 2",
294   "%uint_3 = OpConstant %uint 3",
295        "%a = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1",
296        "%b = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_3",
297        "%c = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_1",
298       "%op = OpConstantComposite %mat3x3 %a %b %c",
299        "%x = OpConstant %uint 2",
300        "%y = OpConstant %uint 3",
301     "%main = OpFunction %void None %main_func_type",
302 "%main_func_entry_block = OpLabel",
303         "OpReturn",
304         "OpFunctionEnd",
305       // clang-format on
306   };
307   SinglePassRunAndCheck<FoldSpecConstantOpAndCompositePass>(
308       builder.GetCode(), JoinAllInsts(expected), /* skip_nop = */ true);
309 }
310 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVector)311 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVector) {
312   const std::string test =
313       R"(
314                OpCapability Shader
315                OpMemoryModel Logical GLSL450
316                OpEntryPoint GLCompute %1 "main"
317                OpExecutionMode %1 LocalSize 1 1 1
318        %void = OpTypeVoid
319           %3 = OpTypeFunction %void
320        %uint = OpTypeInt 32 0
321      %v3uint = OpTypeVector %uint 3
322      %uint_2 = OpConstant %uint 2
323      %uint_3 = OpConstant %uint 3
324           %8 = OpConstantNull %uint
325           %9 = OpSpecConstantComposite %v3uint %uint_2 %uint_2 %uint_2
326  ; CHECK: %15 = OpConstantComposite %v3uint %uint_3 %uint_2 %uint_2
327  ; CHECK: %uint_3_0 = OpConstant %uint 3
328  ; CHECK: %17 = OpConstantComposite %v3uint %8 %uint_2 %uint_2
329  ; CHECK: %18 = OpConstantNull %uint
330          %10 = OpSpecConstantOp %v3uint CompositeInsert %uint_3 %9 0
331          %11 = OpSpecConstantOp %uint CompositeExtract %10 0
332          %12 = OpSpecConstantOp %v3uint CompositeInsert %8 %9 0
333          %13 = OpSpecConstantOp %uint CompositeExtract %12 0
334           %1 = OpFunction %void None %3
335          %14 = OpLabel
336                OpReturn
337                OpFunctionEnd
338 )";
339 
340   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
341 }
342 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorIntoMatrix)343 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
344        CompositeInsertVectorIntoMatrix) {
345   const std::string test =
346       R"(
347                OpCapability Shader
348                OpMemoryModel Logical GLSL450
349                OpEntryPoint GLCompute %1 "main"
350                OpExecutionMode %1 LocalSize 1 1 1
351        %void = OpTypeVoid
352           %3 = OpTypeFunction %void
353       %float = OpTypeFloat 32
354     %v2float = OpTypeVector %float 2
355  %mat2v2float = OpTypeMatrix %v2float 2
356     %float_0 = OpConstant %float 0
357     %float_1 = OpConstant %float 1
358     %float_2 = OpConstant %float 2
359  %v2float_01 = OpConstantComposite %v2float %float_0 %float_1
360  %v2float_12 = OpConstantComposite %v2float %float_1 %float_2
361 
362 ; CHECK: %10 = OpConstantComposite %v2float %float_0 %float_1
363 ; CHECK: %11 = OpConstantComposite %v2float %float_1 %float_2
364 ; CHECK: %12 = OpConstantComposite %mat2v2float %11 %11
365 %mat2v2float_1212 = OpConstantComposite %mat2v2float %v2float_12 %v2float_12
366 
367 ; CHECK: %15 = OpConstantComposite %mat2v2float %10 %11
368      %spec_0 = OpSpecConstantOp %mat2v2float CompositeInsert %v2float_01 %mat2v2float_1212 0
369           %1 = OpFunction %void None %3
370       %label = OpLabel
371                OpReturn
372                OpFunctionEnd
373 )";
374 
375   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
376 }
377 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertMatrix)378 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertMatrix) {
379   const std::string test =
380       R"(
381                OpCapability Shader
382                OpMemoryModel Logical GLSL450
383                OpEntryPoint GLCompute %1 "main"
384                OpExecutionMode %1 LocalSize 1 1 1
385        %void = OpTypeVoid
386           %3 = OpTypeFunction %void
387       %float = OpTypeFloat 32
388     %v3float = OpTypeVector %float 3
389 %mat3v3float = OpTypeMatrix %v3float 3
390     %float_1 = OpConstant %float 1
391     %float_2 = OpConstant %float 2
392           %9 = OpSpecConstantComposite %v3float %float_1 %float_1 %float_1
393          %10 = OpSpecConstantComposite %v3float %float_1 %float_1 %float_1
394          %11 = OpSpecConstantComposite %v3float %float_1 %float_2 %float_1
395          %12 = OpSpecConstantComposite %mat3v3float %9 %10 %11
396  ; CHECK: %float_2_0 = OpConstant %float 2
397  ; CHECK: %18 = OpConstantComposite %v3float %float_1 %float_1 %float_2
398  ; CHECK: %19 = OpConstantComposite %mat3v3float %9 %18 %11
399  ; CHECK: %float_2_1 = OpConstant %float 2
400          %13 = OpSpecConstantOp %float CompositeExtract %12 2 1
401          %14 = OpSpecConstantOp %mat3v3float CompositeInsert %13 %12 1 2
402          %15 = OpSpecConstantOp %float CompositeExtract %14 1 2
403           %1 = OpFunction %void None %3
404          %16 = OpLabel
405                OpReturn
406                OpFunctionEnd
407 )";
408 
409   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
410 }
411 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertFloatNull)412 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertFloatNull) {
413   const std::string test =
414       R"(
415                OpCapability Shader
416                OpMemoryModel Logical GLSL450
417                OpEntryPoint GLCompute %1 "main"
418                OpExecutionMode %1 LocalSize 1 1 1
419        %void = OpTypeVoid
420           %3 = OpTypeFunction %void
421       %float = OpTypeFloat 32
422     %v3float = OpTypeVector %float 3
423     %float_1 = OpConstant %float 1
424 
425 ; CHECK: %7 = OpConstantNull %float
426 ; CHECK: %8 = OpConstantComposite %v3float %7 %7 %7
427 ; CHECK: %12 = OpConstantComposite %v3float %7 %7 %float_1
428        %null = OpConstantNull %float
429      %spec_0 = OpConstantComposite %v3float %null %null %null
430      %spec_1 = OpSpecConstantOp %v3float CompositeInsert %float_1 %spec_0 2
431 
432 ; CHECK: %float_1_0 = OpConstant %float 1
433      %spec_2 = OpSpecConstantOp %float CompositeExtract %spec_1 2
434           %1 = OpFunction %void None %3
435       %label = OpLabel
436                OpReturn
437                OpFunctionEnd
438 )";
439 
440   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
441 }
442 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertFloatSetNull)443 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
444        CompositeInsertFloatSetNull) {
445   const std::string test =
446       R"(
447                OpCapability Shader
448                OpMemoryModel Logical GLSL450
449                OpEntryPoint GLCompute %1 "main"
450                OpExecutionMode %1 LocalSize 1 1 1
451        %void = OpTypeVoid
452           %3 = OpTypeFunction %void
453       %float = OpTypeFloat 32
454     %v3float = OpTypeVector %float 3
455     %float_1 = OpConstant %float 1
456 
457 ; CHECK: %7 = OpConstantNull %float
458 ; CHECK: %8 = OpConstantComposite %v3float %7 %7 %float_1
459 ; CHECK: %12 = OpConstantComposite %v3float %7 %7 %7
460        %null = OpConstantNull %float
461      %spec_0 = OpConstantComposite %v3float %null %null %float_1
462      %spec_1 = OpSpecConstantOp %v3float CompositeInsert %null %spec_0 2
463 
464 ; CHECK: %13 = OpConstantNull %float
465      %spec_2 = OpSpecConstantOp %float CompositeExtract %spec_1 2
466           %1 = OpFunction %void None %3
467       %label = OpLabel
468                OpReturn
469                OpFunctionEnd
470 )";
471 
472   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
473 }
474 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorNull)475 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorNull) {
476   const std::string test =
477       R"(
478                OpCapability Shader
479                OpMemoryModel Logical GLSL450
480                OpEntryPoint GLCompute %1 "main"
481                OpExecutionMode %1 LocalSize 1 1 1
482        %void = OpTypeVoid
483           %3 = OpTypeFunction %void
484       %float = OpTypeFloat 32
485     %v3float = OpTypeVector %float 3
486     %float_1 = OpConstant %float 1
487        %null = OpConstantNull %v3float
488 
489 ; CHECK: %11 = OpConstantNull %float
490 ; CHECK: %12 = OpConstantComposite %v3float %11 %11 %float_1
491      %spec_0 = OpSpecConstantOp %v3float CompositeInsert %float_1 %null 2
492 
493 
494 ; CHECK: %float_1_0 = OpConstant %float 1
495      %spec_1 = OpSpecConstantOp %float CompositeExtract %spec_0 2
496           %1 = OpFunction %void None %3
497       %label = OpLabel
498                OpReturn
499                OpFunctionEnd
500 )";
501 
502   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
503 }
504 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertNullVectorIntoMatrix)505 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
506        CompositeInsertNullVectorIntoMatrix) {
507   const std::string test =
508       R"(
509                OpCapability Shader
510                OpMemoryModel Logical GLSL450
511                OpEntryPoint GLCompute %1 "main"
512                OpExecutionMode %1 LocalSize 1 1 1
513        %void = OpTypeVoid
514           %3 = OpTypeFunction %void
515       %float = OpTypeFloat 32
516     %v2float = OpTypeVector %float 2
517  %mat2v2float = OpTypeMatrix %v2float 2
518        %null = OpConstantNull %mat2v2float
519     %float_1 = OpConstant %float 1
520     %float_2 = OpConstant %float 2
521  %v2float_12 = OpConstantComposite %v2float %float_1 %float_2
522 
523 ; CHECK: %13 = OpConstantNull %v2float
524 ; CHECK: %14 = OpConstantComposite %mat2v2float %10 %13
525      %spec_0 = OpSpecConstantOp %mat2v2float CompositeInsert %v2float_12 %null 0
526           %1 = OpFunction %void None %3
527       %label = OpLabel
528                OpReturn
529                OpFunctionEnd
530 )";
531 
532   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
533 }
534 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorKeepNull)535 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
536        CompositeInsertVectorKeepNull) {
537   const std::string test =
538       R"(
539                OpCapability Shader
540                OpMemoryModel Logical GLSL450
541                OpEntryPoint GLCompute %1 "main"
542                OpExecutionMode %1 LocalSize 1 1 1
543        %void = OpTypeVoid
544           %3 = OpTypeFunction %void
545       %float = OpTypeFloat 32
546     %v3float = OpTypeVector %float 3
547     %float_0 = OpConstant %float 0
548  %null_float = OpConstantNull %float
549    %null_vec = OpConstantNull %v3float
550 
551 ; CHECK: %15 = OpConstantComposite %v3float %7 %7 %float_0
552      %spec_0 = OpSpecConstantOp %v3float CompositeInsert %float_0 %null_vec 2
553 
554 ; CHECK: %float_0_0 = OpConstant %float 0
555      %spec_1 = OpSpecConstantOp %float CompositeExtract %spec_0 2
556 
557 ; CHECK: %17 = OpConstantComposite %v3float %7 %7 %7
558      %spec_2 = OpSpecConstantOp %v3float CompositeInsert %null_float %null_vec 2
559 
560 ; CHECK: %18 = OpConstantNull %float
561      %spec_3 = OpSpecConstantOp %float CompositeExtract %spec_2 2
562           %1 = OpFunction %void None %3
563       %label = OpLabel
564         %add = OpFAdd %float %spec_3 %spec_3
565                OpReturn
566                OpFunctionEnd
567 )";
568 
569   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
570 }
571 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorChainNull)572 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
573        CompositeInsertVectorChainNull) {
574   const std::string test =
575       R"(
576                OpCapability Shader
577                OpMemoryModel Logical GLSL450
578                OpEntryPoint GLCompute %1 "main"
579                OpExecutionMode %1 LocalSize 1 1 1
580        %void = OpTypeVoid
581           %3 = OpTypeFunction %void
582       %float = OpTypeFloat 32
583     %v3float = OpTypeVector %float 3
584     %float_1 = OpConstant %float 1
585        %null = OpConstantNull %v3float
586 
587 ; CHECK: %15 = OpConstantNull %float
588 ; CHECK: %16 = OpConstantComposite %v3float %15 %15 %float_1
589 ; CHECK: %17 = OpConstantComposite %v3float %15 %float_1 %float_1
590 ; CHECK: %18 = OpConstantComposite %v3float %float_1 %float_1 %float_1
591      %spec_0 = OpSpecConstantOp %v3float CompositeInsert %float_1 %null 2
592      %spec_1 = OpSpecConstantOp %v3float CompositeInsert %float_1 %spec_0 1
593      %spec_2 = OpSpecConstantOp %v3float CompositeInsert %float_1 %spec_1 0
594 
595 ; CHECK: %float_1_0 = OpConstant %float 1
596 ; CHECK: %float_1_1 = OpConstant %float 1
597 ; CHECK: %float_1_2 = OpConstant %float 1
598      %spec_3 = OpSpecConstantOp %float CompositeExtract %spec_2 0
599      %spec_4 = OpSpecConstantOp %float CompositeExtract %spec_2 1
600      %spec_5 = OpSpecConstantOp %float CompositeExtract %spec_2 2
601           %1 = OpFunction %void None %3
602       %label = OpLabel
603                OpReturn
604                OpFunctionEnd
605 )";
606 
607   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
608 }
609 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertVectorChainReset)610 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest,
611        CompositeInsertVectorChainReset) {
612   const std::string test =
613       R"(
614                OpCapability Shader
615                OpMemoryModel Logical GLSL450
616                OpEntryPoint GLCompute %1 "main"
617                OpExecutionMode %1 LocalSize 1 1 1
618        %void = OpTypeVoid
619           %3 = OpTypeFunction %void
620       %float = OpTypeFloat 32
621     %v3float = OpTypeVector %float 3
622     %float_1 = OpConstant %float 1
623        %null = OpConstantNull %float
624 ; CHECK: %8 = OpConstantComposite %v3float %7 %7 %float_1
625      %spec_0 = OpConstantComposite %v3float %null %null %float_1
626 
627             ; set to null
628 ; CHECK: %13 = OpConstantComposite %v3float %7 %7 %7
629      %spec_1 = OpSpecConstantOp %v3float CompositeInsert %null %spec_0 2
630 
631             ; set to back to original value
632 ; CHECK: %14 = OpConstantComposite %v3float %7 %7 %float_1
633      %spec_2 = OpSpecConstantOp %v3float CompositeInsert %float_1 %spec_1 2
634 
635 ; CHECK: %float_1_0 = OpConstant %float 1
636      %spec_3 = OpSpecConstantOp %float CompositeExtract %spec_2 2
637           %1 = OpFunction %void None %3
638       %label = OpLabel
639                OpReturn
640                OpFunctionEnd
641 )";
642 
643   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
644 }
645 
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertMatrixNull)646 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertMatrixNull) {
647   const std::string test =
648       R"(
649                OpCapability Shader
650                OpMemoryModel Logical GLSL450
651                OpEntryPoint GLCompute %main "main"
652                OpExecutionMode %main LocalSize 1 1 1
653        %void = OpTypeVoid
654        %func = OpTypeFunction %void
655       %float = OpTypeFloat 32
656         %int = OpTypeInt 32 0
657 %v2float = OpTypeVector %float 2
658 %mat2v2float = OpTypeMatrix %v2float 2
659 %null = OpConstantNull %mat2v2float
660     %float_1 = OpConstant %float 1
661  ; CHECK: %13 = OpConstantNull %v2float
662  ; CHECK: %14 = OpConstantNull %float
663  ; CHECK: %15 = OpConstantComposite %v2float %float_1 %14
664  ; CHECK: %16 = OpConstantComposite %mat2v2float %13 %15
665        %spec = OpSpecConstantOp %mat2v2float CompositeInsert %float_1 %null 1 0
666 ; extra type def to make sure new type def are not just thrown at end
667       %v2int = OpTypeVector %int 2
668        %main = OpFunction %void None %func
669       %label = OpLabel
670                OpReturn
671                OpFunctionEnd
672 )";
673 
674   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
675 }
676 
677 // Silently ignore spec constants that cannot be folded
TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, UnfoldableOp)678 TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, UnfoldableOp) {
679   const std::string test = R"(
680                OpCapability Shader
681                OpCapability SignedZeroInfNanPreserve
682                OpExtension "SPV_KHR_float_controls"
683                OpMemoryModel Logical GLSL450
684                OpEntryPoint Vertex %main "main"
685                OpSource GLSL 450
686                OpDecorate %v SpecId 1
687        %void = OpTypeVoid
688           %3 = OpTypeFunction %void
689        %float = OpTypeFloat 32
690           %v = OpConstant %float 0x1p-1
691 %c = OpSpecConstantOp %float QuantizeToF16 %v
692 ;CHECK: {{%\w+}} = OpSpecConstantOp {{%\w+}} QuantizeToF16 {{%\w+}}
693        %main = OpFunction %void None %3
694           %5 = OpLabel
695                OpReturn
696                OpFunctionEnd
697 )";
698 
699   SinglePassRunAndMatch<FoldSpecConstantOpAndCompositePass>(test, false);
700 }
701 
702 // All types and some common constants that are potentially required in
703 // FoldSpecConstantOpAndCompositeTest.
CommonTypesAndConstants()704 std::vector<std::string> CommonTypesAndConstants() {
705   return std::vector<std::string>{
706       // clang-format off
707       // scalar types
708       "%bool = OpTypeBool",
709       "%ushort = OpTypeInt 16 0",
710       "%short = OpTypeInt 16 1",
711       "%uint = OpTypeInt 32 0",
712       "%int = OpTypeInt 32 1",
713       "%ulong = OpTypeInt 64 0",
714       "%long = OpTypeInt 64 1",
715       "%float = OpTypeFloat 32",
716       "%double = OpTypeFloat 64",
717       // vector types
718       "%v2bool = OpTypeVector %bool 2",
719       "%v2uint = OpTypeVector %uint 2",
720       "%v2int = OpTypeVector %int 2",
721       "%v3int = OpTypeVector %int 3",
722       "%v4int = OpTypeVector %int 4",
723       "%v2long = OpTypeVector %long 2",
724       "%v2ulong = OpTypeVector %ulong 2",
725       "%v2float = OpTypeVector %float 2",
726       "%v2double = OpTypeVector %double 2",
727       // variable pointer types
728       "%_pf_bool = OpTypePointer Function %bool",
729       "%_pf_uint = OpTypePointer Function %uint",
730       "%_pf_int = OpTypePointer Function %int",
731       "%_pf_float = OpTypePointer Function %float",
732       "%_pf_double = OpTypePointer Function %double",
733       "%_pf_v2int = OpTypePointer Function %v2int",
734       "%_pf_v2float = OpTypePointer Function %v2float",
735       "%_pf_v2double = OpTypePointer Function %v2double",
736       // struct types
737       "%inner_struct = OpTypeStruct %bool %int %float",
738       "%outer_struct = OpTypeStruct %inner_struct %int",
739       "%flat_struct = OpTypeStruct %bool %int %float",
740 
741       // common constants
742       // scalar constants:
743       "%bool_true = OpConstantTrue %bool",
744       "%bool_false = OpConstantFalse %bool",
745       "%bool_null = OpConstantNull %bool",
746       "%signed_zero = OpConstant %int 0",
747       "%unsigned_zero = OpConstant %uint 0",
748       "%long_zero = OpConstant %long 0",
749       "%ulong_zero = OpConstant %ulong 0",
750       "%signed_one = OpConstant %int 1",
751       "%unsigned_one = OpConstant %uint 1",
752       "%signed_two = OpConstant %int 2",
753       "%unsigned_two = OpConstant %uint 2",
754       "%signed_three = OpConstant %int 3",
755       "%unsigned_three = OpConstant %uint 3",
756       "%signed_null = OpConstantNull %int",
757       "%unsigned_null = OpConstantNull %uint",
758       "%signed_minus_one = OpConstant %int -1",
759       // vector constants:
760       "%bool_true_vec = OpConstantComposite %v2bool %bool_true %bool_true",
761       "%bool_false_vec = OpConstantComposite %v2bool %bool_false %bool_false",
762       "%bool_null_vec = OpConstantNull %v2bool",
763       "%signed_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
764       "%unsigned_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
765       "%signed_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
766       "%unsigned_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
767       "%signed_two_vec = OpConstantComposite %v2int %signed_two %signed_two",
768       "%unsigned_two_vec = OpConstantComposite %v2uint %unsigned_two %unsigned_two",
769       "%signed_three_vec = OpConstantComposite %v2int %signed_three %signed_three",
770       "%unsigned_three_vec = OpConstantComposite %v2uint %unsigned_three %unsigned_three",
771       "%signed_null_vec = OpConstantNull %v2int",
772       "%unsigned_null_vec = OpConstantNull %v2uint",
773       "%signed_minus_one_vec = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
774       "%v4int_0_1_2_3 = OpConstantComposite %v4int %signed_zero %signed_one %signed_two %signed_three",
775       // clang-format on
776   };
777 }
778 
779 // A helper function to strip OpName instructions from the given string of
780 // disassembly code. Returns the string with all OpName instruction stripped.
StripOpNameInstructions(const std::string& str)781 std::string StripOpNameInstructions(const std::string& str) {
782   std::stringstream ss(str);
783   std::ostringstream oss;
784   std::string inst_str;
785   while (std::getline(ss, inst_str, '\n')) {
786     if (inst_str.find("OpName %") == std::string::npos) {
787       oss << inst_str << '\n';
788     }
789   }
790   return oss.str();
791 }
792 
793 struct FoldSpecConstantOpAndCompositePassTestCase {
794   // Original constants with unfolded spec constants.
795   std::vector<std::string> original;
796   // Expected constant after folding.
797   std::vector<std::string> expected;
798 };
799 
800 using FoldSpecConstantOpAndCompositePassTest = PassTest<
801     ::testing::TestWithParam<FoldSpecConstantOpAndCompositePassTestCase>>;
802 
TEST_P(FoldSpecConstantOpAndCompositePassTest, ParamTestCase)803 TEST_P(FoldSpecConstantOpAndCompositePassTest, ParamTestCase) {
804   AssemblyBuilder test_code_builder, expected_code_builder;
805   const auto& tc = GetParam();
806   test_code_builder.AppendTypesConstantsGlobals(CommonTypesAndConstants());
807   test_code_builder.AppendTypesConstantsGlobals(tc.original);
808   expected_code_builder.AppendTypesConstantsGlobals(CommonTypesAndConstants());
809   expected_code_builder.AppendTypesConstantsGlobals(tc.expected);
810   const std::string original = test_code_builder.GetCode();
811   const std::string expected = expected_code_builder.GetCode();
812 
813   // Run the optimization and get the result code in disassembly.
814   std::string optimized;
815   auto status = Pass::Status::SuccessWithoutChange;
816   std::tie(optimized, status) =
817       SinglePassRunAndDisassemble<FoldSpecConstantOpAndCompositePass>(
818           original, /* skip_nop = */ true, /* do_validation = */ false);
819 
820   // Check the optimized code, but ignore the OpName instructions.
821   EXPECT_NE(Pass::Status::Failure, status);
822   EXPECT_EQ(
823       StripOpNameInstructions(expected) == StripOpNameInstructions(original),
824       status == Pass::Status::SuccessWithoutChange);
825   EXPECT_EQ(StripOpNameInstructions(expected),
826             StripOpNameInstructions(optimized));
827 }
828 
829 // Tests that OpSpecConstantComposite opcodes are replace with
830 // OpConstantComposite correctly.
831 INSTANTIATE_TEST_SUITE_P(
832     Composite, FoldSpecConstantOpAndCompositePassTest,
833     ::testing::ValuesIn(std::vector<
834                         FoldSpecConstantOpAndCompositePassTestCase>({
835         // clang-format off
836             // normal vector
837             {
838               // original
839               {
840                 "%spec_v2bool = OpSpecConstantComposite %v2bool %bool_true %bool_false",
841                 "%spec_v2uint = OpSpecConstantComposite %v2uint %unsigned_one %unsigned_one",
842                 "%spec_v2int_a = OpSpecConstantComposite %v2int %signed_one %signed_two",
843                 // Spec constants whose value can not be fully resolved should
844                 // not be processed.
845                 "%spec_int = OpSpecConstant %int 99",
846                 "%spec_v2int_b = OpSpecConstantComposite %v2int %signed_one %spec_int",
847               },
848               // expected
849               {
850                 "%spec_v2bool = OpConstantComposite %v2bool %bool_true %bool_false",
851                 "%spec_v2uint = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
852                 "%spec_v2int_a = OpConstantComposite %v2int %signed_one %signed_two",
853                 "%spec_int = OpSpecConstant %int 99",
854                 "%spec_v2int_b = OpSpecConstantComposite %v2int %signed_one %spec_int",
855               },
856             },
857             // vector with null constants
858             {
859               // original
860               {
861                 "%null_bool = OpConstantNull %bool",
862                 "%null_int = OpConstantNull %int",
863                 "%spec_v2bool = OpSpecConstantComposite %v2bool %null_bool %null_bool",
864                 "%spec_v3int = OpSpecConstantComposite %v3int %null_int %null_int %null_int",
865                 "%spec_v4int = OpSpecConstantComposite %v4int %null_int %null_int %null_int %null_int",
866               },
867               // expected
868               {
869                 "%null_bool = OpConstantNull %bool",
870                 "%null_int = OpConstantNull %int",
871                 "%spec_v2bool = OpConstantComposite %v2bool %null_bool %null_bool",
872                 "%spec_v3int = OpConstantComposite %v3int %null_int %null_int %null_int",
873                 "%spec_v4int = OpConstantComposite %v4int %null_int %null_int %null_int %null_int",
874               },
875             },
876             // flat struct
877             {
878               // original
879               {
880                 "%float_1 = OpConstant %float 1",
881                 "%flat_1 = OpSpecConstantComposite %flat_struct %bool_true %signed_null %float_1",
882                 // following struct should not be folded as the value of
883                 // %spec_float is not determined.
884                 "%spec_float = OpSpecConstant %float 1",
885                 "%flat_2 = OpSpecConstantComposite %flat_struct %bool_true %signed_one %spec_float",
886               },
887               // expected
888               {
889                 "%float_1 = OpConstant %float 1",
890                 "%flat_1 = OpConstantComposite %flat_struct %bool_true %signed_null %float_1",
891                 "%spec_float = OpSpecConstant %float 1",
892                 "%flat_2 = OpSpecConstantComposite %flat_struct %bool_true %signed_one %spec_float",
893               }
894             },
895             // nested struct
896             {
897               // original
898               {
899                 "%float_1 = OpConstant %float 1",
900                 "%inner_1 = OpSpecConstantComposite %inner_struct %bool_true %signed_null %float_1",
901                 "%outer_1 = OpSpecConstantComposite %outer_struct %inner_1 %signed_one",
902                 // following structs should not be folded as the value of
903                 // %spec_float is not determined.
904                 "%spec_float = OpSpecConstant %float 1",
905                 "%inner_2 = OpSpecConstantComposite %inner_struct %bool_true %signed_null %spec_float",
906                 "%outer_2 = OpSpecConstantComposite %outer_struct %inner_2 %signed_one",
907               },
908               // expected
909               {
910                 "%float_1 = OpConstant %float 1",
911                 "%inner_1 = OpConstantComposite %inner_struct %bool_true %signed_null %float_1",
912                 "%outer_1 = OpConstantComposite %outer_struct %inner_1 %signed_one",
913                 "%spec_float = OpSpecConstant %float 1",
914                 "%inner_2 = OpSpecConstantComposite %inner_struct %bool_true %signed_null %spec_float",
915                 "%outer_2 = OpSpecConstantComposite %outer_struct %inner_2 %signed_one",
916               }
917             },
918             // composite constants touched by OpUndef should be skipped
919             {
920               // original
921               {
922                 "%undef = OpUndef %float",
923                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef",
924                 "%outer = OpSpecConstantComposite %outer_struct %inner %signed_one",
925               },
926               // expected
927               {
928                 "%undef = OpUndef %float",
929                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef",
930                 "%outer = OpSpecConstantComposite %outer_struct %inner %signed_one",
931               },
932             },
933             // Fold an QuantizetoF16 instruction
934             {
935               // original
936               {
937                 "%float_1 = OpConstant %float 1",
938                 "%quant_float = OpSpecConstantOp %float QuantizeToF16 %float_1",
939               },
940               // expected
941               {
942                 "%float_1 = OpConstant %float 1",
943                 "%quant_float = OpConstant %float 1",
944               },
945             }
946         // clang-format on
947     })));
948 
949 // Tests for operations that resulting in different types.
950 INSTANTIATE_TEST_SUITE_P(
951     Cast, FoldSpecConstantOpAndCompositePassTest,
952     ::testing::ValuesIn(std::vector<
953                         FoldSpecConstantOpAndCompositePassTestCase>({
954         // clang-format off
955             // int -> bool scalar
956             {
957               // original
958               {
959                 "%spec_bool_t = OpSpecConstantOp %bool INotEqual %signed_three %signed_zero",
960                 "%spec_bool_f = OpSpecConstantOp %bool INotEqual %signed_zero %signed_zero",
961                 "%spec_bool_from_null = OpSpecConstantOp %bool INotEqual %signed_null %signed_zero",
962               },
963               // expected
964               {
965                 "%spec_bool_t = OpConstantTrue %bool",
966                 "%spec_bool_f = OpConstantFalse %bool",
967                 "%spec_bool_from_null = OpConstantFalse %bool",
968               },
969             },
970 
971             // uint -> bool scalar
972             {
973               // original
974               {
975                 "%spec_bool_t = OpSpecConstantOp %bool INotEqual %unsigned_three %unsigned_zero",
976                 "%spec_bool_f = OpSpecConstantOp %bool INotEqual %unsigned_zero %unsigned_zero",
977                 "%spec_bool_from_null = OpSpecConstantOp %bool INotEqual %unsigned_null %unsigned_zero",
978               },
979               // expected
980               {
981                 "%spec_bool_t = OpConstantTrue %bool",
982                 "%spec_bool_f = OpConstantFalse %bool",
983                 "%spec_bool_from_null = OpConstantFalse %bool",
984               },
985             },
986 
987             // bool -> int scalar
988             {
989               // original
990               {
991                 "%spec_int_one = OpSpecConstantOp %int Select %bool_true %signed_one %signed_zero",
992                 "%spec_int_zero = OpSpecConstantOp %int Select %bool_false %signed_one %signed_zero",
993                 "%spec_int_from_null = OpSpecConstantOp %int Select %bool_null %signed_one %signed_zero",
994               },
995               // expected
996               {
997                 "%spec_int_one = OpConstant %int 1",
998                 "%spec_int_zero = OpConstant %int 0",
999                 "%spec_int_from_null = OpConstant %int 0",
1000               },
1001             },
1002 
1003             // uint -> int scalar
1004             {
1005               // original
1006               {
1007                 "%spec_int_one = OpSpecConstantOp %int IAdd %unsigned_one %signed_zero",
1008                 "%spec_int_zero = OpSpecConstantOp %int IAdd %unsigned_zero %signed_zero",
1009                 "%spec_int_from_null = OpSpecConstantOp %int IAdd %unsigned_null %unsigned_zero",
1010               },
1011               // expected
1012               {
1013                 "%spec_int_one = OpConstant %int 1",
1014                 "%spec_int_zero = OpConstant %int 0",
1015                 "%spec_int_from_null = OpConstant %int 0",
1016               },
1017             },
1018 
1019             // bool -> uint scalar
1020             {
1021               // original
1022               {
1023                 "%spec_uint_one = OpSpecConstantOp %uint Select %bool_true %unsigned_one %unsigned_zero",
1024                 "%spec_uint_zero = OpSpecConstantOp %uint Select %bool_false %unsigned_one %unsigned_zero",
1025                 "%spec_uint_from_null = OpSpecConstantOp %uint Select %bool_null %unsigned_one %unsigned_zero",
1026               },
1027               // expected
1028               {
1029                 "%spec_uint_one = OpConstant %uint 1",
1030                 "%spec_uint_zero = OpConstant %uint 0",
1031                 "%spec_uint_from_null = OpConstant %uint 0",
1032               },
1033             },
1034 
1035             // int -> uint scalar
1036             {
1037               // original
1038               {
1039                 "%spec_uint_one = OpSpecConstantOp %uint IAdd %signed_one %unsigned_zero",
1040                 "%spec_uint_zero = OpSpecConstantOp %uint IAdd %signed_zero %unsigned_zero",
1041                 "%spec_uint_from_null = OpSpecConstantOp %uint IAdd %signed_null %unsigned_zero",
1042               },
1043               // expected
1044               {
1045                 "%spec_uint_one = OpConstant %uint 1",
1046                 "%spec_uint_zero = OpConstant %uint 0",
1047                 "%spec_uint_from_null = OpConstant %uint 0",
1048               },
1049             },
1050 
1051             // int -> bool vector
1052             {
1053               // original
1054               {
1055                 "%spec_bool_t_vec = OpSpecConstantOp %v2bool INotEqual %signed_three_vec %signed_zero_vec",
1056                 "%spec_bool_f_vec = OpSpecConstantOp %v2bool INotEqual %signed_zero_vec %signed_zero_vec",
1057                 "%spec_bool_from_null = OpSpecConstantOp %v2bool INotEqual %signed_null_vec %signed_zero_vec",
1058               },
1059               // expected
1060               {
1061                 "%true = OpConstantTrue %bool",
1062                 "%true_0 = OpConstantTrue %bool",
1063                 "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true",
1064                 "%false = OpConstantFalse %bool",
1065                 "%false_0 = OpConstantFalse %bool",
1066                 "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false",
1067                 "%false_1 = OpConstantFalse %bool",
1068                 "%false_2 = OpConstantFalse %bool",
1069                 "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false",
1070               },
1071             },
1072 
1073             // uint -> bool vector
1074             {
1075               // original
1076               {
1077                 "%spec_bool_t_vec = OpSpecConstantOp %v2bool INotEqual %unsigned_three_vec %unsigned_zero_vec",
1078                 "%spec_bool_f_vec = OpSpecConstantOp %v2bool INotEqual %unsigned_zero_vec %unsigned_zero_vec",
1079                 "%spec_bool_from_null = OpSpecConstantOp %v2bool INotEqual %unsigned_null_vec %unsigned_zero_vec",
1080               },
1081               // expected
1082               {
1083                 "%true = OpConstantTrue %bool",
1084                 "%true_0 = OpConstantTrue %bool",
1085                 "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true",
1086                 "%false = OpConstantFalse %bool",
1087                 "%false_0 = OpConstantFalse %bool",
1088                 "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false",
1089                 "%false_1 = OpConstantFalse %bool",
1090                 "%false_2 = OpConstantFalse %bool",
1091                 "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false",
1092               },
1093             },
1094 
1095             // bool -> int vector
1096             {
1097                 // original
1098               {
1099                 "%spec_int_one_vec = OpSpecConstantOp %v2int Select %bool_true_vec %signed_one_vec %signed_zero_vec",
1100                 "%spec_int_zero_vec = OpSpecConstantOp %v2int Select %bool_false_vec %signed_one_vec %signed_zero_vec",
1101                 "%spec_int_from_null = OpSpecConstantOp %v2int Select %bool_null_vec %signed_one_vec %signed_zero_vec",
1102               },
1103               // expected
1104               {
1105                 "%int_1 = OpConstant %int 1",
1106                 "%int_1_0 = OpConstant %int 1",
1107                 "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
1108                 "%int_0 = OpConstant %int 0",
1109                 "%int_0_0 = OpConstant %int 0",
1110                 "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
1111                 "%int_0_1 = OpConstant %int 0",
1112                 "%int_0_2 = OpConstant %int 0",
1113                 "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero",
1114               },
1115             },
1116 
1117             // uint -> int vector
1118             {
1119               // original
1120               {
1121                 "%spec_int_one_vec = OpSpecConstantOp %v2int IAdd %unsigned_one_vec %signed_zero_vec",
1122                 "%spec_int_zero_vec = OpSpecConstantOp %v2int IAdd %unsigned_zero_vec %signed_zero_vec",
1123                 "%spec_int_from_null = OpSpecConstantOp %v2int IAdd %unsigned_null_vec %signed_zero_vec",
1124               },
1125               // expected
1126               {
1127                 "%int_1 = OpConstant %int 1",
1128                 "%int_1_0 = OpConstant %int 1",
1129                 "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one",
1130                 "%int_0 = OpConstant %int 0",
1131                 "%int_0_0 = OpConstant %int 0",
1132                 "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero",
1133                 "%int_0_1 = OpConstant %int 0",
1134                 "%int_0_2 = OpConstant %int 0",
1135                 "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero",
1136               },
1137             },
1138 
1139             // bool -> uint vector
1140             {
1141               // original
1142               {
1143                 "%spec_uint_one_vec = OpSpecConstantOp %v2uint Select %bool_true_vec %unsigned_one_vec %unsigned_zero_vec",
1144                 "%spec_uint_zero_vec = OpSpecConstantOp %v2uint Select %bool_false_vec %unsigned_one_vec %unsigned_zero_vec",
1145                 "%spec_uint_from_null = OpSpecConstantOp %v2uint Select %bool_null_vec %unsigned_one_vec %unsigned_zero_vec",
1146               },
1147               // expected
1148               {
1149                 "%uint_1 = OpConstant %uint 1",
1150                 "%uint_1_0 = OpConstant %uint 1",
1151                 "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
1152                 "%uint_0 = OpConstant %uint 0",
1153                 "%uint_0_0 = OpConstant %uint 0",
1154                 "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
1155                 "%uint_0_1 = OpConstant %uint 0",
1156                 "%uint_0_2 = OpConstant %uint 0",
1157                 "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
1158               },
1159             },
1160 
1161             // int -> uint vector
1162             {
1163               // original
1164               {
1165                 "%spec_uint_one_vec = OpSpecConstantOp %v2uint IAdd %signed_one_vec %unsigned_zero_vec",
1166                 "%spec_uint_zero_vec = OpSpecConstantOp %v2uint IAdd %signed_zero_vec %unsigned_zero_vec",
1167                 "%spec_uint_from_null = OpSpecConstantOp %v2uint IAdd %signed_null_vec %unsigned_zero_vec",
1168               },
1169               // expected
1170               {
1171                 "%uint_1 = OpConstant %uint 1",
1172                 "%uint_1_0 = OpConstant %uint 1",
1173                 "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
1174                 "%uint_0 = OpConstant %uint 0",
1175                 "%uint_0_0 = OpConstant %uint 0",
1176                 "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
1177                 "%uint_0_1 = OpConstant %uint 0",
1178                 "%uint_0_2 = OpConstant %uint 0",
1179                 "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
1180               },
1181             },
1182 
1183             // UConvert scalar
1184             {
1185               // original
1186               {
1187                 "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false",
1188                 "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true",
1189                 "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero",
1190                 "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one",
1191                 "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero",
1192                 "%spec_short_one = OpSpecConstantOp %ushort UConvert %unsigned_one",
1193                 "%uint_max = OpConstant %uint 4294967295",
1194                 "%spec_ushort_max = OpSpecConstantOp %ushort UConvert %uint_max",
1195                 "%uint_0xDDDDDDDD = OpConstant %uint 3722304989",
1196                 "%spec_ushort_0xDDDD = OpSpecConstantOp %ushort UConvert %uint_0xDDDDDDDD",
1197               },
1198               // expected
1199               {
1200                 "%spec_uint_zero = OpConstant %uint 0",
1201                 "%spec_uint_one = OpConstant %uint 1",
1202                 "%spec_ulong_zero = OpConstant %ulong 0",
1203                 "%spec_ulong_one = OpConstant %ulong 1",
1204                 "%spec_short_zero = OpConstant %ushort 0",
1205                 "%spec_short_one = OpConstant %ushort 1",
1206                 "%uint_max = OpConstant %uint 4294967295",
1207                 "%spec_ushort_max = OpConstant %ushort 65535",
1208                 "%uint_0xDDDDDDDD = OpConstant %uint 3722304989",
1209                 "%spec_ushort_0xDDDD = OpConstant %ushort 56797",
1210               },
1211             },
1212 
1213             // SConvert scalar
1214             {
1215               // original
1216               {
1217                 "%spec_long_zero = OpSpecConstantOp %long SConvert %signed_zero",
1218                 "%spec_long_one = OpSpecConstantOp %long SConvert %signed_one",
1219                 "%spec_long_minus_one = OpSpecConstantOp %long SConvert %signed_minus_one",
1220                 "%spec_short_minus_one_trunc = OpSpecConstantOp %short SConvert %signed_minus_one",
1221                 "%int_2_to_17_minus_one = OpConstant %int 131071",
1222                 "%spec_short_minus_one_trunc2 = OpSpecConstantOp %short SConvert %int_2_to_17_minus_one",
1223               },
1224               // expected
1225               {
1226                 "%spec_long_zero = OpConstant %long 0",
1227                 "%spec_long_one = OpConstant %long 1",
1228                 "%spec_long_minus_one = OpConstant %long -1",
1229                 "%spec_short_minus_one_trunc = OpConstant %short -1",
1230                 "%int_2_to_17_minus_one = OpConstant %int 131071",
1231                 "%spec_short_minus_one_trunc2 = OpConstant %short -1",
1232               },
1233             },
1234 
1235             // UConvert vector
1236             {
1237               // original
1238               {
1239                 "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec",
1240                 "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec",
1241                 "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec",
1242                 "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec",
1243               },
1244               // expected
1245               {
1246                 "%uint_0 = OpConstant %uint 0",
1247                 "%uint_0_0 = OpConstant %uint 0",
1248                 "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero",
1249                 "%uint_1 = OpConstant %uint 1",
1250                 "%uint_1_0 = OpConstant %uint 1",
1251                 "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
1252                 "%ulong_0 = OpConstant %ulong 0",
1253                 "%ulong_0_0 = OpConstant %ulong 0",
1254                 "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero",
1255                 "%ulong_1 = OpConstant %ulong 1",
1256                 "%ulong_1_0 = OpConstant %ulong 1",
1257                 "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1",
1258               },
1259             },
1260 
1261             // SConvert vector
1262             {
1263               // original
1264               {
1265                 "%spec_v2long_zero = OpSpecConstantOp %v2long SConvert %signed_zero_vec",
1266                 "%spec_v2long_one = OpSpecConstantOp %v2long SConvert %signed_one_vec",
1267                 "%spec_v2long_minus_one = OpSpecConstantOp %v2long SConvert %signed_minus_one_vec",
1268               },
1269               // expected
1270               {
1271                 "%long_0 = OpConstant %long 0",
1272                 "%long_0_0 = OpConstant %long 0",
1273                 "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero",
1274                 "%long_1 = OpConstant %long 1",
1275                 "%long_1_0 = OpConstant %long 1",
1276                 "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1",
1277                 "%long_n1 = OpConstant %long -1",
1278                 "%long_n1_0 = OpConstant %long -1",
1279                 "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1",
1280               },
1281             },
1282         // clang-format on
1283     })));
1284 
1285 // Tests about boolean scalar logical operations and comparison operations with
1286 // scalar int/uint type.
1287 INSTANTIATE_TEST_SUITE_P(
1288     Logical, FoldSpecConstantOpAndCompositePassTest,
1289     ::testing::ValuesIn(std::vector<
1290                         FoldSpecConstantOpAndCompositePassTestCase>({
1291         // clang-format off
1292             // scalar integer comparison
1293             {
1294               // original
1295               {
1296                 "%int_minus_1 = OpConstant %int -1",
1297 
1298                 "%slt_0_1 = OpSpecConstantOp %bool SLessThan %signed_zero %signed_one",
1299                 "%sgt_0_1 = OpSpecConstantOp %bool SGreaterThan %signed_zero %signed_one",
1300                 "%sle_2_2 = OpSpecConstantOp %bool SLessThanEqual %signed_two %signed_two",
1301                 "%sge_2_1 = OpSpecConstantOp %bool SGreaterThanEqual %signed_two %signed_one",
1302                 "%sge_2_null = OpSpecConstantOp %bool SGreaterThanEqual %signed_two %signed_null",
1303                 "%sge_minus_1_null = OpSpecConstantOp %bool SGreaterThanEqual %int_minus_1 %signed_null",
1304 
1305                 "%ult_0_1 = OpSpecConstantOp %bool ULessThan %unsigned_zero %unsigned_one",
1306                 "%ugt_0_1 = OpSpecConstantOp %bool UGreaterThan %unsigned_zero %unsigned_one",
1307                 "%ule_2_3 = OpSpecConstantOp %bool ULessThanEqual %unsigned_two %unsigned_three",
1308                 "%uge_1_1 = OpSpecConstantOp %bool UGreaterThanEqual %unsigned_one %unsigned_one",
1309                 "%uge_2_null = OpSpecConstantOp %bool UGreaterThanEqual %unsigned_two %unsigned_null",
1310                 "%uge_minus_1_null = OpSpecConstantOp %bool UGreaterThanEqual %int_minus_1 %unsigned_null",
1311               },
1312               // expected
1313               {
1314                 "%int_minus_1 = OpConstant %int -1",
1315 
1316                 "%slt_0_1 = OpConstantTrue %bool",
1317                 "%sgt_0_1 = OpConstantFalse %bool",
1318                 "%sle_2_2 = OpConstantTrue %bool",
1319                 "%sge_2_1 = OpConstantTrue %bool",
1320                 "%sge_2_null = OpConstantTrue %bool",
1321                 "%sge_minus_1_null = OpConstantFalse %bool",
1322 
1323                 "%ult_0_1 = OpConstantTrue %bool",
1324                 "%ugt_0_1 = OpConstantFalse %bool",
1325                 "%ule_2_3 = OpConstantTrue %bool",
1326                 "%uge_1_1 = OpConstantTrue %bool",
1327                 "%uge_2_null = OpConstantTrue %bool",
1328                 "%uge_minus_1_null = OpConstantTrue %bool",
1329               },
1330             },
1331             // Logical and, or, xor.
1332             {
1333               // original
1334               {
1335                 "%logical_or = OpSpecConstantOp %bool LogicalOr %bool_true %bool_false",
1336                 "%logical_and = OpSpecConstantOp %bool LogicalAnd %bool_true %bool_false",
1337                 "%logical_not = OpSpecConstantOp %bool LogicalNot %bool_true",
1338                 "%logical_eq = OpSpecConstantOp %bool LogicalEqual %bool_true %bool_true",
1339                 "%logical_neq = OpSpecConstantOp %bool LogicalNotEqual %bool_true %bool_true",
1340                 "%logical_and_null = OpSpecConstantOp %bool LogicalAnd %bool_true %bool_null",
1341               },
1342               // expected
1343               {
1344                 "%logical_or = OpConstantTrue %bool",
1345                 "%logical_and = OpConstantFalse %bool",
1346                 "%logical_not = OpConstantFalse %bool",
1347                 "%logical_eq = OpConstantTrue %bool",
1348                 "%logical_neq = OpConstantFalse %bool",
1349                 "%logical_and_null = OpConstantFalse %bool",
1350               },
1351             },
1352         // clang-format on
1353     })));
1354 
1355 // Tests about arithmetic operations for scalar int and uint types.
1356 INSTANTIATE_TEST_SUITE_P(
1357     ScalarArithmetic, FoldSpecConstantOpAndCompositePassTest,
1358     ::testing::ValuesIn(std::vector<
1359                         FoldSpecConstantOpAndCompositePassTestCase>({
1360         // clang-format off
1361             // scalar integer negate
1362             {
1363               // original
1364               {
1365                 "%int_minus_1 = OpSpecConstantOp %int SNegate %signed_one",
1366                 "%int_minus_2 = OpSpecConstantOp %int SNegate %signed_two",
1367                 "%int_neg_null = OpSpecConstantOp %int SNegate %signed_null",
1368                 "%int_max = OpConstant %int 2147483647",
1369                 "%int_neg_max = OpSpecConstantOp %int SNegate %int_max",
1370               },
1371               // expected
1372               {
1373                 "%int_minus_1 = OpConstant %int -1",
1374                 "%int_minus_2 = OpConstant %int -2",
1375                 "%int_neg_null = OpConstant %int 0",
1376                 "%int_max = OpConstant %int 2147483647",
1377                 "%int_neg_max = OpConstant %int -2147483647",
1378               },
1379             },
1380             // scalar integer not
1381             {
1382               // original
1383               {
1384                 "%uint_4294967294 = OpSpecConstantOp %uint Not %unsigned_one",
1385                 "%uint_4294967293 = OpSpecConstantOp %uint Not %unsigned_two",
1386                 "%uint_neg_null = OpSpecConstantOp %uint Not %unsigned_null",
1387               },
1388               // expected
1389               {
1390                 "%uint_4294967294 = OpConstant %uint 4294967294",
1391                 "%uint_4294967293 = OpConstant %uint 4294967293",
1392                 "%uint_neg_null = OpConstant %uint 4294967295",
1393               },
1394             },
1395             // scalar integer add, sub, mul, div
1396             {
1397               // original
1398               {
1399                 "%signed_max = OpConstant %int 2147483647",
1400                 "%signed_min = OpConstant %int -2147483648",
1401 
1402                 "%spec_int_iadd = OpSpecConstantOp %int IAdd %signed_three %signed_two",
1403                 "%spec_int_isub = OpSpecConstantOp %int ISub %signed_one %spec_int_iadd",
1404                 "%spec_int_sdiv = OpSpecConstantOp %int SDiv %spec_int_isub %signed_two",
1405                 "%spec_int_imul = OpSpecConstantOp %int IMul %spec_int_sdiv %signed_three",
1406                 "%spec_int_iadd_null = OpSpecConstantOp %int IAdd %spec_int_imul %signed_null",
1407                 "%spec_int_imul_null = OpSpecConstantOp %int IMul %spec_int_iadd_null %signed_null",
1408                 "%spec_int_iadd_overflow = OpSpecConstantOp %int IAdd %signed_max %signed_three",
1409                 "%spec_int_isub_overflow = OpSpecConstantOp %int ISub %signed_min %signed_three",
1410 
1411                 "%spec_uint_iadd = OpSpecConstantOp %uint IAdd %unsigned_three %unsigned_two",
1412                 "%spec_uint_isub = OpSpecConstantOp %uint ISub %unsigned_one %spec_uint_iadd",
1413                 "%spec_uint_udiv = OpSpecConstantOp %uint UDiv %spec_uint_isub %unsigned_three",
1414                 "%spec_uint_imul = OpSpecConstantOp %uint IMul %spec_uint_udiv %unsigned_two",
1415                 "%spec_uint_isub_null = OpSpecConstantOp %uint ISub %spec_uint_imul %signed_null",
1416               },
1417               // expected
1418               {
1419                 "%signed_max = OpConstant %int 2147483647",
1420                 "%signed_min = OpConstant %int -2147483648",
1421 
1422                 "%spec_int_iadd = OpConstant %int 5",
1423                 "%spec_int_isub = OpConstant %int -4",
1424                 "%spec_int_sdiv = OpConstant %int -2",
1425                 "%spec_int_imul = OpConstant %int -6",
1426                 "%spec_int_iadd_null = OpConstant %int -6",
1427                 "%spec_int_imul_null = OpConstant %int 0",
1428                 "%spec_int_iadd_overflow = OpConstant %int -2147483646",
1429                 "%spec_int_isub_overflow = OpConstant %int 2147483645",
1430 
1431                 "%spec_uint_iadd = OpConstant %uint 5",
1432                 "%spec_uint_isub = OpConstant %uint 4294967292",
1433                 "%spec_uint_udiv = OpConstant %uint 1431655764",
1434                 "%spec_uint_imul = OpConstant %uint 2863311528",
1435                 "%spec_uint_isub_null = OpConstant %uint 2863311528",
1436               },
1437             },
1438             // scalar integer rem, mod
1439             {
1440               // original
1441               {
1442                 // common constants
1443                 "%int_7 = OpConstant %int 7",
1444                 "%uint_7 = OpConstant %uint 7",
1445                 "%int_minus_7 = OpConstant %int -7",
1446                 "%int_minus_3 = OpConstant %int -3",
1447 
1448                 // srem
1449                 "%7_srem_3 = OpSpecConstantOp %int SRem %int_7 %signed_three",
1450                 "%minus_7_srem_3 = OpSpecConstantOp %int SRem %int_minus_7 %signed_three",
1451                 "%7_srem_minus_3 = OpSpecConstantOp %int SRem %int_7 %int_minus_3",
1452                 "%minus_7_srem_minus_3 = OpSpecConstantOp %int SRem %int_minus_7 %int_minus_3",
1453                 // smod
1454                 "%7_smod_3 = OpSpecConstantOp %int SMod %int_7 %signed_three",
1455                 "%minus_7_smod_3 = OpSpecConstantOp %int SMod %int_minus_7 %signed_three",
1456                 "%7_smod_minus_3 = OpSpecConstantOp %int SMod %int_7 %int_minus_3",
1457                 "%minus_7_smod_minus_3 = OpSpecConstantOp %int SMod %int_minus_7 %int_minus_3",
1458                 // umod
1459                 "%7_umod_3 = OpSpecConstantOp %uint UMod %uint_7 %unsigned_three",
1460                 // null constant
1461                 "%null_srem_3 = OpSpecConstantOp %int SRem %signed_null %signed_three",
1462                 "%null_smod_3 = OpSpecConstantOp %int SMod %signed_null %signed_three",
1463                 "%null_umod_3 = OpSpecConstantOp %uint UMod %unsigned_null %unsigned_three",
1464               },
1465               // expected
1466               {
1467                 // common constants
1468                 "%int_7 = OpConstant %int 7",
1469                 "%uint_7 = OpConstant %uint 7",
1470                 "%int_minus_7 = OpConstant %int -7",
1471                 "%int_minus_3 = OpConstant %int -3",
1472 
1473                 // srem
1474                 "%7_srem_3 = OpConstant %int 1",
1475                 "%minus_7_srem_3 = OpConstant %int -1",
1476                 "%7_srem_minus_3 = OpConstant %int 1",
1477                 "%minus_7_srem_minus_3 = OpConstant %int -1",
1478                 // smod
1479                 "%7_smod_3 = OpConstant %int 1",
1480                 "%minus_7_smod_3 = OpConstant %int 2",
1481                 "%7_smod_minus_3 = OpConstant %int -2",
1482                 "%minus_7_smod_minus_3 = OpConstant %int -1",
1483                 // umod
1484                 "%7_umod_3 = OpConstant %uint 1",
1485                 // null constant
1486                 "%null_srem_3 = OpConstant %int 0",
1487                 "%null_smod_3 = OpConstant %int 0",
1488                 "%null_umod_3 = OpConstant %uint 0",
1489               },
1490             },
1491             // scalar integer bitwise and shift
1492             {
1493               // original
1494               {
1495                 // bitwise
1496                 "%xor_1_3 = OpSpecConstantOp %int BitwiseXor %signed_one %signed_three",
1497                 "%and_1_2 = OpSpecConstantOp %int BitwiseAnd %signed_one %xor_1_3",
1498                 "%or_1_2 = OpSpecConstantOp %int BitwiseOr %signed_one %xor_1_3",
1499                 "%xor_3_null = OpSpecConstantOp %int BitwiseXor %or_1_2 %signed_null",
1500 
1501                 // shift
1502                 "%unsigned_31 = OpConstant %uint 31",
1503                 "%unsigned_left_shift_max = OpSpecConstantOp %uint ShiftLeftLogical %unsigned_one %unsigned_31",
1504                 "%unsigned_right_shift_logical = OpSpecConstantOp %uint ShiftRightLogical %unsigned_left_shift_max %unsigned_31",
1505                 "%signed_right_shift_arithmetic = OpSpecConstantOp %int ShiftRightArithmetic %unsigned_left_shift_max %unsigned_31",
1506                 "%left_shift_null_31 = OpSpecConstantOp %uint ShiftLeftLogical %unsigned_null %unsigned_31",
1507                 "%right_shift_31_null = OpSpecConstantOp %uint ShiftRightLogical %unsigned_31 %unsigned_null",
1508               },
1509               // expected
1510               {
1511                 "%xor_1_3 = OpConstant %int 2",
1512                 "%and_1_2 = OpConstant %int 0",
1513                 "%or_1_2 = OpConstant %int 3",
1514                 "%xor_3_null = OpConstant %int 3",
1515 
1516                 "%unsigned_31 = OpConstant %uint 31",
1517                 "%unsigned_left_shift_max = OpConstant %uint 2147483648",
1518                 "%unsigned_right_shift_logical = OpConstant %uint 1",
1519                 "%signed_right_shift_arithmetic = OpConstant %int -1",
1520                 "%left_shift_null_31 = OpConstant %uint 0",
1521                 "%right_shift_31_null = OpConstant %uint 31",
1522               },
1523             },
1524             // Skip folding if any operands have undetermined value.
1525             {
1526               // original
1527               {
1528                 "%spec_int = OpSpecConstant %int 1",
1529                 "%spec_iadd = OpSpecConstantOp %int IAdd %signed_three %spec_int",
1530               },
1531               // expected
1532               {
1533                 "%spec_int = OpSpecConstant %int 1",
1534                 "%spec_iadd = OpSpecConstantOp %int IAdd %signed_three %spec_int",
1535               },
1536             },
1537         // clang-format on
1538     })));
1539 
1540 // Tests about arithmetic operations for vector int and uint types.
1541 INSTANTIATE_TEST_SUITE_P(
1542     VectorArithmetic, FoldSpecConstantOpAndCompositePassTest,
1543     ::testing::ValuesIn(std::vector<
1544                         FoldSpecConstantOpAndCompositePassTestCase>({
1545         // clang-format off
1546             // vector integer negate
1547             {
1548               // original
1549               {
1550                 "%v2int_minus_1 = OpSpecConstantOp %v2int SNegate %signed_one_vec",
1551                 "%v2int_minus_2 = OpSpecConstantOp %v2int SNegate %signed_two_vec",
1552                 "%v2int_neg_null = OpSpecConstantOp %v2int SNegate %signed_null_vec",
1553               },
1554               // expected
1555               {
1556                 "%int_n1 = OpConstant %int -1",
1557                 "%int_n1_0 = OpConstant %int -1",
1558                 "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
1559                 "%int_n2 = OpConstant %int -2",
1560                 "%int_n2_0 = OpConstant %int -2",
1561                 "%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2",
1562                 "%int_0 = OpConstant %int 0",
1563                 "%int_0_0 = OpConstant %int 0",
1564                 "%v2int_neg_null = OpConstantComposite %v2int %signed_zero %signed_zero",
1565               },
1566             },
1567             // vector integer (including null vetors) add, sub, div, mul
1568             {
1569               // original
1570               {
1571                 "%spec_v2int_iadd = OpSpecConstantOp %v2int IAdd %signed_three_vec %signed_two_vec",
1572                 "%spec_v2int_isub = OpSpecConstantOp %v2int ISub %signed_one_vec %spec_v2int_iadd",
1573                 "%spec_v2int_sdiv = OpSpecConstantOp %v2int SDiv %spec_v2int_isub %signed_two_vec",
1574                 "%spec_v2int_imul = OpSpecConstantOp %v2int IMul %spec_v2int_sdiv %signed_three_vec",
1575                 "%spec_v2int_iadd_null = OpSpecConstantOp %v2int IAdd %spec_v2int_imul %signed_null_vec",
1576 
1577                 "%spec_v2uint_iadd = OpSpecConstantOp %v2uint IAdd %unsigned_three_vec %unsigned_two_vec",
1578                 "%spec_v2uint_isub = OpSpecConstantOp %v2uint ISub %unsigned_one_vec %spec_v2uint_iadd",
1579                 "%spec_v2uint_udiv = OpSpecConstantOp %v2uint UDiv %spec_v2uint_isub %unsigned_three_vec",
1580                 "%spec_v2uint_imul = OpSpecConstantOp %v2uint IMul %spec_v2uint_udiv %unsigned_two_vec",
1581                 "%spec_v2uint_isub_null = OpSpecConstantOp %v2uint ISub %spec_v2uint_imul %signed_null_vec",
1582               },
1583               // expected
1584               {
1585                 "%int_5 = OpConstant %int 5",
1586                 "%int_5_0 = OpConstant %int 5",
1587                 "%spec_v2int_iadd = OpConstantComposite %v2int %int_5 %int_5",
1588                 "%int_n4 = OpConstant %int -4",
1589                 "%int_n4_0 = OpConstant %int -4",
1590                 "%spec_v2int_isub = OpConstantComposite %v2int %int_n4 %int_n4",
1591                 "%int_n2 = OpConstant %int -2",
1592                 "%int_n2_0 = OpConstant %int -2",
1593                 "%spec_v2int_sdiv = OpConstantComposite %v2int %int_n2 %int_n2",
1594                 "%int_n6 = OpConstant %int -6",
1595                 "%int_n6_0 = OpConstant %int -6",
1596                 "%spec_v2int_imul = OpConstantComposite %v2int %int_n6 %int_n6",
1597                 "%int_n6_1 = OpConstant %int -6",
1598                 "%int_n6_2 = OpConstant %int -6",
1599                 "%spec_v2int_iadd_null = OpConstantComposite %v2int %int_n6 %int_n6",
1600 
1601                 "%uint_5 = OpConstant %uint 5",
1602                 "%uint_5_0 = OpConstant %uint 5",
1603                 "%spec_v2uint_iadd = OpConstantComposite %v2uint %uint_5 %uint_5",
1604                 "%uint_4294967292 = OpConstant %uint 4294967292",
1605                 "%uint_4294967292_0 = OpConstant %uint 4294967292",
1606                 "%spec_v2uint_isub = OpConstantComposite %v2uint %uint_4294967292 %uint_4294967292",
1607                 "%uint_1431655764 = OpConstant %uint 1431655764",
1608                 "%uint_1431655764_0 = OpConstant %uint 1431655764",
1609                 "%spec_v2uint_udiv = OpConstantComposite %v2uint %uint_1431655764 %uint_1431655764",
1610                 "%uint_2863311528 = OpConstant %uint 2863311528",
1611                 "%uint_2863311528_0 = OpConstant %uint 2863311528",
1612                 "%spec_v2uint_imul = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528",
1613                 "%uint_2863311528_1 = OpConstant %uint 2863311528",
1614                 "%uint_2863311528_2 = OpConstant %uint 2863311528",
1615                 "%spec_v2uint_isub_null = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528",
1616               },
1617             },
1618             // vector integer rem, mod
1619             {
1620               // original
1621               {
1622                 // common constants
1623                 "%int_7 = OpConstant %int 7",
1624                 "%v2int_7 = OpConstantComposite %v2int %int_7 %int_7",
1625                 "%uint_7 = OpConstant %uint 7",
1626                 "%v2uint_7 = OpConstantComposite %v2uint %uint_7 %uint_7",
1627                 "%int_minus_7 = OpConstant %int -7",
1628                 "%v2int_minus_7 = OpConstantComposite %v2int %int_minus_7 %int_minus_7",
1629                 "%int_minus_3 = OpConstant %int -3",
1630                 "%v2int_minus_3 = OpConstantComposite %v2int %int_minus_3 %int_minus_3",
1631 
1632                 // srem
1633                 "%7_srem_3 = OpSpecConstantOp %v2int SRem %v2int_7 %signed_three_vec",
1634                 "%minus_7_srem_3 = OpSpecConstantOp %v2int SRem %v2int_minus_7 %signed_three_vec",
1635                 "%7_srem_minus_3 = OpSpecConstantOp %v2int SRem %v2int_7 %v2int_minus_3",
1636                 "%minus_7_srem_minus_3 = OpSpecConstantOp %v2int SRem %v2int_minus_7 %v2int_minus_3",
1637                 // smod
1638                 "%7_smod_3 = OpSpecConstantOp %v2int SMod %v2int_7 %signed_three_vec",
1639                 "%minus_7_smod_3 = OpSpecConstantOp %v2int SMod %v2int_minus_7 %signed_three_vec",
1640                 "%7_smod_minus_3 = OpSpecConstantOp %v2int SMod %v2int_7 %v2int_minus_3",
1641                 "%minus_7_smod_minus_3 = OpSpecConstantOp %v2int SMod %v2int_minus_7 %v2int_minus_3",
1642                 // umod
1643                 "%7_umod_3 = OpSpecConstantOp %v2uint UMod %v2uint_7 %unsigned_three_vec",
1644               },
1645               // expected
1646               {
1647                 // common constants
1648                 "%int_7 = OpConstant %int 7",
1649                 "%v2int_7 = OpConstantComposite %v2int %int_7 %int_7",
1650                 "%uint_7 = OpConstant %uint 7",
1651                 "%v2uint_7 = OpConstantComposite %v2uint %uint_7 %uint_7",
1652                 "%int_minus_7 = OpConstant %int -7",
1653                 "%v2int_minus_7 = OpConstantComposite %v2int %int_minus_7 %int_minus_7",
1654                 "%int_minus_3 = OpConstant %int -3",
1655                 "%v2int_minus_3 = OpConstantComposite %v2int %int_minus_3 %int_minus_3",
1656 
1657                 // srem
1658                 "%int_1 = OpConstant %int 1",
1659                 "%int_1_0 = OpConstant %int 1",
1660                 "%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one",
1661                 "%int_n1 = OpConstant %int -1",
1662                 "%int_n1_0 = OpConstant %int -1",
1663                 "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
1664                 "%int_1_1 = OpConstant %int 1",
1665                 "%int_1_2 = OpConstant %int 1",
1666                 "%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one",
1667                 "%int_n1_1 = OpConstant %int -1",
1668                 "%int_n1_2 = OpConstant %int -1",
1669                 "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
1670                 // smod
1671                 "%int_1_3 = OpConstant %int 1",
1672                 "%int_1_4 = OpConstant %int 1",
1673                 "%7_smod_3 = OpConstantComposite %v2int %signed_one %signed_one",
1674                 "%int_2 = OpConstant %int 2",
1675                 "%int_2_0 = OpConstant %int 2",
1676                 "%minus_7_smod_3 = OpConstantComposite %v2int %signed_two %signed_two",
1677                 "%int_n2 = OpConstant %int -2",
1678                 "%int_n2_0 = OpConstant %int -2",
1679                 "%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2",
1680                 "%int_n1_3 = OpConstant %int -1",
1681                 "%int_n1_4 = OpConstant %int -1",
1682                 "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
1683                 // umod
1684                 "%uint_1 = OpConstant %uint 1",
1685                 "%uint_1_0 = OpConstant %uint 1",
1686                 "%7_umod_3 = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
1687               },
1688             },
1689             // vector integer bitwise, shift
1690             {
1691               // original
1692               {
1693                 "%xor_1_3 = OpSpecConstantOp %v2int BitwiseXor %signed_one_vec %signed_three_vec",
1694                 "%and_1_2 = OpSpecConstantOp %v2int BitwiseAnd %signed_one_vec %xor_1_3",
1695                 "%or_1_2 = OpSpecConstantOp %v2int BitwiseOr %signed_one_vec %xor_1_3",
1696 
1697                 "%unsigned_31 = OpConstant %uint 31",
1698                 "%v2unsigned_31 = OpConstantComposite %v2uint %unsigned_31 %unsigned_31",
1699                 "%unsigned_left_shift_max = OpSpecConstantOp %v2uint ShiftLeftLogical %unsigned_one_vec %v2unsigned_31",
1700                 "%unsigned_right_shift_logical = OpSpecConstantOp %v2uint ShiftRightLogical %unsigned_left_shift_max %v2unsigned_31",
1701                 "%signed_right_shift_arithmetic = OpSpecConstantOp %v2int ShiftRightArithmetic %unsigned_left_shift_max %v2unsigned_31",
1702               },
1703               // expected
1704               {
1705                 "%int_2 = OpConstant %int 2",
1706                 "%int_2_0 = OpConstant %int 2",
1707                 "%xor_1_3 = OpConstantComposite %v2int %signed_two %signed_two",
1708                 "%int_0 = OpConstant %int 0",
1709                 "%int_0_0 = OpConstant %int 0",
1710                 "%and_1_2 = OpConstantComposite %v2int %signed_zero %signed_zero",
1711                 "%int_3 = OpConstant %int 3",
1712                 "%int_3_0 = OpConstant %int 3",
1713                 "%or_1_2 = OpConstantComposite %v2int %signed_three %signed_three",
1714 
1715                 "%unsigned_31 = OpConstant %uint 31",
1716                 "%v2unsigned_31 = OpConstantComposite %v2uint %unsigned_31 %unsigned_31",
1717                 "%uint_2147483648 = OpConstant %uint 2147483648",
1718                 "%uint_2147483648_0 = OpConstant %uint 2147483648",
1719                 "%unsigned_left_shift_max = OpConstantComposite %v2uint %uint_2147483648 %uint_2147483648",
1720                 "%uint_1 = OpConstant %uint 1",
1721                 "%uint_1_0 = OpConstant %uint 1",
1722                 "%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one",
1723                 "%int_n1 = OpConstant %int -1",
1724                 "%int_n1_0 = OpConstant %int -1",
1725                 "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one",
1726               },
1727             },
1728             // Skip folding if any vector operands or components of the operands
1729             // have undetermined value.
1730             {
1731               // original
1732               {
1733                 "%spec_int = OpSpecConstant %int 1",
1734                 "%spec_vec = OpSpecConstantComposite %v2int %signed_zero %spec_int",
1735                 "%spec_iadd = OpSpecConstantOp %v2int IAdd %signed_three_vec %spec_vec",
1736               },
1737               // expected
1738               {
1739                 "%spec_int = OpSpecConstant %int 1",
1740                 "%spec_vec = OpSpecConstantComposite %v2int %signed_zero %spec_int",
1741                 "%spec_iadd = OpSpecConstantOp %v2int IAdd %signed_three_vec %spec_vec",
1742               },
1743             },
1744             // Skip folding if any vector operands are defined by OpUndef
1745             {
1746               // original
1747               {
1748                 "%undef = OpUndef %int",
1749                 "%vec = OpConstantComposite %v2int %undef %signed_one",
1750                 "%spec_iadd = OpSpecConstantOp %v2int IAdd %signed_three_vec %vec",
1751               },
1752               // expected
1753               {
1754                 "%undef = OpUndef %int",
1755                 "%vec = OpConstantComposite %v2int %undef %signed_one",
1756                 "%spec_iadd = OpSpecConstantOp %v2int IAdd %signed_three_vec %vec",
1757               },
1758             },
1759         // clang-format on
1760     })));
1761 
1762 // Tests for SpecConstantOp CompositeExtract instruction
1763 INSTANTIATE_TEST_SUITE_P(
1764     CompositeExtract, FoldSpecConstantOpAndCompositePassTest,
1765     ::testing::ValuesIn(std::vector<
1766                         FoldSpecConstantOpAndCompositePassTestCase>({
1767         // clang-format off
1768             // normal vector
1769             {
1770               // original
1771               {
1772                 "%r = OpSpecConstantOp %int CompositeExtract %signed_three_vec 0",
1773                 "%x = OpSpecConstantOp %int CompositeExtract %v4int_0_1_2_3 0",
1774                 "%y = OpSpecConstantOp %int CompositeExtract %v4int_0_1_2_3 1",
1775                 "%z = OpSpecConstantOp %int CompositeExtract %v4int_0_1_2_3 2",
1776                 "%w = OpSpecConstantOp %int CompositeExtract %v4int_0_1_2_3 3",
1777               },
1778               // expected
1779               {
1780                 "%r = OpConstant %int 3",
1781                 "%x = OpConstant %int 0",
1782                 "%y = OpConstant %int 1",
1783                 "%z = OpConstant %int 2",
1784                 "%w = OpConstant %int 3",
1785               },
1786             },
1787             // null vector
1788             {
1789               // original
1790               {
1791                 "%x = OpSpecConstantOp %int CompositeExtract %signed_null_vec 0",
1792                 "%y = OpSpecConstantOp %int CompositeExtract %signed_null_vec 1",
1793                 "%null_v4int = OpConstantNull %v4int",
1794                 "%z = OpSpecConstantOp %int CompositeExtract %signed_null_vec 2",
1795               },
1796               // expected
1797               {
1798                 "%x = OpConstantNull %int",
1799                 "%y = OpConstantNull %int",
1800                 "%null_v4int = OpConstantNull %v4int",
1801                 "%z = OpConstantNull %int",
1802               }
1803             },
1804             // normal flat struct
1805             {
1806               // original
1807               {
1808                 "%float_1 = OpConstant %float 1",
1809                 "%flat_1 = OpConstantComposite %flat_struct %bool_true %signed_null %float_1",
1810                 "%extract_bool = OpSpecConstantOp %bool CompositeExtract %flat_1 0",
1811                 "%extract_int = OpSpecConstantOp %int CompositeExtract %flat_1 1",
1812                 "%extract_float_1 = OpSpecConstantOp %float CompositeExtract %flat_1 2",
1813                 // foldable composite constants built with OpSpecConstantComposite
1814                 // should also be processed.
1815                 "%flat_2 = OpSpecConstantComposite %flat_struct %bool_true %signed_null %float_1",
1816                 "%extract_float_2 = OpSpecConstantOp %float CompositeExtract %flat_2 2",
1817               },
1818               // expected
1819               {
1820                 "%float_1 = OpConstant %float 1",
1821                 "%flat_1 = OpConstantComposite %flat_struct %bool_true %signed_null %float_1",
1822                 "%extract_bool = OpConstantTrue %bool",
1823                 "%extract_int = OpConstantNull %int",
1824                 "%extract_float_1 = OpConstant %float 1",
1825                 "%flat_2 = OpConstantComposite %flat_struct %bool_true %signed_null %float_1",
1826                 "%extract_float_2 = OpConstant %float 1",
1827               },
1828             },
1829             // null flat struct
1830             {
1831               // original
1832               {
1833                 "%flat = OpConstantNull %flat_struct",
1834                 "%extract_bool = OpSpecConstantOp %bool CompositeExtract %flat 0",
1835                 "%extract_int = OpSpecConstantOp %int CompositeExtract %flat 1",
1836                 "%extract_float = OpSpecConstantOp %float CompositeExtract %flat 2",
1837               },
1838               // expected
1839               {
1840                 "%flat = OpConstantNull %flat_struct",
1841                 "%extract_bool = OpConstantNull %bool",
1842                 "%extract_int = OpConstantNull %int",
1843                 "%extract_float = OpConstantNull %float",
1844               },
1845             },
1846             // normal nested struct
1847             {
1848               // original
1849               {
1850                 "%float_1 = OpConstant %float 1",
1851                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1",
1852                 "%outer = OpConstantComposite %outer_struct %inner %signed_one",
1853                 "%extract_inner = OpSpecConstantOp %inner_struct CompositeExtract %outer 0",
1854                 "%extract_int = OpSpecConstantOp %int CompositeExtract %outer 1",
1855                 "%extract_inner_float = OpSpecConstantOp %float CompositeExtract %outer 0 2",
1856               },
1857               // expected
1858               {
1859                 "%float_1 = OpConstant %float 1",
1860                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1",
1861                 "%outer = OpConstantComposite %outer_struct %inner %signed_one",
1862                 "%extract_inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1",
1863                 "%extract_int = OpConstant %int 1",
1864                 "%extract_inner_float = OpConstant %float 1",
1865               },
1866             },
1867             // null nested struct
1868             {
1869               // original
1870               {
1871                 "%outer = OpConstantNull %outer_struct",
1872                 "%extract_inner = OpSpecConstantOp %inner_struct CompositeExtract %outer 0",
1873                 "%extract_int = OpSpecConstantOp %int CompositeExtract %outer 1",
1874                 "%extract_inner_float = OpSpecConstantOp %float CompositeExtract %outer 0 2",
1875               },
1876               // expected
1877               {
1878                 "%outer = OpConstantNull %outer_struct",
1879                 "%extract_inner = OpConstantNull %inner_struct",
1880                 "%extract_int = OpConstantNull %int",
1881                 "%extract_inner_float = OpConstantNull %float",
1882               },
1883             },
1884             // skip folding if the any composite constant's value are not fully
1885             // determined, even though the extracting target might have
1886             // determined value.
1887             {
1888               // original
1889               {
1890                 "%float_1 = OpConstant %float 1",
1891                 "%spec_float = OpSpecConstant %float 1",
1892                 "%spec_inner = OpSpecConstantComposite %inner_struct %bool_true %signed_null %spec_float",
1893                 "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %signed_one",
1894                 "%spec_vec = OpSpecConstantComposite %v2float %spec_float %float_1",
1895                 "%extract_inner = OpSpecConstantOp %int CompositeExtract %spec_inner 1",
1896                 "%extract_outer = OpSpecConstantOp %int CompositeExtract %spec_outer 1",
1897                 "%extract_vec = OpSpecConstantOp %float CompositeExtract %spec_vec 1",
1898               },
1899               // expected
1900               {
1901                 "%float_1 = OpConstant %float 1",
1902                 "%spec_float = OpSpecConstant %float 1",
1903                 "%spec_inner = OpSpecConstantComposite %inner_struct %bool_true %signed_null %spec_float",
1904                 "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %signed_one",
1905                 "%spec_vec = OpSpecConstantComposite %v2float %spec_float %float_1",
1906                 "%extract_inner = OpSpecConstantOp %int CompositeExtract %spec_inner 1",
1907                 "%extract_outer = OpSpecConstantOp %int CompositeExtract %spec_outer 1",
1908                 "%extract_vec = OpSpecConstantOp %float CompositeExtract %spec_vec 1",
1909               },
1910             },
1911             // skip if the composite constant depends on the result of OpUndef,
1912             // even though the composite extract target element does not depends
1913             // on the OpUndef.
1914             {
1915               // original
1916               {
1917                 "%undef = OpUndef %float",
1918                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef",
1919                 "%outer = OpConstantComposite %outer_struct %inner %signed_one",
1920                 "%extract_inner = OpSpecConstantOp %int CompositeExtract %inner 1",
1921                 "%extract_outer = OpSpecConstantOp %int CompositeExtract %outer 1",
1922               },
1923               // expected
1924               {
1925                 "%undef = OpUndef %float",
1926                 "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef",
1927                 "%outer = OpConstantComposite %outer_struct %inner %signed_one",
1928                 "%extract_inner = OpSpecConstantOp %int CompositeExtract %inner 1",
1929                 "%extract_outer = OpSpecConstantOp %int CompositeExtract %outer 1",
1930               },
1931             },
1932             // TODO(qining): Add tests for Array and other composite type constants.
1933         // clang-format on
1934     })));
1935 
1936 // Tests the swizzle operations for spec const vectors.
1937 INSTANTIATE_TEST_SUITE_P(
1938     VectorShuffle, FoldSpecConstantOpAndCompositePassTest,
1939     ::testing::ValuesIn(std::vector<
1940                         FoldSpecConstantOpAndCompositePassTestCase>({
1941         // clang-format off
1942             // normal vector
1943             {
1944               // original
1945               {
1946                 "%xy = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 0 1",
1947                 "%yz = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 1 2",
1948                 "%zw = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 2 3",
1949                 "%wx = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 3 0",
1950                 "%xx = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 0 0",
1951                 "%yyy = OpSpecConstantOp %v3int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 1 1 1",
1952                 "%wwww = OpSpecConstantOp %v4int VectorShuffle %v4int_0_1_2_3 %v4int_0_1_2_3 2 2 2 2",
1953               },
1954               // expected
1955               {
1956                 "%xy = OpConstantComposite %v2int %signed_zero %signed_one",
1957                 "%yz = OpConstantComposite %v2int %signed_one %signed_two",
1958                 "%zw = OpConstantComposite %v2int %signed_two %signed_three",
1959                 "%wx = OpConstantComposite %v2int %signed_three %signed_zero",
1960                 "%xx = OpConstantComposite %v2int %signed_zero %signed_zero",
1961                 "%yyy = OpConstantComposite %v3int %signed_one %signed_one %signed_one",
1962                 "%wwww = OpConstantComposite %v4int %signed_two %signed_two %signed_two %signed_two",
1963               },
1964             },
1965             // null vector
1966             {
1967               // original
1968               {
1969                 "%a = OpSpecConstantOp %v2int VectorShuffle %signed_null_vec %v4int_0_1_2_3 0 1",
1970                 "%b = OpSpecConstantOp %v2int VectorShuffle %signed_null_vec %v4int_0_1_2_3 2 3",
1971                 "%c = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %signed_null_vec 3 4",
1972                 "%d = OpSpecConstantOp %v2int VectorShuffle %signed_null_vec %signed_null_vec 1 2",
1973               },
1974               // expected
1975               {
1976                 "%a = OpConstantComposite %v2int %signed_null %signed_null",
1977                 "%b = OpConstantComposite %v2int %signed_zero %signed_one",
1978                 "%c = OpConstantComposite %v2int %signed_three %signed_null",
1979                 "%d = OpConstantComposite %v2int %signed_null %signed_null",
1980               }
1981             },
1982             // skip if any of the components of the vector operands do not have
1983             // determined value, even though the result vector might not be
1984             // built with those undermined values.
1985             {
1986               // original
1987               {
1988                 "%spec_int = OpSpecConstant %int 1",
1989                 "%spec_ivec = OpSpecConstantComposite %v2int %signed_null %spec_int",
1990                 "%a = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %spec_ivec 0 1",
1991                 "%b = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %spec_ivec 3 4",
1992               },
1993               // expected
1994               {
1995                 "%spec_int = OpSpecConstant %int 1",
1996                 "%spec_ivec = OpSpecConstantComposite %v2int %signed_null %spec_int",
1997                 "%a = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %spec_ivec 0 1",
1998                 "%b = OpSpecConstantOp %v2int VectorShuffle %v4int_0_1_2_3 %spec_ivec 3 4",
1999               },
2000             },
2001             // Skip if any components of the two vector operands depend on
2002             // the result of OpUndef. Even though the selected components do
2003             // not depend on the OpUndef result.
2004             {
2005               // original
2006               {
2007                 "%undef = OpUndef %int",
2008                 "%vec_1 = OpConstantComposite %v2int %undef %signed_one",
2009                 "%dep = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 0 3",
2010                 "%not_dep_element = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 1 3",
2011                 "%no_dep_vector = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 2 3",
2012               },
2013               // expected
2014               {
2015                 "%undef = OpUndef %int",
2016                 "%vec_1 = OpConstantComposite %v2int %undef %signed_one",
2017                 "%dep = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 0 3",
2018                 "%not_dep_element = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 1 3",
2019                 "%no_dep_vector = OpSpecConstantOp %v2int VectorShuffle %vec_1 %signed_three_vec 2 3",
2020               },
2021             },
2022         // clang-format on
2023     })));
2024 
2025 // Test with long use-def chain.
2026 INSTANTIATE_TEST_SUITE_P(
2027     LongDefUseChain, FoldSpecConstantOpAndCompositePassTest,
2028     ::testing::ValuesIn(std::vector<
2029                         FoldSpecConstantOpAndCompositePassTestCase>({
2030         // clang-format off
2031         // Long Def-Use chain with binary operations.
2032         {
2033             // original
2034             {
2035               "%array_size = OpConstant %int 4",
2036               "%type_arr_int_4 = OpTypeArray %int %array_size",
2037               "%spec_int_0 = OpConstant %int 100",
2038               "%spec_int_1 = OpConstant %int 1",
2039               "%spec_int_2 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_1",
2040               "%spec_int_3 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_2",
2041               "%spec_int_4 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_3",
2042               "%spec_int_5 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_4",
2043               "%spec_int_6 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_5",
2044               "%spec_int_7 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_6",
2045               "%spec_int_8 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_7",
2046               "%spec_int_9 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_8",
2047               "%spec_int_10 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_9",
2048               "%spec_int_11 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_10",
2049               "%spec_int_12 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_11",
2050               "%spec_int_13 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_12",
2051               "%spec_int_14 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_13",
2052               "%spec_int_15 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_14",
2053               "%spec_int_16 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_15",
2054               "%spec_int_17 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_16",
2055               "%spec_int_18 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_17",
2056               "%spec_int_19 = OpSpecConstantOp %int IAdd %spec_int_0 %spec_int_18",
2057               "%spec_int_20 = OpSpecConstantOp %int ISub %spec_int_0 %spec_int_19",
2058               "%used_vec_a = OpSpecConstantComposite %v2int %spec_int_18 %spec_int_19",
2059               "%used_vec_b = OpSpecConstantOp %v2int IMul %used_vec_a %used_vec_a",
2060               "%spec_int_21 = OpSpecConstantOp %int CompositeExtract %used_vec_b 0",
2061               "%array = OpConstantComposite %type_arr_int_4 %spec_int_20 %spec_int_20 %spec_int_21 %spec_int_21",
2062               // Spec constants whose values can not be fully resolved should
2063               // not be processed.
2064               "%spec_int_22 = OpSpecConstant %int 123",
2065               "%spec_int_23 = OpSpecConstantOp %int IAdd %spec_int_22 %signed_one",
2066             },
2067             // expected
2068             {
2069               "%array_size = OpConstant %int 4",
2070               "%type_arr_int_4 = OpTypeArray %int %array_size",
2071               "%spec_int_0 = OpConstant %int 100",
2072               "%spec_int_1 = OpConstant %int 1",
2073               "%spec_int_2 = OpConstant %int 101",
2074               "%spec_int_3 = OpConstant %int -1",
2075               "%spec_int_4 = OpConstant %int 99",
2076               "%spec_int_5 = OpConstant %int 1",
2077               "%spec_int_6 = OpConstant %int 101",
2078               "%spec_int_7 = OpConstant %int -1",
2079               "%spec_int_8 = OpConstant %int 99",
2080               "%spec_int_9 = OpConstant %int 1",
2081               "%spec_int_10 = OpConstant %int 101",
2082               "%spec_int_11 = OpConstant %int -1",
2083               "%spec_int_12 = OpConstant %int 99",
2084               "%spec_int_13 = OpConstant %int 1",
2085               "%spec_int_14 = OpConstant %int 101",
2086               "%spec_int_15 = OpConstant %int -1",
2087               "%spec_int_16 = OpConstant %int 101",
2088               "%spec_int_17 = OpConstant %int 201",
2089               "%spec_int_18 = OpConstant %int -101",
2090               "%spec_int_19 = OpConstant %int -1",
2091               "%spec_int_20 = OpConstant %int 101",
2092               "%used_vec_a = OpConstantComposite %v2int %spec_int_18 %spec_int_19",
2093               "%int_10201 = OpConstant %int 10201",
2094               "%int_1 = OpConstant %int 1",
2095               "%used_vec_b = OpConstantComposite %v2int %int_10201 %signed_one",
2096               "%spec_int_21 = OpConstant %int 10201",
2097               "%array = OpConstantComposite %type_arr_int_4 %spec_int_20 %spec_int_20 %spec_int_21 %spec_int_21",
2098               "%spec_int_22 = OpSpecConstant %int 123",
2099               "%spec_int_23 = OpSpecConstantOp %int IAdd %spec_int_22 %signed_one",
2100             },
2101         },
2102         // Long Def-Use chain with swizzle
2103         })));
2104 
2105 }  // namespace
2106 }  // namespace opt
2107 }  // namespace spvtools
2108