Add folding of redundant OpSelect insns
[platform/upstream/SPIRV-Tools.git] / test / opt / fold_test.cpp
1 // Copyright (c) 2016 Google Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 #include <memory>
15 #include <unordered_set>
16
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <opt/fold.h>
20
21 #include "opt/build_module.h"
22 #include "opt/def_use_manager.h"
23 #include "opt/ir_context.h"
24 #include "opt/module.h"
25 #include "pass_utils.h"
26 #include "spirv-tools/libspirv.hpp"
27
28 namespace {
29
30 using ::testing::Contains;
31
32 using namespace spvtools;
33 using spvtools::opt::analysis::DefUseManager;
34
35 template <class ResultType>
36 struct InstructionFoldingCase {
37   InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
38       : test_body(tb), id_to_fold(id), expected_result(result) {}
39
40   std::string test_body;
41   uint32_t id_to_fold;
42   ResultType expected_result;
43 };
44
45 using IntegerInstructionFoldingTest =
46     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
47
48 TEST_P(IntegerInstructionFoldingTest, Case) {
49   const auto& tc = GetParam();
50
51   // Build module.
52   std::unique_ptr<ir::IRContext> context =
53       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
54                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
55   ASSERT_NE(nullptr, context);
56
57   // Fold the instruction to test.
58   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
59   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
60   bool succeeded = opt::FoldInstruction(inst);
61
62   // Make sure the instruction folded as expected.
63   EXPECT_TRUE(succeeded);
64   if (inst != nullptr) {
65     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
66     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
67     EXPECT_EQ(inst->opcode(), SpvOpConstant);
68     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
69     const opt::analysis::IntConstant* result =
70         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
71     EXPECT_NE(result, nullptr);
72     if (result != nullptr) {
73       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
74     }
75   }
76 }
77
78 // Returns a common SPIR-V header for all of the test that follow.
79 #define INT_0_ID 100
80 #define TRUE_ID 101
81 #define VEC2_0_ID 102
82 #define INT_7_ID 103
83 const std::string& Header() {
84   static const std::string header = R"(OpCapability Shader
85 %1 = OpExtInstImport "GLSL.std.450"
86 OpMemoryModel Logical GLSL450
87 OpEntryPoint Fragment %main "main"
88 OpExecutionMode %main OriginUpperLeft
89 OpSource GLSL 140
90 OpName %main "main"
91 %void = OpTypeVoid
92 %void_func = OpTypeFunction %void
93 %bool = OpTypeBool
94 %float16 = OpTypeFloat 16
95 %float = OpTypeFloat 32
96 %double = OpTypeFloat 64
97 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
98 %true = OpConstantTrue %bool
99 %false = OpConstantFalse %bool
100 %short = OpTypeInt 16 1
101 %int = OpTypeInt 32 1
102 %long = OpTypeInt 64 1
103 %uint = OpTypeInt 32 1
104 %v2int = OpTypeVector %int 2
105 %v4int = OpTypeVector %int 4
106 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
107 %_ptr_int = OpTypePointer Function %int
108 %_ptr_uint = OpTypePointer Function %uint
109 %_ptr_bool = OpTypePointer Function %bool
110 %short_0 = OpConstant %short 0
111 %short_3 = OpConstant %short 3
112 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
113 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
114 %int_0 = OpConstant %int 0
115 %int_1 = OpConstant %int 1
116 %int_3 = OpConstant %int 3
117 %int_min = OpConstant %int -2147483648
118 %int_max = OpConstant %int 2147483647
119 %long_0 = OpConstant %long 0
120 %long_3 = OpConstant %long 3
121 %uint_0 = OpConstant %uint 0
122 %uint_3 = OpConstant %uint 3
123 %uint_32 = OpConstant %uint 32
124 %uint_max = OpConstant %uint -1
125 %v2int_undef = OpUndef %v2int
126 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
127 %102 = OpConstantComposite %v2int %103 %103
128 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
129 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
130 %float16_0 = OpConstant %float16 0
131 %float16_1 = OpConstant %float16 1
132 %float16_2 = OpConstant %float16 2
133 %float_n1 = OpConstant %float -1
134 %float_0 = OpConstant %float 0
135 %float_1 = OpConstant %float 1
136 %float_2 = OpConstant %float 2
137 %float_3 = OpConstant %float 3
138 %double_n1 = OpConstant %double -1
139 %double_0 = OpConstant %double 0
140 %double_1 = OpConstant %double 1
141 %double_2 = OpConstant %double 2
142 %double_3 = OpConstant %double 3
143 )";
144
145   return header;
146 }
147
148 // clang-format off
149 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
150                         ::testing::Values(
151   // Test case 0: fold 0*n
152   InstructionFoldingCase<uint32_t>(
153     Header() + "%main = OpFunction %void None %void_func\n" +
154     "%main_lab = OpLabel\n" +
155            "%n = OpVariable %_ptr_int Function\n" +
156         "%load = OpLoad %int %n\n" +
157            "%2 = OpIMul %int %int_0 %load\n" +
158                 "OpReturn\n" +
159                 "OpFunctionEnd",
160     2, 0),
161   // Test case 1: fold n*0
162   InstructionFoldingCase<uint32_t>(
163     Header() + "%main = OpFunction %void None %void_func\n" +
164         "%main_lab = OpLabel\n" +
165         "%n = OpVariable %_ptr_int Function\n" +
166         "%load = OpLoad %int %n\n" +
167         "%2 = OpIMul %int %load %int_0\n" +
168         "OpReturn\n" +
169         "OpFunctionEnd",
170     2, 0),
171   // Test case 2: fold 0/n (signed)
172   InstructionFoldingCase<uint32_t>(
173     Header() + "%main = OpFunction %void None %void_func\n" +
174         "%main_lab = OpLabel\n" +
175         "%n = OpVariable %_ptr_int Function\n" +
176         "%load = OpLoad %int %n\n" +
177         "%2 = OpSDiv %int %int_0 %load\n" +
178         "OpReturn\n" +
179         "OpFunctionEnd",
180         2, 0),
181   // Test case 3: fold n/0 (signed)
182   InstructionFoldingCase<uint32_t>(
183     Header() + "%main = OpFunction %void None %void_func\n" +
184         "%main_lab = OpLabel\n" +
185         "%n = OpVariable %_ptr_int Function\n" +
186         "%load = OpLoad %int %n\n" +
187         "%2 = OpSDiv %int %load %int_0\n" +
188         "OpReturn\n" +
189         "OpFunctionEnd",
190     2, 0),
191   // Test case 4: fold 0/n (unsigned)
192   InstructionFoldingCase<uint32_t>(
193     Header() + "%main = OpFunction %void None %void_func\n" +
194         "%main_lab = OpLabel\n" +
195         "%n = OpVariable %_ptr_uint Function\n" +
196         "%load = OpLoad %uint %n\n" +
197         "%2 = OpUDiv %uint %uint_0 %load\n" +
198         "OpReturn\n" +
199         "OpFunctionEnd",
200     2, 0),
201   // Test case 5: fold n/0 (unsigned)
202   InstructionFoldingCase<uint32_t>(
203     Header() + "%main = OpFunction %void None %void_func\n" +
204         "%main_lab = OpLabel\n" +
205         "%n = OpVariable %_ptr_int Function\n" +
206         "%load = OpLoad %int %n\n" +
207         "%2 = OpSDiv %int %load %int_0\n" +
208         "OpReturn\n" +
209         "OpFunctionEnd",
210     2, 0),
211   // Test case 6: fold 0 remainder n
212   InstructionFoldingCase<uint32_t>(
213     Header() + "%main = OpFunction %void None %void_func\n" +
214         "%main_lab = OpLabel\n" +
215         "%n = OpVariable %_ptr_int Function\n" +
216         "%load = OpLoad %int %n\n" +
217         "%2 = OpSRem %int %int_0 %load\n" +
218         "OpReturn\n" +
219         "OpFunctionEnd",
220     2, 0),
221   // Test case 7: fold n remainder 0
222   InstructionFoldingCase<uint32_t>(
223     Header() + "%main = OpFunction %void None %void_func\n" +
224         "%main_lab = OpLabel\n" +
225         "%n = OpVariable %_ptr_int Function\n" +
226         "%load = OpLoad %int %n\n" +
227         "%2 = OpSRem %int %load %int_0\n" +
228         "OpReturn\n" +
229         "OpFunctionEnd",
230     2, 0),
231   // Test case 8: fold 0%n (signed)
232   InstructionFoldingCase<uint32_t>(
233     Header() + "%main = OpFunction %void None %void_func\n" +
234         "%main_lab = OpLabel\n" +
235         "%n = OpVariable %_ptr_int Function\n" +
236         "%load = OpLoad %int %n\n" +
237         "%2 = OpSMod %int %int_0 %load\n" +
238         "OpReturn\n" +
239         "OpFunctionEnd",
240     2, 0),
241   // Test case 9: fold n%0 (signed)
242   InstructionFoldingCase<uint32_t>(
243     Header() + "%main = OpFunction %void None %void_func\n" +
244         "%main_lab = OpLabel\n" +
245         "%n = OpVariable %_ptr_int Function\n" +
246         "%load = OpLoad %int %n\n" +
247         "%2 = OpSMod %int %load %int_0\n" +
248         "OpReturn\n" +
249         "OpFunctionEnd",
250     2, 0),
251   // Test case 10: fold 0%n (unsigned)
252   InstructionFoldingCase<uint32_t>(
253     Header() + "%main = OpFunction %void None %void_func\n" +
254         "%main_lab = OpLabel\n" +
255         "%n = OpVariable %_ptr_uint Function\n" +
256         "%load = OpLoad %uint %n\n" +
257         "%2 = OpUMod %uint %uint_0 %load\n" +
258         "OpReturn\n" +
259         "OpFunctionEnd",
260     2, 0),
261   // Test case 11: fold n%0 (unsigned)
262   InstructionFoldingCase<uint32_t>(
263     Header() + "%main = OpFunction %void None %void_func\n" +
264         "%main_lab = OpLabel\n" +
265         "%n = OpVariable %_ptr_uint Function\n" +
266         "%load = OpLoad %uint %n\n" +
267         "%2 = OpUMod %uint %load %uint_0\n" +
268         "OpReturn\n" +
269         "OpFunctionEnd",
270     2, 0),
271   // Test case 12: fold n << 32
272   InstructionFoldingCase<uint32_t>(
273       Header() + "%main = OpFunction %void None %void_func\n" +
274           "%main_lab = OpLabel\n" +
275           "%n = OpVariable %_ptr_uint Function\n" +
276           "%load = OpLoad %uint %n\n" +
277           "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
278           "OpReturn\n" +
279           "OpFunctionEnd",
280       2, 0),
281   // Test case 13: fold n >> 32
282   InstructionFoldingCase<uint32_t>(
283       Header() + "%main = OpFunction %void None %void_func\n" +
284           "%main_lab = OpLabel\n" +
285           "%n = OpVariable %_ptr_uint Function\n" +
286           "%load = OpLoad %uint %n\n" +
287           "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
288           "OpReturn\n" +
289           "OpFunctionEnd",
290       2, 0),
291   // Test case 14: fold n | 0xFFFFFFFF
292   InstructionFoldingCase<uint32_t>(
293       Header() + "%main = OpFunction %void None %void_func\n" +
294   "%main_lab = OpLabel\n" +
295   "%n = OpVariable %_ptr_uint Function\n" +
296   "%load = OpLoad %uint %n\n" +
297   "%2 = OpBitwiseOr %uint %load %uint_max\n" +
298   "OpReturn\n" +
299   "OpFunctionEnd",
300   2, 0xFFFFFFFF),
301   // Test case 15: fold 0xFFFFFFFF | n
302   InstructionFoldingCase<uint32_t>(
303       Header() + "%main = OpFunction %void None %void_func\n" +
304           "%main_lab = OpLabel\n" +
305           "%n = OpVariable %_ptr_uint Function\n" +
306           "%load = OpLoad %uint %n\n" +
307           "%2 = OpBitwiseOr %uint %uint_max %load\n" +
308           "OpReturn\n" +
309           "OpFunctionEnd",
310       2, 0xFFFFFFFF),
311   // Test case 16: fold n & 0
312   InstructionFoldingCase<uint32_t>(
313       Header() + "%main = OpFunction %void None %void_func\n" +
314           "%main_lab = OpLabel\n" +
315           "%n = OpVariable %_ptr_uint Function\n" +
316           "%load = OpLoad %uint %n\n" +
317           "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
318           "OpReturn\n" +
319           "OpFunctionEnd",
320       2, 0)
321 ));
322 // clang-format on
323
324 using BooleanInstructionFoldingTest =
325     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
326
327 TEST_P(BooleanInstructionFoldingTest, Case) {
328   const auto& tc = GetParam();
329
330   // Build module.
331   std::unique_ptr<ir::IRContext> context =
332       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
333                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
334   ASSERT_NE(nullptr, context);
335
336   // Fold the instruction to test.
337   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
338   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
339   bool succeeded = opt::FoldInstruction(inst);
340
341   // Make sure the instruction folded as expected.
342   EXPECT_TRUE(succeeded);
343   if (inst != nullptr) {
344     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
345     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
346     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
347     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
348     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
349     const opt::analysis::BoolConstant* result =
350         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
351     EXPECT_NE(result, nullptr);
352     if (result != nullptr) {
353       EXPECT_EQ(result->value(), tc.expected_result);
354     }
355   }
356 }
357
358 // clang-format off
359 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest,
360                         ::testing::Values(
361   // Test case 0: fold true || n
362   InstructionFoldingCase<bool>(
363       Header() + "%main = OpFunction %void None %void_func\n" +
364           "%main_lab = OpLabel\n" +
365           "%n = OpVariable %_ptr_bool Function\n" +
366           "%load = OpLoad %bool %n\n" +
367           "%2 = OpLogicalOr %bool %true %load\n" +
368           "OpReturn\n" +
369           "OpFunctionEnd",
370       2, true),
371   // Test case 1: fold n || true
372   InstructionFoldingCase<bool>(
373       Header() + "%main = OpFunction %void None %void_func\n" +
374           "%main_lab = OpLabel\n" +
375           "%n = OpVariable %_ptr_bool Function\n" +
376           "%load = OpLoad %bool %n\n" +
377           "%2 = OpLogicalOr %bool %load %true\n" +
378           "OpReturn\n" +
379           "OpFunctionEnd",
380       2, true),
381   // Test case 2: fold false && n
382   InstructionFoldingCase<bool>(
383       Header() + "%main = OpFunction %void None %void_func\n" +
384           "%main_lab = OpLabel\n" +
385           "%n = OpVariable %_ptr_bool Function\n" +
386           "%load = OpLoad %bool %n\n" +
387           "%2 = OpLogicalAnd %bool %false %load\n" +
388           "OpReturn\n" +
389           "OpFunctionEnd",
390       2, false),
391   // Test case 3: fold n && false
392   InstructionFoldingCase<bool>(
393       Header() + "%main = OpFunction %void None %void_func\n" +
394           "%main_lab = OpLabel\n" +
395           "%n = OpVariable %_ptr_bool Function\n" +
396           "%load = OpLoad %bool %n\n" +
397           "%2 = OpLogicalAnd %bool %load %false\n" +
398           "OpReturn\n" +
399           "OpFunctionEnd",
400       2, false),
401   // Test case 4: fold n < 0 (unsigned)
402   InstructionFoldingCase<bool>(
403       Header() + "%main = OpFunction %void None %void_func\n" +
404           "%main_lab = OpLabel\n" +
405           "%n = OpVariable %_ptr_uint Function\n" +
406           "%load = OpLoad %uint %n\n" +
407           "%2 = OpULessThan %bool %load %uint_0\n" +
408           "OpReturn\n" +
409           "OpFunctionEnd",
410       2, false),
411   // Test case 5: fold UINT_MAX < n (unsigned)
412   InstructionFoldingCase<bool>(
413       Header() + "%main = OpFunction %void None %void_func\n" +
414           "%main_lab = OpLabel\n" +
415           "%n = OpVariable %_ptr_uint Function\n" +
416           "%load = OpLoad %uint %n\n" +
417           "%2 = OpULessThan %bool %uint_max %load\n" +
418           "OpReturn\n" +
419           "OpFunctionEnd",
420       2, false),
421   // Test case 6: fold INT_MAX < n (signed)
422   InstructionFoldingCase<bool>(
423       Header() + "%main = OpFunction %void None %void_func\n" +
424           "%main_lab = OpLabel\n" +
425           "%n = OpVariable %_ptr_int Function\n" +
426           "%load = OpLoad %int %n\n" +
427           "%2 = OpSLessThan %bool %int_max %load\n" +
428           "OpReturn\n" +
429           "OpFunctionEnd",
430       2, false),
431   // Test case 7: fold n < INT_MIN (signed)
432   InstructionFoldingCase<bool>(
433       Header() + "%main = OpFunction %void None %void_func\n" +
434           "%main_lab = OpLabel\n" +
435           "%n = OpVariable %_ptr_int Function\n" +
436           "%load = OpLoad %int %n\n" +
437           "%2 = OpSLessThan %bool %load %int_min\n" +
438           "OpReturn\n" +
439           "OpFunctionEnd",
440       2, false),
441   // Test case 8: fold 0 > n (unsigned)
442   InstructionFoldingCase<bool>(
443       Header() + "%main = OpFunction %void None %void_func\n" +
444           "%main_lab = OpLabel\n" +
445           "%n = OpVariable %_ptr_uint Function\n" +
446           "%load = OpLoad %uint %n\n" +
447           "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
448           "OpReturn\n" +
449           "OpFunctionEnd",
450       2, false),
451   // Test case 9: fold n > UINT_MAX (unsigned)
452   InstructionFoldingCase<bool>(
453       Header() + "%main = OpFunction %void None %void_func\n" +
454           "%main_lab = OpLabel\n" +
455           "%n = OpVariable %_ptr_uint Function\n" +
456           "%load = OpLoad %uint %n\n" +
457           "%2 = OpUGreaterThan %bool %load %uint_max\n" +
458           "OpReturn\n" +
459           "OpFunctionEnd",
460       2, false),
461   // Test case 10: fold n > INT_MAX (signed)
462   InstructionFoldingCase<bool>(
463       Header() + "%main = OpFunction %void None %void_func\n" +
464           "%main_lab = OpLabel\n" +
465           "%n = OpVariable %_ptr_int Function\n" +
466           "%load = OpLoad %int %n\n" +
467           "%2 = OpSGreaterThan %bool %load %int_max\n" +
468           "OpReturn\n" +
469           "OpFunctionEnd",
470       2, false),
471   // Test case 11: fold INT_MIN > n (signed)
472   InstructionFoldingCase<bool>(
473       Header() + "%main = OpFunction %void None %void_func\n" +
474           "%main_lab = OpLabel\n" +
475           "%n = OpVariable %_ptr_uint Function\n" +
476           "%load = OpLoad %uint %n\n" +
477           "%2 = OpSGreaterThan %bool %int_min %load\n" +
478           "OpReturn\n" +
479           "OpFunctionEnd",
480       2, false),
481   // Test case 12: fold 0 <= n (unsigned)
482   InstructionFoldingCase<bool>(
483       Header() + "%main = OpFunction %void None %void_func\n" +
484           "%main_lab = OpLabel\n" +
485           "%n = OpVariable %_ptr_uint Function\n" +
486           "%load = OpLoad %uint %n\n" +
487           "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
488           "OpReturn\n" +
489           "OpFunctionEnd",
490       2, true),
491   // Test case 13: fold n <= UINT_MAX (unsigned)
492   InstructionFoldingCase<bool>(
493       Header() + "%main = OpFunction %void None %void_func\n" +
494           "%main_lab = OpLabel\n" +
495           "%n = OpVariable %_ptr_uint Function\n" +
496           "%load = OpLoad %uint %n\n" +
497           "%2 = OpULessThanEqual %bool %load %uint_max\n" +
498           "OpReturn\n" +
499           "OpFunctionEnd",
500       2, true),
501   // Test case 14: fold INT_MIN <= n (signed)
502   InstructionFoldingCase<bool>(
503       Header() + "%main = OpFunction %void None %void_func\n" +
504           "%main_lab = OpLabel\n" +
505           "%n = OpVariable %_ptr_int Function\n" +
506           "%load = OpLoad %int %n\n" +
507           "%2 = OpSLessThanEqual %bool %int_min %load\n" +
508           "OpReturn\n" +
509           "OpFunctionEnd",
510       2, true),
511   // Test case 15: fold n <= INT_MAX (signed)
512   InstructionFoldingCase<bool>(
513       Header() + "%main = OpFunction %void None %void_func\n" +
514           "%main_lab = OpLabel\n" +
515           "%n = OpVariable %_ptr_int Function\n" +
516           "%load = OpLoad %int %n\n" +
517           "%2 = OpSLessThanEqual %bool %load %int_max\n" +
518           "OpReturn\n" +
519           "OpFunctionEnd",
520       2, true),
521   // Test case 16: fold n >= 0 (unsigned)
522   InstructionFoldingCase<bool>(
523       Header() + "%main = OpFunction %void None %void_func\n" +
524           "%main_lab = OpLabel\n" +
525           "%n = OpVariable %_ptr_uint Function\n" +
526           "%load = OpLoad %uint %n\n" +
527           "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
528           "OpReturn\n" +
529           "OpFunctionEnd",
530       2, true),
531   // Test case 17: fold UINT_MAX >= n (unsigned)
532   InstructionFoldingCase<bool>(
533       Header() + "%main = OpFunction %void None %void_func\n" +
534           "%main_lab = OpLabel\n" +
535           "%n = OpVariable %_ptr_uint Function\n" +
536           "%load = OpLoad %uint %n\n" +
537           "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
538           "OpReturn\n" +
539           "OpFunctionEnd",
540       2, true),
541   // Test case 18: fold n >= INT_MIN (signed)
542   InstructionFoldingCase<bool>(
543       Header() + "%main = OpFunction %void None %void_func\n" +
544           "%main_lab = OpLabel\n" +
545           "%n = OpVariable %_ptr_int Function\n" +
546           "%load = OpLoad %int %n\n" +
547           "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
548           "OpReturn\n" +
549           "OpFunctionEnd",
550       2, true),
551   // Test case 19: fold INT_MAX >= n (signed)
552   InstructionFoldingCase<bool>(
553       Header() + "%main = OpFunction %void None %void_func\n" +
554           "%main_lab = OpLabel\n" +
555           "%n = OpVariable %_ptr_int Function\n" +
556           "%load = OpLoad %int %n\n" +
557           "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
558           "OpReturn\n" +
559           "OpFunctionEnd",
560       2, true)
561 ));
562 // clang-format on
563
564 using FloatInstructionFoldingTest =
565     ::testing::TestWithParam<InstructionFoldingCase<float>>;
566
567 TEST_P(FloatInstructionFoldingTest, Case) {
568   const auto& tc = GetParam();
569
570   // Build module.
571   std::unique_ptr<ir::IRContext> context =
572       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
573                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
574   ASSERT_NE(nullptr, context);
575
576   // Fold the instruction to test.
577   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
578   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
579   bool succeeded = opt::FoldInstruction(inst);
580
581   // Make sure the instruction folded as expected.
582   EXPECT_TRUE(succeeded);
583   if (inst != nullptr) {
584     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
585     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
586     EXPECT_EQ(inst->opcode(), SpvOpConstant);
587     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
588     const opt::analysis::FloatConstant* result =
589         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
590     EXPECT_NE(result, nullptr);
591     if (result != nullptr) {
592       EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
593     }
594   }
595 }
596
597 // Not testing NaNs because there are no expectations concerning NaNs according
598 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
599 // specification.
600
601 // clang-format off
602 INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
603 ::testing::Values(
604     // Test case 0: Fold 2.0 - 1.0
605     InstructionFoldingCase<float>(
606         Header() + "%main = OpFunction %void None %void_func\n" +
607             "%main_lab = OpLabel\n" +
608             "%2 = OpFSub %float %float_2 %float_1\n" +
609             "OpReturn\n" +
610             "OpFunctionEnd",
611         2, 1.0),
612     // Test case 1: Fold 2.0 + 1.0
613     InstructionFoldingCase<float>(
614         Header() + "%main = OpFunction %void None %void_func\n" +
615             "%main_lab = OpLabel\n" +
616             "%2 = OpFAdd %float %float_2 %float_1\n" +
617             "OpReturn\n" +
618             "OpFunctionEnd",
619         2, 3.0),
620     // Test case 2: Fold 3.0 * 2.0
621     InstructionFoldingCase<float>(
622         Header() + "%main = OpFunction %void None %void_func\n" +
623             "%main_lab = OpLabel\n" +
624             "%2 = OpFMul %float %float_3 %float_2\n" +
625             "OpReturn\n" +
626             "OpFunctionEnd",
627         2, 6.0),
628     // Test case 3: Fold 1.0 / 2.0
629     InstructionFoldingCase<float>(
630         Header() + "%main = OpFunction %void None %void_func\n" +
631             "%main_lab = OpLabel\n" +
632             "%2 = OpFDiv %float %float_1 %float_2\n" +
633             "OpReturn\n" +
634             "OpFunctionEnd",
635         2, 0.5),
636     // Test case 4: Fold 1.0 / 0.0
637     InstructionFoldingCase<float>(
638         Header() + "%main = OpFunction %void None %void_func\n" +
639             "%main_lab = OpLabel\n" +
640             "%2 = OpFDiv %float %float_1 %float_0\n" +
641             "OpReturn\n" +
642             "OpFunctionEnd",
643         2, std::numeric_limits<float>::infinity()),
644     // Test case 4: Fold -1.0 / 0.0
645     InstructionFoldingCase<float>(
646         Header() + "%main = OpFunction %void None %void_func\n" +
647             "%main_lab = OpLabel\n" +
648             "%2 = OpFDiv %float %float_n1 %float_0\n" +
649             "OpReturn\n" +
650             "OpFunctionEnd",
651         2, -std::numeric_limits<float>::infinity())
652 ));
653 // clang-format on
654
655 using DoubleInstructionFoldingTest =
656     ::testing::TestWithParam<InstructionFoldingCase<double>>;
657
658 TEST_P(DoubleInstructionFoldingTest, Case) {
659   const auto& tc = GetParam();
660
661   // Build module.
662   std::unique_ptr<ir::IRContext> context =
663       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
664                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
665   ASSERT_NE(nullptr, context);
666
667   // Fold the instruction to test.
668   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
669   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
670   bool succeeded = opt::FoldInstruction(inst);
671
672   // Make sure the instruction folded as expected.
673   EXPECT_TRUE(succeeded);
674   if (inst != nullptr) {
675     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
676     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
677     EXPECT_EQ(inst->opcode(), SpvOpConstant);
678     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
679     const opt::analysis::FloatConstant* result =
680         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
681     EXPECT_NE(result, nullptr);
682     if (result != nullptr) {
683       EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
684     }
685   }
686 }
687
688 // clang-format off
689 INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
690 ::testing::Values(
691     // Test case 0: Fold 2.0 - 1.0
692     InstructionFoldingCase<double>(
693         Header() + "%main = OpFunction %void None %void_func\n" +
694             "%main_lab = OpLabel\n" +
695             "%2 = OpFSub %double %double_2 %double_1\n" +
696             "OpReturn\n" +
697             "OpFunctionEnd",
698         2, 1.0),
699         // Test case 1: Fold 2.0 + 1.0
700         InstructionFoldingCase<double>(
701             Header() + "%main = OpFunction %void None %void_func\n" +
702                 "%main_lab = OpLabel\n" +
703                 "%2 = OpFAdd %double %double_2 %double_1\n" +
704                 "OpReturn\n" +
705                 "OpFunctionEnd",
706             2, 3.0),
707         // Test case 2: Fold 3.0 * 2.0
708         InstructionFoldingCase<double>(
709             Header() + "%main = OpFunction %void None %void_func\n" +
710                 "%main_lab = OpLabel\n" +
711                 "%2 = OpFMul %double %double_3 %double_2\n" +
712                 "OpReturn\n" +
713                 "OpFunctionEnd",
714             2, 6.0),
715         // Test case 3: Fold 1.0 / 2.0
716         InstructionFoldingCase<double>(
717             Header() + "%main = OpFunction %void None %void_func\n" +
718                 "%main_lab = OpLabel\n" +
719                 "%2 = OpFDiv %double %double_1 %double_2\n" +
720                 "OpReturn\n" +
721                 "OpFunctionEnd",
722             2, 0.5),
723         // Test case 4: Fold 1.0 / 0.0
724         InstructionFoldingCase<double>(
725             Header() + "%main = OpFunction %void None %void_func\n" +
726                 "%main_lab = OpLabel\n" +
727                 "%2 = OpFDiv %double %double_1 %double_0\n" +
728                 "OpReturn\n" +
729                 "OpFunctionEnd",
730             2, std::numeric_limits<double>::infinity()),
731         // Test case 4: Fold -1.0 / 0.0
732         InstructionFoldingCase<double>(
733             Header() + "%main = OpFunction %void None %void_func\n" +
734                 "%main_lab = OpLabel\n" +
735                 "%2 = OpFDiv %double %double_n1 %double_0\n" +
736                 "OpReturn\n" +
737                 "OpFunctionEnd",
738             2, -std::numeric_limits<double>::infinity())
739 ));
740 // clang-format on
741 template <class ResultType>
742 struct InstructionFoldingCaseWithMap {
743   InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
744                                 ResultType result,
745                                 std::function<uint32_t(uint32_t)> map)
746       : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
747
748   std::string test_body;
749   uint32_t id_to_fold;
750   ResultType expected_result;
751   std::function<uint32_t(uint32_t)> id_map;
752 };
753
754 using IntegerInstructionFoldingTestWithMap =
755     ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
756
757 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
758   const auto& tc = GetParam();
759
760   // Build module.
761   std::unique_ptr<ir::IRContext> context =
762       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
763                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
764   ASSERT_NE(nullptr, context);
765
766   // Fold the instruction to test.
767   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
768   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
769   inst = opt::FoldInstructionToConstant(inst, tc.id_map);
770
771   // Make sure the instruction folded as expected.
772   EXPECT_NE(inst, nullptr);
773   if (inst != nullptr) {
774     EXPECT_EQ(inst->opcode(), SpvOpConstant);
775     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
776     const opt::analysis::IntConstant* result =
777         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
778     EXPECT_NE(result, nullptr);
779     if (result != nullptr) {
780       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
781     }
782   }
783 }
784 // clang-format off
785 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap,
786   ::testing::Values(
787       // Test case 0: fold %3 = 0; %3 * n
788       InstructionFoldingCaseWithMap<uint32_t>(
789           Header() + "%main = OpFunction %void None %void_func\n" +
790               "%main_lab = OpLabel\n" +
791               "%n = OpVariable %_ptr_int Function\n" +
792               "%load = OpLoad %int %n\n" +
793               "%3 = OpCopyObject %int %int_0\n"
794               "%2 = OpIMul %int %3 %load\n" +
795               "OpReturn\n" +
796               "OpFunctionEnd",
797           2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
798   ));
799 // clang-format on
800
801 using BooleanInstructionFoldingTestWithMap =
802     ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
803
804 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
805   const auto& tc = GetParam();
806
807   // Build module.
808   std::unique_ptr<ir::IRContext> context =
809       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
810                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
811   ASSERT_NE(nullptr, context);
812
813   // Fold the instruction to test.
814   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
815   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
816   inst = opt::FoldInstructionToConstant(inst, tc.id_map);
817
818   // Make sure the instruction folded as expected.
819   EXPECT_NE(inst, nullptr);
820   if (inst != nullptr) {
821     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
822     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
823     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
824     const opt::analysis::BoolConstant* result =
825         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
826     EXPECT_NE(result, nullptr);
827     if (result != nullptr) {
828       EXPECT_EQ(result->value(), tc.expected_result);
829     }
830   }
831 }
832
833 // clang-format off
834 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap,
835   ::testing::Values(
836       // Test case 0: fold %3 = true; %3 || n
837       InstructionFoldingCaseWithMap<bool>(
838           Header() + "%main = OpFunction %void None %void_func\n" +
839               "%main_lab = OpLabel\n" +
840               "%n = OpVariable %_ptr_bool Function\n" +
841               "%load = OpLoad %bool %n\n" +
842               "%3 = OpCopyObject %bool %true\n" +
843               "%2 = OpLogicalOr %bool %3 %load\n" +
844               "OpReturn\n" +
845               "OpFunctionEnd",
846           2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
847   ));
848 // clang-format on
849
850 using GeneralInstructionFoldingTest =
851     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
852
853 TEST_P(GeneralInstructionFoldingTest, Case) {
854   const auto& tc = GetParam();
855
856   // Build module.
857   std::unique_ptr<ir::IRContext> context =
858       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
859                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
860   ASSERT_NE(nullptr, context);
861
862   // Fold the instruction to test.
863   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
864   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
865   std::unique_ptr<ir::Instruction> original_inst(inst->Clone(context.get()));
866   bool succeeded = opt::FoldInstruction(inst);
867
868   // Make sure the instruction folded as expected.
869   EXPECT_EQ(inst->result_id(), original_inst->result_id());
870   EXPECT_EQ(inst->type_id(), original_inst->type_id());
871   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
872   if (succeeded) {
873     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
874     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
875   } else {
876     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
877     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
878       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
879     }
880   }
881 }
882
883 // clang-format off
884 INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
885                         ::testing::Values(
886     // Test case 0: Don't fold n * m
887     InstructionFoldingCase<uint32_t>(
888         Header() + "%main = OpFunction %void None %void_func\n" +
889             "%main_lab = OpLabel\n" +
890             "%n = OpVariable %_ptr_int Function\n" +
891             "%m = OpVariable %_ptr_int Function\n" +
892             "%load_n = OpLoad %int %n\n" +
893             "%load_m = OpLoad %int %m\n" +
894             "%2 = OpIMul %int %load_n %load_m\n" +
895             "OpReturn\n" +
896             "OpFunctionEnd",
897         2, 0),
898     // Test case 1: Don't fold n / m (unsigned)
899     InstructionFoldingCase<uint32_t>(
900         Header() + "%main = OpFunction %void None %void_func\n" +
901             "%main_lab = OpLabel\n" +
902             "%n = OpVariable %_ptr_uint Function\n" +
903             "%m = OpVariable %_ptr_uint Function\n" +
904             "%load_n = OpLoad %uint %n\n" +
905             "%load_m = OpLoad %uint %m\n" +
906             "%2 = OpUDiv %uint %load_n %load_m\n" +
907             "OpReturn\n" +
908             "OpFunctionEnd",
909         2, 0),
910     // Test case 2: Don't fold n / m (signed)
911     InstructionFoldingCase<uint32_t>(
912         Header() + "%main = OpFunction %void None %void_func\n" +
913             "%main_lab = OpLabel\n" +
914             "%n = OpVariable %_ptr_int Function\n" +
915             "%m = OpVariable %_ptr_int Function\n" +
916             "%load_n = OpLoad %int %n\n" +
917             "%load_m = OpLoad %int %m\n" +
918             "%2 = OpSDiv %int %load_n %load_m\n" +
919             "OpReturn\n" +
920             "OpFunctionEnd",
921         2, 0),
922     // Test case 3: Don't fold n remainder m
923     InstructionFoldingCase<uint32_t>(
924         Header() + "%main = OpFunction %void None %void_func\n" +
925             "%main_lab = OpLabel\n" +
926             "%n = OpVariable %_ptr_int Function\n" +
927             "%m = OpVariable %_ptr_int Function\n" +
928             "%load_n = OpLoad %int %n\n" +
929             "%load_m = OpLoad %int %m\n" +
930             "%2 = OpSRem %int %load_n %load_m\n" +
931             "OpReturn\n" +
932             "OpFunctionEnd",
933         2, 0),
934     // Test case 4: Don't fold n % m (signed)
935     InstructionFoldingCase<uint32_t>(
936         Header() + "%main = OpFunction %void None %void_func\n" +
937             "%main_lab = OpLabel\n" +
938             "%n = OpVariable %_ptr_int Function\n" +
939             "%m = OpVariable %_ptr_int Function\n" +
940             "%load_n = OpLoad %int %n\n" +
941             "%load_m = OpLoad %int %m\n" +
942             "%2 = OpSMod %int %load_n %load_m\n" +
943             "OpReturn\n" +
944             "OpFunctionEnd",
945         2, 0),
946     // Test case 5: Don't fold n % m (unsigned)
947     InstructionFoldingCase<uint32_t>(
948         Header() + "%main = OpFunction %void None %void_func\n" +
949             "%main_lab = OpLabel\n" +
950             "%n = OpVariable %_ptr_uint Function\n" +
951             "%m = OpVariable %_ptr_uint Function\n" +
952             "%load_n = OpLoad %uint %n\n" +
953             "%load_m = OpLoad %uint %m\n" +
954             "%2 = OpUMod %int %load_n %load_m\n" +
955             "OpReturn\n" +
956             "OpFunctionEnd",
957         2, 0),
958     // Test case 6: Don't fold n << m
959     InstructionFoldingCase<uint32_t>(
960         Header() + "%main = OpFunction %void None %void_func\n" +
961             "%main_lab = OpLabel\n" +
962             "%n = OpVariable %_ptr_uint Function\n" +
963             "%m = OpVariable %_ptr_uint Function\n" +
964             "%load_n = OpLoad %uint %n\n" +
965             "%load_m = OpLoad %uint %m\n" +
966             "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
967             "OpReturn\n" +
968             "OpFunctionEnd",
969         2, 0),
970     // Test case 7: Don't fold n >> m
971     InstructionFoldingCase<uint32_t>(
972         Header() + "%main = OpFunction %void None %void_func\n" +
973             "%main_lab = OpLabel\n" +
974             "%n = OpVariable %_ptr_uint Function\n" +
975             "%m = OpVariable %_ptr_uint Function\n" +
976             "%load_n = OpLoad %uint %n\n" +
977             "%load_m = OpLoad %uint %m\n" +
978             "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
979             "OpReturn\n" +
980             "OpFunctionEnd",
981         2, 0),
982     // Test case 8: Don't fold n | m
983     InstructionFoldingCase<uint32_t>(
984         Header() + "%main = OpFunction %void None %void_func\n" +
985             "%main_lab = OpLabel\n" +
986             "%n = OpVariable %_ptr_uint Function\n" +
987             "%m = OpVariable %_ptr_uint Function\n" +
988             "%load_n = OpLoad %uint %n\n" +
989             "%load_m = OpLoad %uint %m\n" +
990             "%2 = OpBitwiseOr %int %load_n %load_m\n" +
991             "OpReturn\n" +
992             "OpFunctionEnd",
993         2, 0),
994     // Test case 9: Don't fold n & m
995     InstructionFoldingCase<uint32_t>(
996         Header() + "%main = OpFunction %void None %void_func\n" +
997             "%main_lab = OpLabel\n" +
998             "%n = OpVariable %_ptr_uint Function\n" +
999             "%m = OpVariable %_ptr_uint Function\n" +
1000             "%load_n = OpLoad %uint %n\n" +
1001             "%load_m = OpLoad %uint %m\n" +
1002             "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
1003             "OpReturn\n" +
1004             "OpFunctionEnd",
1005         2, 0),
1006     // Test case 10: Don't fold n < m (unsigned)
1007     InstructionFoldingCase<uint32_t>(
1008         Header() + "%main = OpFunction %void None %void_func\n" +
1009             "%main_lab = OpLabel\n" +
1010             "%n = OpVariable %_ptr_uint Function\n" +
1011             "%m = OpVariable %_ptr_uint Function\n" +
1012             "%load_n = OpLoad %uint %n\n" +
1013             "%load_m = OpLoad %uint %m\n" +
1014             "%2 = OpULessThan %bool %load_n %load_m\n" +
1015             "OpReturn\n" +
1016             "OpFunctionEnd",
1017         2, 0),
1018     // Test case 11: Don't fold n > m (unsigned)
1019     InstructionFoldingCase<uint32_t>(
1020         Header() + "%main = OpFunction %void None %void_func\n" +
1021             "%main_lab = OpLabel\n" +
1022             "%n = OpVariable %_ptr_uint Function\n" +
1023             "%m = OpVariable %_ptr_uint Function\n" +
1024             "%load_n = OpLoad %uint %n\n" +
1025             "%load_m = OpLoad %uint %m\n" +
1026             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1027             "OpReturn\n" +
1028             "OpFunctionEnd",
1029         2, 0),
1030     // Test case 12: Don't fold n <= m (unsigned)
1031     InstructionFoldingCase<uint32_t>(
1032         Header() + "%main = OpFunction %void None %void_func\n" +
1033             "%main_lab = OpLabel\n" +
1034             "%n = OpVariable %_ptr_uint Function\n" +
1035             "%m = OpVariable %_ptr_uint Function\n" +
1036             "%load_n = OpLoad %uint %n\n" +
1037             "%load_m = OpLoad %uint %m\n" +
1038             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1039             "OpReturn\n" +
1040             "OpFunctionEnd",
1041         2, 0),
1042     // Test case 13: Don't fold n >= m (unsigned)
1043     InstructionFoldingCase<uint32_t>(
1044         Header() + "%main = OpFunction %void None %void_func\n" +
1045             "%main_lab = OpLabel\n" +
1046             "%n = OpVariable %_ptr_uint Function\n" +
1047             "%m = OpVariable %_ptr_uint Function\n" +
1048             "%load_n = OpLoad %uint %n\n" +
1049             "%load_m = OpLoad %uint %m\n" +
1050             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1051             "OpReturn\n" +
1052             "OpFunctionEnd",
1053         2, 0),
1054     // Test case 14: Don't fold n < m (signed)
1055     InstructionFoldingCase<uint32_t>(
1056         Header() + "%main = OpFunction %void None %void_func\n" +
1057             "%main_lab = OpLabel\n" +
1058             "%n = OpVariable %_ptr_int Function\n" +
1059             "%m = OpVariable %_ptr_int Function\n" +
1060             "%load_n = OpLoad %int %n\n" +
1061             "%load_m = OpLoad %int %m\n" +
1062             "%2 = OpULessThan %bool %load_n %load_m\n" +
1063             "OpReturn\n" +
1064             "OpFunctionEnd",
1065         2, 0),
1066     // Test case 15: Don't fold n > m (signed)
1067     InstructionFoldingCase<uint32_t>(
1068         Header() + "%main = OpFunction %void None %void_func\n" +
1069             "%main_lab = OpLabel\n" +
1070             "%n = OpVariable %_ptr_int Function\n" +
1071             "%m = OpVariable %_ptr_int Function\n" +
1072             "%load_n = OpLoad %int %n\n" +
1073             "%load_m = OpLoad %int %m\n" +
1074             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1075             "OpReturn\n" +
1076             "OpFunctionEnd",
1077         2, 0),
1078     // Test case 16: Don't fold n <= m (signed)
1079     InstructionFoldingCase<uint32_t>(
1080         Header() + "%main = OpFunction %void None %void_func\n" +
1081             "%main_lab = OpLabel\n" +
1082             "%n = OpVariable %_ptr_int Function\n" +
1083             "%m = OpVariable %_ptr_int Function\n" +
1084             "%load_n = OpLoad %int %n\n" +
1085             "%load_m = OpLoad %int %m\n" +
1086             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1087             "OpReturn\n" +
1088             "OpFunctionEnd",
1089         2, 0),
1090     // Test case 17: Don't fold n >= m (signed)
1091     InstructionFoldingCase<uint32_t>(
1092         Header() + "%main = OpFunction %void None %void_func\n" +
1093             "%main_lab = OpLabel\n" +
1094             "%n = OpVariable %_ptr_int Function\n" +
1095             "%m = OpVariable %_ptr_int Function\n" +
1096             "%load_n = OpLoad %int %n\n" +
1097             "%load_m = OpLoad %int %m\n" +
1098             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1099             "OpReturn\n" +
1100             "OpFunctionEnd",
1101         2, 0),
1102     // Test case 18: Don't fold n || m
1103     InstructionFoldingCase<uint32_t>(
1104         Header() + "%main = OpFunction %void None %void_func\n" +
1105             "%main_lab = OpLabel\n" +
1106             "%n = OpVariable %_ptr_bool Function\n" +
1107             "%m = OpVariable %_ptr_bool Function\n" +
1108             "%load_n = OpLoad %bool %n\n" +
1109             "%load_m = OpLoad %bool %m\n" +
1110             "%2 = OpLogicalOr %bool %load_n %load_m\n" +
1111             "OpReturn\n" +
1112             "OpFunctionEnd",
1113         2, 0),
1114     // Test case 19: Don't fold n && m
1115     InstructionFoldingCase<uint32_t>(
1116         Header() + "%main = OpFunction %void None %void_func\n" +
1117             "%main_lab = OpLabel\n" +
1118             "%n = OpVariable %_ptr_bool Function\n" +
1119             "%m = OpVariable %_ptr_bool Function\n" +
1120             "%load_n = OpLoad %bool %n\n" +
1121             "%load_m = OpLoad %bool %m\n" +
1122             "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
1123             "OpReturn\n" +
1124             "OpFunctionEnd",
1125         2, 0),
1126     // Test case 20: Don't fold n * 3
1127     InstructionFoldingCase<uint32_t>(
1128         Header() + "%main = OpFunction %void None %void_func\n" +
1129             "%main_lab = OpLabel\n" +
1130             "%n = OpVariable %_ptr_int Function\n" +
1131             "%load_n = OpLoad %int %n\n" +
1132             "%2 = OpIMul %int %load_n %int_3\n" +
1133             "OpReturn\n" +
1134             "OpFunctionEnd",
1135         2, 0),
1136     // Test case 21: Don't fold n / 3 (unsigned)
1137     InstructionFoldingCase<uint32_t>(
1138         Header() + "%main = OpFunction %void None %void_func\n" +
1139             "%main_lab = OpLabel\n" +
1140             "%n = OpVariable %_ptr_uint Function\n" +
1141             "%load_n = OpLoad %uint %n\n" +
1142             "%2 = OpUDiv %uint %load_n %uint_3\n" +
1143             "OpReturn\n" +
1144             "OpFunctionEnd",
1145         2, 0),
1146     // Test case 22: Don't fold n / 3 (signed)
1147     InstructionFoldingCase<uint32_t>(
1148         Header() + "%main = OpFunction %void None %void_func\n" +
1149             "%main_lab = OpLabel\n" +
1150             "%n = OpVariable %_ptr_int Function\n" +
1151             "%load_n = OpLoad %int %n\n" +
1152             "%2 = OpSDiv %int %load_n %int_3\n" +
1153             "OpReturn\n" +
1154             "OpFunctionEnd",
1155         2, 0),
1156     // Test case 23: Don't fold n remainder 3
1157     InstructionFoldingCase<uint32_t>(
1158         Header() + "%main = OpFunction %void None %void_func\n" +
1159             "%main_lab = OpLabel\n" +
1160             "%n = OpVariable %_ptr_int Function\n" +
1161             "%load_n = OpLoad %int %n\n" +
1162             "%2 = OpSRem %int %load_n %int_3\n" +
1163             "OpReturn\n" +
1164             "OpFunctionEnd",
1165         2, 0),
1166     // Test case 24: Don't fold n % 3 (signed)
1167     InstructionFoldingCase<uint32_t>(
1168         Header() + "%main = OpFunction %void None %void_func\n" +
1169             "%main_lab = OpLabel\n" +
1170             "%n = OpVariable %_ptr_int Function\n" +
1171             "%load_n = OpLoad %int %n\n" +
1172             "%2 = OpSMod %int %load_n %int_3\n" +
1173             "OpReturn\n" +
1174             "OpFunctionEnd",
1175         2, 0),
1176     // Test case 25: Don't fold n % 3 (unsigned)
1177     InstructionFoldingCase<uint32_t>(
1178         Header() + "%main = OpFunction %void None %void_func\n" +
1179             "%main_lab = OpLabel\n" +
1180             "%n = OpVariable %_ptr_uint Function\n" +
1181             "%load_n = OpLoad %uint %n\n" +
1182             "%2 = OpUMod %int %load_n %int_3\n" +
1183             "OpReturn\n" +
1184             "OpFunctionEnd",
1185         2, 0),
1186     // Test case 26: Don't fold n << 3
1187     InstructionFoldingCase<uint32_t>(
1188         Header() + "%main = OpFunction %void None %void_func\n" +
1189             "%main_lab = OpLabel\n" +
1190             "%n = OpVariable %_ptr_uint Function\n" +
1191             "%load_n = OpLoad %uint %n\n" +
1192             "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
1193             "OpReturn\n" +
1194             "OpFunctionEnd",
1195         2, 0),
1196     // Test case 27: Don't fold n >> 3
1197     InstructionFoldingCase<uint32_t>(
1198         Header() + "%main = OpFunction %void None %void_func\n" +
1199             "%main_lab = OpLabel\n" +
1200             "%n = OpVariable %_ptr_uint Function\n" +
1201             "%load_n = OpLoad %uint %n\n" +
1202             "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
1203             "OpReturn\n" +
1204             "OpFunctionEnd",
1205         2, 0),
1206     // Test case 28: Don't fold n | 3
1207     InstructionFoldingCase<uint32_t>(
1208         Header() + "%main = OpFunction %void None %void_func\n" +
1209             "%main_lab = OpLabel\n" +
1210             "%n = OpVariable %_ptr_uint Function\n" +
1211             "%load_n = OpLoad %uint %n\n" +
1212             "%2 = OpBitwiseOr %int %load_n %int_3\n" +
1213             "OpReturn\n" +
1214             "OpFunctionEnd",
1215         2, 0),
1216     // Test case 29: Don't fold n & 3
1217     InstructionFoldingCase<uint32_t>(
1218         Header() + "%main = OpFunction %void None %void_func\n" +
1219             "%main_lab = OpLabel\n" +
1220             "%n = OpVariable %_ptr_uint Function\n" +
1221             "%load_n = OpLoad %uint %n\n" +
1222             "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
1223             "OpReturn\n" +
1224             "OpFunctionEnd",
1225         2, 0),
1226     // Test case 30: Don't fold n < 3 (unsigned)
1227     InstructionFoldingCase<uint32_t>(
1228         Header() + "%main = OpFunction %void None %void_func\n" +
1229             "%main_lab = OpLabel\n" +
1230             "%n = OpVariable %_ptr_uint Function\n" +
1231             "%load_n = OpLoad %uint %n\n" +
1232             "%2 = OpULessThan %bool %load_n %uint_3\n" +
1233             "OpReturn\n" +
1234             "OpFunctionEnd",
1235         2, 0),
1236     // Test case 31: Don't fold n > 3 (unsigned)
1237     InstructionFoldingCase<uint32_t>(
1238         Header() + "%main = OpFunction %void None %void_func\n" +
1239             "%main_lab = OpLabel\n" +
1240             "%n = OpVariable %_ptr_uint Function\n" +
1241             "%load_n = OpLoad %uint %n\n" +
1242             "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
1243             "OpReturn\n" +
1244             "OpFunctionEnd",
1245         2, 0),
1246     // Test case 32: Don't fold n <= 3 (unsigned)
1247     InstructionFoldingCase<uint32_t>(
1248         Header() + "%main = OpFunction %void None %void_func\n" +
1249             "%main_lab = OpLabel\n" +
1250             "%n = OpVariable %_ptr_uint Function\n" +
1251             "%load_n = OpLoad %uint %n\n" +
1252             "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
1253             "OpReturn\n" +
1254             "OpFunctionEnd",
1255         2, 0),
1256     // Test case 33: Don't fold n >= 3 (unsigned)
1257     InstructionFoldingCase<uint32_t>(
1258         Header() + "%main = OpFunction %void None %void_func\n" +
1259             "%main_lab = OpLabel\n" +
1260             "%n = OpVariable %_ptr_uint Function\n" +
1261             "%load_n = OpLoad %uint %n\n" +
1262             "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
1263             "OpReturn\n" +
1264             "OpFunctionEnd",
1265         2, 0),
1266     // Test case 34: Don't fold n < 3 (signed)
1267     InstructionFoldingCase<uint32_t>(
1268         Header() + "%main = OpFunction %void None %void_func\n" +
1269             "%main_lab = OpLabel\n" +
1270             "%n = OpVariable %_ptr_int Function\n" +
1271             "%load_n = OpLoad %int %n\n" +
1272             "%2 = OpULessThan %bool %load_n %int_3\n" +
1273             "OpReturn\n" +
1274             "OpFunctionEnd",
1275         2, 0),
1276     // Test case 35: Don't fold n > 3 (signed)
1277     InstructionFoldingCase<uint32_t>(
1278         Header() + "%main = OpFunction %void None %void_func\n" +
1279             "%main_lab = OpLabel\n" +
1280             "%n = OpVariable %_ptr_int Function\n" +
1281             "%load_n = OpLoad %int %n\n" +
1282             "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
1283             "OpReturn\n" +
1284             "OpFunctionEnd",
1285         2, 0),
1286     // Test case 36: Don't fold n <= 3 (signed)
1287     InstructionFoldingCase<uint32_t>(
1288         Header() + "%main = OpFunction %void None %void_func\n" +
1289             "%main_lab = OpLabel\n" +
1290             "%n = OpVariable %_ptr_int Function\n" +
1291             "%load_n = OpLoad %int %n\n" +
1292             "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
1293             "OpReturn\n" +
1294             "OpFunctionEnd",
1295         2, 0),
1296     // Test case 37: Don't fold n >= 3 (signed)
1297     InstructionFoldingCase<uint32_t>(
1298         Header() + "%main = OpFunction %void None %void_func\n" +
1299             "%main_lab = OpLabel\n" +
1300             "%n = OpVariable %_ptr_int Function\n" +
1301             "%load_n = OpLoad %int %n\n" +
1302             "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
1303             "OpReturn\n" +
1304             "OpFunctionEnd",
1305         2, 0),
1306     // Test case 38: Don't fold 0 + 3 (long), bad length
1307     InstructionFoldingCase<uint32_t>(
1308         Header() + "%main = OpFunction %void None %void_func\n" +
1309             "%main_lab = OpLabel\n" +
1310             "%2 = OpIAdd %long %long_0 %long_3\n" +
1311             "OpReturn\n" +
1312             "OpFunctionEnd",
1313         2, 0),
1314     // Test case 39: Don't fold 0 + 3 (short), bad length
1315     InstructionFoldingCase<uint32_t>(
1316         Header() + "%main = OpFunction %void None %void_func\n" +
1317             "%main_lab = OpLabel\n" +
1318             "%2 = OpIAdd %short %short_0 %short_3\n" +
1319             "OpReturn\n" +
1320             "OpFunctionEnd",
1321         2, 0),
1322     // Test case 40: fold 1*n
1323     InstructionFoldingCase<uint32_t>(
1324         Header() + "%main = OpFunction %void None %void_func\n" +
1325             "%main_lab = OpLabel\n" +
1326             "%n = OpVariable %_ptr_int Function\n" +
1327             "%3 = OpLoad %int %n\n" +
1328             "%2 = OpIMul %int %int_1 %3\n" +
1329             "OpReturn\n" +
1330             "OpFunctionEnd",
1331         2, 3),
1332     // Test case 41: fold n*1
1333     InstructionFoldingCase<uint32_t>(
1334         Header() + "%main = OpFunction %void None %void_func\n" +
1335             "%main_lab = OpLabel\n" +
1336             "%n = OpVariable %_ptr_int Function\n" +
1337             "%3 = OpLoad %int %n\n" +
1338             "%2 = OpIMul %int %3 %int_1\n" +
1339             "OpReturn\n" +
1340             "OpFunctionEnd",
1341         2, 3)
1342 ));
1343
1344 INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
1345 ::testing::Values(
1346     // Test case 0: fold Insert feeding extract
1347     InstructionFoldingCase<uint32_t>(
1348         Header() + "%main = OpFunction %void None %void_func\n" +
1349             "%main_lab = OpLabel\n" +
1350             "%n = OpVariable %_ptr_int Function\n" +
1351             "%2 = OpLoad %int %n\n" +
1352             "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
1353             "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
1354             "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
1355             "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
1356             "%7 = OpCompositeExtract %int %6 0\n" +
1357             "OpReturn\n" +
1358             "OpFunctionEnd",
1359         7, 2),
1360     // Test case 1: fold Composite construct feeding extract (position 0)
1361     InstructionFoldingCase<uint32_t>(
1362         Header() + "%main = OpFunction %void None %void_func\n" +
1363             "%main_lab = OpLabel\n" +
1364             "%n = OpVariable %_ptr_int Function\n" +
1365             "%2 = OpLoad %int %n\n" +
1366             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
1367             "%4 = OpCompositeExtract %int %3 0\n" +
1368             "OpReturn\n" +
1369             "OpFunctionEnd",
1370         4, 2),
1371     // Test case 2: fold Composite construct feeding extract (position 3)
1372     InstructionFoldingCase<uint32_t>(
1373         Header() + "%main = OpFunction %void None %void_func\n" +
1374             "%main_lab = OpLabel\n" +
1375             "%n = OpVariable %_ptr_int Function\n" +
1376             "%2 = OpLoad %int %n\n" +
1377             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
1378             "%4 = OpCompositeExtract %int %3 3\n" +
1379             "OpReturn\n" +
1380             "OpFunctionEnd",
1381         4, INT_0_ID),
1382     // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
1383     InstructionFoldingCase<uint32_t>(
1384         Header() + "%main = OpFunction %void None %void_func\n" +
1385             "%main_lab = OpLabel\n" +
1386             "%n = OpVariable %_ptr_int Function\n" +
1387             "%2 = OpLoad %int %n\n" +
1388             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
1389             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1390             "%5 = OpCompositeExtract %int %4 3\n" +
1391             "OpReturn\n" +
1392             "OpFunctionEnd",
1393         5, INT_0_ID),
1394     // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
1395     InstructionFoldingCase<uint32_t>(
1396         Header() + "%main = OpFunction %void None %void_func\n" +
1397             "%main_lab = OpLabel\n" +
1398             "%n = OpVariable %_ptr_int Function\n" +
1399             "%2 = OpLoad %int %n\n" +
1400             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
1401             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1402             "%5 = OpCompositeExtract %int %4 0\n" +
1403             "OpReturn\n" +
1404             "OpFunctionEnd",
1405         5, 2),
1406     // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
1407     InstructionFoldingCase<uint32_t>(
1408         Header() + "%main = OpFunction %void None %void_func\n" +
1409             "%main_lab = OpLabel\n" +
1410             "%n = OpVariable %_ptr_int Function\n" +
1411             "%2 = OpLoad %int %n\n" +
1412             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
1413             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1414             "%5 = OpCompositeExtract %int %4 1\n" +
1415             "OpReturn\n" +
1416             "OpFunctionEnd",
1417         5, 2),
1418     // Test case 6: fold Composite construct with multiple indices.
1419     InstructionFoldingCase<uint32_t>(
1420         Header() + "%main = OpFunction %void None %void_func\n" +
1421             "%main_lab = OpLabel\n" +
1422             "%n = OpVariable %_ptr_int Function\n" +
1423             "%2 = OpLoad %int %n\n" +
1424             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
1425             "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
1426             "%5 = OpCompositeExtract %int %4 0 1\n" +
1427             "OpReturn\n" +
1428             "OpFunctionEnd",
1429         5, 2),
1430     // Test case 7: fold constant extract.
1431     InstructionFoldingCase<uint32_t>(
1432         Header() + "%main = OpFunction %void None %void_func\n" +
1433             "%main_lab = OpLabel\n" +
1434             "%2 = OpCompositeExtract %int %102 1\n" +
1435             "OpReturn\n" +
1436             "OpFunctionEnd",
1437         2, INT_7_ID),
1438     // Test case 8: constant struct has OpUndef
1439     InstructionFoldingCase<uint32_t>(
1440         Header() + "%main = OpFunction %void None %void_func\n" +
1441             "%main_lab = OpLabel\n" +
1442             "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
1443             "OpReturn\n" +
1444             "OpFunctionEnd",
1445         2, 0)
1446 ));
1447
1448 INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
1449 ::testing::Values(
1450     // Test case 0: fold Extracts feeding construct
1451     InstructionFoldingCase<uint32_t>(
1452         Header() + "%main = OpFunction %void None %void_func\n" +
1453             "%main_lab = OpLabel\n" +
1454             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1455             "%3 = OpCompositeExtract %int %2 0\n" +
1456             "%4 = OpCompositeExtract %int %2 1\n" +
1457             "%5 = OpCompositeExtract %int %2 2\n" +
1458             "%6 = OpCompositeExtract %int %2 3\n" +
1459             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1460             "OpReturn\n" +
1461             "OpFunctionEnd",
1462         7, 2),
1463     // Test case 1: Don't fold Extracts feeding construct (Different source)
1464     InstructionFoldingCase<uint32_t>(
1465         Header() + "%main = OpFunction %void None %void_func\n" +
1466             "%main_lab = OpLabel\n" +
1467             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1468             "%3 = OpCompositeExtract %int %2 0\n" +
1469             "%4 = OpCompositeExtract %int %2 1\n" +
1470             "%5 = OpCompositeExtract %int %2 2\n" +
1471             "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
1472             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1473             "OpReturn\n" +
1474             "OpFunctionEnd",
1475         7, 0),
1476     // Test case 2: Don't fold Extracts feeding construct (bad indices)
1477     InstructionFoldingCase<uint32_t>(
1478         Header() + "%main = OpFunction %void None %void_func\n" +
1479             "%main_lab = OpLabel\n" +
1480             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1481             "%3 = OpCompositeExtract %int %2 0\n" +
1482             "%4 = OpCompositeExtract %int %2 0\n" +
1483             "%5 = OpCompositeExtract %int %2 2\n" +
1484             "%6 = OpCompositeExtract %int %2 3\n" +
1485             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1486             "OpReturn\n" +
1487             "OpFunctionEnd",
1488         7, 0),
1489     // Test case 3: Don't fold Extracts feeding construct (different type)
1490     InstructionFoldingCase<uint32_t>(
1491         Header() + "%main = OpFunction %void None %void_func\n" +
1492             "%main_lab = OpLabel\n" +
1493             "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
1494             "%3 = OpCompositeExtract %v2int %2 0\n" +
1495             "%4 = OpCompositeExtract %int %2 1\n" +
1496             "%5 = OpCompositeExtract %int %2 2\n" +
1497             "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
1498             "OpReturn\n" +
1499             "OpFunctionEnd",
1500         7, 0),
1501     // Test case 4: Fold construct with constants to constant.
1502     InstructionFoldingCase<uint32_t>(
1503         Header() + "%main = OpFunction %void None %void_func\n" +
1504             "%main_lab = OpLabel\n" +
1505             "%2 = OpCompositeConstruct %v2int %103 %103\n" +
1506             "OpReturn\n" +
1507             "OpFunctionEnd",
1508         2, VEC2_0_ID)
1509 ));
1510
1511 INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
1512 ::testing::Values(
1513   // Test case 0: Fold phi with the same values for all edges.
1514   InstructionFoldingCase<uint32_t>(
1515       Header() + "%main = OpFunction %void None %void_func\n" +
1516           "%main_lab = OpLabel\n" +
1517           "            OpBranchConditional %true %l1 %l2\n" +
1518           "%l1 = OpLabel\n" +
1519           "      OpBranch %merge_lab\n" +
1520           "%l2 = OpLabel\n" +
1521           "      OpBranch %merge_lab\n" +
1522           "%merge_lab = OpLabel\n" +
1523           "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
1524           "OpReturn\n" +
1525           "OpFunctionEnd",
1526       2, INT_0_ID),
1527   // Test case 1: Fold phi in pass through loop.
1528   InstructionFoldingCase<uint32_t>(
1529       Header() + "%main = OpFunction %void None %void_func\n" +
1530           "%main_lab = OpLabel\n" +
1531           "            OpBranch %l1\n" +
1532           "%l1 = OpLabel\n" +
1533           "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
1534           "      OpBranchConditional %true %l1 %merge_lab\n" +
1535           "%merge_lab = OpLabel\n" +
1536           "OpReturn\n" +
1537           "OpFunctionEnd",
1538       2, INT_0_ID),
1539   // Test case 2: Don't Fold phi because of different values.
1540   InstructionFoldingCase<uint32_t>(
1541       Header() + "%main = OpFunction %void None %void_func\n" +
1542           "%main_lab = OpLabel\n" +
1543           "            OpBranch %l1\n" +
1544           "%l1 = OpLabel\n" +
1545           "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
1546           "      OpBranchConditional %true %l1 %merge_lab\n" +
1547           "%merge_lab = OpLabel\n" +
1548           "OpReturn\n" +
1549           "OpFunctionEnd",
1550       2, 0)
1551 ));
1552
1553 INSTANTIATE_TEST_CASE_P(SelectFoldingTest, GeneralInstructionFoldingTest,
1554 ::testing::Values(
1555   // Test case 0: Fold select with the same values for both sides
1556   InstructionFoldingCase<uint32_t>(
1557       Header() + "%main = OpFunction %void None %void_func\n" +
1558           "%main_lab = OpLabel\n" +
1559           "%n = OpVariable %_ptr_bool Function\n" +
1560           "%load = OpLoad %bool %n\n" +
1561           "%2 = OpSelect %int %load %100 %100\n" +
1562           "OpReturn\n" +
1563           "OpFunctionEnd",
1564       2, INT_0_ID),
1565   // Test case 1: Fold select true to left side
1566   InstructionFoldingCase<uint32_t>(
1567       Header() + "%main = OpFunction %void None %void_func\n" +
1568           "%main_lab = OpLabel\n" +
1569           "%n = OpVariable %_ptr_int Function\n" +
1570           "%load = OpLoad %bool %n\n" +
1571           "%2 = OpSelect %int %true %100 %n\n" +
1572           "OpReturn\n" +
1573           "OpFunctionEnd",
1574       2, INT_0_ID),
1575   // Test case 2: Fold select false to right side
1576   InstructionFoldingCase<uint32_t>(
1577       Header() + "%main = OpFunction %void None %void_func\n" +
1578           "%main_lab = OpLabel\n" +
1579           "%n = OpVariable %_ptr_int Function\n" +
1580           "%load = OpLoad %bool %n\n" +
1581           "%2 = OpSelect %int %false %n %100\n" +
1582           "OpReturn\n" +
1583           "OpFunctionEnd",
1584       2, INT_0_ID)
1585 ));
1586 // clang-format off
1587 }  // anonymous namespace