• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <limits>
15 #include <memory>
16 #include <string>
17 #include <unordered_set>
18 #include <vector>
19 
20 #include "effcee/effcee.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "source/opt/build_module.h"
24 #include "source/opt/def_use_manager.h"
25 #include "source/opt/fold.h"
26 #include "source/opt/ir_context.h"
27 #include "source/opt/module.h"
28 #include "spirv-tools/libspirv.hpp"
29 #include "test/opt/pass_utils.h"
30 
31 namespace spvtools {
32 namespace opt {
33 namespace {
34 
35 using ::testing::Contains;
36 
Disassemble(const std::string & original,IRContext * context,uint32_t disassemble_options=0)37 std::string Disassemble(const std::string& original, IRContext* context,
38                         uint32_t disassemble_options = 0) {
39   std::vector<uint32_t> optimized_bin;
40   context->module()->ToBinary(&optimized_bin, true);
41   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
42   SpirvTools tools(target_env);
43   std::string optimized_asm;
44   EXPECT_TRUE(
45       tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
46       << "Disassembling failed for shader:\n"
47       << original << std::endl;
48   return optimized_asm;
49 }
50 
Match(const std::string & original,IRContext * context,uint32_t disassemble_options=0)51 void Match(const std::string& original, IRContext* context,
52            uint32_t disassemble_options = 0) {
53   std::string disassembly = Disassemble(original, context, disassemble_options);
54   auto match_result = effcee::Match(disassembly, original);
55   EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
56       << match_result.message() << "\nChecking result:\n"
57       << disassembly;
58 }
59 
60 template <class ResultType>
61 struct InstructionFoldingCase {
InstructionFoldingCasespvtools::opt::__anon2055d22d0111::InstructionFoldingCase62   InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
63       : test_body(tb), id_to_fold(id), expected_result(result) {}
64 
65   std::string test_body;
66   uint32_t id_to_fold;
67   ResultType expected_result;
68 };
69 
70 using IntegerInstructionFoldingTest =
71     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
72 
TEST_P(IntegerInstructionFoldingTest,Case)73 TEST_P(IntegerInstructionFoldingTest, Case) {
74   const auto& tc = GetParam();
75 
76   // Build module.
77   std::unique_ptr<IRContext> context =
78       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
79                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
80   ASSERT_NE(nullptr, context);
81 
82   // Fold the instruction to test.
83   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
84   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
85   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
86 
87   // Make sure the instruction folded as expected.
88   EXPECT_TRUE(succeeded);
89   if (inst != nullptr) {
90     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
91     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
92     EXPECT_EQ(inst->opcode(), SpvOpConstant);
93     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
94     const analysis::IntConstant* result =
95         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
96     EXPECT_NE(result, nullptr);
97     if (result != nullptr) {
98       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
99     }
100   }
101 }
102 
103 // Returns a common SPIR-V header for all of the test that follow.
104 #define INT_0_ID 100
105 #define TRUE_ID 101
106 #define VEC2_0_ID 102
107 #define INT_7_ID 103
108 #define FLOAT_0_ID 104
109 #define DOUBLE_0_ID 105
110 #define VEC4_0_ID 106
111 #define DVEC4_0_ID 106
112 #define HALF_0_ID 108
Header()113 const std::string& Header() {
114   static const std::string header = R"(OpCapability Shader
115 OpCapability Float16
116 OpCapability Float64
117 OpCapability Int16
118 OpCapability Int64
119 %1 = OpExtInstImport "GLSL.std.450"
120 OpMemoryModel Logical GLSL450
121 OpEntryPoint Fragment %main "main"
122 OpExecutionMode %main OriginUpperLeft
123 OpSource GLSL 140
124 OpName %main "main"
125 %void = OpTypeVoid
126 %void_func = OpTypeFunction %void
127 %bool = OpTypeBool
128 %float = OpTypeFloat 32
129 %double = OpTypeFloat 64
130 %half = OpTypeFloat 16
131 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
132 %true = OpConstantTrue %bool
133 %false = OpConstantFalse %bool
134 %bool_null = OpConstantNull %bool
135 %short = OpTypeInt 16 1
136 %int = OpTypeInt 32 1
137 %long = OpTypeInt 64 1
138 %uint = OpTypeInt 32 0
139 %v2int = OpTypeVector %int 2
140 %v4int = OpTypeVector %int 4
141 %v4float = OpTypeVector %float 4
142 %v4double = OpTypeVector %double 4
143 %v2float = OpTypeVector %float 2
144 %v2double = OpTypeVector %double 2
145 %v2bool = OpTypeVector %bool 2
146 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
147 %_ptr_int = OpTypePointer Function %int
148 %_ptr_uint = OpTypePointer Function %uint
149 %_ptr_bool = OpTypePointer Function %bool
150 %_ptr_float = OpTypePointer Function %float
151 %_ptr_double = OpTypePointer Function %double
152 %_ptr_half = OpTypePointer Function %half
153 %_ptr_long = OpTypePointer Function %long
154 %_ptr_v2int = OpTypePointer Function %v2int
155 %_ptr_v4int = OpTypePointer Function %v4int
156 %_ptr_v4float = OpTypePointer Function %v4float
157 %_ptr_v4double = OpTypePointer Function %v4double
158 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
159 %_ptr_v2float = OpTypePointer Function %v2float
160 %_ptr_v2double = OpTypePointer Function %v2double
161 %short_0 = OpConstant %short 0
162 %short_2 = OpConstant %short 2
163 %short_3 = OpConstant %short 3
164 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
165 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
166 %int_0 = OpConstant %int 0
167 %int_1 = OpConstant %int 1
168 %int_2 = OpConstant %int 2
169 %int_3 = OpConstant %int 3
170 %int_4 = OpConstant %int 4
171 %int_n24 = OpConstant %int -24
172 %int_min = OpConstant %int -2147483648
173 %int_max = OpConstant %int 2147483647
174 %long_0 = OpConstant %long 0
175 %long_2 = OpConstant %long 2
176 %long_3 = OpConstant %long 3
177 %uint_0 = OpConstant %uint 0
178 %uint_1 = OpConstant %uint 1
179 %uint_2 = OpConstant %uint 2
180 %uint_3 = OpConstant %uint 3
181 %uint_4 = OpConstant %uint 4
182 %uint_32 = OpConstant %uint 32
183 %uint_42 = OpConstant %uint 42
184 %uint_max = OpConstant %uint 4294967295
185 %v2int_undef = OpUndef %v2int
186 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
187 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
188 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
189 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
190 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
191 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
192 %v2bool_null = OpConstantNull %v2bool
193 %v2bool_true_false = OpConstantComposite %v2bool %true %false
194 %v2bool_false_true = OpConstantComposite %v2bool %false %true
195 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
196 %v2int_null = OpConstantNull %v2int
197 %102 = OpConstantComposite %v2int %103 %103
198 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
199 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
200 %float_n1 = OpConstant %float -1
201 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
202 %float_null = OpConstantNull %float
203 %float_0 = OpConstant %float 0
204 %float_1 = OpConstant %float 1
205 %float_2 = OpConstant %float 2
206 %float_3 = OpConstant %float 3
207 %float_4 = OpConstant %float 4
208 %float_0p5 = OpConstant %float 0.5
209 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
210 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
211 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
212 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
213 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
214 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
215 %v2float_null = OpConstantNull %v2float
216 %double_n1 = OpConstant %double -1
217 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
218 %double_null = OpConstantNull %double
219 %double_0 = OpConstant %double 0
220 %double_1 = OpConstant %double 1
221 %double_2 = OpConstant %double 2
222 %double_3 = OpConstant %double 3
223 %double_4 = OpConstant %double 4
224 %double_0p5 = OpConstant %double 0.5
225 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
226 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
227 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
228 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
229 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
230 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
231 %v2double_null = OpConstantNull %v2double
232 %108 = OpConstant %half 0
233 %half_1 = OpConstant %half 1
234 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
235 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
236 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
237 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
238 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
239 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
240 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
241 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
242 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
243 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
244 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
245 %v4double_null = OpConstantNull %v4double
246 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
247 )";
248 
249   return header;
250 }
251 
252 // Returns the header with definitions of float NaN and double NaN. Since FC
253 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
254 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
255 // %double_n0 = OpConstant %double -0,
256 // we separates those definitions from Header().
HeaderWithNaN()257 const std::string& HeaderWithNaN() {
258   static const std::string headerWithNaN =
259       Header() +
260       R"(%float_nan = OpConstant %float -0x1.8p+128
261 %double_nan = OpConstant %double -0x1.8p+1024
262 )";
263 
264   return headerWithNaN;
265 }
266 
267 // clang-format off
268 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
269                         ::testing::Values(
270   // Test case 0: fold 0*n
271   InstructionFoldingCase<uint32_t>(
272     Header() + "%main = OpFunction %void None %void_func\n" +
273     "%main_lab = OpLabel\n" +
274            "%n = OpVariable %_ptr_int Function\n" +
275         "%load = OpLoad %int %n\n" +
276            "%2 = OpIMul %int %int_0 %load\n" +
277                 "OpReturn\n" +
278                 "OpFunctionEnd",
279     2, 0),
280   // Test case 1: fold n*0
281   InstructionFoldingCase<uint32_t>(
282     Header() + "%main = OpFunction %void None %void_func\n" +
283         "%main_lab = OpLabel\n" +
284         "%n = OpVariable %_ptr_int Function\n" +
285         "%load = OpLoad %int %n\n" +
286         "%2 = OpIMul %int %load %int_0\n" +
287         "OpReturn\n" +
288         "OpFunctionEnd",
289     2, 0),
290   // Test case 2: fold 0/n (signed)
291   InstructionFoldingCase<uint32_t>(
292     Header() + "%main = OpFunction %void None %void_func\n" +
293         "%main_lab = OpLabel\n" +
294         "%n = OpVariable %_ptr_int Function\n" +
295         "%load = OpLoad %int %n\n" +
296         "%2 = OpSDiv %int %int_0 %load\n" +
297         "OpReturn\n" +
298         "OpFunctionEnd",
299         2, 0),
300   // Test case 3: fold n/0 (signed)
301   InstructionFoldingCase<uint32_t>(
302     Header() + "%main = OpFunction %void None %void_func\n" +
303         "%main_lab = OpLabel\n" +
304         "%n = OpVariable %_ptr_int Function\n" +
305         "%load = OpLoad %int %n\n" +
306         "%2 = OpSDiv %int %load %int_0\n" +
307         "OpReturn\n" +
308         "OpFunctionEnd",
309     2, 0),
310   // Test case 4: fold 0/n (unsigned)
311   InstructionFoldingCase<uint32_t>(
312     Header() + "%main = OpFunction %void None %void_func\n" +
313         "%main_lab = OpLabel\n" +
314         "%n = OpVariable %_ptr_uint Function\n" +
315         "%load = OpLoad %uint %n\n" +
316         "%2 = OpUDiv %uint %uint_0 %load\n" +
317         "OpReturn\n" +
318         "OpFunctionEnd",
319     2, 0),
320   // Test case 5: fold n/0 (unsigned)
321   InstructionFoldingCase<uint32_t>(
322     Header() + "%main = OpFunction %void None %void_func\n" +
323         "%main_lab = OpLabel\n" +
324         "%n = OpVariable %_ptr_int Function\n" +
325         "%load = OpLoad %int %n\n" +
326         "%2 = OpSDiv %int %load %int_0\n" +
327         "OpReturn\n" +
328         "OpFunctionEnd",
329     2, 0),
330   // Test case 6: fold 0 remainder n
331   InstructionFoldingCase<uint32_t>(
332     Header() + "%main = OpFunction %void None %void_func\n" +
333         "%main_lab = OpLabel\n" +
334         "%n = OpVariable %_ptr_int Function\n" +
335         "%load = OpLoad %int %n\n" +
336         "%2 = OpSRem %int %int_0 %load\n" +
337         "OpReturn\n" +
338         "OpFunctionEnd",
339     2, 0),
340   // Test case 7: fold n remainder 0
341   InstructionFoldingCase<uint32_t>(
342     Header() + "%main = OpFunction %void None %void_func\n" +
343         "%main_lab = OpLabel\n" +
344         "%n = OpVariable %_ptr_int Function\n" +
345         "%load = OpLoad %int %n\n" +
346         "%2 = OpSRem %int %load %int_0\n" +
347         "OpReturn\n" +
348         "OpFunctionEnd",
349     2, 0),
350   // Test case 8: fold 0%n (signed)
351   InstructionFoldingCase<uint32_t>(
352     Header() + "%main = OpFunction %void None %void_func\n" +
353         "%main_lab = OpLabel\n" +
354         "%n = OpVariable %_ptr_int Function\n" +
355         "%load = OpLoad %int %n\n" +
356         "%2 = OpSMod %int %int_0 %load\n" +
357         "OpReturn\n" +
358         "OpFunctionEnd",
359     2, 0),
360   // Test case 9: fold n%0 (signed)
361   InstructionFoldingCase<uint32_t>(
362     Header() + "%main = OpFunction %void None %void_func\n" +
363         "%main_lab = OpLabel\n" +
364         "%n = OpVariable %_ptr_int Function\n" +
365         "%load = OpLoad %int %n\n" +
366         "%2 = OpSMod %int %load %int_0\n" +
367         "OpReturn\n" +
368         "OpFunctionEnd",
369     2, 0),
370   // Test case 10: fold 0%n (unsigned)
371   InstructionFoldingCase<uint32_t>(
372     Header() + "%main = OpFunction %void None %void_func\n" +
373         "%main_lab = OpLabel\n" +
374         "%n = OpVariable %_ptr_uint Function\n" +
375         "%load = OpLoad %uint %n\n" +
376         "%2 = OpUMod %uint %uint_0 %load\n" +
377         "OpReturn\n" +
378         "OpFunctionEnd",
379     2, 0),
380   // Test case 11: fold n%0 (unsigned)
381   InstructionFoldingCase<uint32_t>(
382     Header() + "%main = OpFunction %void None %void_func\n" +
383         "%main_lab = OpLabel\n" +
384         "%n = OpVariable %_ptr_uint Function\n" +
385         "%load = OpLoad %uint %n\n" +
386         "%2 = OpUMod %uint %load %uint_0\n" +
387         "OpReturn\n" +
388         "OpFunctionEnd",
389     2, 0),
390   // Test case 12: fold n << 32
391   InstructionFoldingCase<uint32_t>(
392       Header() + "%main = OpFunction %void None %void_func\n" +
393           "%main_lab = OpLabel\n" +
394           "%n = OpVariable %_ptr_uint Function\n" +
395           "%load = OpLoad %uint %n\n" +
396           "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
397           "OpReturn\n" +
398           "OpFunctionEnd",
399       2, 0),
400   // Test case 13: fold n >> 32
401   InstructionFoldingCase<uint32_t>(
402       Header() + "%main = OpFunction %void None %void_func\n" +
403           "%main_lab = OpLabel\n" +
404           "%n = OpVariable %_ptr_uint Function\n" +
405           "%load = OpLoad %uint %n\n" +
406           "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
407           "OpReturn\n" +
408           "OpFunctionEnd",
409       2, 0),
410   // Test case 14: fold n | 0xFFFFFFFF
411   InstructionFoldingCase<uint32_t>(
412       Header() + "%main = OpFunction %void None %void_func\n" +
413   "%main_lab = OpLabel\n" +
414   "%n = OpVariable %_ptr_uint Function\n" +
415   "%load = OpLoad %uint %n\n" +
416   "%2 = OpBitwiseOr %uint %load %uint_max\n" +
417   "OpReturn\n" +
418   "OpFunctionEnd",
419   2, 0xFFFFFFFF),
420   // Test case 15: fold 0xFFFFFFFF | n
421   InstructionFoldingCase<uint32_t>(
422       Header() + "%main = OpFunction %void None %void_func\n" +
423           "%main_lab = OpLabel\n" +
424           "%n = OpVariable %_ptr_uint Function\n" +
425           "%load = OpLoad %uint %n\n" +
426           "%2 = OpBitwiseOr %uint %uint_max %load\n" +
427           "OpReturn\n" +
428           "OpFunctionEnd",
429       2, 0xFFFFFFFF),
430   // Test case 16: fold n & 0
431   InstructionFoldingCase<uint32_t>(
432       Header() + "%main = OpFunction %void None %void_func\n" +
433           "%main_lab = OpLabel\n" +
434           "%n = OpVariable %_ptr_uint Function\n" +
435           "%load = OpLoad %uint %n\n" +
436           "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
437           "OpReturn\n" +
438           "OpFunctionEnd",
439       2, 0),
440   // Test case 17: fold 1/0 (signed)
441   InstructionFoldingCase<uint32_t>(
442       Header() + "%main = OpFunction %void None %void_func\n" +
443           "%main_lab = OpLabel\n" +
444           "%2 = OpSDiv %int %int_1 %int_0\n" +
445           "OpReturn\n" +
446           "OpFunctionEnd",
447       2, 0),
448   // Test case 18: fold 1/0 (unsigned)
449   InstructionFoldingCase<uint32_t>(
450       Header() + "%main = OpFunction %void None %void_func\n" +
451           "%main_lab = OpLabel\n" +
452           "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
453           "OpReturn\n" +
454           "OpFunctionEnd",
455       2, 0),
456   // Test case 19: fold OpSRem 1 0 (signed)
457   InstructionFoldingCase<uint32_t>(
458       Header() + "%main = OpFunction %void None %void_func\n" +
459           "%main_lab = OpLabel\n" +
460           "%2 = OpSRem %int %int_1 %int_0\n" +
461           "OpReturn\n" +
462           "OpFunctionEnd",
463       2, 0),
464   // Test case 20: fold 1%0 (signed)
465   InstructionFoldingCase<uint32_t>(
466       Header() + "%main = OpFunction %void None %void_func\n" +
467           "%main_lab = OpLabel\n" +
468           "%2 = OpSMod %int %int_1 %int_0\n" +
469           "OpReturn\n" +
470           "OpFunctionEnd",
471       2, 0),
472   // Test case 21: fold 1%0 (unsigned)
473   InstructionFoldingCase<uint32_t>(
474       Header() + "%main = OpFunction %void None %void_func\n" +
475           "%main_lab = OpLabel\n" +
476           "%2 = OpUMod %uint %uint_1 %uint_0\n" +
477           "OpReturn\n" +
478           "OpFunctionEnd",
479       2, 0),
480   // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
481   InstructionFoldingCase<uint32_t>(
482       Header() + "%main = OpFunction %void None %void_func\n" +
483           "%main_lab = OpLabel\n" +
484           "%n = OpVariable %_ptr_uint Function\n" +
485           "%load = OpLoad %uint %n\n" +
486           "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
487           "OpReturn\n" +
488           "OpFunctionEnd",
489       2, 0),
490   // Test case 23: fold signed n >> 42 (undefined, so set to zero).
491   InstructionFoldingCase<uint32_t>(
492       Header() + "%main = OpFunction %void None %void_func\n" +
493           "%main_lab = OpLabel\n" +
494           "%n = OpVariable %_ptr_int Function\n" +
495           "%load = OpLoad %int %n\n" +
496           "%2 = OpShiftRightLogical %int %load %uint_42\n" +
497           "OpReturn\n" +
498           "OpFunctionEnd",
499       2, 0),
500   // Test case 24: fold n << 42 (undefined, so set to zero).
501   InstructionFoldingCase<uint32_t>(
502       Header() + "%main = OpFunction %void None %void_func\n" +
503           "%main_lab = OpLabel\n" +
504           "%n = OpVariable %_ptr_int Function\n" +
505           "%load = OpLoad %int %n\n" +
506           "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
507           "OpReturn\n" +
508           "OpFunctionEnd",
509       2, 0),
510   // Test case 25: fold -24 >> 32 (defined as -1)
511   InstructionFoldingCase<uint32_t>(
512       Header() + "%main = OpFunction %void None %void_func\n" +
513           "%main_lab = OpLabel\n" +
514           "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
515           "OpReturn\n" +
516           "OpFunctionEnd",
517       2, -1),
518   // Test case 26: fold 2 >> 32 (signed)
519   InstructionFoldingCase<uint32_t>(
520       Header() + "%main = OpFunction %void None %void_func\n" +
521           "%main_lab = OpLabel\n" +
522           "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
523           "OpReturn\n" +
524           "OpFunctionEnd",
525       2, 0),
526   // Test case 27: fold 2 >> 32 (unsigned)
527   InstructionFoldingCase<uint32_t>(
528       Header() + "%main = OpFunction %void None %void_func\n" +
529           "%main_lab = OpLabel\n" +
530           "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
531           "OpReturn\n" +
532           "OpFunctionEnd",
533       2, 0),
534   // Test case 28: fold 2 << 32
535   InstructionFoldingCase<uint32_t>(
536       Header() + "%main = OpFunction %void None %void_func\n" +
537           "%main_lab = OpLabel\n" +
538           "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
539           "OpReturn\n" +
540           "OpFunctionEnd",
541       2, 0),
542   // Test case 29: fold -INT_MIN
543   InstructionFoldingCase<uint32_t>(
544       Header() + "%main = OpFunction %void None %void_func\n" +
545           "%main_lab = OpLabel\n" +
546           "%2 = OpSNegate %int %int_min\n" +
547           "OpReturn\n" +
548           "OpFunctionEnd",
549       2, std::numeric_limits<int32_t>::min())
550 ));
551 // clang-format on
552 
553 using IntVectorInstructionFoldingTest =
554     ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
555 
TEST_P(IntVectorInstructionFoldingTest,Case)556 TEST_P(IntVectorInstructionFoldingTest, Case) {
557   const auto& tc = GetParam();
558 
559   // Build module.
560   std::unique_ptr<IRContext> context =
561       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
562                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
563   ASSERT_NE(nullptr, context);
564 
565   // Fold the instruction to test.
566   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
567   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
568   SpvOp original_opcode = inst->opcode();
569   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
570 
571   // Make sure the instruction folded as expected.
572   EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
573   if (succeeded && inst != nullptr) {
574     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
575     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
576     std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
577     EXPECT_THAT(opcodes, Contains(inst->opcode()));
578     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
579     const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
580     EXPECT_NE(result, nullptr);
581     if (result != nullptr) {
582       const std::vector<const analysis::Constant*>& componenets =
583           result->AsVectorConstant()->GetComponents();
584       EXPECT_EQ(componenets.size(), tc.expected_result.size());
585       for (size_t i = 0; i < componenets.size(); i++) {
586         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
587       }
588     }
589   }
590 }
591 
592 // clang-format off
593 INSTANTIATE_TEST_CASE_P(TestCase, IntVectorInstructionFoldingTest,
594 ::testing::Values(
595     // Test case 0: fold 0*n
596     InstructionFoldingCase<std::vector<uint32_t>>(
597         Header() + "%main = OpFunction %void None %void_func\n" +
598             "%main_lab = OpLabel\n" +
599             "%n = OpVariable %_ptr_int Function\n" +
600             "%load = OpLoad %int %n\n" +
601             "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
602             "OpReturn\n" +
603             "OpFunctionEnd",
604         2, {2,3}),
605     InstructionFoldingCase<std::vector<uint32_t>>(
606       Header() + "%main = OpFunction %void None %void_func\n" +
607           "%main_lab = OpLabel\n" +
608           "%n = OpVariable %_ptr_int Function\n" +
609           "%load = OpLoad %int %n\n" +
610           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
611           "OpReturn\n" +
612           "OpFunctionEnd",
613       2, {0,3}),
614     InstructionFoldingCase<std::vector<uint32_t>>(
615       Header() + "%main = OpFunction %void None %void_func\n" +
616           "%main_lab = OpLabel\n" +
617           "%n = OpVariable %_ptr_int Function\n" +
618           "%load = OpLoad %int %n\n" +
619           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
620           "OpReturn\n" +
621           "OpFunctionEnd",
622       2, {0,0}),
623     InstructionFoldingCase<std::vector<uint32_t>>(
624       Header() + "%main = OpFunction %void None %void_func\n" +
625           "%main_lab = OpLabel\n" +
626           "%n = OpVariable %_ptr_int Function\n" +
627           "%load = OpLoad %int %n\n" +
628           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
629           "OpReturn\n" +
630           "OpFunctionEnd",
631       2, {0,0})
632 ));
633 // clang-format on
634 
635 using BooleanInstructionFoldingTest =
636     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
637 
TEST_P(BooleanInstructionFoldingTest,Case)638 TEST_P(BooleanInstructionFoldingTest, Case) {
639   const auto& tc = GetParam();
640 
641   // Build module.
642   std::unique_ptr<IRContext> context =
643       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
644                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
645   ASSERT_NE(nullptr, context);
646 
647   // Fold the instruction to test.
648   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
649   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
650   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
651 
652   // Make sure the instruction folded as expected.
653   EXPECT_TRUE(succeeded);
654   if (inst != nullptr) {
655     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
656     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
657     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
658     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
659     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
660     const analysis::BoolConstant* result =
661         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
662     EXPECT_NE(result, nullptr);
663     if (result != nullptr) {
664       EXPECT_EQ(result->value(), tc.expected_result);
665     }
666   }
667 }
668 
669 // clang-format off
670 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest,
671                         ::testing::Values(
672   // Test case 0: fold true || n
673   InstructionFoldingCase<bool>(
674       Header() + "%main = OpFunction %void None %void_func\n" +
675           "%main_lab = OpLabel\n" +
676           "%n = OpVariable %_ptr_bool Function\n" +
677           "%load = OpLoad %bool %n\n" +
678           "%2 = OpLogicalOr %bool %true %load\n" +
679           "OpReturn\n" +
680           "OpFunctionEnd",
681       2, true),
682   // Test case 1: fold n || true
683   InstructionFoldingCase<bool>(
684       Header() + "%main = OpFunction %void None %void_func\n" +
685           "%main_lab = OpLabel\n" +
686           "%n = OpVariable %_ptr_bool Function\n" +
687           "%load = OpLoad %bool %n\n" +
688           "%2 = OpLogicalOr %bool %load %true\n" +
689           "OpReturn\n" +
690           "OpFunctionEnd",
691       2, true),
692   // Test case 2: fold false && n
693   InstructionFoldingCase<bool>(
694       Header() + "%main = OpFunction %void None %void_func\n" +
695           "%main_lab = OpLabel\n" +
696           "%n = OpVariable %_ptr_bool Function\n" +
697           "%load = OpLoad %bool %n\n" +
698           "%2 = OpLogicalAnd %bool %false %load\n" +
699           "OpReturn\n" +
700           "OpFunctionEnd",
701       2, false),
702   // Test case 3: fold n && false
703   InstructionFoldingCase<bool>(
704       Header() + "%main = OpFunction %void None %void_func\n" +
705           "%main_lab = OpLabel\n" +
706           "%n = OpVariable %_ptr_bool Function\n" +
707           "%load = OpLoad %bool %n\n" +
708           "%2 = OpLogicalAnd %bool %load %false\n" +
709           "OpReturn\n" +
710           "OpFunctionEnd",
711       2, false),
712   // Test case 4: fold n < 0 (unsigned)
713   InstructionFoldingCase<bool>(
714       Header() + "%main = OpFunction %void None %void_func\n" +
715           "%main_lab = OpLabel\n" +
716           "%n = OpVariable %_ptr_uint Function\n" +
717           "%load = OpLoad %uint %n\n" +
718           "%2 = OpULessThan %bool %load %uint_0\n" +
719           "OpReturn\n" +
720           "OpFunctionEnd",
721       2, false),
722   // Test case 5: fold UINT_MAX < n (unsigned)
723   InstructionFoldingCase<bool>(
724       Header() + "%main = OpFunction %void None %void_func\n" +
725           "%main_lab = OpLabel\n" +
726           "%n = OpVariable %_ptr_uint Function\n" +
727           "%load = OpLoad %uint %n\n" +
728           "%2 = OpULessThan %bool %uint_max %load\n" +
729           "OpReturn\n" +
730           "OpFunctionEnd",
731       2, false),
732   // Test case 6: fold INT_MAX < n (signed)
733   InstructionFoldingCase<bool>(
734       Header() + "%main = OpFunction %void None %void_func\n" +
735           "%main_lab = OpLabel\n" +
736           "%n = OpVariable %_ptr_int Function\n" +
737           "%load = OpLoad %int %n\n" +
738           "%2 = OpSLessThan %bool %int_max %load\n" +
739           "OpReturn\n" +
740           "OpFunctionEnd",
741       2, false),
742   // Test case 7: fold n < INT_MIN (signed)
743   InstructionFoldingCase<bool>(
744       Header() + "%main = OpFunction %void None %void_func\n" +
745           "%main_lab = OpLabel\n" +
746           "%n = OpVariable %_ptr_int Function\n" +
747           "%load = OpLoad %int %n\n" +
748           "%2 = OpSLessThan %bool %load %int_min\n" +
749           "OpReturn\n" +
750           "OpFunctionEnd",
751       2, false),
752   // Test case 8: fold 0 > n (unsigned)
753   InstructionFoldingCase<bool>(
754       Header() + "%main = OpFunction %void None %void_func\n" +
755           "%main_lab = OpLabel\n" +
756           "%n = OpVariable %_ptr_uint Function\n" +
757           "%load = OpLoad %uint %n\n" +
758           "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
759           "OpReturn\n" +
760           "OpFunctionEnd",
761       2, false),
762   // Test case 9: fold n > UINT_MAX (unsigned)
763   InstructionFoldingCase<bool>(
764       Header() + "%main = OpFunction %void None %void_func\n" +
765           "%main_lab = OpLabel\n" +
766           "%n = OpVariable %_ptr_uint Function\n" +
767           "%load = OpLoad %uint %n\n" +
768           "%2 = OpUGreaterThan %bool %load %uint_max\n" +
769           "OpReturn\n" +
770           "OpFunctionEnd",
771       2, false),
772   // Test case 10: fold n > INT_MAX (signed)
773   InstructionFoldingCase<bool>(
774       Header() + "%main = OpFunction %void None %void_func\n" +
775           "%main_lab = OpLabel\n" +
776           "%n = OpVariable %_ptr_int Function\n" +
777           "%load = OpLoad %int %n\n" +
778           "%2 = OpSGreaterThan %bool %load %int_max\n" +
779           "OpReturn\n" +
780           "OpFunctionEnd",
781       2, false),
782   // Test case 11: fold INT_MIN > n (signed)
783   InstructionFoldingCase<bool>(
784       Header() + "%main = OpFunction %void None %void_func\n" +
785           "%main_lab = OpLabel\n" +
786           "%n = OpVariable %_ptr_uint Function\n" +
787           "%load = OpLoad %uint %n\n" +
788           "%2 = OpSGreaterThan %bool %int_min %load\n" +
789           "OpReturn\n" +
790           "OpFunctionEnd",
791       2, false),
792   // Test case 12: fold 0 <= n (unsigned)
793   InstructionFoldingCase<bool>(
794       Header() + "%main = OpFunction %void None %void_func\n" +
795           "%main_lab = OpLabel\n" +
796           "%n = OpVariable %_ptr_uint Function\n" +
797           "%load = OpLoad %uint %n\n" +
798           "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
799           "OpReturn\n" +
800           "OpFunctionEnd",
801       2, true),
802   // Test case 13: fold n <= UINT_MAX (unsigned)
803   InstructionFoldingCase<bool>(
804       Header() + "%main = OpFunction %void None %void_func\n" +
805           "%main_lab = OpLabel\n" +
806           "%n = OpVariable %_ptr_uint Function\n" +
807           "%load = OpLoad %uint %n\n" +
808           "%2 = OpULessThanEqual %bool %load %uint_max\n" +
809           "OpReturn\n" +
810           "OpFunctionEnd",
811       2, true),
812   // Test case 14: fold INT_MIN <= n (signed)
813   InstructionFoldingCase<bool>(
814       Header() + "%main = OpFunction %void None %void_func\n" +
815           "%main_lab = OpLabel\n" +
816           "%n = OpVariable %_ptr_int Function\n" +
817           "%load = OpLoad %int %n\n" +
818           "%2 = OpSLessThanEqual %bool %int_min %load\n" +
819           "OpReturn\n" +
820           "OpFunctionEnd",
821       2, true),
822   // Test case 15: fold n <= INT_MAX (signed)
823   InstructionFoldingCase<bool>(
824       Header() + "%main = OpFunction %void None %void_func\n" +
825           "%main_lab = OpLabel\n" +
826           "%n = OpVariable %_ptr_int Function\n" +
827           "%load = OpLoad %int %n\n" +
828           "%2 = OpSLessThanEqual %bool %load %int_max\n" +
829           "OpReturn\n" +
830           "OpFunctionEnd",
831       2, true),
832   // Test case 16: fold n >= 0 (unsigned)
833   InstructionFoldingCase<bool>(
834       Header() + "%main = OpFunction %void None %void_func\n" +
835           "%main_lab = OpLabel\n" +
836           "%n = OpVariable %_ptr_uint Function\n" +
837           "%load = OpLoad %uint %n\n" +
838           "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
839           "OpReturn\n" +
840           "OpFunctionEnd",
841       2, true),
842   // Test case 17: fold UINT_MAX >= n (unsigned)
843   InstructionFoldingCase<bool>(
844       Header() + "%main = OpFunction %void None %void_func\n" +
845           "%main_lab = OpLabel\n" +
846           "%n = OpVariable %_ptr_uint Function\n" +
847           "%load = OpLoad %uint %n\n" +
848           "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
849           "OpReturn\n" +
850           "OpFunctionEnd",
851       2, true),
852   // Test case 18: fold n >= INT_MIN (signed)
853   InstructionFoldingCase<bool>(
854       Header() + "%main = OpFunction %void None %void_func\n" +
855           "%main_lab = OpLabel\n" +
856           "%n = OpVariable %_ptr_int Function\n" +
857           "%load = OpLoad %int %n\n" +
858           "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
859           "OpReturn\n" +
860           "OpFunctionEnd",
861       2, true),
862   // Test case 19: fold INT_MAX >= n (signed)
863   InstructionFoldingCase<bool>(
864       Header() + "%main = OpFunction %void None %void_func\n" +
865           "%main_lab = OpLabel\n" +
866           "%n = OpVariable %_ptr_int Function\n" +
867           "%load = OpLoad %int %n\n" +
868           "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
869           "OpReturn\n" +
870           "OpFunctionEnd",
871       2, true)
872 ));
873 
874 INSTANTIATE_TEST_CASE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
875 ::testing::Values(
876     // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
877     InstructionFoldingCase<bool>(
878         Header() + "%main = OpFunction %void None %void_func\n" +
879             "%main_lab = OpLabel\n" +
880             "%n = OpVariable %_ptr_float Function\n" +
881             "%ld = OpLoad %float %n\n" +
882             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
883             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
884             "OpReturn\n" +
885             "OpFunctionEnd",
886         2, false),
887     // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
888     InstructionFoldingCase<bool>(
889         Header() + "%main = OpFunction %void None %void_func\n" +
890             "%main_lab = OpLabel\n" +
891             "%n = OpVariable %_ptr_float Function\n" +
892             "%ld = OpLoad %float %n\n" +
893             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
894             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
895             "OpReturn\n" +
896             "OpFunctionEnd",
897         2, true),
898     // Test case 2: fold 0.0 >= clamp(n, 1, 2)
899     InstructionFoldingCase<bool>(
900         Header() + "%main = OpFunction %void None %void_func\n" +
901             "%main_lab = OpLabel\n" +
902             "%n = OpVariable %_ptr_float Function\n" +
903             "%ld = OpLoad %float %n\n" +
904             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
905             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
906             "OpReturn\n" +
907             "OpFunctionEnd",
908         2, false),
909     // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
910     InstructionFoldingCase<bool>(
911         Header() + "%main = OpFunction %void None %void_func\n" +
912             "%main_lab = OpLabel\n" +
913             "%n = OpVariable %_ptr_float Function\n" +
914             "%ld = OpLoad %float %n\n" +
915             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
916             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
917             "OpReturn\n" +
918             "OpFunctionEnd",
919         2, true),
920     // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
921     InstructionFoldingCase<bool>(
922         Header() + "%main = OpFunction %void None %void_func\n" +
923             "%main_lab = OpLabel\n" +
924             "%n = OpVariable %_ptr_float Function\n" +
925             "%ld = OpLoad %float %n\n" +
926             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
927             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
928             "OpReturn\n" +
929             "OpFunctionEnd",
930         2, true),
931     // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
932     InstructionFoldingCase<bool>(
933         Header() + "%main = OpFunction %void None %void_func\n" +
934             "%main_lab = OpLabel\n" +
935             "%n = OpVariable %_ptr_float Function\n" +
936             "%ld = OpLoad %float %n\n" +
937             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
938             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
939             "OpReturn\n" +
940             "OpFunctionEnd",
941         2, false),
942     // Test case 6: fold 0.0 < clamp(n, 1, 2)
943     InstructionFoldingCase<bool>(
944         Header() + "%main = OpFunction %void None %void_func\n" +
945             "%main_lab = OpLabel\n" +
946             "%n = OpVariable %_ptr_float Function\n" +
947             "%ld = OpLoad %float %n\n" +
948             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
949             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
950             "OpReturn\n" +
951             "OpFunctionEnd",
952         2, true),
953     // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
954     InstructionFoldingCase<bool>(
955         Header() + "%main = OpFunction %void None %void_func\n" +
956             "%main_lab = OpLabel\n" +
957             "%n = OpVariable %_ptr_float Function\n" +
958             "%ld = OpLoad %float %n\n" +
959             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
960             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
961             "OpReturn\n" +
962             "OpFunctionEnd",
963         2, false),
964     // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
965     InstructionFoldingCase<bool>(
966         Header() + "%main = OpFunction %void None %void_func\n" +
967             "%main_lab = OpLabel\n" +
968             "%n = OpVariable %_ptr_float Function\n" +
969             "%ld = OpLoad %float %n\n" +
970             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
971             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
972             "OpReturn\n" +
973             "OpFunctionEnd",
974         2, false),
975     // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
976     InstructionFoldingCase<bool>(
977         Header() + "%main = OpFunction %void None %void_func\n" +
978             "%main_lab = OpLabel\n" +
979             "%n = OpVariable %_ptr_float Function\n" +
980             "%ld = OpLoad %float %n\n" +
981             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
982             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
983             "OpReturn\n" +
984             "OpFunctionEnd",
985         2, true),
986     // Test case 10: fold 0.0 >= clamp(n, 1, 2)
987     InstructionFoldingCase<bool>(
988         Header() + "%main = OpFunction %void None %void_func\n" +
989             "%main_lab = OpLabel\n" +
990             "%n = OpVariable %_ptr_float Function\n" +
991             "%ld = OpLoad %float %n\n" +
992             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
993             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
994             "OpReturn\n" +
995             "OpFunctionEnd",
996         2, false),
997     // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
998     InstructionFoldingCase<bool>(
999         Header() + "%main = OpFunction %void None %void_func\n" +
1000             "%main_lab = OpLabel\n" +
1001             "%n = OpVariable %_ptr_float Function\n" +
1002             "%ld = OpLoad %float %n\n" +
1003             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1004             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1005             "OpReturn\n" +
1006             "OpFunctionEnd",
1007         2, true),
1008     // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
1009     InstructionFoldingCase<bool>(
1010         Header() + "%main = OpFunction %void None %void_func\n" +
1011             "%main_lab = OpLabel\n" +
1012             "%n = OpVariable %_ptr_float Function\n" +
1013             "%ld = OpLoad %float %n\n" +
1014             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1015             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1016             "OpReturn\n" +
1017             "OpFunctionEnd",
1018         2, true),
1019     // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
1020     InstructionFoldingCase<bool>(
1021         Header() + "%main = OpFunction %void None %void_func\n" +
1022             "%main_lab = OpLabel\n" +
1023             "%n = OpVariable %_ptr_float Function\n" +
1024             "%ld = OpLoad %float %n\n" +
1025             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1026             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1027             "OpReturn\n" +
1028             "OpFunctionEnd",
1029         2, false),
1030     // Test case 14: fold 0.0 < clamp(n, 1, 2)
1031     InstructionFoldingCase<bool>(
1032         Header() + "%main = OpFunction %void None %void_func\n" +
1033             "%main_lab = OpLabel\n" +
1034             "%n = OpVariable %_ptr_float Function\n" +
1035             "%ld = OpLoad %float %n\n" +
1036             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1037             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1038             "OpReturn\n" +
1039             "OpFunctionEnd",
1040         2, true),
1041     // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
1042     InstructionFoldingCase<bool>(
1043         Header() + "%main = OpFunction %void None %void_func\n" +
1044             "%main_lab = OpLabel\n" +
1045             "%n = OpVariable %_ptr_float Function\n" +
1046             "%ld = OpLoad %float %n\n" +
1047             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1048             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1049             "OpReturn\n" +
1050             "OpFunctionEnd",
1051         2, false)
1052 ));
1053 
1054 INSTANTIATE_TEST_CASE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
1055 ::testing::Values(
1056     // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
1057     InstructionFoldingCase<bool>(
1058       Header() + "%main = OpFunction %void None %void_func\n" +
1059       "%main_lab = OpLabel\n" +
1060       "%n = OpVariable %_ptr_float Function\n" +
1061       "%ld = OpLoad %float %n\n" +
1062       "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1063       "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
1064       "OpReturn\n" +
1065       "OpFunctionEnd",
1066       2, false),
1067     // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
1068     InstructionFoldingCase<bool>(
1069       Header() + "%main = OpFunction %void None %void_func\n" +
1070       "%main_lab = OpLabel\n" +
1071       "%n = OpVariable %_ptr_float Function\n" +
1072       "%ld = OpLoad %float %n\n" +
1073       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1074       "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
1075       "OpReturn\n" +
1076       "OpFunctionEnd",
1077       2, true),
1078     // Test case 2: fold clamp(n, 1, 2) >= 0.0
1079     InstructionFoldingCase<bool>(
1080       Header() + "%main = OpFunction %void None %void_func\n" +
1081       "%main_lab = OpLabel\n" +
1082       "%n = OpVariable %_ptr_float Function\n" +
1083       "%ld = OpLoad %float %n\n" +
1084       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1085       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
1086       "OpReturn\n" +
1087       "OpFunctionEnd",
1088       2, true),
1089     // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
1090     InstructionFoldingCase<bool>(
1091       Header() + "%main = OpFunction %void None %void_func\n" +
1092       "%main_lab = OpLabel\n" +
1093       "%n = OpVariable %_ptr_float Function\n" +
1094       "%ld = OpLoad %float %n\n" +
1095       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1096       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
1097       "OpReturn\n" +
1098       "OpFunctionEnd",
1099       2, false),
1100     // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
1101     InstructionFoldingCase<bool>(
1102         Header() + "%main = OpFunction %void None %void_func\n" +
1103             "%main_lab = OpLabel\n" +
1104             "%n = OpVariable %_ptr_float Function\n" +
1105             "%ld = OpLoad %float %n\n" +
1106             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1107             "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
1108             "OpReturn\n" +
1109             "OpFunctionEnd",
1110         2, true),
1111     // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
1112     InstructionFoldingCase<bool>(
1113         Header() + "%main = OpFunction %void None %void_func\n" +
1114             "%main_lab = OpLabel\n" +
1115             "%n = OpVariable %_ptr_float Function\n" +
1116             "%ld = OpLoad %float %n\n" +
1117             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1118             "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
1119             "OpReturn\n" +
1120             "OpFunctionEnd",
1121         2, false),
1122     // Test case 6: fold clamp(n, 1, 2) < 3
1123     InstructionFoldingCase<bool>(
1124         Header() + "%main = OpFunction %void None %void_func\n" +
1125             "%main_lab = OpLabel\n" +
1126             "%n = OpVariable %_ptr_float Function\n" +
1127             "%ld = OpLoad %float %n\n" +
1128             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1129             "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
1130             "OpReturn\n" +
1131             "OpFunctionEnd",
1132         2, true),
1133     // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
1134     InstructionFoldingCase<bool>(
1135         Header() + "%main = OpFunction %void None %void_func\n" +
1136             "%main_lab = OpLabel\n" +
1137             "%n = OpVariable %_ptr_float Function\n" +
1138             "%ld = OpLoad %float %n\n" +
1139             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1140             "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
1141             "OpReturn\n" +
1142             "OpFunctionEnd",
1143         2, false),
1144     // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
1145     InstructionFoldingCase<bool>(
1146         Header() + "%main = OpFunction %void None %void_func\n" +
1147             "%main_lab = OpLabel\n" +
1148             "%n = OpVariable %_ptr_float Function\n" +
1149             "%ld = OpLoad %float %n\n" +
1150             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1151             "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
1152             "OpReturn\n" +
1153             "OpFunctionEnd",
1154         2, false),
1155     // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
1156     InstructionFoldingCase<bool>(
1157         Header() + "%main = OpFunction %void None %void_func\n" +
1158             "%main_lab = OpLabel\n" +
1159             "%n = OpVariable %_ptr_float Function\n" +
1160             "%ld = OpLoad %float %n\n" +
1161             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1162             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
1163             "OpReturn\n" +
1164             "OpFunctionEnd",
1165         2, true),
1166     // Test case 10: fold clamp(n, 1, 2) >= 3.0
1167     InstructionFoldingCase<bool>(
1168         Header() + "%main = OpFunction %void None %void_func\n" +
1169             "%main_lab = OpLabel\n" +
1170             "%n = OpVariable %_ptr_float Function\n" +
1171             "%ld = OpLoad %float %n\n" +
1172             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1173             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
1174             "OpReturn\n" +
1175             "OpFunctionEnd",
1176         2, false),
1177     // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
1178     InstructionFoldingCase<bool>(
1179         Header() + "%main = OpFunction %void None %void_func\n" +
1180             "%main_lab = OpLabel\n" +
1181             "%n = OpVariable %_ptr_float Function\n" +
1182             "%ld = OpLoad %float %n\n" +
1183             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1184             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
1185             "OpReturn\n" +
1186             "OpFunctionEnd",
1187         2, true),
1188     // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
1189     InstructionFoldingCase<bool>(
1190         Header() + "%main = OpFunction %void None %void_func\n" +
1191             "%main_lab = OpLabel\n" +
1192             "%n = OpVariable %_ptr_float Function\n" +
1193             "%ld = OpLoad %float %n\n" +
1194             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1195             "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
1196             "OpReturn\n" +
1197             "OpFunctionEnd",
1198         2, true),
1199     // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
1200     InstructionFoldingCase<bool>(
1201         Header() + "%main = OpFunction %void None %void_func\n" +
1202             "%main_lab = OpLabel\n" +
1203             "%n = OpVariable %_ptr_float Function\n" +
1204             "%ld = OpLoad %float %n\n" +
1205             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1206             "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
1207             "OpReturn\n" +
1208             "OpFunctionEnd",
1209         2, false),
1210     // Test case 14: fold clamp(n, 1, 2) < 3
1211     InstructionFoldingCase<bool>(
1212         Header() + "%main = OpFunction %void None %void_func\n" +
1213             "%main_lab = OpLabel\n" +
1214             "%n = OpVariable %_ptr_float Function\n" +
1215             "%ld = OpLoad %float %n\n" +
1216             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1217             "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
1218             "OpReturn\n" +
1219             "OpFunctionEnd",
1220         2, true),
1221     // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
1222     InstructionFoldingCase<bool>(
1223         Header() + "%main = OpFunction %void None %void_func\n" +
1224             "%main_lab = OpLabel\n" +
1225             "%n = OpVariable %_ptr_float Function\n" +
1226             "%ld = OpLoad %float %n\n" +
1227             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1228             "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
1229             "OpReturn\n" +
1230             "OpFunctionEnd",
1231         2, false),
1232     // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
1233     InstructionFoldingCase<bool>(
1234         Header() + "%main = OpFunction %void None %void_func\n" +
1235             "%main_lab = OpLabel\n" +
1236             "%n = OpVariable %_ptr_double Function\n" +
1237             "%ld = OpLoad %double %n\n" +
1238             "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
1239             "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
1240             "OpReturn\n" +
1241             "OpFunctionEnd",
1242         2, false)
1243 ));
1244 // clang-format on
1245 
1246 using FloatInstructionFoldingTest =
1247     ::testing::TestWithParam<InstructionFoldingCase<float>>;
1248 
TEST_P(FloatInstructionFoldingTest,Case)1249 TEST_P(FloatInstructionFoldingTest, Case) {
1250   const auto& tc = GetParam();
1251 
1252   // Build module.
1253   std::unique_ptr<IRContext> context =
1254       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1255                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1256   ASSERT_NE(nullptr, context);
1257 
1258   // Fold the instruction to test.
1259   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1260   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1261   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1262 
1263   // Make sure the instruction folded as expected.
1264   EXPECT_TRUE(succeeded);
1265   if (inst != nullptr) {
1266     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1267     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1268     EXPECT_EQ(inst->opcode(), SpvOpConstant);
1269     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1270     const analysis::FloatConstant* result =
1271         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
1272     EXPECT_NE(result, nullptr);
1273     if (result != nullptr) {
1274       EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
1275     }
1276   }
1277 }
1278 
1279 // Not testing NaNs because there are no expectations concerning NaNs according
1280 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
1281 // specification.
1282 
1283 // clang-format off
1284 INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
1285 ::testing::Values(
1286     // Test case 0: Fold 2.0 - 1.0
1287     InstructionFoldingCase<float>(
1288         Header() + "%main = OpFunction %void None %void_func\n" +
1289             "%main_lab = OpLabel\n" +
1290             "%2 = OpFSub %float %float_2 %float_1\n" +
1291             "OpReturn\n" +
1292             "OpFunctionEnd",
1293         2, 1.0),
1294     // Test case 1: Fold 2.0 + 1.0
1295     InstructionFoldingCase<float>(
1296         Header() + "%main = OpFunction %void None %void_func\n" +
1297             "%main_lab = OpLabel\n" +
1298             "%2 = OpFAdd %float %float_2 %float_1\n" +
1299             "OpReturn\n" +
1300             "OpFunctionEnd",
1301         2, 3.0),
1302     // Test case 2: Fold 3.0 * 2.0
1303     InstructionFoldingCase<float>(
1304         Header() + "%main = OpFunction %void None %void_func\n" +
1305             "%main_lab = OpLabel\n" +
1306             "%2 = OpFMul %float %float_3 %float_2\n" +
1307             "OpReturn\n" +
1308             "OpFunctionEnd",
1309         2, 6.0),
1310     // Test case 3: Fold 1.0 / 2.0
1311     InstructionFoldingCase<float>(
1312         Header() + "%main = OpFunction %void None %void_func\n" +
1313             "%main_lab = OpLabel\n" +
1314             "%2 = OpFDiv %float %float_1 %float_2\n" +
1315             "OpReturn\n" +
1316             "OpFunctionEnd",
1317         2, 0.5),
1318     // Test case 4: Fold 1.0 / 0.0
1319     InstructionFoldingCase<float>(
1320         Header() + "%main = OpFunction %void None %void_func\n" +
1321             "%main_lab = OpLabel\n" +
1322             "%2 = OpFDiv %float %float_1 %float_0\n" +
1323             "OpReturn\n" +
1324             "OpFunctionEnd",
1325         2, std::numeric_limits<float>::infinity()),
1326     // Test case 5: Fold -1.0 / 0.0
1327     InstructionFoldingCase<float>(
1328         Header() + "%main = OpFunction %void None %void_func\n" +
1329             "%main_lab = OpLabel\n" +
1330             "%2 = OpFDiv %float %float_n1 %float_0\n" +
1331             "OpReturn\n" +
1332             "OpFunctionEnd",
1333         2, -std::numeric_limits<float>::infinity()),
1334     // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
1335     InstructionFoldingCase<float>(
1336         Header() + "%main = OpFunction %void None %void_func\n" +
1337             "%main_lab = OpLabel\n" +
1338             "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
1339             "OpReturn\n" +
1340             "OpFunctionEnd",
1341         2, 5.5f),
1342     // Test case 7: Fold (0.0, 0.0) dot v
1343     InstructionFoldingCase<float>(
1344         Header() + "%main = OpFunction %void None %void_func\n" +
1345             "%main_lab = OpLabel\n" +
1346             "%v = OpVariable %_ptr_v2float Function\n" +
1347             "%2 = OpLoad %v2float %v\n" +
1348             "%3 = OpDot %float %v2float_0_0 %2\n" +
1349             "OpReturn\n" +
1350             "OpFunctionEnd",
1351         3, 0.0f),
1352     // Test case 8: Fold v dot (0.0, 0.0)
1353     InstructionFoldingCase<float>(
1354         Header() + "%main = OpFunction %void None %void_func\n" +
1355             "%main_lab = OpLabel\n" +
1356             "%v = OpVariable %_ptr_v2float Function\n" +
1357             "%2 = OpLoad %v2float %v\n" +
1358             "%3 = OpDot %float %2 %v2float_0_0\n" +
1359             "OpReturn\n" +
1360             "OpFunctionEnd",
1361         3, 0.0f),
1362     // Test case 9: Fold Null dot v
1363     InstructionFoldingCase<float>(
1364         Header() + "%main = OpFunction %void None %void_func\n" +
1365             "%main_lab = OpLabel\n" +
1366             "%v = OpVariable %_ptr_v2float Function\n" +
1367             "%2 = OpLoad %v2float %v\n" +
1368             "%3 = OpDot %float %v2float_null %2\n" +
1369             "OpReturn\n" +
1370             "OpFunctionEnd",
1371         3, 0.0f),
1372     // Test case 10: Fold v dot Null
1373     InstructionFoldingCase<float>(
1374         Header() + "%main = OpFunction %void None %void_func\n" +
1375             "%main_lab = OpLabel\n" +
1376             "%v = OpVariable %_ptr_v2float Function\n" +
1377             "%2 = OpLoad %v2float %v\n" +
1378             "%3 = OpDot %float %2 %v2float_null\n" +
1379             "OpReturn\n" +
1380             "OpFunctionEnd",
1381         3, 0.0f),
1382     // Test case 11: Fold -2.0
1383     InstructionFoldingCase<float>(
1384         Header() + "%main = OpFunction %void None %void_func\n" +
1385             "%main_lab = OpLabel\n" +
1386             "%2 = OpFNegate %float %float_2\n" +
1387             "OpReturn\n" +
1388             "OpFunctionEnd",
1389         2, -2)
1390 ));
1391 // clang-format on
1392 
1393 using DoubleInstructionFoldingTest =
1394     ::testing::TestWithParam<InstructionFoldingCase<double>>;
1395 
TEST_P(DoubleInstructionFoldingTest,Case)1396 TEST_P(DoubleInstructionFoldingTest, Case) {
1397   const auto& tc = GetParam();
1398 
1399   // Build module.
1400   std::unique_ptr<IRContext> context =
1401       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1402                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1403   ASSERT_NE(nullptr, context);
1404 
1405   // Fold the instruction to test.
1406   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1407   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1408   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1409 
1410   // Make sure the instruction folded as expected.
1411   EXPECT_TRUE(succeeded);
1412   if (inst != nullptr) {
1413     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1414     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1415     EXPECT_EQ(inst->opcode(), SpvOpConstant);
1416     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1417     const analysis::FloatConstant* result =
1418         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
1419     EXPECT_NE(result, nullptr);
1420     if (result != nullptr) {
1421       EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
1422     }
1423   }
1424 }
1425 
1426 // clang-format off
1427 INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
1428 ::testing::Values(
1429     // Test case 0: Fold 2.0 - 1.0
1430     InstructionFoldingCase<double>(
1431         Header() + "%main = OpFunction %void None %void_func\n" +
1432             "%main_lab = OpLabel\n" +
1433             "%2 = OpFSub %double %double_2 %double_1\n" +
1434             "OpReturn\n" +
1435             "OpFunctionEnd",
1436         2, 1.0),
1437         // Test case 1: Fold 2.0 + 1.0
1438         InstructionFoldingCase<double>(
1439             Header() + "%main = OpFunction %void None %void_func\n" +
1440                 "%main_lab = OpLabel\n" +
1441                 "%2 = OpFAdd %double %double_2 %double_1\n" +
1442                 "OpReturn\n" +
1443                 "OpFunctionEnd",
1444             2, 3.0),
1445         // Test case 2: Fold 3.0 * 2.0
1446         InstructionFoldingCase<double>(
1447             Header() + "%main = OpFunction %void None %void_func\n" +
1448                 "%main_lab = OpLabel\n" +
1449                 "%2 = OpFMul %double %double_3 %double_2\n" +
1450                 "OpReturn\n" +
1451                 "OpFunctionEnd",
1452             2, 6.0),
1453         // Test case 3: Fold 1.0 / 2.0
1454         InstructionFoldingCase<double>(
1455             Header() + "%main = OpFunction %void None %void_func\n" +
1456                 "%main_lab = OpLabel\n" +
1457                 "%2 = OpFDiv %double %double_1 %double_2\n" +
1458                 "OpReturn\n" +
1459                 "OpFunctionEnd",
1460             2, 0.5),
1461         // Test case 4: Fold 1.0 / 0.0
1462         InstructionFoldingCase<double>(
1463             Header() + "%main = OpFunction %void None %void_func\n" +
1464                 "%main_lab = OpLabel\n" +
1465                 "%2 = OpFDiv %double %double_1 %double_0\n" +
1466                 "OpReturn\n" +
1467                 "OpFunctionEnd",
1468             2, std::numeric_limits<double>::infinity()),
1469         // Test case 5: Fold -1.0 / 0.0
1470         InstructionFoldingCase<double>(
1471             Header() + "%main = OpFunction %void None %void_func\n" +
1472                 "%main_lab = OpLabel\n" +
1473                 "%2 = OpFDiv %double %double_n1 %double_0\n" +
1474                 "OpReturn\n" +
1475                 "OpFunctionEnd",
1476             2, -std::numeric_limits<double>::infinity()),
1477         // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
1478         InstructionFoldingCase<double>(
1479             Header() + "%main = OpFunction %void None %void_func\n" +
1480                 "%main_lab = OpLabel\n" +
1481                 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
1482                 "OpReturn\n" +
1483                 "OpFunctionEnd",
1484             2, 5.5f),
1485         // Test case 7: Fold (0.0, 0.0) dot v
1486         InstructionFoldingCase<double>(
1487             Header() + "%main = OpFunction %void None %void_func\n" +
1488                 "%main_lab = OpLabel\n" +
1489                 "%v = OpVariable %_ptr_v2double Function\n" +
1490                 "%2 = OpLoad %v2double %v\n" +
1491                 "%3 = OpDot %double %v2double_0_0 %2\n" +
1492                 "OpReturn\n" +
1493                 "OpFunctionEnd",
1494             3, 0.0f),
1495         // Test case 8: Fold v dot (0.0, 0.0)
1496         InstructionFoldingCase<double>(
1497             Header() + "%main = OpFunction %void None %void_func\n" +
1498                 "%main_lab = OpLabel\n" +
1499                 "%v = OpVariable %_ptr_v2double Function\n" +
1500                 "%2 = OpLoad %v2double %v\n" +
1501                 "%3 = OpDot %double %2 %v2double_0_0\n" +
1502                 "OpReturn\n" +
1503                 "OpFunctionEnd",
1504             3, 0.0f),
1505         // Test case 9: Fold Null dot v
1506         InstructionFoldingCase<double>(
1507             Header() + "%main = OpFunction %void None %void_func\n" +
1508                 "%main_lab = OpLabel\n" +
1509                 "%v = OpVariable %_ptr_v2double Function\n" +
1510                 "%2 = OpLoad %v2double %v\n" +
1511                 "%3 = OpDot %double %v2double_null %2\n" +
1512                 "OpReturn\n" +
1513                 "OpFunctionEnd",
1514             3, 0.0f),
1515         // Test case 10: Fold v dot Null
1516         InstructionFoldingCase<double>(
1517             Header() + "%main = OpFunction %void None %void_func\n" +
1518                 "%main_lab = OpLabel\n" +
1519                 "%v = OpVariable %_ptr_v2double Function\n" +
1520                 "%2 = OpLoad %v2double %v\n" +
1521                 "%3 = OpDot %double %2 %v2double_null\n" +
1522                 "OpReturn\n" +
1523                 "OpFunctionEnd",
1524             3, 0.0f),
1525         // Test case 11: Fold -2.0
1526         InstructionFoldingCase<double>(
1527             Header() + "%main = OpFunction %void None %void_func\n" +
1528                 "%main_lab = OpLabel\n" +
1529                 "%2 = OpFNegate %double %double_2\n" +
1530                 "OpReturn\n" +
1531                 "OpFunctionEnd",
1532             2, -2)
1533 ));
1534 // clang-format on
1535 
1536 // clang-format off
1537 INSTANTIATE_TEST_CASE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1538                         ::testing::Values(
1539   // Test case 0: fold 1.0 == 2.0
1540   InstructionFoldingCase<bool>(
1541       Header() + "%main = OpFunction %void None %void_func\n" +
1542           "%main_lab = OpLabel\n" +
1543           "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
1544           "OpReturn\n" +
1545           "OpFunctionEnd",
1546       2, false),
1547   // Test case 1: fold 1.0 != 2.0
1548   InstructionFoldingCase<bool>(
1549       Header() + "%main = OpFunction %void None %void_func\n" +
1550           "%main_lab = OpLabel\n" +
1551           "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
1552           "OpReturn\n" +
1553           "OpFunctionEnd",
1554       2, true),
1555   // Test case 2: fold 1.0 < 2.0
1556   InstructionFoldingCase<bool>(
1557       Header() + "%main = OpFunction %void None %void_func\n" +
1558           "%main_lab = OpLabel\n" +
1559           "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
1560           "OpReturn\n" +
1561           "OpFunctionEnd",
1562       2, true),
1563   // Test case 3: fold 1.0 > 2.0
1564   InstructionFoldingCase<bool>(
1565       Header() + "%main = OpFunction %void None %void_func\n" +
1566           "%main_lab = OpLabel\n" +
1567           "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
1568           "OpReturn\n" +
1569           "OpFunctionEnd",
1570       2, false),
1571   // Test case 4: fold 1.0 <= 2.0
1572   InstructionFoldingCase<bool>(
1573       Header() + "%main = OpFunction %void None %void_func\n" +
1574           "%main_lab = OpLabel\n" +
1575           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
1576           "OpReturn\n" +
1577           "OpFunctionEnd",
1578       2, true),
1579   // Test case 5: fold 1.0 >= 2.0
1580   InstructionFoldingCase<bool>(
1581       Header() + "%main = OpFunction %void None %void_func\n" +
1582           "%main_lab = OpLabel\n" +
1583           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
1584           "OpReturn\n" +
1585           "OpFunctionEnd",
1586       2, false),
1587   // Test case 6: fold 1.0 == 1.0
1588   InstructionFoldingCase<bool>(
1589       Header() + "%main = OpFunction %void None %void_func\n" +
1590           "%main_lab = OpLabel\n" +
1591           "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
1592           "OpReturn\n" +
1593           "OpFunctionEnd",
1594       2, true),
1595   // Test case 7: fold 1.0 != 1.0
1596   InstructionFoldingCase<bool>(
1597       Header() + "%main = OpFunction %void None %void_func\n" +
1598           "%main_lab = OpLabel\n" +
1599           "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
1600           "OpReturn\n" +
1601           "OpFunctionEnd",
1602       2, false),
1603   // Test case 8: fold 1.0 < 1.0
1604   InstructionFoldingCase<bool>(
1605       Header() + "%main = OpFunction %void None %void_func\n" +
1606           "%main_lab = OpLabel\n" +
1607           "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
1608           "OpReturn\n" +
1609           "OpFunctionEnd",
1610       2, false),
1611   // Test case 9: fold 1.0 > 1.0
1612   InstructionFoldingCase<bool>(
1613       Header() + "%main = OpFunction %void None %void_func\n" +
1614           "%main_lab = OpLabel\n" +
1615           "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
1616           "OpReturn\n" +
1617           "OpFunctionEnd",
1618       2, false),
1619   // Test case 10: fold 1.0 <= 1.0
1620   InstructionFoldingCase<bool>(
1621       Header() + "%main = OpFunction %void None %void_func\n" +
1622           "%main_lab = OpLabel\n" +
1623           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
1624           "OpReturn\n" +
1625           "OpFunctionEnd",
1626       2, true),
1627   // Test case 11: fold 1.0 >= 1.0
1628   InstructionFoldingCase<bool>(
1629       Header() + "%main = OpFunction %void None %void_func\n" +
1630           "%main_lab = OpLabel\n" +
1631           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
1632           "OpReturn\n" +
1633           "OpFunctionEnd",
1634       2, true),
1635   // Test case 12: fold 2.0 < 1.0
1636   InstructionFoldingCase<bool>(
1637       Header() + "%main = OpFunction %void None %void_func\n" +
1638           "%main_lab = OpLabel\n" +
1639           "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
1640           "OpReturn\n" +
1641           "OpFunctionEnd",
1642       2, false),
1643   // Test case 13: fold 2.0 > 1.0
1644   InstructionFoldingCase<bool>(
1645       Header() + "%main = OpFunction %void None %void_func\n" +
1646           "%main_lab = OpLabel\n" +
1647           "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
1648           "OpReturn\n" +
1649           "OpFunctionEnd",
1650       2, true),
1651   // Test case 14: fold 2.0 <= 1.0
1652   InstructionFoldingCase<bool>(
1653       Header() + "%main = OpFunction %void None %void_func\n" +
1654           "%main_lab = OpLabel\n" +
1655           "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
1656           "OpReturn\n" +
1657           "OpFunctionEnd",
1658       2, false),
1659   // Test case 15: fold 2.0 >= 1.0
1660   InstructionFoldingCase<bool>(
1661       Header() + "%main = OpFunction %void None %void_func\n" +
1662           "%main_lab = OpLabel\n" +
1663           "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
1664           "OpReturn\n" +
1665           "OpFunctionEnd",
1666       2, true)
1667 ));
1668 
1669 INSTANTIATE_TEST_CASE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1670                         ::testing::Values(
1671   // Test case 0: fold 1.0 == 2.0
1672   InstructionFoldingCase<bool>(
1673       Header() + "%main = OpFunction %void None %void_func\n" +
1674           "%main_lab = OpLabel\n" +
1675           "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
1676           "OpReturn\n" +
1677           "OpFunctionEnd",
1678       2, false),
1679   // Test case 1: fold 1.0 != 2.0
1680   InstructionFoldingCase<bool>(
1681       Header() + "%main = OpFunction %void None %void_func\n" +
1682           "%main_lab = OpLabel\n" +
1683           "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
1684           "OpReturn\n" +
1685           "OpFunctionEnd",
1686       2, true),
1687   // Test case 2: fold 1.0 < 2.0
1688   InstructionFoldingCase<bool>(
1689       Header() + "%main = OpFunction %void None %void_func\n" +
1690           "%main_lab = OpLabel\n" +
1691           "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
1692           "OpReturn\n" +
1693           "OpFunctionEnd",
1694       2, true),
1695   // Test case 3: fold 1.0 > 2.0
1696   InstructionFoldingCase<bool>(
1697       Header() + "%main = OpFunction %void None %void_func\n" +
1698           "%main_lab = OpLabel\n" +
1699           "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
1700           "OpReturn\n" +
1701           "OpFunctionEnd",
1702       2, false),
1703   // Test case 4: fold 1.0 <= 2.0
1704   InstructionFoldingCase<bool>(
1705       Header() + "%main = OpFunction %void None %void_func\n" +
1706           "%main_lab = OpLabel\n" +
1707           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
1708           "OpReturn\n" +
1709           "OpFunctionEnd",
1710       2, true),
1711   // Test case 5: fold 1.0 >= 2.0
1712   InstructionFoldingCase<bool>(
1713       Header() + "%main = OpFunction %void None %void_func\n" +
1714           "%main_lab = OpLabel\n" +
1715           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
1716           "OpReturn\n" +
1717           "OpFunctionEnd",
1718       2, false),
1719   // Test case 6: fold 1.0 == 1.0
1720   InstructionFoldingCase<bool>(
1721       Header() + "%main = OpFunction %void None %void_func\n" +
1722           "%main_lab = OpLabel\n" +
1723           "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
1724           "OpReturn\n" +
1725           "OpFunctionEnd",
1726       2, true),
1727   // Test case 7: fold 1.0 != 1.0
1728   InstructionFoldingCase<bool>(
1729       Header() + "%main = OpFunction %void None %void_func\n" +
1730           "%main_lab = OpLabel\n" +
1731           "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
1732           "OpReturn\n" +
1733           "OpFunctionEnd",
1734       2, false),
1735   // Test case 8: fold 1.0 < 1.0
1736   InstructionFoldingCase<bool>(
1737       Header() + "%main = OpFunction %void None %void_func\n" +
1738           "%main_lab = OpLabel\n" +
1739           "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
1740           "OpReturn\n" +
1741           "OpFunctionEnd",
1742       2, false),
1743   // Test case 9: fold 1.0 > 1.0
1744   InstructionFoldingCase<bool>(
1745       Header() + "%main = OpFunction %void None %void_func\n" +
1746           "%main_lab = OpLabel\n" +
1747           "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
1748           "OpReturn\n" +
1749           "OpFunctionEnd",
1750       2, false),
1751   // Test case 10: fold 1.0 <= 1.0
1752   InstructionFoldingCase<bool>(
1753       Header() + "%main = OpFunction %void None %void_func\n" +
1754           "%main_lab = OpLabel\n" +
1755           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
1756           "OpReturn\n" +
1757           "OpFunctionEnd",
1758       2, true),
1759   // Test case 11: fold 1.0 >= 1.0
1760   InstructionFoldingCase<bool>(
1761       Header() + "%main = OpFunction %void None %void_func\n" +
1762           "%main_lab = OpLabel\n" +
1763           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
1764           "OpReturn\n" +
1765           "OpFunctionEnd",
1766       2, true),
1767   // Test case 12: fold 2.0 < 1.0
1768   InstructionFoldingCase<bool>(
1769       Header() + "%main = OpFunction %void None %void_func\n" +
1770           "%main_lab = OpLabel\n" +
1771           "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
1772           "OpReturn\n" +
1773           "OpFunctionEnd",
1774       2, false),
1775   // Test case 13: fold 2.0 > 1.0
1776   InstructionFoldingCase<bool>(
1777       Header() + "%main = OpFunction %void None %void_func\n" +
1778           "%main_lab = OpLabel\n" +
1779           "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
1780           "OpReturn\n" +
1781           "OpFunctionEnd",
1782       2, true),
1783   // Test case 14: fold 2.0 <= 1.0
1784   InstructionFoldingCase<bool>(
1785       Header() + "%main = OpFunction %void None %void_func\n" +
1786           "%main_lab = OpLabel\n" +
1787           "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
1788           "OpReturn\n" +
1789           "OpFunctionEnd",
1790       2, false),
1791   // Test case 15: fold 2.0 >= 1.0
1792   InstructionFoldingCase<bool>(
1793       Header() + "%main = OpFunction %void None %void_func\n" +
1794           "%main_lab = OpLabel\n" +
1795           "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
1796           "OpReturn\n" +
1797           "OpFunctionEnd",
1798       2, true)
1799 ));
1800 
1801 INSTANTIATE_TEST_CASE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1802                         ::testing::Values(
1803   // Test case 0: fold 1.0 == 2.0
1804   InstructionFoldingCase<bool>(
1805       Header() + "%main = OpFunction %void None %void_func\n" +
1806           "%main_lab = OpLabel\n" +
1807           "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
1808           "OpReturn\n" +
1809           "OpFunctionEnd",
1810       2, false),
1811   // Test case 1: fold 1.0 != 2.0
1812   InstructionFoldingCase<bool>(
1813       Header() + "%main = OpFunction %void None %void_func\n" +
1814           "%main_lab = OpLabel\n" +
1815           "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
1816           "OpReturn\n" +
1817           "OpFunctionEnd",
1818       2, true),
1819   // Test case 2: fold 1.0 < 2.0
1820   InstructionFoldingCase<bool>(
1821       Header() + "%main = OpFunction %void None %void_func\n" +
1822           "%main_lab = OpLabel\n" +
1823           "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
1824           "OpReturn\n" +
1825           "OpFunctionEnd",
1826       2, true),
1827   // Test case 3: fold 1.0 > 2.0
1828   InstructionFoldingCase<bool>(
1829       Header() + "%main = OpFunction %void None %void_func\n" +
1830           "%main_lab = OpLabel\n" +
1831           "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
1832           "OpReturn\n" +
1833           "OpFunctionEnd",
1834       2, false),
1835   // Test case 4: fold 1.0 <= 2.0
1836   InstructionFoldingCase<bool>(
1837       Header() + "%main = OpFunction %void None %void_func\n" +
1838           "%main_lab = OpLabel\n" +
1839           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
1840           "OpReturn\n" +
1841           "OpFunctionEnd",
1842       2, true),
1843   // Test case 5: fold 1.0 >= 2.0
1844   InstructionFoldingCase<bool>(
1845       Header() + "%main = OpFunction %void None %void_func\n" +
1846           "%main_lab = OpLabel\n" +
1847           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
1848           "OpReturn\n" +
1849           "OpFunctionEnd",
1850       2, false),
1851   // Test case 6: fold 1.0 == 1.0
1852   InstructionFoldingCase<bool>(
1853       Header() + "%main = OpFunction %void None %void_func\n" +
1854           "%main_lab = OpLabel\n" +
1855           "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
1856           "OpReturn\n" +
1857           "OpFunctionEnd",
1858       2, true),
1859   // Test case 7: fold 1.0 != 1.0
1860   InstructionFoldingCase<bool>(
1861       Header() + "%main = OpFunction %void None %void_func\n" +
1862           "%main_lab = OpLabel\n" +
1863           "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
1864           "OpReturn\n" +
1865           "OpFunctionEnd",
1866       2, false),
1867   // Test case 8: fold 1.0 < 1.0
1868   InstructionFoldingCase<bool>(
1869       Header() + "%main = OpFunction %void None %void_func\n" +
1870           "%main_lab = OpLabel\n" +
1871           "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
1872           "OpReturn\n" +
1873           "OpFunctionEnd",
1874       2, false),
1875   // Test case 9: fold 1.0 > 1.0
1876   InstructionFoldingCase<bool>(
1877       Header() + "%main = OpFunction %void None %void_func\n" +
1878           "%main_lab = OpLabel\n" +
1879           "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
1880           "OpReturn\n" +
1881           "OpFunctionEnd",
1882       2, false),
1883   // Test case 10: fold 1.0 <= 1.0
1884   InstructionFoldingCase<bool>(
1885       Header() + "%main = OpFunction %void None %void_func\n" +
1886           "%main_lab = OpLabel\n" +
1887           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
1888           "OpReturn\n" +
1889           "OpFunctionEnd",
1890       2, true),
1891   // Test case 11: fold 1.0 >= 1.0
1892   InstructionFoldingCase<bool>(
1893       Header() + "%main = OpFunction %void None %void_func\n" +
1894           "%main_lab = OpLabel\n" +
1895           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
1896           "OpReturn\n" +
1897           "OpFunctionEnd",
1898       2, true),
1899   // Test case 12: fold 2.0 < 1.0
1900   InstructionFoldingCase<bool>(
1901       Header() + "%main = OpFunction %void None %void_func\n" +
1902           "%main_lab = OpLabel\n" +
1903           "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
1904           "OpReturn\n" +
1905           "OpFunctionEnd",
1906       2, false),
1907   // Test case 13: fold 2.0 > 1.0
1908   InstructionFoldingCase<bool>(
1909       Header() + "%main = OpFunction %void None %void_func\n" +
1910           "%main_lab = OpLabel\n" +
1911           "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
1912           "OpReturn\n" +
1913           "OpFunctionEnd",
1914       2, true),
1915   // Test case 14: fold 2.0 <= 1.0
1916   InstructionFoldingCase<bool>(
1917       Header() + "%main = OpFunction %void None %void_func\n" +
1918           "%main_lab = OpLabel\n" +
1919           "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
1920           "OpReturn\n" +
1921           "OpFunctionEnd",
1922       2, false),
1923   // Test case 15: fold 2.0 >= 1.0
1924   InstructionFoldingCase<bool>(
1925       Header() + "%main = OpFunction %void None %void_func\n" +
1926           "%main_lab = OpLabel\n" +
1927           "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
1928           "OpReturn\n" +
1929           "OpFunctionEnd",
1930       2, true)
1931 ));
1932 
1933 INSTANTIATE_TEST_CASE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1934                         ::testing::Values(
1935   // Test case 0: fold 1.0 == 2.0
1936   InstructionFoldingCase<bool>(
1937       Header() + "%main = OpFunction %void None %void_func\n" +
1938           "%main_lab = OpLabel\n" +
1939           "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
1940           "OpReturn\n" +
1941           "OpFunctionEnd",
1942       2, false),
1943   // Test case 1: fold 1.0 != 2.0
1944   InstructionFoldingCase<bool>(
1945       Header() + "%main = OpFunction %void None %void_func\n" +
1946           "%main_lab = OpLabel\n" +
1947           "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
1948           "OpReturn\n" +
1949           "OpFunctionEnd",
1950       2, true),
1951   // Test case 2: fold 1.0 < 2.0
1952   InstructionFoldingCase<bool>(
1953       Header() + "%main = OpFunction %void None %void_func\n" +
1954           "%main_lab = OpLabel\n" +
1955           "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
1956           "OpReturn\n" +
1957           "OpFunctionEnd",
1958       2, true),
1959   // Test case 3: fold 1.0 > 2.0
1960   InstructionFoldingCase<bool>(
1961       Header() + "%main = OpFunction %void None %void_func\n" +
1962           "%main_lab = OpLabel\n" +
1963           "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
1964           "OpReturn\n" +
1965           "OpFunctionEnd",
1966       2, false),
1967   // Test case 4: fold 1.0 <= 2.0
1968   InstructionFoldingCase<bool>(
1969       Header() + "%main = OpFunction %void None %void_func\n" +
1970           "%main_lab = OpLabel\n" +
1971           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
1972           "OpReturn\n" +
1973           "OpFunctionEnd",
1974       2, true),
1975   // Test case 5: fold 1.0 >= 2.0
1976   InstructionFoldingCase<bool>(
1977       Header() + "%main = OpFunction %void None %void_func\n" +
1978           "%main_lab = OpLabel\n" +
1979           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
1980           "OpReturn\n" +
1981           "OpFunctionEnd",
1982       2, false),
1983   // Test case 6: fold 1.0 == 1.0
1984   InstructionFoldingCase<bool>(
1985       Header() + "%main = OpFunction %void None %void_func\n" +
1986           "%main_lab = OpLabel\n" +
1987           "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
1988           "OpReturn\n" +
1989           "OpFunctionEnd",
1990       2, true),
1991   // Test case 7: fold 1.0 != 1.0
1992   InstructionFoldingCase<bool>(
1993       Header() + "%main = OpFunction %void None %void_func\n" +
1994           "%main_lab = OpLabel\n" +
1995           "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
1996           "OpReturn\n" +
1997           "OpFunctionEnd",
1998       2, false),
1999   // Test case 8: fold 1.0 < 1.0
2000   InstructionFoldingCase<bool>(
2001       Header() + "%main = OpFunction %void None %void_func\n" +
2002           "%main_lab = OpLabel\n" +
2003           "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
2004           "OpReturn\n" +
2005           "OpFunctionEnd",
2006       2, false),
2007   // Test case 9: fold 1.0 > 1.0
2008   InstructionFoldingCase<bool>(
2009       Header() + "%main = OpFunction %void None %void_func\n" +
2010           "%main_lab = OpLabel\n" +
2011           "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
2012           "OpReturn\n" +
2013           "OpFunctionEnd",
2014       2, false),
2015   // Test case 10: fold 1.0 <= 1.0
2016   InstructionFoldingCase<bool>(
2017       Header() + "%main = OpFunction %void None %void_func\n" +
2018           "%main_lab = OpLabel\n" +
2019           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
2020           "OpReturn\n" +
2021           "OpFunctionEnd",
2022       2, true),
2023   // Test case 11: fold 1.0 >= 1.0
2024   InstructionFoldingCase<bool>(
2025       Header() + "%main = OpFunction %void None %void_func\n" +
2026           "%main_lab = OpLabel\n" +
2027           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
2028           "OpReturn\n" +
2029           "OpFunctionEnd",
2030       2, true),
2031   // Test case 12: fold 2.0 < 1.0
2032   InstructionFoldingCase<bool>(
2033       Header() + "%main = OpFunction %void None %void_func\n" +
2034           "%main_lab = OpLabel\n" +
2035           "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
2036           "OpReturn\n" +
2037           "OpFunctionEnd",
2038       2, false),
2039   // Test case 13: fold 2.0 > 1.0
2040   InstructionFoldingCase<bool>(
2041       Header() + "%main = OpFunction %void None %void_func\n" +
2042           "%main_lab = OpLabel\n" +
2043           "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
2044           "OpReturn\n" +
2045           "OpFunctionEnd",
2046       2, true),
2047   // Test case 14: fold 2.0 <= 1.0
2048   InstructionFoldingCase<bool>(
2049       Header() + "%main = OpFunction %void None %void_func\n" +
2050           "%main_lab = OpLabel\n" +
2051           "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
2052           "OpReturn\n" +
2053           "OpFunctionEnd",
2054       2, false),
2055   // Test case 15: fold 2.0 >= 1.0
2056   InstructionFoldingCase<bool>(
2057       Header() + "%main = OpFunction %void None %void_func\n" +
2058           "%main_lab = OpLabel\n" +
2059           "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
2060           "OpReturn\n" +
2061           "OpFunctionEnd",
2062       2, true)
2063 ));
2064 
2065 INSTANTIATE_TEST_CASE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2066                         ::testing::Values(
2067   // Test case 0: fold NaN == 0 (ord)
2068   InstructionFoldingCase<bool>(
2069       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2070           "%main_lab = OpLabel\n" +
2071           "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
2072           "OpReturn\n" +
2073           "OpFunctionEnd",
2074       2, false),
2075   // Test case 1: fold NaN == NaN (unord)
2076   InstructionFoldingCase<bool>(
2077       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2078           "%main_lab = OpLabel\n" +
2079           "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
2080           "OpReturn\n" +
2081           "OpFunctionEnd",
2082       2, true),
2083   // Test case 2: fold NaN != NaN (ord)
2084   InstructionFoldingCase<bool>(
2085       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2086           "%main_lab = OpLabel\n" +
2087           "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
2088           "OpReturn\n" +
2089           "OpFunctionEnd",
2090       2, false),
2091   // Test case 3: fold NaN != NaN (unord)
2092   InstructionFoldingCase<bool>(
2093       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2094           "%main_lab = OpLabel\n" +
2095           "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
2096           "OpReturn\n" +
2097           "OpFunctionEnd",
2098       2, true)
2099 ));
2100 
2101 INSTANTIATE_TEST_CASE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2102                         ::testing::Values(
2103   // Test case 0: fold NaN == 0 (ord)
2104   InstructionFoldingCase<bool>(
2105       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2106           "%main_lab = OpLabel\n" +
2107           "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
2108           "OpReturn\n" +
2109           "OpFunctionEnd",
2110       2, false),
2111   // Test case 1: fold NaN == NaN (unord)
2112   InstructionFoldingCase<bool>(
2113       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2114           "%main_lab = OpLabel\n" +
2115           "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
2116           "OpReturn\n" +
2117           "OpFunctionEnd",
2118       2, true),
2119   // Test case 2: fold NaN != NaN (ord)
2120   InstructionFoldingCase<bool>(
2121       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2122           "%main_lab = OpLabel\n" +
2123           "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
2124           "OpReturn\n" +
2125           "OpFunctionEnd",
2126       2, false),
2127   // Test case 3: fold NaN != NaN (unord)
2128   InstructionFoldingCase<bool>(
2129       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2130           "%main_lab = OpLabel\n" +
2131           "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
2132           "OpReturn\n" +
2133           "OpFunctionEnd",
2134       2, true)
2135 ));
2136 // clang-format on
2137 
2138 template <class ResultType>
2139 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anon2055d22d0111::InstructionFoldingCaseWithMap2140   InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
2141                                 ResultType result,
2142                                 std::function<uint32_t(uint32_t)> map)
2143       : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
2144 
2145   std::string test_body;
2146   uint32_t id_to_fold;
2147   ResultType expected_result;
2148   std::function<uint32_t(uint32_t)> id_map;
2149 };
2150 
2151 using IntegerInstructionFoldingTestWithMap =
2152     ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
2153 
TEST_P(IntegerInstructionFoldingTestWithMap,Case)2154 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
2155   const auto& tc = GetParam();
2156 
2157   // Build module.
2158   std::unique_ptr<IRContext> context =
2159       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2160                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2161   ASSERT_NE(nullptr, context);
2162 
2163   // Fold the instruction to test.
2164   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2165   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2166   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
2167                                                                      tc.id_map);
2168 
2169   // Make sure the instruction folded as expected.
2170   EXPECT_NE(inst, nullptr);
2171   if (inst != nullptr) {
2172     EXPECT_EQ(inst->opcode(), SpvOpConstant);
2173     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2174     const analysis::IntConstant* result =
2175         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
2176     EXPECT_NE(result, nullptr);
2177     if (result != nullptr) {
2178       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
2179     }
2180   }
2181 }
2182 // clang-format off
2183 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap,
2184   ::testing::Values(
2185       // Test case 0: fold %3 = 0; %3 * n
2186       InstructionFoldingCaseWithMap<uint32_t>(
2187           Header() + "%main = OpFunction %void None %void_func\n" +
2188               "%main_lab = OpLabel\n" +
2189               "%n = OpVariable %_ptr_int Function\n" +
2190               "%load = OpLoad %int %n\n" +
2191               "%3 = OpCopyObject %int %int_0\n"
2192               "%2 = OpIMul %int %3 %load\n" +
2193               "OpReturn\n" +
2194               "OpFunctionEnd",
__anon2055d22d0202(uint32_t id) 2195           2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
2196   ));
2197 // clang-format on
2198 
2199 using BooleanInstructionFoldingTestWithMap =
2200     ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
2201 
TEST_P(BooleanInstructionFoldingTestWithMap,Case)2202 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
2203   const auto& tc = GetParam();
2204 
2205   // Build module.
2206   std::unique_ptr<IRContext> context =
2207       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2208                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2209   ASSERT_NE(nullptr, context);
2210 
2211   // Fold the instruction to test.
2212   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2213   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2214   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
2215                                                                      tc.id_map);
2216 
2217   // Make sure the instruction folded as expected.
2218   EXPECT_NE(inst, nullptr);
2219   if (inst != nullptr) {
2220     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
2221     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
2222     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2223     const analysis::BoolConstant* result =
2224         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
2225     EXPECT_NE(result, nullptr);
2226     if (result != nullptr) {
2227       EXPECT_EQ(result->value(), tc.expected_result);
2228     }
2229   }
2230 }
2231 
2232 // clang-format off
2233 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap,
2234   ::testing::Values(
2235       // Test case 0: fold %3 = true; %3 || n
2236       InstructionFoldingCaseWithMap<bool>(
2237           Header() + "%main = OpFunction %void None %void_func\n" +
2238               "%main_lab = OpLabel\n" +
2239               "%n = OpVariable %_ptr_bool Function\n" +
2240               "%load = OpLoad %bool %n\n" +
2241               "%3 = OpCopyObject %bool %true\n" +
2242               "%2 = OpLogicalOr %bool %3 %load\n" +
2243               "OpReturn\n" +
2244               "OpFunctionEnd",
__anon2055d22d0302(uint32_t id) 2245           2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
2246   ));
2247 // clang-format on
2248 
2249 using GeneralInstructionFoldingTest =
2250     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
2251 
TEST_P(GeneralInstructionFoldingTest,Case)2252 TEST_P(GeneralInstructionFoldingTest, Case) {
2253   const auto& tc = GetParam();
2254 
2255   // Build module.
2256   std::unique_ptr<IRContext> context =
2257       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2258                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2259   ASSERT_NE(nullptr, context);
2260 
2261   // Fold the instruction to test.
2262   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2263   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2264   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
2265   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2266 
2267   // Make sure the instruction folded as expected.
2268   EXPECT_EQ(inst->result_id(), original_inst->result_id());
2269   EXPECT_EQ(inst->type_id(), original_inst->type_id());
2270   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
2271   if (succeeded) {
2272     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
2273     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
2274   } else {
2275     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
2276     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
2277       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
2278     }
2279   }
2280 }
2281 
2282 // clang-format off
2283 INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
2284                         ::testing::Values(
2285     // Test case 0: Don't fold n * m
2286     InstructionFoldingCase<uint32_t>(
2287         Header() + "%main = OpFunction %void None %void_func\n" +
2288             "%main_lab = OpLabel\n" +
2289             "%n = OpVariable %_ptr_int Function\n" +
2290             "%m = OpVariable %_ptr_int Function\n" +
2291             "%load_n = OpLoad %int %n\n" +
2292             "%load_m = OpLoad %int %m\n" +
2293             "%2 = OpIMul %int %load_n %load_m\n" +
2294             "OpReturn\n" +
2295             "OpFunctionEnd",
2296         2, 0),
2297     // Test case 1: Don't fold n / m (unsigned)
2298     InstructionFoldingCase<uint32_t>(
2299         Header() + "%main = OpFunction %void None %void_func\n" +
2300             "%main_lab = OpLabel\n" +
2301             "%n = OpVariable %_ptr_uint Function\n" +
2302             "%m = OpVariable %_ptr_uint Function\n" +
2303             "%load_n = OpLoad %uint %n\n" +
2304             "%load_m = OpLoad %uint %m\n" +
2305             "%2 = OpUDiv %uint %load_n %load_m\n" +
2306             "OpReturn\n" +
2307             "OpFunctionEnd",
2308         2, 0),
2309     // Test case 2: Don't fold n / m (signed)
2310     InstructionFoldingCase<uint32_t>(
2311         Header() + "%main = OpFunction %void None %void_func\n" +
2312             "%main_lab = OpLabel\n" +
2313             "%n = OpVariable %_ptr_int Function\n" +
2314             "%m = OpVariable %_ptr_int Function\n" +
2315             "%load_n = OpLoad %int %n\n" +
2316             "%load_m = OpLoad %int %m\n" +
2317             "%2 = OpSDiv %int %load_n %load_m\n" +
2318             "OpReturn\n" +
2319             "OpFunctionEnd",
2320         2, 0),
2321     // Test case 3: Don't fold n remainder m
2322     InstructionFoldingCase<uint32_t>(
2323         Header() + "%main = OpFunction %void None %void_func\n" +
2324             "%main_lab = OpLabel\n" +
2325             "%n = OpVariable %_ptr_int Function\n" +
2326             "%m = OpVariable %_ptr_int Function\n" +
2327             "%load_n = OpLoad %int %n\n" +
2328             "%load_m = OpLoad %int %m\n" +
2329             "%2 = OpSRem %int %load_n %load_m\n" +
2330             "OpReturn\n" +
2331             "OpFunctionEnd",
2332         2, 0),
2333     // Test case 4: Don't fold n % m (signed)
2334     InstructionFoldingCase<uint32_t>(
2335         Header() + "%main = OpFunction %void None %void_func\n" +
2336             "%main_lab = OpLabel\n" +
2337             "%n = OpVariable %_ptr_int Function\n" +
2338             "%m = OpVariable %_ptr_int Function\n" +
2339             "%load_n = OpLoad %int %n\n" +
2340             "%load_m = OpLoad %int %m\n" +
2341             "%2 = OpSMod %int %load_n %load_m\n" +
2342             "OpReturn\n" +
2343             "OpFunctionEnd",
2344         2, 0),
2345     // Test case 5: Don't fold n % m (unsigned)
2346     InstructionFoldingCase<uint32_t>(
2347         Header() + "%main = OpFunction %void None %void_func\n" +
2348             "%main_lab = OpLabel\n" +
2349             "%n = OpVariable %_ptr_uint Function\n" +
2350             "%m = OpVariable %_ptr_uint Function\n" +
2351             "%load_n = OpLoad %uint %n\n" +
2352             "%load_m = OpLoad %uint %m\n" +
2353             "%2 = OpUMod %int %load_n %load_m\n" +
2354             "OpReturn\n" +
2355             "OpFunctionEnd",
2356         2, 0),
2357     // Test case 6: Don't fold n << m
2358     InstructionFoldingCase<uint32_t>(
2359         Header() + "%main = OpFunction %void None %void_func\n" +
2360             "%main_lab = OpLabel\n" +
2361             "%n = OpVariable %_ptr_uint Function\n" +
2362             "%m = OpVariable %_ptr_uint Function\n" +
2363             "%load_n = OpLoad %uint %n\n" +
2364             "%load_m = OpLoad %uint %m\n" +
2365             "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
2366             "OpReturn\n" +
2367             "OpFunctionEnd",
2368         2, 0),
2369     // Test case 7: Don't fold n >> m
2370     InstructionFoldingCase<uint32_t>(
2371         Header() + "%main = OpFunction %void None %void_func\n" +
2372             "%main_lab = OpLabel\n" +
2373             "%n = OpVariable %_ptr_uint Function\n" +
2374             "%m = OpVariable %_ptr_uint Function\n" +
2375             "%load_n = OpLoad %uint %n\n" +
2376             "%load_m = OpLoad %uint %m\n" +
2377             "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
2378             "OpReturn\n" +
2379             "OpFunctionEnd",
2380         2, 0),
2381     // Test case 8: Don't fold n | m
2382     InstructionFoldingCase<uint32_t>(
2383         Header() + "%main = OpFunction %void None %void_func\n" +
2384             "%main_lab = OpLabel\n" +
2385             "%n = OpVariable %_ptr_uint Function\n" +
2386             "%m = OpVariable %_ptr_uint Function\n" +
2387             "%load_n = OpLoad %uint %n\n" +
2388             "%load_m = OpLoad %uint %m\n" +
2389             "%2 = OpBitwiseOr %int %load_n %load_m\n" +
2390             "OpReturn\n" +
2391             "OpFunctionEnd",
2392         2, 0),
2393     // Test case 9: Don't fold n & m
2394     InstructionFoldingCase<uint32_t>(
2395         Header() + "%main = OpFunction %void None %void_func\n" +
2396             "%main_lab = OpLabel\n" +
2397             "%n = OpVariable %_ptr_uint Function\n" +
2398             "%m = OpVariable %_ptr_uint Function\n" +
2399             "%load_n = OpLoad %uint %n\n" +
2400             "%load_m = OpLoad %uint %m\n" +
2401             "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
2402             "OpReturn\n" +
2403             "OpFunctionEnd",
2404         2, 0),
2405     // Test case 10: Don't fold n < m (unsigned)
2406     InstructionFoldingCase<uint32_t>(
2407         Header() + "%main = OpFunction %void None %void_func\n" +
2408             "%main_lab = OpLabel\n" +
2409             "%n = OpVariable %_ptr_uint Function\n" +
2410             "%m = OpVariable %_ptr_uint Function\n" +
2411             "%load_n = OpLoad %uint %n\n" +
2412             "%load_m = OpLoad %uint %m\n" +
2413             "%2 = OpULessThan %bool %load_n %load_m\n" +
2414             "OpReturn\n" +
2415             "OpFunctionEnd",
2416         2, 0),
2417     // Test case 11: Don't fold n > m (unsigned)
2418     InstructionFoldingCase<uint32_t>(
2419         Header() + "%main = OpFunction %void None %void_func\n" +
2420             "%main_lab = OpLabel\n" +
2421             "%n = OpVariable %_ptr_uint Function\n" +
2422             "%m = OpVariable %_ptr_uint Function\n" +
2423             "%load_n = OpLoad %uint %n\n" +
2424             "%load_m = OpLoad %uint %m\n" +
2425             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
2426             "OpReturn\n" +
2427             "OpFunctionEnd",
2428         2, 0),
2429     // Test case 12: Don't fold n <= m (unsigned)
2430     InstructionFoldingCase<uint32_t>(
2431         Header() + "%main = OpFunction %void None %void_func\n" +
2432             "%main_lab = OpLabel\n" +
2433             "%n = OpVariable %_ptr_uint Function\n" +
2434             "%m = OpVariable %_ptr_uint Function\n" +
2435             "%load_n = OpLoad %uint %n\n" +
2436             "%load_m = OpLoad %uint %m\n" +
2437             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
2438             "OpReturn\n" +
2439             "OpFunctionEnd",
2440         2, 0),
2441     // Test case 13: Don't fold n >= m (unsigned)
2442     InstructionFoldingCase<uint32_t>(
2443         Header() + "%main = OpFunction %void None %void_func\n" +
2444             "%main_lab = OpLabel\n" +
2445             "%n = OpVariable %_ptr_uint Function\n" +
2446             "%m = OpVariable %_ptr_uint Function\n" +
2447             "%load_n = OpLoad %uint %n\n" +
2448             "%load_m = OpLoad %uint %m\n" +
2449             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
2450             "OpReturn\n" +
2451             "OpFunctionEnd",
2452         2, 0),
2453     // Test case 14: Don't fold n < m (signed)
2454     InstructionFoldingCase<uint32_t>(
2455         Header() + "%main = OpFunction %void None %void_func\n" +
2456             "%main_lab = OpLabel\n" +
2457             "%n = OpVariable %_ptr_int Function\n" +
2458             "%m = OpVariable %_ptr_int Function\n" +
2459             "%load_n = OpLoad %int %n\n" +
2460             "%load_m = OpLoad %int %m\n" +
2461             "%2 = OpULessThan %bool %load_n %load_m\n" +
2462             "OpReturn\n" +
2463             "OpFunctionEnd",
2464         2, 0),
2465     // Test case 15: Don't fold n > m (signed)
2466     InstructionFoldingCase<uint32_t>(
2467         Header() + "%main = OpFunction %void None %void_func\n" +
2468             "%main_lab = OpLabel\n" +
2469             "%n = OpVariable %_ptr_int Function\n" +
2470             "%m = OpVariable %_ptr_int Function\n" +
2471             "%load_n = OpLoad %int %n\n" +
2472             "%load_m = OpLoad %int %m\n" +
2473             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
2474             "OpReturn\n" +
2475             "OpFunctionEnd",
2476         2, 0),
2477     // Test case 16: Don't fold n <= m (signed)
2478     InstructionFoldingCase<uint32_t>(
2479         Header() + "%main = OpFunction %void None %void_func\n" +
2480             "%main_lab = OpLabel\n" +
2481             "%n = OpVariable %_ptr_int Function\n" +
2482             "%m = OpVariable %_ptr_int Function\n" +
2483             "%load_n = OpLoad %int %n\n" +
2484             "%load_m = OpLoad %int %m\n" +
2485             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
2486             "OpReturn\n" +
2487             "OpFunctionEnd",
2488         2, 0),
2489     // Test case 17: Don't fold n >= m (signed)
2490     InstructionFoldingCase<uint32_t>(
2491         Header() + "%main = OpFunction %void None %void_func\n" +
2492             "%main_lab = OpLabel\n" +
2493             "%n = OpVariable %_ptr_int Function\n" +
2494             "%m = OpVariable %_ptr_int Function\n" +
2495             "%load_n = OpLoad %int %n\n" +
2496             "%load_m = OpLoad %int %m\n" +
2497             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
2498             "OpReturn\n" +
2499             "OpFunctionEnd",
2500         2, 0),
2501     // Test case 18: Don't fold n || m
2502     InstructionFoldingCase<uint32_t>(
2503         Header() + "%main = OpFunction %void None %void_func\n" +
2504             "%main_lab = OpLabel\n" +
2505             "%n = OpVariable %_ptr_bool Function\n" +
2506             "%m = OpVariable %_ptr_bool Function\n" +
2507             "%load_n = OpLoad %bool %n\n" +
2508             "%load_m = OpLoad %bool %m\n" +
2509             "%2 = OpLogicalOr %bool %load_n %load_m\n" +
2510             "OpReturn\n" +
2511             "OpFunctionEnd",
2512         2, 0),
2513     // Test case 19: Don't fold n && m
2514     InstructionFoldingCase<uint32_t>(
2515         Header() + "%main = OpFunction %void None %void_func\n" +
2516             "%main_lab = OpLabel\n" +
2517             "%n = OpVariable %_ptr_bool Function\n" +
2518             "%m = OpVariable %_ptr_bool Function\n" +
2519             "%load_n = OpLoad %bool %n\n" +
2520             "%load_m = OpLoad %bool %m\n" +
2521             "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
2522             "OpReturn\n" +
2523             "OpFunctionEnd",
2524         2, 0),
2525     // Test case 20: Don't fold n * 3
2526     InstructionFoldingCase<uint32_t>(
2527         Header() + "%main = OpFunction %void None %void_func\n" +
2528             "%main_lab = OpLabel\n" +
2529             "%n = OpVariable %_ptr_int Function\n" +
2530             "%load_n = OpLoad %int %n\n" +
2531             "%2 = OpIMul %int %load_n %int_3\n" +
2532             "OpReturn\n" +
2533             "OpFunctionEnd",
2534         2, 0),
2535     // Test case 21: Don't fold n / 3 (unsigned)
2536     InstructionFoldingCase<uint32_t>(
2537         Header() + "%main = OpFunction %void None %void_func\n" +
2538             "%main_lab = OpLabel\n" +
2539             "%n = OpVariable %_ptr_uint Function\n" +
2540             "%load_n = OpLoad %uint %n\n" +
2541             "%2 = OpUDiv %uint %load_n %uint_3\n" +
2542             "OpReturn\n" +
2543             "OpFunctionEnd",
2544         2, 0),
2545     // Test case 22: Don't fold n / 3 (signed)
2546     InstructionFoldingCase<uint32_t>(
2547         Header() + "%main = OpFunction %void None %void_func\n" +
2548             "%main_lab = OpLabel\n" +
2549             "%n = OpVariable %_ptr_int Function\n" +
2550             "%load_n = OpLoad %int %n\n" +
2551             "%2 = OpSDiv %int %load_n %int_3\n" +
2552             "OpReturn\n" +
2553             "OpFunctionEnd",
2554         2, 0),
2555     // Test case 23: Don't fold n remainder 3
2556     InstructionFoldingCase<uint32_t>(
2557         Header() + "%main = OpFunction %void None %void_func\n" +
2558             "%main_lab = OpLabel\n" +
2559             "%n = OpVariable %_ptr_int Function\n" +
2560             "%load_n = OpLoad %int %n\n" +
2561             "%2 = OpSRem %int %load_n %int_3\n" +
2562             "OpReturn\n" +
2563             "OpFunctionEnd",
2564         2, 0),
2565     // Test case 24: Don't fold n % 3 (signed)
2566     InstructionFoldingCase<uint32_t>(
2567         Header() + "%main = OpFunction %void None %void_func\n" +
2568             "%main_lab = OpLabel\n" +
2569             "%n = OpVariable %_ptr_int Function\n" +
2570             "%load_n = OpLoad %int %n\n" +
2571             "%2 = OpSMod %int %load_n %int_3\n" +
2572             "OpReturn\n" +
2573             "OpFunctionEnd",
2574         2, 0),
2575     // Test case 25: Don't fold n % 3 (unsigned)
2576     InstructionFoldingCase<uint32_t>(
2577         Header() + "%main = OpFunction %void None %void_func\n" +
2578             "%main_lab = OpLabel\n" +
2579             "%n = OpVariable %_ptr_uint Function\n" +
2580             "%load_n = OpLoad %uint %n\n" +
2581             "%2 = OpUMod %int %load_n %int_3\n" +
2582             "OpReturn\n" +
2583             "OpFunctionEnd",
2584         2, 0),
2585     // Test case 26: Don't fold n << 3
2586     InstructionFoldingCase<uint32_t>(
2587         Header() + "%main = OpFunction %void None %void_func\n" +
2588             "%main_lab = OpLabel\n" +
2589             "%n = OpVariable %_ptr_uint Function\n" +
2590             "%load_n = OpLoad %uint %n\n" +
2591             "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
2592             "OpReturn\n" +
2593             "OpFunctionEnd",
2594         2, 0),
2595     // Test case 27: Don't fold n >> 3
2596     InstructionFoldingCase<uint32_t>(
2597         Header() + "%main = OpFunction %void None %void_func\n" +
2598             "%main_lab = OpLabel\n" +
2599             "%n = OpVariable %_ptr_uint Function\n" +
2600             "%load_n = OpLoad %uint %n\n" +
2601             "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
2602             "OpReturn\n" +
2603             "OpFunctionEnd",
2604         2, 0),
2605     // Test case 28: Don't fold n | 3
2606     InstructionFoldingCase<uint32_t>(
2607         Header() + "%main = OpFunction %void None %void_func\n" +
2608             "%main_lab = OpLabel\n" +
2609             "%n = OpVariable %_ptr_uint Function\n" +
2610             "%load_n = OpLoad %uint %n\n" +
2611             "%2 = OpBitwiseOr %int %load_n %int_3\n" +
2612             "OpReturn\n" +
2613             "OpFunctionEnd",
2614         2, 0),
2615     // Test case 29: Don't fold n & 3
2616     InstructionFoldingCase<uint32_t>(
2617         Header() + "%main = OpFunction %void None %void_func\n" +
2618             "%main_lab = OpLabel\n" +
2619             "%n = OpVariable %_ptr_uint Function\n" +
2620             "%load_n = OpLoad %uint %n\n" +
2621             "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
2622             "OpReturn\n" +
2623             "OpFunctionEnd",
2624         2, 0),
2625     // Test case 30: Don't fold n < 3 (unsigned)
2626     InstructionFoldingCase<uint32_t>(
2627         Header() + "%main = OpFunction %void None %void_func\n" +
2628             "%main_lab = OpLabel\n" +
2629             "%n = OpVariable %_ptr_uint Function\n" +
2630             "%load_n = OpLoad %uint %n\n" +
2631             "%2 = OpULessThan %bool %load_n %uint_3\n" +
2632             "OpReturn\n" +
2633             "OpFunctionEnd",
2634         2, 0),
2635     // Test case 31: Don't fold n > 3 (unsigned)
2636     InstructionFoldingCase<uint32_t>(
2637         Header() + "%main = OpFunction %void None %void_func\n" +
2638             "%main_lab = OpLabel\n" +
2639             "%n = OpVariable %_ptr_uint Function\n" +
2640             "%load_n = OpLoad %uint %n\n" +
2641             "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
2642             "OpReturn\n" +
2643             "OpFunctionEnd",
2644         2, 0),
2645     // Test case 32: Don't fold n <= 3 (unsigned)
2646     InstructionFoldingCase<uint32_t>(
2647         Header() + "%main = OpFunction %void None %void_func\n" +
2648             "%main_lab = OpLabel\n" +
2649             "%n = OpVariable %_ptr_uint Function\n" +
2650             "%load_n = OpLoad %uint %n\n" +
2651             "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
2652             "OpReturn\n" +
2653             "OpFunctionEnd",
2654         2, 0),
2655     // Test case 33: Don't fold n >= 3 (unsigned)
2656     InstructionFoldingCase<uint32_t>(
2657         Header() + "%main = OpFunction %void None %void_func\n" +
2658             "%main_lab = OpLabel\n" +
2659             "%n = OpVariable %_ptr_uint Function\n" +
2660             "%load_n = OpLoad %uint %n\n" +
2661             "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
2662             "OpReturn\n" +
2663             "OpFunctionEnd",
2664         2, 0),
2665     // Test case 34: Don't fold n < 3 (signed)
2666     InstructionFoldingCase<uint32_t>(
2667         Header() + "%main = OpFunction %void None %void_func\n" +
2668             "%main_lab = OpLabel\n" +
2669             "%n = OpVariable %_ptr_int Function\n" +
2670             "%load_n = OpLoad %int %n\n" +
2671             "%2 = OpULessThan %bool %load_n %int_3\n" +
2672             "OpReturn\n" +
2673             "OpFunctionEnd",
2674         2, 0),
2675     // Test case 35: Don't fold n > 3 (signed)
2676     InstructionFoldingCase<uint32_t>(
2677         Header() + "%main = OpFunction %void None %void_func\n" +
2678             "%main_lab = OpLabel\n" +
2679             "%n = OpVariable %_ptr_int Function\n" +
2680             "%load_n = OpLoad %int %n\n" +
2681             "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
2682             "OpReturn\n" +
2683             "OpFunctionEnd",
2684         2, 0),
2685     // Test case 36: Don't fold n <= 3 (signed)
2686     InstructionFoldingCase<uint32_t>(
2687         Header() + "%main = OpFunction %void None %void_func\n" +
2688             "%main_lab = OpLabel\n" +
2689             "%n = OpVariable %_ptr_int Function\n" +
2690             "%load_n = OpLoad %int %n\n" +
2691             "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
2692             "OpReturn\n" +
2693             "OpFunctionEnd",
2694         2, 0),
2695     // Test case 37: Don't fold n >= 3 (signed)
2696     InstructionFoldingCase<uint32_t>(
2697         Header() + "%main = OpFunction %void None %void_func\n" +
2698             "%main_lab = OpLabel\n" +
2699             "%n = OpVariable %_ptr_int Function\n" +
2700             "%load_n = OpLoad %int %n\n" +
2701             "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
2702             "OpReturn\n" +
2703             "OpFunctionEnd",
2704         2, 0),
2705     // Test case 38: Don't fold 2 + 3 (long), bad length
2706     InstructionFoldingCase<uint32_t>(
2707         Header() + "%main = OpFunction %void None %void_func\n" +
2708             "%main_lab = OpLabel\n" +
2709             "%2 = OpIAdd %long %long_2 %long_3\n" +
2710             "OpReturn\n" +
2711             "OpFunctionEnd",
2712         2, 0),
2713     // Test case 39: Don't fold 2 + 3 (short), bad length
2714     InstructionFoldingCase<uint32_t>(
2715         Header() + "%main = OpFunction %void None %void_func\n" +
2716             "%main_lab = OpLabel\n" +
2717             "%2 = OpIAdd %short %short_2 %short_3\n" +
2718             "OpReturn\n" +
2719             "OpFunctionEnd",
2720         2, 0),
2721     // Test case 40: fold 1*n
2722     InstructionFoldingCase<uint32_t>(
2723         Header() + "%main = OpFunction %void None %void_func\n" +
2724             "%main_lab = OpLabel\n" +
2725             "%n = OpVariable %_ptr_int Function\n" +
2726             "%3 = OpLoad %int %n\n" +
2727             "%2 = OpIMul %int %int_1 %3\n" +
2728             "OpReturn\n" +
2729             "OpFunctionEnd",
2730         2, 3),
2731     // Test case 41: fold n*1
2732     InstructionFoldingCase<uint32_t>(
2733         Header() + "%main = OpFunction %void None %void_func\n" +
2734             "%main_lab = OpLabel\n" +
2735             "%n = OpVariable %_ptr_int Function\n" +
2736             "%3 = OpLoad %int %n\n" +
2737             "%2 = OpIMul %int %3 %int_1\n" +
2738             "OpReturn\n" +
2739             "OpFunctionEnd",
2740         2, 3)
2741 ));
2742 
2743 INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
2744 ::testing::Values(
2745     // Test case 0: fold Insert feeding extract
2746     InstructionFoldingCase<uint32_t>(
2747         Header() + "%main = OpFunction %void None %void_func\n" +
2748             "%main_lab = OpLabel\n" +
2749             "%n = OpVariable %_ptr_int Function\n" +
2750             "%2 = OpLoad %int %n\n" +
2751             "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
2752             "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
2753             "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
2754             "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
2755             "%7 = OpCompositeExtract %int %6 0\n" +
2756             "OpReturn\n" +
2757             "OpFunctionEnd",
2758         7, 2),
2759     // Test case 1: fold Composite construct feeding extract (position 0)
2760     InstructionFoldingCase<uint32_t>(
2761         Header() + "%main = OpFunction %void None %void_func\n" +
2762             "%main_lab = OpLabel\n" +
2763             "%n = OpVariable %_ptr_int Function\n" +
2764             "%2 = OpLoad %int %n\n" +
2765             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
2766             "%4 = OpCompositeExtract %int %3 0\n" +
2767             "OpReturn\n" +
2768             "OpFunctionEnd",
2769         4, 2),
2770     // Test case 2: fold Composite construct feeding extract (position 3)
2771     InstructionFoldingCase<uint32_t>(
2772         Header() + "%main = OpFunction %void None %void_func\n" +
2773             "%main_lab = OpLabel\n" +
2774             "%n = OpVariable %_ptr_int Function\n" +
2775             "%2 = OpLoad %int %n\n" +
2776             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
2777             "%4 = OpCompositeExtract %int %3 3\n" +
2778             "OpReturn\n" +
2779             "OpFunctionEnd",
2780         4, INT_0_ID),
2781     // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
2782     InstructionFoldingCase<uint32_t>(
2783         Header() + "%main = OpFunction %void None %void_func\n" +
2784             "%main_lab = OpLabel\n" +
2785             "%n = OpVariable %_ptr_int Function\n" +
2786             "%2 = OpLoad %int %n\n" +
2787             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
2788             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2789             "%5 = OpCompositeExtract %int %4 3\n" +
2790             "OpReturn\n" +
2791             "OpFunctionEnd",
2792         5, INT_0_ID),
2793     // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
2794     InstructionFoldingCase<uint32_t>(
2795         Header() + "%main = OpFunction %void None %void_func\n" +
2796             "%main_lab = OpLabel\n" +
2797             "%n = OpVariable %_ptr_int Function\n" +
2798             "%2 = OpLoad %int %n\n" +
2799             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
2800             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2801             "%5 = OpCompositeExtract %int %4 0\n" +
2802             "OpReturn\n" +
2803             "OpFunctionEnd",
2804         5, 2),
2805     // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
2806     InstructionFoldingCase<uint32_t>(
2807         Header() + "%main = OpFunction %void None %void_func\n" +
2808             "%main_lab = OpLabel\n" +
2809             "%n = OpVariable %_ptr_int Function\n" +
2810             "%2 = OpLoad %int %n\n" +
2811             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
2812             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2813             "%5 = OpCompositeExtract %int %4 1\n" +
2814             "OpReturn\n" +
2815             "OpFunctionEnd",
2816         5, 2),
2817     // Test case 6: fold Composite construct with multiple indices.
2818     InstructionFoldingCase<uint32_t>(
2819         Header() + "%main = OpFunction %void None %void_func\n" +
2820             "%main_lab = OpLabel\n" +
2821             "%n = OpVariable %_ptr_int Function\n" +
2822             "%2 = OpLoad %int %n\n" +
2823             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
2824             "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
2825             "%5 = OpCompositeExtract %int %4 0 1\n" +
2826             "OpReturn\n" +
2827             "OpFunctionEnd",
2828         5, 2),
2829     // Test case 7: fold constant extract.
2830     InstructionFoldingCase<uint32_t>(
2831         Header() + "%main = OpFunction %void None %void_func\n" +
2832             "%main_lab = OpLabel\n" +
2833             "%2 = OpCompositeExtract %int %102 1\n" +
2834             "OpReturn\n" +
2835             "OpFunctionEnd",
2836         2, INT_7_ID),
2837     // Test case 8: constant struct has OpUndef
2838     InstructionFoldingCase<uint32_t>(
2839         Header() + "%main = OpFunction %void None %void_func\n" +
2840             "%main_lab = OpLabel\n" +
2841             "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
2842             "OpReturn\n" +
2843             "OpFunctionEnd",
2844         2, 0),
2845     // Test case 9: Extracting a member of element inserted via Insert
2846     InstructionFoldingCase<uint32_t>(
2847         Header() + "%main = OpFunction %void None %void_func\n" +
2848             "%main_lab = OpLabel\n" +
2849             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
2850             "%2 = OpLoad %struct_v2int_int_int %n\n" +
2851             "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
2852             "%4 = OpCompositeExtract %int %3 0 1\n" +
2853             "OpReturn\n" +
2854             "OpFunctionEnd",
2855         4, 103),
2856     // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
2857     InstructionFoldingCase<uint32_t>(
2858         Header() + "%main = OpFunction %void None %void_func\n" +
2859             "%main_lab = OpLabel\n" +
2860             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
2861             "%2 = OpLoad %struct_v2int_int_int %n\n" +
2862             "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
2863             "%4 = OpCompositeExtract %v2int %3 0\n" +
2864             "OpReturn\n" +
2865             "OpFunctionEnd",
2866         4, 0),
2867     // Test case 11: Extracting from result of vector shuffle (first input)
2868     InstructionFoldingCase<uint32_t>(
2869         Header() + "%main = OpFunction %void None %void_func\n" +
2870             "%main_lab = OpLabel\n" +
2871             "%n = OpVariable %_ptr_v2int Function\n" +
2872             "%2 = OpLoad %v2int %n\n" +
2873             "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
2874             "%4 = OpCompositeExtract %int %3 1\n" +
2875             "OpReturn\n" +
2876             "OpFunctionEnd",
2877         4, INT_7_ID),
2878     // Test case 12: Extracting from result of vector shuffle (second input)
2879     InstructionFoldingCase<uint32_t>(
2880         Header() + "%main = OpFunction %void None %void_func\n" +
2881             "%main_lab = OpLabel\n" +
2882             "%n = OpVariable %_ptr_v2int Function\n" +
2883             "%2 = OpLoad %v2int %n\n" +
2884             "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
2885             "%4 = OpCompositeExtract %int %3 0\n" +
2886             "OpReturn\n" +
2887             "OpFunctionEnd",
2888         4, INT_7_ID)
2889 ));
2890 
2891 INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
2892 ::testing::Values(
2893     // Test case 0: fold Extracts feeding construct
2894     InstructionFoldingCase<uint32_t>(
2895         Header() + "%main = OpFunction %void None %void_func\n" +
2896             "%main_lab = OpLabel\n" +
2897             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2898             "%3 = OpCompositeExtract %int %2 0\n" +
2899             "%4 = OpCompositeExtract %int %2 1\n" +
2900             "%5 = OpCompositeExtract %int %2 2\n" +
2901             "%6 = OpCompositeExtract %int %2 3\n" +
2902             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2903             "OpReturn\n" +
2904             "OpFunctionEnd",
2905         7, 2),
2906     // Test case 1: Don't fold Extracts feeding construct (Different source)
2907     InstructionFoldingCase<uint32_t>(
2908         Header() + "%main = OpFunction %void None %void_func\n" +
2909             "%main_lab = OpLabel\n" +
2910             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2911             "%3 = OpCompositeExtract %int %2 0\n" +
2912             "%4 = OpCompositeExtract %int %2 1\n" +
2913             "%5 = OpCompositeExtract %int %2 2\n" +
2914             "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
2915             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2916             "OpReturn\n" +
2917             "OpFunctionEnd",
2918         7, 0),
2919     // Test case 2: Don't fold Extracts feeding construct (bad indices)
2920     InstructionFoldingCase<uint32_t>(
2921         Header() + "%main = OpFunction %void None %void_func\n" +
2922             "%main_lab = OpLabel\n" +
2923             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2924             "%3 = OpCompositeExtract %int %2 0\n" +
2925             "%4 = OpCompositeExtract %int %2 0\n" +
2926             "%5 = OpCompositeExtract %int %2 2\n" +
2927             "%6 = OpCompositeExtract %int %2 3\n" +
2928             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2929             "OpReturn\n" +
2930             "OpFunctionEnd",
2931         7, 0),
2932     // Test case 3: Don't fold Extracts feeding construct (different type)
2933     InstructionFoldingCase<uint32_t>(
2934         Header() + "%main = OpFunction %void None %void_func\n" +
2935             "%main_lab = OpLabel\n" +
2936             "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
2937             "%3 = OpCompositeExtract %v2int %2 0\n" +
2938             "%4 = OpCompositeExtract %int %2 1\n" +
2939             "%5 = OpCompositeExtract %int %2 2\n" +
2940             "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
2941             "OpReturn\n" +
2942             "OpFunctionEnd",
2943         7, 0),
2944     // Test case 4: Fold construct with constants to constant.
2945     InstructionFoldingCase<uint32_t>(
2946         Header() + "%main = OpFunction %void None %void_func\n" +
2947             "%main_lab = OpLabel\n" +
2948             "%2 = OpCompositeConstruct %v2int %103 %103\n" +
2949             "OpReturn\n" +
2950             "OpFunctionEnd",
2951         2, VEC2_0_ID)
2952 ));
2953 
2954 INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
2955 ::testing::Values(
2956   // Test case 0: Fold phi with the same values for all edges.
2957   InstructionFoldingCase<uint32_t>(
2958       Header() + "%main = OpFunction %void None %void_func\n" +
2959           "%main_lab = OpLabel\n" +
2960           "            OpBranchConditional %true %l1 %l2\n" +
2961           "%l1 = OpLabel\n" +
2962           "      OpBranch %merge_lab\n" +
2963           "%l2 = OpLabel\n" +
2964           "      OpBranch %merge_lab\n" +
2965           "%merge_lab = OpLabel\n" +
2966           "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
2967           "OpReturn\n" +
2968           "OpFunctionEnd",
2969       2, INT_0_ID),
2970   // Test case 1: Fold phi in pass through loop.
2971   InstructionFoldingCase<uint32_t>(
2972       Header() + "%main = OpFunction %void None %void_func\n" +
2973           "%main_lab = OpLabel\n" +
2974           "            OpBranch %l1\n" +
2975           "%l1 = OpLabel\n" +
2976           "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
2977           "      OpBranchConditional %true %l1 %merge_lab\n" +
2978           "%merge_lab = OpLabel\n" +
2979           "OpReturn\n" +
2980           "OpFunctionEnd",
2981       2, INT_0_ID),
2982   // Test case 2: Don't Fold phi because of different values.
2983   InstructionFoldingCase<uint32_t>(
2984       Header() + "%main = OpFunction %void None %void_func\n" +
2985           "%main_lab = OpLabel\n" +
2986           "            OpBranch %l1\n" +
2987           "%l1 = OpLabel\n" +
2988           "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
2989           "      OpBranchConditional %true %l1 %merge_lab\n" +
2990           "%merge_lab = OpLabel\n" +
2991           "OpReturn\n" +
2992           "OpFunctionEnd",
2993       2, 0)
2994 ));
2995 
2996 INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
2997                         ::testing::Values(
2998     // Test case 0: Don't fold n + 1.0
2999     InstructionFoldingCase<uint32_t>(
3000         Header() + "%main = OpFunction %void None %void_func\n" +
3001             "%main_lab = OpLabel\n" +
3002             "%n = OpVariable %_ptr_float Function\n" +
3003             "%3 = OpLoad %float %n\n" +
3004             "%2 = OpFAdd %float %3 %float_2\n" +
3005             "OpReturn\n" +
3006             "OpFunctionEnd",
3007         2, 0),
3008     // Test case 1: Don't fold n - 1.0
3009     InstructionFoldingCase<uint32_t>(
3010         Header() + "%main = OpFunction %void None %void_func\n" +
3011             "%main_lab = OpLabel\n" +
3012             "%n = OpVariable %_ptr_float Function\n" +
3013             "%3 = OpLoad %float %n\n" +
3014             "%2 = OpFSub %float %3 %float_2\n" +
3015             "OpReturn\n" +
3016             "OpFunctionEnd",
3017         2, 0),
3018     // Test case 2: Don't fold n * 2.0
3019     InstructionFoldingCase<uint32_t>(
3020         Header() + "%main = OpFunction %void None %void_func\n" +
3021             "%main_lab = OpLabel\n" +
3022             "%n = OpVariable %_ptr_float Function\n" +
3023             "%3 = OpLoad %float %n\n" +
3024             "%2 = OpFMul %float %3 %float_2\n" +
3025             "OpReturn\n" +
3026             "OpFunctionEnd",
3027         2, 0),
3028     // Test case 3: Fold n + 0.0
3029     InstructionFoldingCase<uint32_t>(
3030         Header() + "%main = OpFunction %void None %void_func\n" +
3031             "%main_lab = OpLabel\n" +
3032             "%n = OpVariable %_ptr_float Function\n" +
3033             "%3 = OpLoad %float %n\n" +
3034             "%2 = OpFAdd %float %3 %float_0\n" +
3035             "OpReturn\n" +
3036             "OpFunctionEnd",
3037         2, 3),
3038     // Test case 4: Fold 0.0 + n
3039     InstructionFoldingCase<uint32_t>(
3040         Header() + "%main = OpFunction %void None %void_func\n" +
3041             "%main_lab = OpLabel\n" +
3042             "%n = OpVariable %_ptr_float Function\n" +
3043             "%3 = OpLoad %float %n\n" +
3044             "%2 = OpFAdd %float %float_0 %3\n" +
3045             "OpReturn\n" +
3046             "OpFunctionEnd",
3047         2, 3),
3048     // Test case 5: Fold n - 0.0
3049     InstructionFoldingCase<uint32_t>(
3050         Header() + "%main = OpFunction %void None %void_func\n" +
3051             "%main_lab = OpLabel\n" +
3052             "%n = OpVariable %_ptr_float Function\n" +
3053             "%3 = OpLoad %float %n\n" +
3054             "%2 = OpFSub %float %3 %float_0\n" +
3055             "OpReturn\n" +
3056             "OpFunctionEnd",
3057         2, 3),
3058     // Test case 6: Fold n * 1.0
3059     InstructionFoldingCase<uint32_t>(
3060         Header() + "%main = OpFunction %void None %void_func\n" +
3061             "%main_lab = OpLabel\n" +
3062             "%n = OpVariable %_ptr_float Function\n" +
3063             "%3 = OpLoad %float %n\n" +
3064             "%2 = OpFMul %float %3 %float_1\n" +
3065             "OpReturn\n" +
3066             "OpFunctionEnd",
3067         2, 3),
3068     // Test case 7: Fold 1.0 * n
3069     InstructionFoldingCase<uint32_t>(
3070         Header() + "%main = OpFunction %void None %void_func\n" +
3071             "%main_lab = OpLabel\n" +
3072             "%n = OpVariable %_ptr_float Function\n" +
3073             "%3 = OpLoad %float %n\n" +
3074             "%2 = OpFMul %float %float_1 %3\n" +
3075             "OpReturn\n" +
3076             "OpFunctionEnd",
3077         2, 3),
3078     // Test case 8: Fold n / 1.0
3079     InstructionFoldingCase<uint32_t>(
3080         Header() + "%main = OpFunction %void None %void_func\n" +
3081             "%main_lab = OpLabel\n" +
3082             "%n = OpVariable %_ptr_float Function\n" +
3083             "%3 = OpLoad %float %n\n" +
3084             "%2 = OpFDiv %float %3 %float_1\n" +
3085             "OpReturn\n" +
3086             "OpFunctionEnd",
3087         2, 3),
3088     // Test case 9: Fold n * 0.0
3089     InstructionFoldingCase<uint32_t>(
3090         Header() + "%main = OpFunction %void None %void_func\n" +
3091             "%main_lab = OpLabel\n" +
3092             "%n = OpVariable %_ptr_float Function\n" +
3093             "%3 = OpLoad %float %n\n" +
3094             "%2 = OpFMul %float %3 %104\n" +
3095             "OpReturn\n" +
3096             "OpFunctionEnd",
3097         2, FLOAT_0_ID),
3098     // Test case 10: Fold 0.0 * n
3099     InstructionFoldingCase<uint32_t>(
3100         Header() + "%main = OpFunction %void None %void_func\n" +
3101             "%main_lab = OpLabel\n" +
3102             "%n = OpVariable %_ptr_float Function\n" +
3103             "%3 = OpLoad %float %n\n" +
3104             "%2 = OpFMul %float %104 %3\n" +
3105             "OpReturn\n" +
3106             "OpFunctionEnd",
3107         2, FLOAT_0_ID),
3108     // Test case 11: Fold 0.0 / n
3109     InstructionFoldingCase<uint32_t>(
3110         Header() + "%main = OpFunction %void None %void_func\n" +
3111             "%main_lab = OpLabel\n" +
3112             "%n = OpVariable %_ptr_float Function\n" +
3113             "%3 = OpLoad %float %n\n" +
3114             "%2 = OpFDiv %float %104 %3\n" +
3115             "OpReturn\n" +
3116             "OpFunctionEnd",
3117         2, FLOAT_0_ID),
3118     // Test case 12: Don't fold mix(a, b, 2.0)
3119     InstructionFoldingCase<uint32_t>(
3120         Header() + "%main = OpFunction %void None %void_func\n" +
3121             "%main_lab = OpLabel\n" +
3122             "%a = OpVariable %_ptr_float Function\n" +
3123             "%b = OpVariable %_ptr_float Function\n" +
3124             "%3 = OpLoad %float %a\n" +
3125             "%4 = OpLoad %float %b\n" +
3126             "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
3127             "OpReturn\n" +
3128             "OpFunctionEnd",
3129         2, 0),
3130     // Test case 13: Fold mix(a, b, 0.0)
3131     InstructionFoldingCase<uint32_t>(
3132         Header() + "%main = OpFunction %void None %void_func\n" +
3133             "%main_lab = OpLabel\n" +
3134             "%a = OpVariable %_ptr_float Function\n" +
3135             "%b = OpVariable %_ptr_float Function\n" +
3136             "%3 = OpLoad %float %a\n" +
3137             "%4 = OpLoad %float %b\n" +
3138             "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
3139             "OpReturn\n" +
3140             "OpFunctionEnd",
3141         2, 3),
3142     // Test case 14: Fold mix(a, b, 1.0)
3143     InstructionFoldingCase<uint32_t>(
3144         Header() + "%main = OpFunction %void None %void_func\n" +
3145             "%main_lab = OpLabel\n" +
3146             "%a = OpVariable %_ptr_float Function\n" +
3147             "%b = OpVariable %_ptr_float Function\n" +
3148             "%3 = OpLoad %float %a\n" +
3149             "%4 = OpLoad %float %b\n" +
3150             "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
3151             "OpReturn\n" +
3152             "OpFunctionEnd",
3153         2, 4),
3154     // Test case 15: Fold vector fadd with null
3155     InstructionFoldingCase<uint32_t>(
3156         Header() + "%main = OpFunction %void None %void_func\n" +
3157             "%main_lab = OpLabel\n" +
3158             "%a = OpVariable %_ptr_v2float Function\n" +
3159             "%2 = OpLoad %v2float %a\n" +
3160             "%3 = OpFAdd %v2float %2 %v2float_null\n" +
3161             "OpReturn\n" +
3162             "OpFunctionEnd",
3163         3, 2),
3164     // Test case 16: Fold vector fadd with null
3165     InstructionFoldingCase<uint32_t>(
3166         Header() + "%main = OpFunction %void None %void_func\n" +
3167             "%main_lab = OpLabel\n" +
3168             "%a = OpVariable %_ptr_v2float Function\n" +
3169             "%2 = OpLoad %v2float %a\n" +
3170             "%3 = OpFAdd %v2float %v2float_null %2\n" +
3171             "OpReturn\n" +
3172             "OpFunctionEnd",
3173         3, 2),
3174     // Test case 15: Fold vector fsub with null
3175     InstructionFoldingCase<uint32_t>(
3176         Header() + "%main = OpFunction %void None %void_func\n" +
3177             "%main_lab = OpLabel\n" +
3178             "%a = OpVariable %_ptr_v2float Function\n" +
3179             "%2 = OpLoad %v2float %a\n" +
3180             "%3 = OpFSub %v2float %2 %v2float_null\n" +
3181             "OpReturn\n" +
3182             "OpFunctionEnd",
3183         3, 2),
3184     // Test case 16: Fold 0.0(half) * n
3185     InstructionFoldingCase<uint32_t>(
3186         Header() + "%main = OpFunction %void None %void_func\n" +
3187             "%main_lab = OpLabel\n" +
3188             "%n = OpVariable %_ptr_half Function\n" +
3189             "%3 = OpLoad %half %n\n" +
3190             "%2 = OpFMul %half %108 %3\n" +
3191             "OpReturn\n" +
3192             "OpFunctionEnd",
3193         2, HALF_0_ID),
3194     // Test case 17: Don't fold 1.0(half) * n
3195     InstructionFoldingCase<uint32_t>(
3196         Header() + "%main = OpFunction %void None %void_func\n" +
3197             "%main_lab = OpLabel\n" +
3198             "%n = OpVariable %_ptr_half Function\n" +
3199             "%3 = OpLoad %half %n\n" +
3200             "%2 = OpFMul %half %half_1 %3\n" +
3201             "OpReturn\n" +
3202             "OpFunctionEnd",
3203         2, 0),
3204     // Test case 18: Don't fold 1.0 * 1.0 (half)
3205     InstructionFoldingCase<uint32_t>(
3206         Header() + "%main = OpFunction %void None %void_func\n" +
3207             "%main_lab = OpLabel\n" +
3208             "%2 = OpFMul %half %half_1 %half_1\n" +
3209             "OpReturn\n" +
3210             "OpFunctionEnd",
3211         2, 0)
3212 ));
3213 
3214 INSTANTIATE_TEST_CASE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
3215                         ::testing::Values(
3216     // Test case 0: Don't fold n + 1.0
3217     InstructionFoldingCase<uint32_t>(
3218         Header() + "%main = OpFunction %void None %void_func\n" +
3219             "%main_lab = OpLabel\n" +
3220             "%n = OpVariable %_ptr_double Function\n" +
3221             "%3 = OpLoad %double %n\n" +
3222             "%2 = OpFAdd %double %3 %double_2\n" +
3223             "OpReturn\n" +
3224             "OpFunctionEnd",
3225         2, 0),
3226     // Test case 1: Don't fold n - 1.0
3227     InstructionFoldingCase<uint32_t>(
3228         Header() + "%main = OpFunction %void None %void_func\n" +
3229             "%main_lab = OpLabel\n" +
3230             "%n = OpVariable %_ptr_double Function\n" +
3231             "%3 = OpLoad %double %n\n" +
3232             "%2 = OpFSub %double %3 %double_2\n" +
3233             "OpReturn\n" +
3234             "OpFunctionEnd",
3235         2, 0),
3236     // Test case 2: Don't fold n * 2.0
3237     InstructionFoldingCase<uint32_t>(
3238         Header() + "%main = OpFunction %void None %void_func\n" +
3239             "%main_lab = OpLabel\n" +
3240             "%n = OpVariable %_ptr_double Function\n" +
3241             "%3 = OpLoad %double %n\n" +
3242             "%2 = OpFMul %double %3 %double_2\n" +
3243             "OpReturn\n" +
3244             "OpFunctionEnd",
3245         2, 0),
3246     // Test case 3: Fold n + 0.0
3247     InstructionFoldingCase<uint32_t>(
3248         Header() + "%main = OpFunction %void None %void_func\n" +
3249             "%main_lab = OpLabel\n" +
3250             "%n = OpVariable %_ptr_double Function\n" +
3251             "%3 = OpLoad %double %n\n" +
3252             "%2 = OpFAdd %double %3 %double_0\n" +
3253             "OpReturn\n" +
3254             "OpFunctionEnd",
3255         2, 3),
3256     // Test case 4: Fold 0.0 + n
3257     InstructionFoldingCase<uint32_t>(
3258         Header() + "%main = OpFunction %void None %void_func\n" +
3259             "%main_lab = OpLabel\n" +
3260             "%n = OpVariable %_ptr_double Function\n" +
3261             "%3 = OpLoad %double %n\n" +
3262             "%2 = OpFAdd %double %double_0 %3\n" +
3263             "OpReturn\n" +
3264             "OpFunctionEnd",
3265         2, 3),
3266     // Test case 5: Fold n - 0.0
3267     InstructionFoldingCase<uint32_t>(
3268         Header() + "%main = OpFunction %void None %void_func\n" +
3269             "%main_lab = OpLabel\n" +
3270             "%n = OpVariable %_ptr_double Function\n" +
3271             "%3 = OpLoad %double %n\n" +
3272             "%2 = OpFSub %double %3 %double_0\n" +
3273             "OpReturn\n" +
3274             "OpFunctionEnd",
3275         2, 3),
3276     // Test case 6: Fold n * 1.0
3277     InstructionFoldingCase<uint32_t>(
3278         Header() + "%main = OpFunction %void None %void_func\n" +
3279             "%main_lab = OpLabel\n" +
3280             "%n = OpVariable %_ptr_double Function\n" +
3281             "%3 = OpLoad %double %n\n" +
3282             "%2 = OpFMul %double %3 %double_1\n" +
3283             "OpReturn\n" +
3284             "OpFunctionEnd",
3285         2, 3),
3286     // Test case 7: Fold 1.0 * n
3287     InstructionFoldingCase<uint32_t>(
3288         Header() + "%main = OpFunction %void None %void_func\n" +
3289             "%main_lab = OpLabel\n" +
3290             "%n = OpVariable %_ptr_double Function\n" +
3291             "%3 = OpLoad %double %n\n" +
3292             "%2 = OpFMul %double %double_1 %3\n" +
3293             "OpReturn\n" +
3294             "OpFunctionEnd",
3295         2, 3),
3296     // Test case 8: Fold n / 1.0
3297     InstructionFoldingCase<uint32_t>(
3298         Header() + "%main = OpFunction %void None %void_func\n" +
3299             "%main_lab = OpLabel\n" +
3300             "%n = OpVariable %_ptr_double Function\n" +
3301             "%3 = OpLoad %double %n\n" +
3302             "%2 = OpFDiv %double %3 %double_1\n" +
3303             "OpReturn\n" +
3304             "OpFunctionEnd",
3305         2, 3),
3306     // Test case 9: Fold n * 0.0
3307     InstructionFoldingCase<uint32_t>(
3308         Header() + "%main = OpFunction %void None %void_func\n" +
3309             "%main_lab = OpLabel\n" +
3310             "%n = OpVariable %_ptr_double Function\n" +
3311             "%3 = OpLoad %double %n\n" +
3312             "%2 = OpFMul %double %3 %105\n" +
3313             "OpReturn\n" +
3314             "OpFunctionEnd",
3315         2, DOUBLE_0_ID),
3316     // Test case 10: Fold 0.0 * n
3317     InstructionFoldingCase<uint32_t>(
3318         Header() + "%main = OpFunction %void None %void_func\n" +
3319             "%main_lab = OpLabel\n" +
3320             "%n = OpVariable %_ptr_double Function\n" +
3321             "%3 = OpLoad %double %n\n" +
3322             "%2 = OpFMul %double %105 %3\n" +
3323             "OpReturn\n" +
3324             "OpFunctionEnd",
3325         2, DOUBLE_0_ID),
3326     // Test case 11: Fold 0.0 / n
3327     InstructionFoldingCase<uint32_t>(
3328         Header() + "%main = OpFunction %void None %void_func\n" +
3329             "%main_lab = OpLabel\n" +
3330             "%n = OpVariable %_ptr_double Function\n" +
3331             "%3 = OpLoad %double %n\n" +
3332             "%2 = OpFDiv %double %105 %3\n" +
3333             "OpReturn\n" +
3334             "OpFunctionEnd",
3335         2, DOUBLE_0_ID),
3336     // Test case 12: Don't fold mix(a, b, 2.0)
3337     InstructionFoldingCase<uint32_t>(
3338         Header() + "%main = OpFunction %void None %void_func\n" +
3339             "%main_lab = OpLabel\n" +
3340             "%a = OpVariable %_ptr_double Function\n" +
3341             "%b = OpVariable %_ptr_double Function\n" +
3342             "%3 = OpLoad %double %a\n" +
3343             "%4 = OpLoad %double %b\n" +
3344             "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
3345             "OpReturn\n" +
3346             "OpFunctionEnd",
3347         2, 0),
3348     // Test case 13: Fold mix(a, b, 0.0)
3349     InstructionFoldingCase<uint32_t>(
3350         Header() + "%main = OpFunction %void None %void_func\n" +
3351             "%main_lab = OpLabel\n" +
3352             "%a = OpVariable %_ptr_double Function\n" +
3353             "%b = OpVariable %_ptr_double Function\n" +
3354             "%3 = OpLoad %double %a\n" +
3355             "%4 = OpLoad %double %b\n" +
3356             "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
3357             "OpReturn\n" +
3358             "OpFunctionEnd",
3359         2, 3),
3360     // Test case 14: Fold mix(a, b, 1.0)
3361     InstructionFoldingCase<uint32_t>(
3362         Header() + "%main = OpFunction %void None %void_func\n" +
3363             "%main_lab = OpLabel\n" +
3364             "%a = OpVariable %_ptr_double Function\n" +
3365             "%b = OpVariable %_ptr_double Function\n" +
3366             "%3 = OpLoad %double %a\n" +
3367             "%4 = OpLoad %double %b\n" +
3368             "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
3369             "OpReturn\n" +
3370             "OpFunctionEnd",
3371         2, 4)
3372 ));
3373 
3374 INSTANTIATE_TEST_CASE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
3375                         ::testing::Values(
3376     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
3377     InstructionFoldingCase<uint32_t>(
3378         Header() + "%main = OpFunction %void None %void_func\n" +
3379             "%main_lab = OpLabel\n" +
3380             "%n = OpVariable %_ptr_v4float Function\n" +
3381             "%3 = OpLoad %v4float %n\n" +
3382             "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
3383             "OpReturn\n" +
3384             "OpFunctionEnd",
3385         2, 0),
3386     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
3387     InstructionFoldingCase<uint32_t>(
3388         Header() + "%main = OpFunction %void None %void_func\n" +
3389             "%main_lab = OpLabel\n" +
3390             "%n = OpVariable %_ptr_v4float Function\n" +
3391             "%3 = OpLoad %v4float %n\n" +
3392             "%2 = OpFMul %v4float %3 %106\n" +
3393             "OpReturn\n" +
3394             "OpFunctionEnd",
3395         2, VEC4_0_ID),
3396     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
3397     InstructionFoldingCase<uint32_t>(
3398         Header() + "%main = OpFunction %void None %void_func\n" +
3399             "%main_lab = OpLabel\n" +
3400             "%n = OpVariable %_ptr_v4float Function\n" +
3401             "%3 = OpLoad %v4float %n\n" +
3402             "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
3403             "OpReturn\n" +
3404             "OpFunctionEnd",
3405         2, 3)
3406 ));
3407 
3408 INSTANTIATE_TEST_CASE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
3409                         ::testing::Values(
3410     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
3411     InstructionFoldingCase<uint32_t>(
3412         Header() + "%main = OpFunction %void None %void_func\n" +
3413             "%main_lab = OpLabel\n" +
3414             "%n = OpVariable %_ptr_v4double Function\n" +
3415             "%3 = OpLoad %v4double %n\n" +
3416             "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
3417             "OpReturn\n" +
3418             "OpFunctionEnd",
3419         2, 0),
3420     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
3421     InstructionFoldingCase<uint32_t>(
3422         Header() + "%main = OpFunction %void None %void_func\n" +
3423             "%main_lab = OpLabel\n" +
3424             "%n = OpVariable %_ptr_v4double Function\n" +
3425             "%3 = OpLoad %v4double %n\n" +
3426             "%2 = OpFMul %v4double %3 %106\n" +
3427             "OpReturn\n" +
3428             "OpFunctionEnd",
3429         2, DVEC4_0_ID),
3430     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
3431     InstructionFoldingCase<uint32_t>(
3432         Header() + "%main = OpFunction %void None %void_func\n" +
3433             "%main_lab = OpLabel\n" +
3434             "%n = OpVariable %_ptr_v4double Function\n" +
3435             "%3 = OpLoad %v4double %n\n" +
3436             "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
3437             "OpReturn\n" +
3438             "OpFunctionEnd",
3439         2, 3)
3440 ));
3441 
3442 INSTANTIATE_TEST_CASE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
3443                         ::testing::Values(
3444     // Test case 0: Don't fold n + 1
3445     InstructionFoldingCase<uint32_t>(
3446         Header() + "%main = OpFunction %void None %void_func\n" +
3447             "%main_lab = OpLabel\n" +
3448             "%n = OpVariable %_ptr_uint Function\n" +
3449             "%3 = OpLoad %uint %n\n" +
3450             "%2 = OpIAdd %uint %3 %uint_1\n" +
3451             "OpReturn\n" +
3452             "OpFunctionEnd",
3453         2, 0),
3454     // Test case 1: Don't fold 1 + n
3455     InstructionFoldingCase<uint32_t>(
3456         Header() + "%main = OpFunction %void None %void_func\n" +
3457             "%main_lab = OpLabel\n" +
3458             "%n = OpVariable %_ptr_uint Function\n" +
3459             "%3 = OpLoad %uint %n\n" +
3460             "%2 = OpIAdd %uint %uint_1 %3\n" +
3461             "OpReturn\n" +
3462             "OpFunctionEnd",
3463         2, 0),
3464     // Test case 2: Fold n + 0
3465     InstructionFoldingCase<uint32_t>(
3466         Header() + "%main = OpFunction %void None %void_func\n" +
3467             "%main_lab = OpLabel\n" +
3468             "%n = OpVariable %_ptr_uint Function\n" +
3469             "%3 = OpLoad %uint %n\n" +
3470             "%2 = OpIAdd %uint %3 %uint_0\n" +
3471             "OpReturn\n" +
3472             "OpFunctionEnd",
3473         2, 3),
3474     // Test case 3: Fold 0 + n
3475     InstructionFoldingCase<uint32_t>(
3476         Header() + "%main = OpFunction %void None %void_func\n" +
3477             "%main_lab = OpLabel\n" +
3478             "%n = OpVariable %_ptr_uint Function\n" +
3479             "%3 = OpLoad %uint %n\n" +
3480             "%2 = OpIAdd %uint %uint_0 %3\n" +
3481             "OpReturn\n" +
3482             "OpFunctionEnd",
3483         2, 3),
3484     // Test case 4: Don't fold n + (1,0)
3485     InstructionFoldingCase<uint32_t>(
3486         Header() + "%main = OpFunction %void None %void_func\n" +
3487             "%main_lab = OpLabel\n" +
3488             "%n = OpVariable %_ptr_v2int Function\n" +
3489             "%3 = OpLoad %v2int %n\n" +
3490             "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
3491             "OpReturn\n" +
3492             "OpFunctionEnd",
3493         2, 0),
3494     // Test case 5: Don't fold (1,0) + n
3495     InstructionFoldingCase<uint32_t>(
3496         Header() + "%main = OpFunction %void None %void_func\n" +
3497             "%main_lab = OpLabel\n" +
3498             "%n = OpVariable %_ptr_v2int Function\n" +
3499             "%3 = OpLoad %v2int %n\n" +
3500             "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
3501             "OpReturn\n" +
3502             "OpFunctionEnd",
3503         2, 0),
3504     // Test case 6: Fold n + (0,0)
3505     InstructionFoldingCase<uint32_t>(
3506         Header() + "%main = OpFunction %void None %void_func\n" +
3507             "%main_lab = OpLabel\n" +
3508             "%n = OpVariable %_ptr_v2int Function\n" +
3509             "%3 = OpLoad %v2int %n\n" +
3510             "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
3511             "OpReturn\n" +
3512             "OpFunctionEnd",
3513         2, 3),
3514     // Test case 7: Fold (0,0) + n
3515     InstructionFoldingCase<uint32_t>(
3516         Header() + "%main = OpFunction %void None %void_func\n" +
3517             "%main_lab = OpLabel\n" +
3518             "%n = OpVariable %_ptr_v2int Function\n" +
3519             "%3 = OpLoad %v2int %n\n" +
3520             "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
3521             "OpReturn\n" +
3522             "OpFunctionEnd",
3523         2, 3)
3524 ));
3525 
3526 INSTANTIATE_TEST_CASE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
3527 ::testing::Values(
3528     // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
3529     InstructionFoldingCase<uint32_t>(
3530         Header() + "%main = OpFunction %void None %void_func\n" +
3531             "%main_lab = OpLabel\n" +
3532             "%n = OpVariable %_ptr_float Function\n" +
3533             "%ld = OpLoad %float %n\n" +
3534             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3535             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
3536             "OpReturn\n" +
3537             "OpFunctionEnd",
3538         2, 0),
3539     // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
3540     InstructionFoldingCase<uint32_t>(
3541         Header() + "%main = OpFunction %void None %void_func\n" +
3542             "%main_lab = OpLabel\n" +
3543             "%n = OpVariable %_ptr_float Function\n" +
3544             "%ld = OpLoad %float %n\n" +
3545             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3546             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
3547             "OpReturn\n" +
3548             "OpFunctionEnd",
3549         2, 0),
3550     // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
3551     InstructionFoldingCase<uint32_t>(
3552         Header() + "%main = OpFunction %void None %void_func\n" +
3553             "%main_lab = OpLabel\n" +
3554             "%n = OpVariable %_ptr_float Function\n" +
3555             "%ld = OpLoad %float %n\n" +
3556             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3557             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
3558             "OpReturn\n" +
3559             "OpFunctionEnd",
3560         2, 0),
3561     // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
3562     InstructionFoldingCase<uint32_t>(
3563         Header() + "%main = OpFunction %void None %void_func\n" +
3564             "%main_lab = OpLabel\n" +
3565             "%n = OpVariable %_ptr_float Function\n" +
3566             "%ld = OpLoad %float %n\n" +
3567             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3568             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
3569             "OpReturn\n" +
3570             "OpFunctionEnd",
3571         2, 0),
3572     // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
3573     InstructionFoldingCase<uint32_t>(
3574         Header() + "%main = OpFunction %void None %void_func\n" +
3575             "%main_lab = OpLabel\n" +
3576             "%n = OpVariable %_ptr_float Function\n" +
3577             "%ld = OpLoad %float %n\n" +
3578             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3579             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
3580             "OpReturn\n" +
3581             "OpFunctionEnd",
3582         2, 0),
3583     // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
3584     InstructionFoldingCase<uint32_t>(
3585         Header() + "%main = OpFunction %void None %void_func\n" +
3586             "%main_lab = OpLabel\n" +
3587             "%n = OpVariable %_ptr_float Function\n" +
3588             "%ld = OpLoad %float %n\n" +
3589             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3590             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
3591             "OpReturn\n" +
3592             "OpFunctionEnd",
3593         2, 0),
3594     // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
3595     InstructionFoldingCase<uint32_t>(
3596         Header() + "%main = OpFunction %void None %void_func\n" +
3597             "%main_lab = OpLabel\n" +
3598             "%n = OpVariable %_ptr_float Function\n" +
3599             "%ld = OpLoad %float %n\n" +
3600             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3601             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
3602             "OpReturn\n" +
3603             "OpFunctionEnd",
3604         2, 0),
3605     // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
3606     InstructionFoldingCase<uint32_t>(
3607         Header() + "%main = OpFunction %void None %void_func\n" +
3608             "%main_lab = OpLabel\n" +
3609             "%n = OpVariable %_ptr_float Function\n" +
3610             "%ld = OpLoad %float %n\n" +
3611             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3612             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
3613             "OpReturn\n" +
3614             "OpFunctionEnd",
3615         2, 0),
3616     // Test case 8: Don't Fold 0.0 < clamp(0, 1)
3617     InstructionFoldingCase<uint32_t>(
3618         Header() + "%main = OpFunction %void None %void_func\n" +
3619             "%main_lab = OpLabel\n" +
3620             "%n = OpVariable %_ptr_float Function\n" +
3621             "%ld = OpLoad %float %n\n" +
3622             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
3623             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
3624             "OpReturn\n" +
3625             "OpFunctionEnd",
3626         2, 0),
3627     // Test case 9: Don't Fold 0.0 < clamp(0, 1)
3628     InstructionFoldingCase<uint32_t>(
3629         Header() + "%main = OpFunction %void None %void_func\n" +
3630             "%main_lab = OpLabel\n" +
3631             "%n = OpVariable %_ptr_float Function\n" +
3632             "%ld = OpLoad %float %n\n" +
3633             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
3634             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
3635             "OpReturn\n" +
3636             "OpFunctionEnd",
3637         2, 0),
3638     // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
3639     InstructionFoldingCase<uint32_t>(
3640         Header() + "%main = OpFunction %void None %void_func\n" +
3641             "%main_lab = OpLabel\n" +
3642             "%n = OpVariable %_ptr_float Function\n" +
3643             "%ld = OpLoad %float %n\n" +
3644             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
3645             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
3646             "OpReturn\n" +
3647             "OpFunctionEnd",
3648         2, 0),
3649     // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
3650     InstructionFoldingCase<uint32_t>(
3651         Header() + "%main = OpFunction %void None %void_func\n" +
3652             "%main_lab = OpLabel\n" +
3653             "%n = OpVariable %_ptr_float Function\n" +
3654             "%ld = OpLoad %float %n\n" +
3655             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
3656             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
3657             "OpReturn\n" +
3658             "OpFunctionEnd",
3659         2, 0)
3660 ));
3661 
3662 INSTANTIATE_TEST_CASE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
3663 ::testing::Values(
3664     // Test case 0: Don't Fold clamp(-1, 1) < 0.0
3665     InstructionFoldingCase<uint32_t>(
3666       Header() + "%main = OpFunction %void None %void_func\n" +
3667           "%main_lab = OpLabel\n" +
3668           "%n = OpVariable %_ptr_float Function\n" +
3669           "%ld = OpLoad %float %n\n" +
3670           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3671           "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
3672           "OpReturn\n" +
3673           "OpFunctionEnd",
3674       2, 0),
3675     // Test case 1: Don't Fold clamp(-1, 1) < 0.0
3676     InstructionFoldingCase<uint32_t>(
3677       Header() + "%main = OpFunction %void None %void_func\n" +
3678           "%main_lab = OpLabel\n" +
3679           "%n = OpVariable %_ptr_float Function\n" +
3680           "%ld = OpLoad %float %n\n" +
3681           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3682           "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
3683           "OpReturn\n" +
3684           "OpFunctionEnd",
3685       2, 0),
3686     // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
3687     InstructionFoldingCase<uint32_t>(
3688       Header() + "%main = OpFunction %void None %void_func\n" +
3689           "%main_lab = OpLabel\n" +
3690           "%n = OpVariable %_ptr_float Function\n" +
3691           "%ld = OpLoad %float %n\n" +
3692           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3693           "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
3694           "OpReturn\n" +
3695           "OpFunctionEnd",
3696       2, 0),
3697     // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
3698     InstructionFoldingCase<uint32_t>(
3699       Header() + "%main = OpFunction %void None %void_func\n" +
3700           "%main_lab = OpLabel\n" +
3701           "%n = OpVariable %_ptr_float Function\n" +
3702           "%ld = OpLoad %float %n\n" +
3703           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3704           "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
3705           "OpReturn\n" +
3706           "OpFunctionEnd",
3707       2, 0),
3708     // Test case 4: Don't Fold clamp(-1, 1) > 0.0
3709     InstructionFoldingCase<uint32_t>(
3710         Header() + "%main = OpFunction %void None %void_func\n" +
3711             "%main_lab = OpLabel\n" +
3712             "%n = OpVariable %_ptr_float Function\n" +
3713             "%ld = OpLoad %float %n\n" +
3714             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3715             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
3716             "OpReturn\n" +
3717             "OpFunctionEnd",
3718         2, 0),
3719     // Test case 5: Don't Fold clamp(-1, 1) > 0.0
3720     InstructionFoldingCase<uint32_t>(
3721         Header() + "%main = OpFunction %void None %void_func\n" +
3722             "%main_lab = OpLabel\n" +
3723             "%n = OpVariable %_ptr_float Function\n" +
3724             "%ld = OpLoad %float %n\n" +
3725             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3726             "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
3727             "OpReturn\n" +
3728             "OpFunctionEnd",
3729         2, 0),
3730     // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
3731     InstructionFoldingCase<uint32_t>(
3732         Header() + "%main = OpFunction %void None %void_func\n" +
3733             "%main_lab = OpLabel\n" +
3734             "%n = OpVariable %_ptr_float Function\n" +
3735             "%ld = OpLoad %float %n\n" +
3736             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3737             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
3738             "OpReturn\n" +
3739             "OpFunctionEnd",
3740         2, 0),
3741     // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
3742     InstructionFoldingCase<uint32_t>(
3743         Header() + "%main = OpFunction %void None %void_func\n" +
3744             "%main_lab = OpLabel\n" +
3745             "%n = OpVariable %_ptr_float Function\n" +
3746             "%ld = OpLoad %float %n\n" +
3747             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
3748             "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
3749             "OpReturn\n" +
3750             "OpFunctionEnd",
3751         2, 0),
3752     // Test case 8: Don't Fold clamp(-1, 0) < 0.0
3753     InstructionFoldingCase<uint32_t>(
3754         Header() + "%main = OpFunction %void None %void_func\n" +
3755             "%main_lab = OpLabel\n" +
3756             "%n = OpVariable %_ptr_float Function\n" +
3757             "%ld = OpLoad %float %n\n" +
3758             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
3759             "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
3760             "OpReturn\n" +
3761             "OpFunctionEnd",
3762         2, 0),
3763     // Test case 9: Don't Fold clamp(0, 1) < 1
3764     InstructionFoldingCase<uint32_t>(
3765         Header() + "%main = OpFunction %void None %void_func\n" +
3766             "%main_lab = OpLabel\n" +
3767             "%n = OpVariable %_ptr_float Function\n" +
3768             "%ld = OpLoad %float %n\n" +
3769             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
3770             "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
3771             "OpReturn\n" +
3772             "OpFunctionEnd",
3773         2, 0),
3774     // Test case 10: Don't Fold clamp(-1, 0) > -1
3775     InstructionFoldingCase<uint32_t>(
3776         Header() + "%main = OpFunction %void None %void_func\n" +
3777             "%main_lab = OpLabel\n" +
3778             "%n = OpVariable %_ptr_float Function\n" +
3779             "%ld = OpLoad %float %n\n" +
3780             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
3781             "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
3782             "OpReturn\n" +
3783             "OpFunctionEnd",
3784         2, 0),
3785     // Test case 11: Don't Fold clamp(-1, 0) > -1
3786     InstructionFoldingCase<uint32_t>(
3787         Header() + "%main = OpFunction %void None %void_func\n" +
3788             "%main_lab = OpLabel\n" +
3789             "%n = OpVariable %_ptr_float Function\n" +
3790             "%ld = OpLoad %float %n\n" +
3791             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
3792             "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
3793             "OpReturn\n" +
3794             "OpFunctionEnd",
3795         2, 0)
3796 ));
3797 
3798 INSTANTIATE_TEST_CASE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
3799                         ::testing::Values(
3800     // Test case 0: Fold int(3.0)
3801     InstructionFoldingCase<uint32_t>(
3802         Header() + "%main = OpFunction %void None %void_func\n" +
3803             "%main_lab = OpLabel\n" +
3804             "%2 = OpConvertFToS %int %float_3\n" +
3805             "OpReturn\n" +
3806             "OpFunctionEnd",
3807         2, 3),
3808     // Test case 1: Fold uint(3.0)
3809     InstructionFoldingCase<uint32_t>(
3810         Header() + "%main = OpFunction %void None %void_func\n" +
3811             "%main_lab = OpLabel\n" +
3812             "%2 = OpConvertFToU %int %float_3\n" +
3813             "OpReturn\n" +
3814             "OpFunctionEnd",
3815         2, 3)
3816 ));
3817 
3818 INSTANTIATE_TEST_CASE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
3819                         ::testing::Values(
3820     // Test case 0: Fold float(3)
3821     InstructionFoldingCase<float>(
3822         Header() + "%main = OpFunction %void None %void_func\n" +
3823             "%main_lab = OpLabel\n" +
3824             "%2 = OpConvertSToF %float %int_3\n" +
3825             "OpReturn\n" +
3826             "OpFunctionEnd",
3827         2, 3.0),
3828     // Test case 1: Fold float(3u)
3829     InstructionFoldingCase<float>(
3830         Header() + "%main = OpFunction %void None %void_func\n" +
3831             "%main_lab = OpLabel\n" +
3832             "%2 = OpConvertUToF %float %uint_3\n" +
3833             "OpReturn\n" +
3834             "OpFunctionEnd",
3835         2, 3.0)
3836 ));
3837 // clang-format on
3838 
3839 using ToNegateFoldingTest =
3840     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
3841 
TEST_P(ToNegateFoldingTest,Case)3842 TEST_P(ToNegateFoldingTest, Case) {
3843   const auto& tc = GetParam();
3844 
3845   // Build module.
3846   std::unique_ptr<IRContext> context =
3847       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3848                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3849   ASSERT_NE(nullptr, context);
3850 
3851   // Fold the instruction to test.
3852   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3853   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3854   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
3855   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
3856 
3857   // Make sure the instruction folded as expected.
3858   EXPECT_EQ(inst->result_id(), original_inst->result_id());
3859   EXPECT_EQ(inst->type_id(), original_inst->type_id());
3860   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
3861   if (succeeded) {
3862     EXPECT_EQ(inst->opcode(), SpvOpFNegate);
3863     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
3864   } else {
3865     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
3866     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
3867       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
3868     }
3869   }
3870 }
3871 
3872 // clang-format off
3873 INSTANTIATE_TEST_CASE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
3874                         ::testing::Values(
3875     // Test case 0: Don't fold 1.0 - n
3876     InstructionFoldingCase<uint32_t>(
3877         Header() + "%main = OpFunction %void None %void_func\n" +
3878             "%main_lab = OpLabel\n" +
3879             "%n = OpVariable %_ptr_float Function\n" +
3880             "%3 = OpLoad %float %n\n" +
3881             "%2 = OpFSub %float %float_1 %3\n" +
3882             "OpReturn\n" +
3883             "OpFunctionEnd",
3884         2, 0),
3885     // Test case 1: Fold 0.0 - n
3886     InstructionFoldingCase<uint32_t>(
3887         Header() + "%main = OpFunction %void None %void_func\n" +
3888             "%main_lab = OpLabel\n" +
3889             "%n = OpVariable %_ptr_float Function\n" +
3890             "%3 = OpLoad %float %n\n" +
3891             "%2 = OpFSub %float %float_0 %3\n" +
3892             "OpReturn\n" +
3893             "OpFunctionEnd",
3894         2, 3),
3895 	// Test case 2: Don't fold (0,0,0,1) - n
3896     InstructionFoldingCase<uint32_t>(
3897         Header() + "%main = OpFunction %void None %void_func\n" +
3898             "%main_lab = OpLabel\n" +
3899             "%n = OpVariable %_ptr_v4float Function\n" +
3900             "%3 = OpLoad %v4float %n\n" +
3901             "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
3902             "OpReturn\n" +
3903             "OpFunctionEnd",
3904         2, 0),
3905 	// Test case 3: Fold (0,0,0,0) - n
3906     InstructionFoldingCase<uint32_t>(
3907         Header() + "%main = OpFunction %void None %void_func\n" +
3908             "%main_lab = OpLabel\n" +
3909             "%n = OpVariable %_ptr_v4float Function\n" +
3910             "%3 = OpLoad %v4float %n\n" +
3911             "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
3912             "OpReturn\n" +
3913             "OpFunctionEnd",
3914         2, 3)
3915 ));
3916 
3917 INSTANTIATE_TEST_CASE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
3918                         ::testing::Values(
3919     // Test case 0: Don't fold 1.0 - n
3920     InstructionFoldingCase<uint32_t>(
3921         Header() + "%main = OpFunction %void None %void_func\n" +
3922             "%main_lab = OpLabel\n" +
3923             "%n = OpVariable %_ptr_double Function\n" +
3924             "%3 = OpLoad %double %n\n" +
3925             "%2 = OpFSub %double %double_1 %3\n" +
3926             "OpReturn\n" +
3927             "OpFunctionEnd",
3928         2, 0),
3929     // Test case 1: Fold 0.0 - n
3930     InstructionFoldingCase<uint32_t>(
3931         Header() + "%main = OpFunction %void None %void_func\n" +
3932             "%main_lab = OpLabel\n" +
3933             "%n = OpVariable %_ptr_double Function\n" +
3934             "%3 = OpLoad %double %n\n" +
3935             "%2 = OpFSub %double %double_0 %3\n" +
3936             "OpReturn\n" +
3937             "OpFunctionEnd",
3938         2, 3),
3939 	// Test case 2: Don't fold (0,0,0,1) - n
3940     InstructionFoldingCase<uint32_t>(
3941         Header() + "%main = OpFunction %void None %void_func\n" +
3942             "%main_lab = OpLabel\n" +
3943             "%n = OpVariable %_ptr_v4double Function\n" +
3944             "%3 = OpLoad %v4double %n\n" +
3945             "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
3946             "OpReturn\n" +
3947             "OpFunctionEnd",
3948         2, 0),
3949 	// Test case 3: Fold (0,0,0,0) - n
3950     InstructionFoldingCase<uint32_t>(
3951         Header() + "%main = OpFunction %void None %void_func\n" +
3952             "%main_lab = OpLabel\n" +
3953             "%n = OpVariable %_ptr_v4double Function\n" +
3954             "%3 = OpLoad %v4double %n\n" +
3955             "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
3956             "OpReturn\n" +
3957             "OpFunctionEnd",
3958         2, 3)
3959 ));
3960 
3961 using MatchingInstructionFoldingTest =
3962     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
3963 
TEST_P(MatchingInstructionFoldingTest,Case)3964 TEST_P(MatchingInstructionFoldingTest, Case) {
3965   const auto& tc = GetParam();
3966 
3967   // Build module.
3968   std::unique_ptr<IRContext> context =
3969       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3970                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3971   ASSERT_NE(nullptr, context);
3972 
3973   // Fold the instruction to test.
3974   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3975   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3976   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
3977   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
3978   EXPECT_EQ(succeeded, tc.expected_result);
3979   if (succeeded) {
3980     Match(tc.test_body, context.get());
3981   }
3982 }
3983 
3984 INSTANTIATE_TEST_CASE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
3985 ::testing::Values(
3986     // Test case 0: Fold 0 + n (change sign)
3987     InstructionFoldingCase<bool>(
3988         Header() +
3989             "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
3990             "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
3991             "%main = OpFunction %void None %void_func\n" +
3992             "%main_lab = OpLabel\n" +
3993             "%n = OpVariable %_ptr_int Function\n" +
3994             "%3 = OpLoad %uint %n\n" +
3995             "%2 = OpIAdd %uint %int_0 %3\n" +
3996             "OpReturn\n" +
3997             "OpFunctionEnd\n",
3998         2, true),
3999     // Test case 0: Fold 0 + n (change sign)
4000     InstructionFoldingCase<bool>(
4001         Header() +
4002             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4003             "; CHECK: %2 = OpBitcast [[int]] %3\n" +
4004             "%main = OpFunction %void None %void_func\n" +
4005             "%main_lab = OpLabel\n" +
4006             "%n = OpVariable %_ptr_int Function\n" +
4007             "%3 = OpLoad %int %n\n" +
4008             "%2 = OpIAdd %int %uint_0 %3\n" +
4009             "OpReturn\n" +
4010             "OpFunctionEnd\n",
4011         2, true)
4012 ));
4013 
4014 INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest,
4015 ::testing::Values(
4016   // Test case 0: fold consecutive fnegate
4017   // -(-x) = x
4018   InstructionFoldingCase<bool>(
4019     Header() +
4020       "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
4021       "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
4022       "%main = OpFunction %void None %void_func\n" +
4023       "%main_lab = OpLabel\n" +
4024       "%var = OpVariable %_ptr_float Function\n" +
4025       "%2 = OpLoad %float %var\n" +
4026       "%3 = OpFNegate %float %2\n" +
4027       "%4 = OpFNegate %float %3\n" +
4028       "OpReturn\n" +
4029       "OpFunctionEnd",
4030     4, true),
4031   // Test case 1: fold fnegate(fmul with const).
4032   // -(x * 2.0) = x * -2.0
4033   InstructionFoldingCase<bool>(
4034     Header() +
4035       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4036       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4037       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4038       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
4039       "%main = OpFunction %void None %void_func\n" +
4040       "%main_lab = OpLabel\n" +
4041       "%var = OpVariable %_ptr_float Function\n" +
4042       "%2 = OpLoad %float %var\n" +
4043       "%3 = OpFMul %float %2 %float_2\n" +
4044       "%4 = OpFNegate %float %3\n" +
4045       "OpReturn\n" +
4046       "OpFunctionEnd",
4047     4, true),
4048   // Test case 2: fold fnegate(fmul with const).
4049   // -(2.0 * x) = x * 2.0
4050   InstructionFoldingCase<bool>(
4051     Header() +
4052       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4053       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4054       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4055       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
4056       "%main = OpFunction %void None %void_func\n" +
4057       "%main_lab = OpLabel\n" +
4058       "%var = OpVariable %_ptr_float Function\n" +
4059       "%2 = OpLoad %float %var\n" +
4060       "%3 = OpFMul %float %float_2 %2\n" +
4061       "%4 = OpFNegate %float %3\n" +
4062       "OpReturn\n" +
4063       "OpFunctionEnd",
4064     4, true),
4065   // Test case 3: fold fnegate(fdiv with const).
4066   // -(x / 2.0) = x * -0.5
4067   InstructionFoldingCase<bool>(
4068     Header() +
4069       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4070       "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
4071       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4072       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
4073       "%main = OpFunction %void None %void_func\n" +
4074       "%main_lab = OpLabel\n" +
4075       "%var = OpVariable %_ptr_float Function\n" +
4076       "%2 = OpLoad %float %var\n" +
4077       "%3 = OpFDiv %float %2 %float_2\n" +
4078       "%4 = OpFNegate %float %3\n" +
4079       "OpReturn\n" +
4080       "OpFunctionEnd",
4081     4, true),
4082   // Test case 4: fold fnegate(fdiv with const).
4083   // -(2.0 / x) = -2.0 / x
4084   InstructionFoldingCase<bool>(
4085     Header() +
4086       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4087       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4088       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4089       "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
4090       "%main = OpFunction %void None %void_func\n" +
4091       "%main_lab = OpLabel\n" +
4092       "%var = OpVariable %_ptr_float Function\n" +
4093       "%2 = OpLoad %float %var\n" +
4094       "%3 = OpFDiv %float %float_2 %2\n" +
4095       "%4 = OpFNegate %float %3\n" +
4096       "OpReturn\n" +
4097       "OpFunctionEnd",
4098     4, true),
4099   // Test case 5: fold fnegate(fadd with const).
4100   // -(2.0 + x) = -2.0 - x
4101   InstructionFoldingCase<bool>(
4102     Header() +
4103       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4104       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4105       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4106       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
4107       "%main = OpFunction %void None %void_func\n" +
4108       "%main_lab = OpLabel\n" +
4109       "%var = OpVariable %_ptr_float Function\n" +
4110       "%2 = OpLoad %float %var\n" +
4111       "%3 = OpFAdd %float %float_2 %2\n" +
4112       "%4 = OpFNegate %float %3\n" +
4113       "OpReturn\n" +
4114       "OpFunctionEnd",
4115     4, true),
4116   // Test case 6: fold fnegate(fadd with const).
4117   // -(x + 2.0) = -2.0 - x
4118   InstructionFoldingCase<bool>(
4119     Header() +
4120       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4121       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4122       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4123       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
4124       "%main = OpFunction %void None %void_func\n" +
4125       "%main_lab = OpLabel\n" +
4126       "%var = OpVariable %_ptr_float Function\n" +
4127       "%2 = OpLoad %float %var\n" +
4128       "%3 = OpFAdd %float %2 %float_2\n" +
4129       "%4 = OpFNegate %float %3\n" +
4130       "OpReturn\n" +
4131       "OpFunctionEnd",
4132     4, true),
4133   // Test case 7: fold fnegate(fsub with const).
4134   // -(2.0 - x) = x - 2.0
4135   InstructionFoldingCase<bool>(
4136     Header() +
4137       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4138       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4139       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4140       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
4141       "%main = OpFunction %void None %void_func\n" +
4142       "%main_lab = OpLabel\n" +
4143       "%var = OpVariable %_ptr_float Function\n" +
4144       "%2 = OpLoad %float %var\n" +
4145       "%3 = OpFSub %float %float_2 %2\n" +
4146       "%4 = OpFNegate %float %3\n" +
4147       "OpReturn\n" +
4148       "OpFunctionEnd",
4149     4, true),
4150   // Test case 8: fold fnegate(fsub with const).
4151   // -(x - 2.0) = 2.0 - x
4152   InstructionFoldingCase<bool>(
4153     Header() +
4154       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4155       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4156       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4157       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
4158       "%main = OpFunction %void None %void_func\n" +
4159       "%main_lab = OpLabel\n" +
4160       "%var = OpVariable %_ptr_float Function\n" +
4161       "%2 = OpLoad %float %var\n" +
4162       "%3 = OpFSub %float %2 %float_2\n" +
4163       "%4 = OpFNegate %float %3\n" +
4164       "OpReturn\n" +
4165       "OpFunctionEnd",
4166     4, true),
4167   // Test case 9: fold consecutive snegate
4168   // -(-x) = x
4169   InstructionFoldingCase<bool>(
4170     Header() +
4171       "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
4172       "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
4173       "%main = OpFunction %void None %void_func\n" +
4174       "%main_lab = OpLabel\n" +
4175       "%var = OpVariable %_ptr_int Function\n" +
4176       "%2 = OpLoad %int %var\n" +
4177       "%3 = OpSNegate %int %2\n" +
4178       "%4 = OpSNegate %int %3\n" +
4179       "OpReturn\n" +
4180       "OpFunctionEnd",
4181     4, true),
4182   // Test case 10: fold consecutive vector negate
4183   // -(-x) = x
4184   InstructionFoldingCase<bool>(
4185     Header() +
4186       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
4187       "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
4188       "%main = OpFunction %void None %void_func\n" +
4189       "%main_lab = OpLabel\n" +
4190       "%var = OpVariable %_ptr_v2float Function\n" +
4191       "%2 = OpLoad %v2float %var\n" +
4192       "%3 = OpFNegate %v2float %2\n" +
4193       "%4 = OpFNegate %v2float %3\n" +
4194       "OpReturn\n" +
4195       "OpFunctionEnd",
4196     4, true),
4197   // Test case 11: fold snegate(iadd with const).
4198   // -(2 + x) = -2 - x
4199   InstructionFoldingCase<bool>(
4200     Header() +
4201       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4202       "; CHECK: OpConstant [[int]] -2147483648\n" +
4203       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
4204       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4205       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
4206       "%main = OpFunction %void None %void_func\n" +
4207       "%main_lab = OpLabel\n" +
4208       "%var = OpVariable %_ptr_int Function\n" +
4209       "%2 = OpLoad %int %var\n" +
4210       "%3 = OpIAdd %int %int_2 %2\n" +
4211       "%4 = OpSNegate %int %3\n" +
4212       "OpReturn\n" +
4213       "OpFunctionEnd",
4214     4, true),
4215   // Test case 12: fold snegate(iadd with const).
4216   // -(x + 2) = -2 - x
4217   InstructionFoldingCase<bool>(
4218     Header() +
4219       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4220       "; CHECK: OpConstant [[int]] -2147483648\n" +
4221       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
4222       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4223       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
4224       "%main = OpFunction %void None %void_func\n" +
4225       "%main_lab = OpLabel\n" +
4226       "%var = OpVariable %_ptr_int Function\n" +
4227       "%2 = OpLoad %int %var\n" +
4228       "%3 = OpIAdd %int %2 %int_2\n" +
4229       "%4 = OpSNegate %int %3\n" +
4230       "OpReturn\n" +
4231       "OpFunctionEnd",
4232     4, true),
4233   // Test case 13: fold snegate(isub with const).
4234   // -(2 - x) = x - 2
4235   InstructionFoldingCase<bool>(
4236     Header() +
4237       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4238       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
4239       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4240       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
4241       "%main = OpFunction %void None %void_func\n" +
4242       "%main_lab = OpLabel\n" +
4243       "%var = OpVariable %_ptr_int Function\n" +
4244       "%2 = OpLoad %int %var\n" +
4245       "%3 = OpISub %int %int_2 %2\n" +
4246       "%4 = OpSNegate %int %3\n" +
4247       "OpReturn\n" +
4248       "OpFunctionEnd",
4249     4, true),
4250   // Test case 14: fold snegate(isub with const).
4251   // -(x - 2) = 2 - x
4252   InstructionFoldingCase<bool>(
4253     Header() +
4254       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4255       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
4256       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4257       "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
4258       "%main = OpFunction %void None %void_func\n" +
4259       "%main_lab = OpLabel\n" +
4260       "%var = OpVariable %_ptr_int Function\n" +
4261       "%2 = OpLoad %int %var\n" +
4262       "%3 = OpISub %int %2 %int_2\n" +
4263       "%4 = OpSNegate %int %3\n" +
4264       "OpReturn\n" +
4265       "OpFunctionEnd",
4266     4, true),
4267   // Test case 15: fold snegate(iadd with const).
4268   // -(x + 2) = -2 - x
4269   InstructionFoldingCase<bool>(
4270     Header() +
4271       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
4272       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
4273       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4274       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
4275       "%main = OpFunction %void None %void_func\n" +
4276       "%main_lab = OpLabel\n" +
4277       "%var = OpVariable %_ptr_long Function\n" +
4278       "%2 = OpLoad %long %var\n" +
4279       "%3 = OpIAdd %long %2 %long_2\n" +
4280       "%4 = OpSNegate %long %3\n" +
4281       "OpReturn\n" +
4282       "OpFunctionEnd",
4283     4, true),
4284   // Test case 16: fold snegate(isub with const).
4285   // -(2 - x) = x - 2
4286   InstructionFoldingCase<bool>(
4287     Header() +
4288       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
4289       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
4290       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4291       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
4292       "%main = OpFunction %void None %void_func\n" +
4293       "%main_lab = OpLabel\n" +
4294       "%var = OpVariable %_ptr_long Function\n" +
4295       "%2 = OpLoad %long %var\n" +
4296       "%3 = OpISub %long %long_2 %2\n" +
4297       "%4 = OpSNegate %long %3\n" +
4298       "OpReturn\n" +
4299       "OpFunctionEnd",
4300     4, true),
4301   // Test case 17: fold snegate(isub with const).
4302   // -(x - 2) = 2 - x
4303   InstructionFoldingCase<bool>(
4304     Header() +
4305       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
4306       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
4307       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4308       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
4309       "%main = OpFunction %void None %void_func\n" +
4310       "%main_lab = OpLabel\n" +
4311       "%var = OpVariable %_ptr_long Function\n" +
4312       "%2 = OpLoad %long %var\n" +
4313       "%3 = OpISub %long %2 %long_2\n" +
4314       "%4 = OpSNegate %long %3\n" +
4315       "OpReturn\n" +
4316       "OpFunctionEnd",
4317     4, true),
4318     // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
4319     InstructionFoldingCase<bool>(
4320         Header() +
4321       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4322       "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4\n" +
4323       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
4324       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4325       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4326       "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3\n" +
4327       "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
4328       "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
4329         "%main = OpFunction %void None %void_func\n" +
4330             "%main_lab = OpLabel\n" +
4331             "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
4332             "OpReturn\n" +
4333             "OpFunctionEnd",
4334         2, true),
4335     // Test case 19: fold vector fnegate with null
4336     InstructionFoldingCase<bool>(
4337         Header() +
4338       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4339       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
4340       "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
4341       "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
4342       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
4343         "%main = OpFunction %void None %void_func\n" +
4344             "%main_lab = OpLabel\n" +
4345             "%2 = OpFNegate %v2double %v2double_null\n" +
4346             "OpReturn\n" +
4347             "OpFunctionEnd",
4348         2, true)
4349 ));
4350 
4351 INSTANTIATE_TEST_CASE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
4352 ::testing::Values(
4353   // Test case 0: scalar reicprocal
4354   // x / 0.5 = x * 2.0
4355   InstructionFoldingCase<bool>(
4356     Header() +
4357       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4358       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4359       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4360       "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
4361       "%main = OpFunction %void None %void_func\n" +
4362       "%main_lab = OpLabel\n" +
4363       "%var = OpVariable %_ptr_float Function\n" +
4364       "%2 = OpLoad %float %var\n" +
4365       "%3 = OpFDiv %float %2 %float_0p5\n" +
4366       "OpReturn\n" +
4367       "OpFunctionEnd\n",
4368     3, true),
4369   // Test case 1: Unfoldable
4370   InstructionFoldingCase<bool>(
4371     Header() +
4372       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4373       "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
4374       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4375       "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
4376       "%main = OpFunction %void None %void_func\n" +
4377       "%main_lab = OpLabel\n" +
4378       "%var = OpVariable %_ptr_float Function\n" +
4379       "%2 = OpLoad %float %var\n" +
4380       "%3 = OpFDiv %float %2 %104\n" +
4381       "OpReturn\n" +
4382       "OpFunctionEnd\n",
4383     3, false),
4384   // Test case 2: Vector reciprocal
4385   // x / {2.0, 0.5} = x * {0.5, 2.0}
4386   InstructionFoldingCase<bool>(
4387     Header() +
4388       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4389       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
4390       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4391       "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
4392       "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
4393       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
4394       "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
4395       "%main = OpFunction %void None %void_func\n" +
4396       "%main_lab = OpLabel\n" +
4397       "%var = OpVariable %_ptr_v2float Function\n" +
4398       "%2 = OpLoad %v2float %var\n" +
4399       "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
4400       "OpReturn\n" +
4401       "OpFunctionEnd\n",
4402     3, true),
4403   // Test case 3: double reciprocal
4404   // x / 2.0 = x * 0.5
4405   InstructionFoldingCase<bool>(
4406     Header() +
4407       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4408       "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
4409       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
4410       "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
4411       "%main = OpFunction %void None %void_func\n" +
4412       "%main_lab = OpLabel\n" +
4413       "%var = OpVariable %_ptr_double Function\n" +
4414       "%2 = OpLoad %double %var\n" +
4415       "%3 = OpFDiv %double %2 %double_2\n" +
4416       "OpReturn\n" +
4417       "OpFunctionEnd\n",
4418     3, true),
4419   // Test case 4: don't fold x / 0.
4420   InstructionFoldingCase<bool>(
4421     Header() +
4422       "%main = OpFunction %void None %void_func\n" +
4423       "%main_lab = OpLabel\n" +
4424       "%var = OpVariable %_ptr_v2float Function\n" +
4425       "%2 = OpLoad %v2float %var\n" +
4426       "%3 = OpFDiv %v2float %2 %v2float_null\n" +
4427       "OpReturn\n" +
4428       "OpFunctionEnd\n",
4429     3, false)
4430 ));
4431 
4432 INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest,
4433 ::testing::Values(
4434   // Test case 0: fold consecutive fmuls
4435   // (x * 3.0) * 2.0 = x * 6.0
4436   InstructionFoldingCase<bool>(
4437     Header() +
4438       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4439       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
4440       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4441       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
4442       "%main = OpFunction %void None %void_func\n" +
4443       "%main_lab = OpLabel\n" +
4444       "%var = OpVariable %_ptr_float Function\n" +
4445       "%2 = OpLoad %float %var\n" +
4446       "%3 = OpFMul %float %2 %float_3\n" +
4447       "%4 = OpFMul %float %3 %float_2\n" +
4448       "OpReturn\n" +
4449       "OpFunctionEnd\n",
4450     4, true),
4451   // Test case 1: fold consecutive fmuls
4452   // 2.0 * (x * 3.0) = x * 6.0
4453   InstructionFoldingCase<bool>(
4454     Header() +
4455       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4456       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
4457       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4458       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
4459       "%main = OpFunction %void None %void_func\n" +
4460       "%main_lab = OpLabel\n" +
4461       "%var = OpVariable %_ptr_float Function\n" +
4462       "%2 = OpLoad %float %var\n" +
4463       "%3 = OpFMul %float %2 %float_3\n" +
4464       "%4 = OpFMul %float %float_2 %3\n" +
4465       "OpReturn\n" +
4466       "OpFunctionEnd\n",
4467     4, true),
4468   // Test case 2: fold consecutive fmuls
4469   // (3.0 * x) * 2.0 = x * 6.0
4470   InstructionFoldingCase<bool>(
4471     Header() +
4472       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4473       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
4474       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4475       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
4476       "%main = OpFunction %void None %void_func\n" +
4477       "%main_lab = OpLabel\n" +
4478       "%var = OpVariable %_ptr_float Function\n" +
4479       "%2 = OpLoad %float %var\n" +
4480       "%3 = OpFMul %float %float_3 %2\n" +
4481       "%4 = OpFMul %float %float_2 %3\n" +
4482       "OpReturn\n" +
4483       "OpFunctionEnd\n",
4484     4, true),
4485   // Test case 3: fold vector fmul
4486   InstructionFoldingCase<bool>(
4487     Header() +
4488       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4489       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
4490       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
4491       "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
4492       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
4493       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
4494       "%main = OpFunction %void None %void_func\n" +
4495       "%main_lab = OpLabel\n" +
4496       "%var = OpVariable %_ptr_v2float Function\n" +
4497       "%2 = OpLoad %v2float %var\n" +
4498       "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
4499       "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
4500       "OpReturn\n" +
4501       "OpFunctionEnd\n",
4502     4, true),
4503   // Test case 4: fold double fmuls
4504   // (x * 3.0) * 2.0 = x * 6.0
4505   InstructionFoldingCase<bool>(
4506     Header() +
4507       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4508       "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
4509       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
4510       "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
4511       "%main = OpFunction %void None %void_func\n" +
4512       "%main_lab = OpLabel\n" +
4513       "%var = OpVariable %_ptr_double Function\n" +
4514       "%2 = OpLoad %double %var\n" +
4515       "%3 = OpFMul %double %2 %double_3\n" +
4516       "%4 = OpFMul %double %3 %double_2\n" +
4517       "OpReturn\n" +
4518       "OpFunctionEnd\n",
4519     4, true),
4520   // Test case 5: fold 32 bit imuls
4521   // (x * 3) * 2 = x * 6
4522   InstructionFoldingCase<bool>(
4523     Header() +
4524       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4525       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
4526       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4527       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
4528       "%main = OpFunction %void None %void_func\n" +
4529       "%main_lab = OpLabel\n" +
4530       "%var = OpVariable %_ptr_int Function\n" +
4531       "%2 = OpLoad %int %var\n" +
4532       "%3 = OpIMul %int %2 %int_3\n" +
4533       "%4 = OpIMul %int %3 %int_2\n" +
4534       "OpReturn\n" +
4535       "OpFunctionEnd\n",
4536     4, true),
4537   // Test case 6: fold 64 bit imuls
4538   // (x * 3) * 2 = x * 6
4539   InstructionFoldingCase<bool>(
4540     Header() +
4541       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
4542       "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
4543       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4544       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
4545       "%main = OpFunction %void None %void_func\n" +
4546       "%main_lab = OpLabel\n" +
4547       "%var = OpVariable %_ptr_long Function\n" +
4548       "%2 = OpLoad %long %var\n" +
4549       "%3 = OpIMul %long %2 %long_3\n" +
4550       "%4 = OpIMul %long %3 %long_2\n" +
4551       "OpReturn\n" +
4552       "OpFunctionEnd\n",
4553     4, true),
4554   // Test case 7: merge vector integer mults
4555   InstructionFoldingCase<bool>(
4556     Header() +
4557       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4558       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4559       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
4560       "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
4561       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
4562       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
4563       "%main = OpFunction %void None %void_func\n" +
4564       "%main_lab = OpLabel\n" +
4565       "%var = OpVariable %_ptr_v2int Function\n" +
4566       "%2 = OpLoad %v2int %var\n" +
4567       "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
4568       "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
4569       "OpReturn\n" +
4570       "OpFunctionEnd\n",
4571     4, true),
4572   // Test case 8: merge fmul of fdiv
4573   // 2.0 * (2.0 / x) = 4.0 / x
4574   InstructionFoldingCase<bool>(
4575     Header() +
4576       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4577       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
4578       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4579       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
4580       "%main = OpFunction %void None %void_func\n" +
4581       "%main_lab = OpLabel\n" +
4582       "%var = OpVariable %_ptr_float Function\n" +
4583       "%2 = OpLoad %float %var\n" +
4584       "%3 = OpFDiv %float %float_2 %2\n" +
4585       "%4 = OpFMul %float %float_2 %3\n" +
4586       "OpReturn\n" +
4587       "OpFunctionEnd\n",
4588     4, true),
4589   // Test case 9: merge fmul of fdiv
4590   // (2.0 / x) * 2.0 = 4.0 / x
4591   InstructionFoldingCase<bool>(
4592     Header() +
4593       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4594       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
4595       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4596       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
4597       "%main = OpFunction %void None %void_func\n" +
4598       "%main_lab = OpLabel\n" +
4599       "%var = OpVariable %_ptr_float Function\n" +
4600       "%2 = OpLoad %float %var\n" +
4601       "%3 = OpFDiv %float %float_2 %2\n" +
4602       "%4 = OpFMul %float %3 %float_2\n" +
4603       "OpReturn\n" +
4604       "OpFunctionEnd\n",
4605     4, true),
4606   // Test case 10: Do not merge imul of sdiv
4607   // 4 * (x / 2)
4608   InstructionFoldingCase<bool>(
4609     Header() +
4610       "%main = OpFunction %void None %void_func\n" +
4611       "%main_lab = OpLabel\n" +
4612       "%var = OpVariable %_ptr_int Function\n" +
4613       "%2 = OpLoad %int %var\n" +
4614       "%3 = OpSDiv %int %2 %int_2\n" +
4615       "%4 = OpIMul %int %int_4 %3\n" +
4616       "OpReturn\n" +
4617       "OpFunctionEnd\n",
4618     4, false),
4619   // Test case 11: Do not merge imul of sdiv
4620   // (x / 2) * 4
4621   InstructionFoldingCase<bool>(
4622     Header() +
4623       "%main = OpFunction %void None %void_func\n" +
4624       "%main_lab = OpLabel\n" +
4625       "%var = OpVariable %_ptr_int Function\n" +
4626       "%2 = OpLoad %int %var\n" +
4627       "%3 = OpSDiv %int %2 %int_2\n" +
4628       "%4 = OpIMul %int %3 %int_4\n" +
4629       "OpReturn\n" +
4630       "OpFunctionEnd\n",
4631     4, false),
4632   // Test case 12: Do not merge imul of udiv
4633   // 4 * (x / 2)
4634   InstructionFoldingCase<bool>(
4635     Header() +
4636       "%main = OpFunction %void None %void_func\n" +
4637       "%main_lab = OpLabel\n" +
4638       "%var = OpVariable %_ptr_uint Function\n" +
4639       "%2 = OpLoad %uint %var\n" +
4640       "%3 = OpUDiv %uint %2 %uint_2\n" +
4641       "%4 = OpIMul %uint %uint_4 %3\n" +
4642       "OpReturn\n" +
4643       "OpFunctionEnd\n",
4644     4, false),
4645   // Test case 13: Do not merge imul of udiv
4646   // (x / 2) * 4
4647   InstructionFoldingCase<bool>(
4648     Header() +
4649       "%main = OpFunction %void None %void_func\n" +
4650       "%main_lab = OpLabel\n" +
4651       "%var = OpVariable %_ptr_uint Function\n" +
4652       "%2 = OpLoad %uint %var\n" +
4653       "%3 = OpUDiv %uint %2 %uint_2\n" +
4654       "%4 = OpIMul %uint %3 %uint_4\n" +
4655       "OpReturn\n" +
4656       "OpFunctionEnd\n",
4657     4, false),
4658   // Test case 14: Don't fold
4659   // (x / 3) * 4
4660   InstructionFoldingCase<bool>(
4661     Header() +
4662       "%main = OpFunction %void None %void_func\n" +
4663       "%main_lab = OpLabel\n" +
4664       "%var = OpVariable %_ptr_uint Function\n" +
4665       "%2 = OpLoad %uint %var\n" +
4666       "%3 = OpUDiv %uint %2 %uint_3\n" +
4667       "%4 = OpIMul %uint %3 %uint_4\n" +
4668       "OpReturn\n" +
4669       "OpFunctionEnd\n",
4670     4, false),
4671   // Test case 15: merge vector fmul of fdiv
4672   // (x / {2,2}) * {4,4} = x * {2,2}
4673   InstructionFoldingCase<bool>(
4674     Header() +
4675       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4676       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
4677       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4678       "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
4679       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
4680       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
4681       "%main = OpFunction %void None %void_func\n" +
4682       "%main_lab = OpLabel\n" +
4683       "%var = OpVariable %_ptr_v2float Function\n" +
4684       "%2 = OpLoad %v2float %var\n" +
4685       "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
4686       "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
4687       "OpReturn\n" +
4688       "OpFunctionEnd\n",
4689     4, true),
4690   // Test case 16: merge vector imul of snegate
4691   // (-x) * {2,2} = x * {-2,-2}
4692   InstructionFoldingCase<bool>(
4693     Header() +
4694       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4695       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4696       "; CHECK: OpConstant [[int]] -2147483648\n" +
4697       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
4698       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
4699       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
4700       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
4701       "%main = OpFunction %void None %void_func\n" +
4702       "%main_lab = OpLabel\n" +
4703       "%var = OpVariable %_ptr_v2int Function\n" +
4704       "%2 = OpLoad %v2int %var\n" +
4705       "%3 = OpSNegate %v2int %2\n" +
4706       "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
4707       "OpReturn\n" +
4708       "OpFunctionEnd\n",
4709     4, true),
4710   // Test case 17: merge vector imul of snegate
4711   // {2,2} * (-x) = x * {-2,-2}
4712   InstructionFoldingCase<bool>(
4713     Header() +
4714       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4715       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4716       "; CHECK: OpConstant [[int]] -2147483648\n" +
4717       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
4718       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
4719       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
4720       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
4721       "%main = OpFunction %void None %void_func\n" +
4722       "%main_lab = OpLabel\n" +
4723       "%var = OpVariable %_ptr_v2int Function\n" +
4724       "%2 = OpLoad %v2int %var\n" +
4725       "%3 = OpSNegate %v2int %2\n" +
4726       "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
4727       "OpReturn\n" +
4728       "OpFunctionEnd\n",
4729     4, true),
4730   // Test case 18: Fold OpVectorTimesScalar
4731   // {4,4} = OpVectorTimesScalar v2float {2,2} 2
4732   InstructionFoldingCase<bool>(
4733     Header() +
4734       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4735       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
4736       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
4737       "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
4738       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
4739       "%main = OpFunction %void None %void_func\n" +
4740       "%main_lab = OpLabel\n" +
4741       "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
4742       "OpReturn\n" +
4743       "OpFunctionEnd",
4744     2, true),
4745   // Test case 19: Fold OpVectorTimesScalar
4746   // {0,0} = OpVectorTimesScalar v2float v2float_null -1
4747   InstructionFoldingCase<bool>(
4748     Header() +
4749       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4750       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
4751       "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
4752       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
4753       "%main = OpFunction %void None %void_func\n" +
4754       "%main_lab = OpLabel\n" +
4755       "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
4756       "OpReturn\n" +
4757       "OpFunctionEnd",
4758     2, true),
4759   // Test case 20: Fold OpVectorTimesScalar
4760   // {4,4} = OpVectorTimesScalar v2double {2,2} 2
4761   InstructionFoldingCase<bool>(
4762     Header() +
4763       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4764       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
4765       "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
4766       "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
4767       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
4768       "%main = OpFunction %void None %void_func\n" +
4769       "%main_lab = OpLabel\n" +
4770       "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
4771       "OpReturn\n" +
4772       "OpFunctionEnd",
4773     2, true),
4774   // Test case 21: Fold OpVectorTimesScalar
4775   // {0,0} = OpVectorTimesScalar v2double {0,0} n
4776   InstructionFoldingCase<bool>(
4777     Header() +
4778         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4779         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
4780         "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
4781         "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
4782         "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
4783         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
4784         "%main = OpFunction %void None %void_func\n" +
4785         "%main_lab = OpLabel\n" +
4786         "%n = OpVariable %_ptr_double Function\n" +
4787         "%load = OpLoad %double %n\n" +
4788         "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
4789         "OpReturn\n" +
4790         "OpFunctionEnd",
4791     2, true),
4792   // Test case 22: Fold OpVectorTimesScalar
4793   // {0,0} = OpVectorTimesScalar v2double n 0
4794   InstructionFoldingCase<bool>(
4795     Header() +
4796         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
4797         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
4798         "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
4799         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
4800         "%main = OpFunction %void None %void_func\n" +
4801         "%main_lab = OpLabel\n" +
4802         "%n = OpVariable %_ptr_v2double Function\n" +
4803         "%load = OpLoad %v2double %n\n" +
4804         "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
4805         "OpReturn\n" +
4806         "OpFunctionEnd",
4807     2, true),
4808   // Test case 23: merge fmul of fdiv
4809   // x * (y / x) = y
4810   InstructionFoldingCase<bool>(
4811     Header() +
4812         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4813         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
4814         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
4815         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
4816         "%main = OpFunction %void None %void_func\n" +
4817         "%main_lab = OpLabel\n" +
4818         "%x = OpVariable %_ptr_float Function\n" +
4819         "%y = OpVariable %_ptr_float Function\n" +
4820         "%2 = OpLoad %float %x\n" +
4821         "%3 = OpLoad %float %y\n" +
4822         "%4 = OpFDiv %float %3 %2\n" +
4823         "%5 = OpFMul %float %2 %4\n" +
4824         "OpReturn\n" +
4825         "OpFunctionEnd\n",
4826     5, true),
4827   // Test case 24: merge fmul of fdiv
4828   // (y / x) * x = y
4829   InstructionFoldingCase<bool>(
4830     Header() +
4831         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4832         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
4833         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
4834         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
4835         "%main = OpFunction %void None %void_func\n" +
4836         "%main_lab = OpLabel\n" +
4837         "%x = OpVariable %_ptr_float Function\n" +
4838         "%y = OpVariable %_ptr_float Function\n" +
4839         "%2 = OpLoad %float %x\n" +
4840         "%3 = OpLoad %float %y\n" +
4841         "%4 = OpFDiv %float %3 %2\n" +
4842         "%5 = OpFMul %float %4 %2\n" +
4843         "OpReturn\n" +
4844         "OpFunctionEnd\n",
4845     5, true)
4846 ));
4847 
4848 INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest,
4849 ::testing::Values(
4850   // Test case 0: merge consecutive fdiv
4851   // 4.0 / (2.0 / x) = 2.0 * x
4852   InstructionFoldingCase<bool>(
4853     Header() +
4854       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4855       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4856       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4857       "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
4858       "%main = OpFunction %void None %void_func\n" +
4859       "%main_lab = OpLabel\n" +
4860       "%var = OpVariable %_ptr_float Function\n" +
4861       "%2 = OpLoad %float %var\n" +
4862       "%3 = OpFDiv %float %float_2 %2\n" +
4863       "%4 = OpFDiv %float %float_4 %3\n" +
4864       "OpReturn\n" +
4865       "OpFunctionEnd\n",
4866     4, true),
4867   // Test case 1: merge consecutive fdiv
4868   // 4.0 / (x / 2.0) = 8.0 / x
4869   InstructionFoldingCase<bool>(
4870     Header() +
4871       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4872       "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
4873       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4874       "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
4875       "%main = OpFunction %void None %void_func\n" +
4876       "%main_lab = OpLabel\n" +
4877       "%var = OpVariable %_ptr_float Function\n" +
4878       "%2 = OpLoad %float %var\n" +
4879       "%3 = OpFDiv %float %2 %float_2\n" +
4880       "%4 = OpFDiv %float %float_4 %3\n" +
4881       "OpReturn\n" +
4882       "OpFunctionEnd\n",
4883     4, true),
4884   // Test case 2: merge consecutive fdiv
4885   // (4.0 / x) / 2.0 = 2.0 / x
4886   InstructionFoldingCase<bool>(
4887     Header() +
4888       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4889       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4890       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4891       "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
4892       "%main = OpFunction %void None %void_func\n" +
4893       "%main_lab = OpLabel\n" +
4894       "%var = OpVariable %_ptr_float Function\n" +
4895       "%2 = OpLoad %float %var\n" +
4896       "%3 = OpFDiv %float %float_4 %2\n" +
4897       "%4 = OpFDiv %float %3 %float_2\n" +
4898       "OpReturn\n" +
4899       "OpFunctionEnd\n",
4900     4, true),
4901   // Test case 3: Do not merge consecutive sdiv
4902   // 4 / (2 / x)
4903   InstructionFoldingCase<bool>(
4904     Header() +
4905       "%main = OpFunction %void None %void_func\n" +
4906       "%main_lab = OpLabel\n" +
4907       "%var = OpVariable %_ptr_int Function\n" +
4908       "%2 = OpLoad %int %var\n" +
4909       "%3 = OpSDiv %int %int_2 %2\n" +
4910       "%4 = OpSDiv %int %int_4 %3\n" +
4911       "OpReturn\n" +
4912       "OpFunctionEnd\n",
4913     4, false),
4914   // Test case 4: Do not merge consecutive sdiv
4915   // 4 / (x / 2)
4916   InstructionFoldingCase<bool>(
4917     Header() +
4918       "%main = OpFunction %void None %void_func\n" +
4919       "%main_lab = OpLabel\n" +
4920       "%var = OpVariable %_ptr_int Function\n" +
4921       "%2 = OpLoad %int %var\n" +
4922       "%3 = OpSDiv %int %2 %int_2\n" +
4923       "%4 = OpSDiv %int %int_4 %3\n" +
4924       "OpReturn\n" +
4925       "OpFunctionEnd\n",
4926     4, false),
4927   // Test case 5: Do not merge consecutive sdiv
4928   // (4 / x) / 2
4929   InstructionFoldingCase<bool>(
4930     Header() +
4931       "%main = OpFunction %void None %void_func\n" +
4932       "%main_lab = OpLabel\n" +
4933       "%var = OpVariable %_ptr_int Function\n" +
4934       "%2 = OpLoad %int %var\n" +
4935       "%3 = OpSDiv %int %int_4 %2\n" +
4936       "%4 = OpSDiv %int %3 %int_2\n" +
4937       "OpReturn\n" +
4938       "OpFunctionEnd\n",
4939     4, false),
4940   // Test case 6: Do not merge consecutive sdiv
4941   // (x / 4) / 2
4942   InstructionFoldingCase<bool>(
4943     Header() +
4944       "%main = OpFunction %void None %void_func\n" +
4945       "%main_lab = OpLabel\n" +
4946       "%var = OpVariable %_ptr_int Function\n" +
4947       "%2 = OpLoad %int %var\n" +
4948       "%3 = OpSDiv %int %2 %int_4\n" +
4949       "%4 = OpSDiv %int %3 %int_2\n" +
4950       "OpReturn\n" +
4951       "OpFunctionEnd\n",
4952     4, false),
4953   // Test case 7: Do not merge sdiv of imul
4954   // 4 / (2 * x)
4955   InstructionFoldingCase<bool>(
4956     Header() +
4957       "%main = OpFunction %void None %void_func\n" +
4958       "%main_lab = OpLabel\n" +
4959       "%var = OpVariable %_ptr_int Function\n" +
4960       "%2 = OpLoad %int %var\n" +
4961       "%3 = OpIMul %int %int_2 %2\n" +
4962       "%4 = OpSDiv %int %int_4 %3\n" +
4963       "OpReturn\n" +
4964       "OpFunctionEnd\n",
4965     4, false),
4966   // Test case 8: Do not merge sdiv of imul
4967   // 4 / (x * 2)
4968   InstructionFoldingCase<bool>(
4969     Header() +
4970       "%main = OpFunction %void None %void_func\n" +
4971       "%main_lab = OpLabel\n" +
4972       "%var = OpVariable %_ptr_int Function\n" +
4973       "%2 = OpLoad %int %var\n" +
4974       "%3 = OpIMul %int %2 %int_2\n" +
4975       "%4 = OpSDiv %int %int_4 %3\n" +
4976       "OpReturn\n" +
4977       "OpFunctionEnd\n",
4978     4, false),
4979   // Test case 9: Do not merge sdiv of imul
4980   // (4 * x) / 2
4981   InstructionFoldingCase<bool>(
4982     Header() +
4983       "%main = OpFunction %void None %void_func\n" +
4984       "%main_lab = OpLabel\n" +
4985       "%var = OpVariable %_ptr_int Function\n" +
4986       "%2 = OpLoad %int %var\n" +
4987       "%3 = OpIMul %int %int_4 %2\n" +
4988       "%4 = OpSDiv %int %3 %int_2\n" +
4989       "OpReturn\n" +
4990       "OpFunctionEnd\n",
4991     4, false),
4992   // Test case 10: Do not merge sdiv of imul
4993   // (x * 4) / 2
4994   InstructionFoldingCase<bool>(
4995     Header() +
4996       "%main = OpFunction %void None %void_func\n" +
4997       "%main_lab = OpLabel\n" +
4998       "%var = OpVariable %_ptr_int Function\n" +
4999       "%2 = OpLoad %int %var\n" +
5000       "%3 = OpIMul %int %2 %int_4\n" +
5001       "%4 = OpSDiv %int %3 %int_2\n" +
5002       "OpReturn\n" +
5003       "OpFunctionEnd\n",
5004     4, false),
5005   // Test case 11: merge sdiv of snegate
5006   // (-x) / 2 = x / -2
5007   InstructionFoldingCase<bool>(
5008     Header() +
5009       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5010       "; CHECK: OpConstant [[int]] -2147483648\n" +
5011       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
5012       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5013       "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[int_n2]]\n" +
5014       "%main = OpFunction %void None %void_func\n" +
5015       "%main_lab = OpLabel\n" +
5016       "%var = OpVariable %_ptr_int Function\n" +
5017       "%2 = OpLoad %int %var\n" +
5018       "%3 = OpSNegate %int %2\n" +
5019       "%4 = OpSDiv %int %3 %int_2\n" +
5020       "OpReturn\n" +
5021       "OpFunctionEnd\n",
5022     4, true),
5023   // Test case 12: merge sdiv of snegate
5024   // 2 / (-x) = -2 / x
5025   InstructionFoldingCase<bool>(
5026     Header() +
5027       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5028       "; CHECK: OpConstant [[int]] -2147483648\n" +
5029       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
5030       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5031       "; CHECK: %4 = OpSDiv [[int]] [[int_n2]] [[ld]]\n" +
5032       "%main = OpFunction %void None %void_func\n" +
5033       "%main_lab = OpLabel\n" +
5034       "%var = OpVariable %_ptr_int Function\n" +
5035       "%2 = OpLoad %int %var\n" +
5036       "%3 = OpSNegate %int %2\n" +
5037       "%4 = OpSDiv %int %int_2 %3\n" +
5038       "OpReturn\n" +
5039       "OpFunctionEnd\n",
5040     4, true),
5041   // Test case 13: Don't merge
5042   // (x / {null}) / {null}
5043   InstructionFoldingCase<bool>(
5044     Header() +
5045       "%main = OpFunction %void None %void_func\n" +
5046       "%main_lab = OpLabel\n" +
5047       "%var = OpVariable %_ptr_v2float Function\n" +
5048       "%2 = OpLoad %float %var\n" +
5049       "%3 = OpFDiv %float %2 %v2float_null\n" +
5050       "%4 = OpFDiv %float %3 %v2float_null\n" +
5051       "OpReturn\n" +
5052       "OpFunctionEnd\n",
5053     4, false),
5054   // Test case 14: merge fmul of fdiv
5055   // (y * x) / x = y
5056   InstructionFoldingCase<bool>(
5057     Header() +
5058         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5059         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5060         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5061         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5062         "%main = OpFunction %void None %void_func\n" +
5063         "%main_lab = OpLabel\n" +
5064         "%x = OpVariable %_ptr_float Function\n" +
5065         "%y = OpVariable %_ptr_float Function\n" +
5066         "%2 = OpLoad %float %x\n" +
5067         "%3 = OpLoad %float %y\n" +
5068         "%4 = OpFMul %float %3 %2\n" +
5069         "%5 = OpFDiv %float %4 %2\n" +
5070         "OpReturn\n" +
5071         "OpFunctionEnd\n",
5072     5, true),
5073   // Test case 15: merge fmul of fdiv
5074   // (x * y) / x = y
5075   InstructionFoldingCase<bool>(
5076     Header() +
5077         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5078         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5079         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5080         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5081         "%main = OpFunction %void None %void_func\n" +
5082         "%main_lab = OpLabel\n" +
5083         "%x = OpVariable %_ptr_float Function\n" +
5084         "%y = OpVariable %_ptr_float Function\n" +
5085         "%2 = OpLoad %float %x\n" +
5086         "%3 = OpLoad %float %y\n" +
5087         "%4 = OpFMul %float %2 %3\n" +
5088         "%5 = OpFDiv %float %4 %2\n" +
5089         "OpReturn\n" +
5090         "OpFunctionEnd\n",
5091     5, true)
5092 ));
5093 
5094 INSTANTIATE_TEST_CASE_P(MergeAddTest, MatchingInstructionFoldingTest,
5095 ::testing::Values(
5096   // Test case 0: merge add of negate
5097   // (-x) + 2 = 2 - x
5098   InstructionFoldingCase<bool>(
5099     Header() +
5100       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5101       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5102       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5103       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5104       "%main = OpFunction %void None %void_func\n" +
5105       "%main_lab = OpLabel\n" +
5106       "%var = OpVariable %_ptr_float Function\n" +
5107       "%2 = OpLoad %float %var\n" +
5108       "%3 = OpFNegate %float %2\n" +
5109       "%4 = OpFAdd %float %3 %float_2\n" +
5110       "OpReturn\n" +
5111       "OpFunctionEnd\n",
5112     4, true),
5113   // Test case 1: merge add of negate
5114   // 2 + (-x) = 2 - x
5115   InstructionFoldingCase<bool>(
5116     Header() +
5117       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5118       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5119       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5120       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5121       "%main = OpFunction %void None %void_func\n" +
5122       "%main_lab = OpLabel\n" +
5123       "%var = OpVariable %_ptr_float Function\n" +
5124       "%2 = OpLoad %float %var\n" +
5125       "%3 = OpSNegate %float %2\n" +
5126       "%4 = OpIAdd %float %float_2 %3\n" +
5127       "OpReturn\n" +
5128       "OpFunctionEnd\n",
5129     4, true),
5130   // Test case 2: merge add of negate
5131   // (-x) + 2 = 2 - x
5132   InstructionFoldingCase<bool>(
5133     Header() +
5134       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5135       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5136       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5137       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5138       "%main = OpFunction %void None %void_func\n" +
5139       "%main_lab = OpLabel\n" +
5140       "%var = OpVariable %_ptr_long Function\n" +
5141       "%2 = OpLoad %long %var\n" +
5142       "%3 = OpSNegate %long %2\n" +
5143       "%4 = OpIAdd %long %3 %long_2\n" +
5144       "OpReturn\n" +
5145       "OpFunctionEnd\n",
5146     4, true),
5147   // Test case 3: merge add of negate
5148   // 2 + (-x) = 2 - x
5149   InstructionFoldingCase<bool>(
5150     Header() +
5151       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5152       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5153       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5154       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5155       "%main = OpFunction %void None %void_func\n" +
5156       "%main_lab = OpLabel\n" +
5157       "%var = OpVariable %_ptr_long Function\n" +
5158       "%2 = OpLoad %long %var\n" +
5159       "%3 = OpSNegate %long %2\n" +
5160       "%4 = OpIAdd %long %long_2 %3\n" +
5161       "OpReturn\n" +
5162       "OpFunctionEnd\n",
5163     4, true),
5164   // Test case 4: merge add of subtract
5165   // (x - 1) + 2 = x + 1
5166   InstructionFoldingCase<bool>(
5167     Header() +
5168       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5169       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5170       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5171       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
5172       "%main = OpFunction %void None %void_func\n" +
5173       "%main_lab = OpLabel\n" +
5174       "%var = OpVariable %_ptr_float Function\n" +
5175       "%2 = OpLoad %float %var\n" +
5176       "%3 = OpFSub %float %2 %float_1\n" +
5177       "%4 = OpFAdd %float %3 %float_2\n" +
5178       "OpReturn\n" +
5179       "OpFunctionEnd\n",
5180     4, true),
5181   // Test case 5: merge add of subtract
5182   // (1 - x) + 2 = 3 - x
5183   InstructionFoldingCase<bool>(
5184     Header() +
5185       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5186       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5187       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5188       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
5189       "%main = OpFunction %void None %void_func\n" +
5190       "%main_lab = OpLabel\n" +
5191       "%var = OpVariable %_ptr_float Function\n" +
5192       "%2 = OpLoad %float %var\n" +
5193       "%3 = OpFSub %float %float_1 %2\n" +
5194       "%4 = OpFAdd %float %3 %float_2\n" +
5195       "OpReturn\n" +
5196       "OpFunctionEnd\n",
5197     4, true),
5198   // Test case 6: merge add of subtract
5199   // 2 + (x - 1) = x + 1
5200   InstructionFoldingCase<bool>(
5201     Header() +
5202       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5203       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5204       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5205       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
5206       "%main = OpFunction %void None %void_func\n" +
5207       "%main_lab = OpLabel\n" +
5208       "%var = OpVariable %_ptr_float Function\n" +
5209       "%2 = OpLoad %float %var\n" +
5210       "%3 = OpFSub %float %2 %float_1\n" +
5211       "%4 = OpFAdd %float %float_2 %3\n" +
5212       "OpReturn\n" +
5213       "OpFunctionEnd\n",
5214     4, true),
5215   // Test case 7: merge add of subtract
5216   // 2 + (1 - x) = 3 - x
5217   InstructionFoldingCase<bool>(
5218     Header() +
5219       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5220       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5221       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5222       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
5223       "%main = OpFunction %void None %void_func\n" +
5224       "%main_lab = OpLabel\n" +
5225       "%var = OpVariable %_ptr_float Function\n" +
5226       "%2 = OpLoad %float %var\n" +
5227       "%3 = OpFSub %float %float_1 %2\n" +
5228       "%4 = OpFAdd %float %float_2 %3\n" +
5229       "OpReturn\n" +
5230       "OpFunctionEnd\n",
5231     4, true),
5232   // Test case 8: merge add of add
5233   // (x + 1) + 2 = x + 3
5234   InstructionFoldingCase<bool>(
5235     Header() +
5236       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5237       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5238       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5239       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
5240       "%main = OpFunction %void None %void_func\n" +
5241       "%main_lab = OpLabel\n" +
5242       "%var = OpVariable %_ptr_float Function\n" +
5243       "%2 = OpLoad %float %var\n" +
5244       "%3 = OpFAdd %float %2 %float_1\n" +
5245       "%4 = OpFAdd %float %3 %float_2\n" +
5246       "OpReturn\n" +
5247       "OpFunctionEnd\n",
5248     4, true),
5249   // Test case 9: merge add of add
5250   // (1 + x) + 2 = 3 + x
5251   InstructionFoldingCase<bool>(
5252     Header() +
5253       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5254       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5255       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5256       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
5257       "%main = OpFunction %void None %void_func\n" +
5258       "%main_lab = OpLabel\n" +
5259       "%var = OpVariable %_ptr_float Function\n" +
5260       "%2 = OpLoad %float %var\n" +
5261       "%3 = OpFAdd %float %float_1 %2\n" +
5262       "%4 = OpFAdd %float %3 %float_2\n" +
5263       "OpReturn\n" +
5264       "OpFunctionEnd\n",
5265     4, true),
5266   // Test case 10: merge add of add
5267   // 2 + (x + 1) = x + 1
5268   InstructionFoldingCase<bool>(
5269     Header() +
5270       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5271       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5272       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5273       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
5274       "%main = OpFunction %void None %void_func\n" +
5275       "%main_lab = OpLabel\n" +
5276       "%var = OpVariable %_ptr_float Function\n" +
5277       "%2 = OpLoad %float %var\n" +
5278       "%3 = OpFAdd %float %2 %float_1\n" +
5279       "%4 = OpFAdd %float %float_2 %3\n" +
5280       "OpReturn\n" +
5281       "OpFunctionEnd\n",
5282     4, true),
5283   // Test case 11: merge add of add
5284   // 2 + (1 + x) = 3 - x
5285   InstructionFoldingCase<bool>(
5286     Header() +
5287       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5288       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5289       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5290       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
5291       "%main = OpFunction %void None %void_func\n" +
5292       "%main_lab = OpLabel\n" +
5293       "%var = OpVariable %_ptr_float Function\n" +
5294       "%2 = OpLoad %float %var\n" +
5295       "%3 = OpFAdd %float %float_1 %2\n" +
5296       "%4 = OpFAdd %float %float_2 %3\n" +
5297       "OpReturn\n" +
5298       "OpFunctionEnd\n",
5299     4, true)
5300 ));
5301 
5302 INSTANTIATE_TEST_CASE_P(MergeSubTest, MatchingInstructionFoldingTest,
5303 ::testing::Values(
5304   // Test case 0: merge sub of negate
5305   // (-x) - 2 = -2 - x
5306   InstructionFoldingCase<bool>(
5307     Header() +
5308       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5309       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
5310       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5311       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5312       "%main = OpFunction %void None %void_func\n" +
5313       "%main_lab = OpLabel\n" +
5314       "%var = OpVariable %_ptr_float Function\n" +
5315       "%2 = OpLoad %float %var\n" +
5316       "%3 = OpFNegate %float %2\n" +
5317       "%4 = OpFSub %float %3 %float_2\n" +
5318       "OpReturn\n" +
5319       "OpFunctionEnd\n",
5320     4, true),
5321   // Test case 1: merge sub of negate
5322   // 2 - (-x) = x + 2
5323   InstructionFoldingCase<bool>(
5324     Header() +
5325       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5326       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5327       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5328       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
5329       "%main = OpFunction %void None %void_func\n" +
5330       "%main_lab = OpLabel\n" +
5331       "%var = OpVariable %_ptr_float Function\n" +
5332       "%2 = OpLoad %float %var\n" +
5333       "%3 = OpFNegate %float %2\n" +
5334       "%4 = OpFSub %float %float_2 %3\n" +
5335       "OpReturn\n" +
5336       "OpFunctionEnd\n",
5337     4, true),
5338   // Test case 2: merge sub of negate
5339   // (-x) - 2 = -2 - x
5340   InstructionFoldingCase<bool>(
5341     Header() +
5342       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5343       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
5344       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5345       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5346       "%main = OpFunction %void None %void_func\n" +
5347       "%main_lab = OpLabel\n" +
5348       "%var = OpVariable %_ptr_long Function\n" +
5349       "%2 = OpLoad %long %var\n" +
5350       "%3 = OpSNegate %long %2\n" +
5351       "%4 = OpISub %long %3 %long_2\n" +
5352       "OpReturn\n" +
5353       "OpFunctionEnd\n",
5354     4, true),
5355   // Test case 3: merge sub of negate
5356   // 2 - (-x) = x + 2
5357   InstructionFoldingCase<bool>(
5358     Header() +
5359       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5360       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5361       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5362       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
5363       "%main = OpFunction %void None %void_func\n" +
5364       "%main_lab = OpLabel\n" +
5365       "%var = OpVariable %_ptr_long Function\n" +
5366       "%2 = OpLoad %long %var\n" +
5367       "%3 = OpSNegate %long %2\n" +
5368       "%4 = OpISub %long %long_2 %3\n" +
5369       "OpReturn\n" +
5370       "OpFunctionEnd\n",
5371     4, true),
5372   // Test case 4: merge add of subtract
5373   // (x + 2) - 1 = x + 1
5374   InstructionFoldingCase<bool>(
5375     Header() +
5376       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5377       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5378       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5379       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
5380       "%main = OpFunction %void None %void_func\n" +
5381       "%main_lab = OpLabel\n" +
5382       "%var = OpVariable %_ptr_float Function\n" +
5383       "%2 = OpLoad %float %var\n" +
5384       "%3 = OpFAdd %float %2 %float_2\n" +
5385       "%4 = OpFSub %float %3 %float_1\n" +
5386       "OpReturn\n" +
5387       "OpFunctionEnd\n",
5388     4, true),
5389   // Test case 5: merge add of subtract
5390   // (2 + x) - 1 = x + 1
5391   InstructionFoldingCase<bool>(
5392     Header() +
5393       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5394       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5395       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5396       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
5397       "%main = OpFunction %void None %void_func\n" +
5398       "%main_lab = OpLabel\n" +
5399       "%var = OpVariable %_ptr_float Function\n" +
5400       "%2 = OpLoad %float %var\n" +
5401       "%3 = OpFAdd %float %float_2 %2\n" +
5402       "%4 = OpFSub %float %3 %float_1\n" +
5403       "OpReturn\n" +
5404       "OpFunctionEnd\n",
5405     4, true),
5406   // Test case 6: merge add of subtract
5407   // 2 - (x + 1) = 1 - x
5408   InstructionFoldingCase<bool>(
5409     Header() +
5410       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5411       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5412       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5413       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
5414       "%main = OpFunction %void None %void_func\n" +
5415       "%main_lab = OpLabel\n" +
5416       "%var = OpVariable %_ptr_float Function\n" +
5417       "%2 = OpLoad %float %var\n" +
5418       "%3 = OpFAdd %float %2 %float_1\n" +
5419       "%4 = OpFSub %float %float_2 %3\n" +
5420       "OpReturn\n" +
5421       "OpFunctionEnd\n",
5422     4, true),
5423   // Test case 7: merge add of subtract
5424   // 2 - (1 + x) = 1 - x
5425   InstructionFoldingCase<bool>(
5426     Header() +
5427       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5428       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5429       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5430       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
5431       "%main = OpFunction %void None %void_func\n" +
5432       "%main_lab = OpLabel\n" +
5433       "%var = OpVariable %_ptr_float Function\n" +
5434       "%2 = OpLoad %float %var\n" +
5435       "%3 = OpFAdd %float %float_1 %2\n" +
5436       "%4 = OpFSub %float %float_2 %3\n" +
5437       "OpReturn\n" +
5438       "OpFunctionEnd\n",
5439     4, true),
5440   // Test case 8: merge subtract of subtract
5441   // (x - 2) - 1 = x - 3
5442   InstructionFoldingCase<bool>(
5443     Header() +
5444       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5445       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5446       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5447       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
5448       "%main = OpFunction %void None %void_func\n" +
5449       "%main_lab = OpLabel\n" +
5450       "%var = OpVariable %_ptr_float Function\n" +
5451       "%2 = OpLoad %float %var\n" +
5452       "%3 = OpFSub %float %2 %float_2\n" +
5453       "%4 = OpFSub %float %3 %float_1\n" +
5454       "OpReturn\n" +
5455       "OpFunctionEnd\n",
5456     4, true),
5457   // Test case 9: merge subtract of subtract
5458   // (2 - x) - 1 = 1 - x
5459   InstructionFoldingCase<bool>(
5460     Header() +
5461       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5462       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5463       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5464       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
5465       "%main = OpFunction %void None %void_func\n" +
5466       "%main_lab = OpLabel\n" +
5467       "%var = OpVariable %_ptr_float Function\n" +
5468       "%2 = OpLoad %float %var\n" +
5469       "%3 = OpFSub %float %float_2 %2\n" +
5470       "%4 = OpFSub %float %3 %float_1\n" +
5471       "OpReturn\n" +
5472       "OpFunctionEnd\n",
5473     4, true),
5474   // Test case 10: merge subtract of subtract
5475   // 2 - (x - 1) = 3 - x
5476   InstructionFoldingCase<bool>(
5477     Header() +
5478       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5479       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
5480       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5481       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
5482       "%main = OpFunction %void None %void_func\n" +
5483       "%main_lab = OpLabel\n" +
5484       "%var = OpVariable %_ptr_float Function\n" +
5485       "%2 = OpLoad %float %var\n" +
5486       "%3 = OpFSub %float %2 %float_1\n" +
5487       "%4 = OpFSub %float %float_2 %3\n" +
5488       "OpReturn\n" +
5489       "OpFunctionEnd\n",
5490     4, true),
5491   // Test case 11: merge subtract of subtract
5492   // 1 - (2 - x) = x + (-1)
5493   InstructionFoldingCase<bool>(
5494     Header() +
5495       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5496       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
5497       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5498       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
5499       "%main = OpFunction %void None %void_func\n" +
5500       "%main_lab = OpLabel\n" +
5501       "%var = OpVariable %_ptr_float Function\n" +
5502       "%2 = OpLoad %float %var\n" +
5503       "%3 = OpFSub %float %float_2 %2\n" +
5504       "%4 = OpFSub %float %float_1 %3\n" +
5505       "OpReturn\n" +
5506       "OpFunctionEnd\n",
5507     4, true),
5508   // Test case 12: merge subtract of subtract
5509   // 2 - (1 - x) = x + 1
5510   InstructionFoldingCase<bool>(
5511     Header() +
5512       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5513       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
5514       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5515       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
5516       "%main = OpFunction %void None %void_func\n" +
5517       "%main_lab = OpLabel\n" +
5518       "%var = OpVariable %_ptr_float Function\n" +
5519       "%2 = OpLoad %float %var\n" +
5520       "%3 = OpFSub %float %float_1 %2\n" +
5521       "%4 = OpFSub %float %float_2 %3\n" +
5522       "OpReturn\n" +
5523       "OpFunctionEnd\n",
5524     4, true)
5525 ));
5526 
5527 INSTANTIATE_TEST_CASE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
5528 ::testing::Values(
5529   // Test case 0: Fold select with the same values for both sides
5530   InstructionFoldingCase<bool>(
5531       Header() +
5532           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5533           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
5534           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
5535           "%main = OpFunction %void None %void_func\n" +
5536           "%main_lab = OpLabel\n" +
5537           "%n = OpVariable %_ptr_bool Function\n" +
5538           "%load = OpLoad %bool %n\n" +
5539           "%2 = OpSelect %int %load %100 %100\n" +
5540           "OpReturn\n" +
5541           "OpFunctionEnd",
5542       2, true),
5543   // Test case 1: Fold select true to left side
5544   InstructionFoldingCase<bool>(
5545       Header() +
5546           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5547           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
5548           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
5549           "%main = OpFunction %void None %void_func\n" +
5550           "%main_lab = OpLabel\n" +
5551           "%n = OpVariable %_ptr_int Function\n" +
5552           "%load = OpLoad %bool %n\n" +
5553           "%2 = OpSelect %int %true %100 %n\n" +
5554           "OpReturn\n" +
5555           "OpFunctionEnd",
5556       2, true),
5557   // Test case 2: Fold select false to right side
5558   InstructionFoldingCase<bool>(
5559       Header() +
5560           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5561           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
5562           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
5563           "%main = OpFunction %void None %void_func\n" +
5564           "%main_lab = OpLabel\n" +
5565           "%n = OpVariable %_ptr_int Function\n" +
5566           "%load = OpLoad %bool %n\n" +
5567           "%2 = OpSelect %int %false %n %100\n" +
5568           "OpReturn\n" +
5569           "OpFunctionEnd",
5570       2, true),
5571   // Test case 3: Fold select null to right side
5572   InstructionFoldingCase<bool>(
5573       Header() +
5574           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5575           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
5576           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
5577           "%main = OpFunction %void None %void_func\n" +
5578           "%main_lab = OpLabel\n" +
5579           "%n = OpVariable %_ptr_int Function\n" +
5580           "%load = OpLoad %int %n\n" +
5581           "%2 = OpSelect %int %bool_null %load %100\n" +
5582           "OpReturn\n" +
5583           "OpFunctionEnd",
5584       2, true),
5585   // Test case 4: vector null
5586   InstructionFoldingCase<bool>(
5587       Header() +
5588           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5589           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5590           "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
5591           "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
5592           "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
5593           "%main = OpFunction %void None %void_func\n" +
5594           "%main_lab = OpLabel\n" +
5595           "%n = OpVariable %_ptr_v2int Function\n" +
5596           "%load = OpLoad %v2int %n\n" +
5597           "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
5598           "OpReturn\n" +
5599           "OpFunctionEnd",
5600       2, true),
5601   // Test case 5: vector select
5602   InstructionFoldingCase<bool>(
5603       Header() +
5604           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5605           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5606           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
5607           "%main = OpFunction %void None %void_func\n" +
5608           "%main_lab = OpLabel\n" +
5609           "%m = OpVariable %_ptr_v2int Function\n" +
5610           "%n = OpVariable %_ptr_v2int Function\n" +
5611           "%2 = OpLoad %v2int %n\n" +
5612           "%3 = OpLoad %v2int %n\n" +
5613           "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
5614           "OpReturn\n" +
5615           "OpFunctionEnd",
5616       4, true),
5617   // Test case 6: vector select
5618   InstructionFoldingCase<bool>(
5619       Header() +
5620           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5621           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5622           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
5623           "%main = OpFunction %void None %void_func\n" +
5624           "%main_lab = OpLabel\n" +
5625           "%m = OpVariable %_ptr_v2int Function\n" +
5626           "%n = OpVariable %_ptr_v2int Function\n" +
5627           "%2 = OpLoad %v2int %n\n" +
5628           "%3 = OpLoad %v2int %n\n" +
5629           "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
5630           "OpReturn\n" +
5631           "OpFunctionEnd",
5632       4, true)
5633 ));
5634 
5635 INSTANTIATE_TEST_CASE_P(CompositeExtractMatchingTest, MatchingInstructionFoldingTest,
5636 ::testing::Values(
5637     // Test case 0: Extracting from result of consecutive shuffles of differing
5638     // size.
5639     InstructionFoldingCase<bool>(
5640         Header() +
5641             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5642             "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
5643             "%main = OpFunction %void None %void_func\n" +
5644             "%main_lab = OpLabel\n" +
5645             "%n = OpVariable %_ptr_v4int Function\n" +
5646             "%2 = OpLoad %v4int %n\n" +
5647             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
5648             "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
5649             "%5 = OpCompositeExtract %int %4 1\n" +
5650             "OpReturn\n" +
5651             "OpFunctionEnd",
5652         5, true),
5653     // Test case 1: Extracting from result of vector shuffle of differing
5654     // input and result sizes.
5655     InstructionFoldingCase<bool>(
5656         Header() +
5657             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5658             "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
5659             "%main = OpFunction %void None %void_func\n" +
5660             "%main_lab = OpLabel\n" +
5661             "%n = OpVariable %_ptr_v4int Function\n" +
5662             "%2 = OpLoad %v4int %n\n" +
5663             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
5664             "%4 = OpCompositeExtract %int %3 0\n" +
5665             "OpReturn\n" +
5666             "OpFunctionEnd",
5667         4, true),
5668     // Test case 2: Extracting from result of vector shuffle of differing
5669     // input and result sizes.
5670     InstructionFoldingCase<bool>(
5671         Header() +
5672             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5673             "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
5674             "%main = OpFunction %void None %void_func\n" +
5675             "%main_lab = OpLabel\n" +
5676             "%n = OpVariable %_ptr_v4int Function\n" +
5677             "%2 = OpLoad %v4int %n\n" +
5678             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
5679             "%4 = OpCompositeExtract %int %3 1\n" +
5680             "OpReturn\n" +
5681             "OpFunctionEnd",
5682         4, true),
5683     // Test case 3: Using fmix feeding extract with a 1 in the a position.
5684     InstructionFoldingCase<bool>(
5685         Header() +
5686             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5687             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
5688             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
5689             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5690             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5691             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
5692             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
5693             "%main = OpFunction %void None %void_func\n" +
5694             "%main_lab = OpLabel\n" +
5695             "%m = OpVariable %_ptr_v4double Function\n" +
5696             "%n = OpVariable %_ptr_v4double Function\n" +
5697             "%2 = OpLoad %v4double %m\n" +
5698             "%3 = OpLoad %v4double %n\n" +
5699             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
5700             "%5 = OpCompositeExtract %double %4 1\n" +
5701             "OpReturn\n" +
5702             "OpFunctionEnd",
5703         5, true),
5704     // Test case 4: Using fmix feeding extract with a 0 in the a position.
5705     InstructionFoldingCase<bool>(
5706         Header() +
5707             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5708             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
5709             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
5710             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5711             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5712             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
5713             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
5714             "%main = OpFunction %void None %void_func\n" +
5715             "%main_lab = OpLabel\n" +
5716             "%m = OpVariable %_ptr_v4double Function\n" +
5717             "%n = OpVariable %_ptr_v4double Function\n" +
5718             "%2 = OpLoad %v4double %m\n" +
5719             "%3 = OpLoad %v4double %n\n" +
5720             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
5721             "%5 = OpCompositeExtract %double %4 2\n" +
5722             "OpReturn\n" +
5723             "OpFunctionEnd",
5724         5, true),
5725     // Test case 5: Using fmix feeding extract with a null for the alpha
5726     InstructionFoldingCase<bool>(
5727         Header() +
5728             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5729             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
5730             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
5731             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5732             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
5733             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
5734             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
5735             "%main = OpFunction %void None %void_func\n" +
5736             "%main_lab = OpLabel\n" +
5737             "%m = OpVariable %_ptr_v4double Function\n" +
5738             "%n = OpVariable %_ptr_v4double Function\n" +
5739             "%2 = OpLoad %v4double %m\n" +
5740             "%3 = OpLoad %v4double %n\n" +
5741             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
5742             "%5 = OpCompositeExtract %double %4 0\n" +
5743             "OpReturn\n" +
5744             "OpFunctionEnd",
5745         5, true),
5746     // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
5747     // position.
5748     InstructionFoldingCase<bool>(
5749         Header() +
5750             "%main = OpFunction %void None %void_func\n" +
5751             "%main_lab = OpLabel\n" +
5752             "%m = OpVariable %_ptr_v4double Function\n" +
5753             "%n = OpVariable %_ptr_v4double Function\n" +
5754             "%2 = OpLoad %v4double %m\n" +
5755             "%3 = OpLoad %v4double %n\n" +
5756             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
5757             "%5 = OpCompositeExtract %double %4 3\n" +
5758             "OpReturn\n" +
5759             "OpFunctionEnd",
5760         5, false),
5761     // Test case 7: Extracting the undefined literal value from a vector
5762     // shuffle.
5763     InstructionFoldingCase<bool>(
5764         Header() +
5765             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5766             "; CHECK: %4 = OpUndef [[int]]\n" +
5767             "%main = OpFunction %void None %void_func\n" +
5768             "%main_lab = OpLabel\n" +
5769             "%n = OpVariable %_ptr_v4int Function\n" +
5770             "%2 = OpLoad %v4int %n\n" +
5771             "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
5772             "%4 = OpCompositeExtract %int %3 1\n" +
5773             "OpReturn\n" +
5774             "OpFunctionEnd",
5775         4, true)
5776 ));
5777 
5778 INSTANTIATE_TEST_CASE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
5779 ::testing::Values(
5780     // Test case 0: Using OpDot to extract last element.
5781     InstructionFoldingCase<bool>(
5782         Header() +
5783             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5784             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
5785             "%main = OpFunction %void None %void_func\n" +
5786             "%main_lab = OpLabel\n" +
5787             "%n = OpVariable %_ptr_v4float Function\n" +
5788             "%2 = OpLoad %v4float %n\n" +
5789             "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
5790             "OpReturn\n" +
5791             "OpFunctionEnd",
5792         3, true),
5793     // Test case 1: Using OpDot to extract last element.
5794     InstructionFoldingCase<bool>(
5795         Header() +
5796             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5797             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
5798             "%main = OpFunction %void None %void_func\n" +
5799             "%main_lab = OpLabel\n" +
5800             "%n = OpVariable %_ptr_v4float Function\n" +
5801             "%2 = OpLoad %v4float %n\n" +
5802             "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
5803             "OpReturn\n" +
5804             "OpFunctionEnd",
5805         3, true),
5806     // Test case 2: Using OpDot to extract second element.
5807     InstructionFoldingCase<bool>(
5808         Header() +
5809             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5810             "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
5811             "%main = OpFunction %void None %void_func\n" +
5812             "%main_lab = OpLabel\n" +
5813             "%n = OpVariable %_ptr_v4float Function\n" +
5814             "%2 = OpLoad %v4float %n\n" +
5815             "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
5816             "OpReturn\n" +
5817             "OpFunctionEnd",
5818         3, true),
5819     // Test case 3: Using OpDot to extract last element.
5820     InstructionFoldingCase<bool>(
5821         Header() +
5822             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5823             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
5824             "%main = OpFunction %void None %void_func\n" +
5825             "%main_lab = OpLabel\n" +
5826             "%n = OpVariable %_ptr_v4double Function\n" +
5827             "%2 = OpLoad %v4double %n\n" +
5828             "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
5829             "OpReturn\n" +
5830             "OpFunctionEnd",
5831         3, true),
5832     // Test case 4: Using OpDot to extract last element.
5833     InstructionFoldingCase<bool>(
5834         Header() +
5835             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5836             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
5837             "%main = OpFunction %void None %void_func\n" +
5838             "%main_lab = OpLabel\n" +
5839             "%n = OpVariable %_ptr_v4double Function\n" +
5840             "%2 = OpLoad %v4double %n\n" +
5841             "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
5842             "OpReturn\n" +
5843             "OpFunctionEnd",
5844         3, true),
5845     // Test case 5: Using OpDot to extract second element.
5846     InstructionFoldingCase<bool>(
5847         Header() +
5848             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5849             "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
5850             "%main = OpFunction %void None %void_func\n" +
5851             "%main_lab = OpLabel\n" +
5852             "%n = OpVariable %_ptr_v4double Function\n" +
5853             "%2 = OpLoad %v4double %n\n" +
5854             "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
5855             "OpReturn\n" +
5856             "OpFunctionEnd",
5857         3, true)
5858 ));
5859 
5860 using MatchingInstructionWithNoResultFoldingTest =
5861 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
5862 
5863 // Test folding instructions that do not have a result.  The instruction
5864 // that will be folded is the last instruction before the return.  If there
5865 // are multiple returns, there is not guarentee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest,Case)5866 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
5867   const auto& tc = GetParam();
5868 
5869   // Build module.
5870   std::unique_ptr<IRContext> context =
5871       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5872                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5873   ASSERT_NE(nullptr, context);
5874 
5875   // Fold the instruction to test.
5876   Instruction* inst = nullptr;
5877   Function* func = &*context->module()->begin();
5878   for (auto& bb : *func) {
5879     Instruction* terminator = bb.terminator();
5880     if (terminator->IsReturnOrAbort()) {
5881       inst = terminator->PreviousNode();
5882       break;
5883     }
5884   }
5885   assert(inst && "Invalid test.  Could not find instruction to fold.");
5886   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5887   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5888   EXPECT_EQ(succeeded, tc.expected_result);
5889   if (succeeded) {
5890     Match(tc.test_body, context.get());
5891   }
5892 }
5893 
5894 INSTANTIATE_TEST_CASE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
5895 ::testing::Values(
5896     // Test case 0: Remove store of undef.
5897     InstructionFoldingCase<bool>(
5898         Header() +
5899             "; CHECK: OpLabel\n" +
5900             "; CHECK-NOT: OpStore\n" +
5901             "; CHECK: OpReturn\n" +
5902             "%main = OpFunction %void None %void_func\n" +
5903             "%main_lab = OpLabel\n" +
5904             "%n = OpVariable %_ptr_v4double Function\n" +
5905             "%undef = OpUndef %v4double\n" +
5906             "OpStore %n %undef\n" +
5907             "OpReturn\n" +
5908             "OpFunctionEnd",
5909         0 /* OpStore */, true),
5910     // Test case 1: Keep volatile store.
5911     InstructionFoldingCase<bool>(
5912         Header() +
5913             "%main = OpFunction %void None %void_func\n" +
5914             "%main_lab = OpLabel\n" +
5915             "%n = OpVariable %_ptr_v4double Function\n" +
5916             "%undef = OpUndef %v4double\n" +
5917             "OpStore %n %undef Volatile\n" +
5918             "OpReturn\n" +
5919             "OpFunctionEnd",
5920         0 /* OpStore */, false)
5921 ));
5922 
5923 INSTANTIATE_TEST_CASE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
5924 ::testing::Values(
5925     // Test case 0: Basic test 1
5926     InstructionFoldingCase<bool>(
5927         Header() +
5928             "; CHECK: OpVectorShuffle\n" +
5929             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
5930             "; CHECK: OpReturn\n" +
5931             "%main = OpFunction %void None %void_func\n" +
5932             "%main_lab = OpLabel\n" +
5933             "%2 = OpVariable %_ptr_v4double Function\n" +
5934             "%3 = OpVariable %_ptr_v4double Function\n" +
5935             "%4 = OpVariable %_ptr_v4double Function\n" +
5936             "%5 = OpLoad %v4double %2\n" +
5937             "%6 = OpLoad %v4double %3\n" +
5938             "%7 = OpLoad %v4double %4\n" +
5939             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
5940             "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
5941             "OpReturn\n" +
5942             "OpFunctionEnd",
5943         9, true),
5944     // Test case 1: Basic test 2
5945     InstructionFoldingCase<bool>(
5946         Header() +
5947             "; CHECK: OpVectorShuffle\n" +
5948             "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
5949             "; CHECK: OpReturn\n" +
5950             "%main = OpFunction %void None %void_func\n" +
5951             "%main_lab = OpLabel\n" +
5952             "%2 = OpVariable %_ptr_v4double Function\n" +
5953             "%3 = OpVariable %_ptr_v4double Function\n" +
5954             "%4 = OpVariable %_ptr_v4double Function\n" +
5955             "%5 = OpLoad %v4double %2\n" +
5956             "%6 = OpLoad %v4double %3\n" +
5957             "%7 = OpLoad %v4double %4\n" +
5958             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
5959             "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
5960             "OpReturn\n" +
5961             "OpFunctionEnd",
5962         9, true),
5963     // Test case 2: Basic test 3
5964     InstructionFoldingCase<bool>(
5965         Header() +
5966             "; CHECK: OpVectorShuffle\n" +
5967             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
5968             "; CHECK: OpReturn\n" +
5969             "%main = OpFunction %void None %void_func\n" +
5970             "%main_lab = OpLabel\n" +
5971             "%2 = OpVariable %_ptr_v4double Function\n" +
5972             "%3 = OpVariable %_ptr_v4double Function\n" +
5973             "%4 = OpVariable %_ptr_v4double Function\n" +
5974             "%5 = OpLoad %v4double %2\n" +
5975             "%6 = OpLoad %v4double %3\n" +
5976             "%7 = OpLoad %v4double %4\n" +
5977             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
5978             "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
5979             "OpReturn\n" +
5980             "OpFunctionEnd",
5981         9, true),
5982     // Test case 3: Basic test 4
5983     InstructionFoldingCase<bool>(
5984         Header() +
5985             "; CHECK: OpVectorShuffle\n" +
5986             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
5987             "; CHECK: OpReturn\n" +
5988             "%main = OpFunction %void None %void_func\n" +
5989             "%main_lab = OpLabel\n" +
5990             "%2 = OpVariable %_ptr_v4double Function\n" +
5991             "%3 = OpVariable %_ptr_v4double Function\n" +
5992             "%4 = OpVariable %_ptr_v4double Function\n" +
5993             "%5 = OpLoad %v4double %2\n" +
5994             "%6 = OpLoad %v4double %3\n" +
5995             "%7 = OpLoad %v4double %4\n" +
5996             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
5997             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
5998             "OpReturn\n" +
5999             "OpFunctionEnd",
6000         9, true),
6001     // Test case 4: Don't fold, need both operands of the feeder.
6002     InstructionFoldingCase<bool>(
6003         Header() +
6004             "%main = OpFunction %void None %void_func\n" +
6005             "%main_lab = OpLabel\n" +
6006             "%2 = OpVariable %_ptr_v4double Function\n" +
6007             "%3 = OpVariable %_ptr_v4double Function\n" +
6008             "%4 = OpVariable %_ptr_v4double Function\n" +
6009             "%5 = OpLoad %v4double %2\n" +
6010             "%6 = OpLoad %v4double %3\n" +
6011             "%7 = OpLoad %v4double %4\n" +
6012             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
6013             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
6014             "OpReturn\n" +
6015             "OpFunctionEnd",
6016         9, false),
6017     // Test case 5: Don't fold, need both operands of the feeder.
6018     InstructionFoldingCase<bool>(
6019         Header() +
6020             "%main = OpFunction %void None %void_func\n" +
6021             "%main_lab = OpLabel\n" +
6022             "%2 = OpVariable %_ptr_v4double Function\n" +
6023             "%3 = OpVariable %_ptr_v4double Function\n" +
6024             "%4 = OpVariable %_ptr_v4double Function\n" +
6025             "%5 = OpLoad %v4double %2\n" +
6026             "%6 = OpLoad %v4double %3\n" +
6027             "%7 = OpLoad %v4double %4\n" +
6028             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
6029             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
6030             "OpReturn\n" +
6031             "OpFunctionEnd",
6032         9, false),
6033     // Test case 6: Fold, need both operands of the feeder, but they are the same.
6034     InstructionFoldingCase<bool>(
6035         Header() +
6036             "; CHECK: OpVectorShuffle\n" +
6037             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
6038             "; CHECK: OpReturn\n" +
6039             "%main = OpFunction %void None %void_func\n" +
6040             "%main_lab = OpLabel\n" +
6041             "%2 = OpVariable %_ptr_v4double Function\n" +
6042             "%3 = OpVariable %_ptr_v4double Function\n" +
6043             "%4 = OpVariable %_ptr_v4double Function\n" +
6044             "%5 = OpLoad %v4double %2\n" +
6045             "%6 = OpLoad %v4double %3\n" +
6046             "%7 = OpLoad %v4double %4\n" +
6047             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
6048             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
6049             "OpReturn\n" +
6050             "OpFunctionEnd",
6051         9, true),
6052     // Test case 7: Fold, need both operands of the feeder, but they are the same.
6053     InstructionFoldingCase<bool>(
6054         Header() +
6055             "; CHECK: OpVectorShuffle\n" +
6056             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
6057             "; CHECK: OpReturn\n" +
6058             "%main = OpFunction %void None %void_func\n" +
6059             "%main_lab = OpLabel\n" +
6060             "%2 = OpVariable %_ptr_v4double Function\n" +
6061             "%3 = OpVariable %_ptr_v4double Function\n" +
6062             "%4 = OpVariable %_ptr_v4double Function\n" +
6063             "%5 = OpLoad %v4double %2\n" +
6064             "%6 = OpLoad %v4double %3\n" +
6065             "%7 = OpLoad %v4double %4\n" +
6066             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
6067             "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
6068             "OpReturn\n" +
6069             "OpFunctionEnd",
6070         9, true),
6071     // Test case 8: Replace first operand with a smaller vector.
6072     InstructionFoldingCase<bool>(
6073         Header() +
6074             "; CHECK: OpVectorShuffle\n" +
6075             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
6076             "; CHECK: OpReturn\n" +
6077             "%main = OpFunction %void None %void_func\n" +
6078             "%main_lab = OpLabel\n" +
6079             "%2 = OpVariable %_ptr_v2double Function\n" +
6080             "%3 = OpVariable %_ptr_v4double Function\n" +
6081             "%4 = OpVariable %_ptr_v4double Function\n" +
6082             "%5 = OpLoad %v2double %2\n" +
6083             "%6 = OpLoad %v4double %3\n" +
6084             "%7 = OpLoad %v4double %4\n" +
6085             "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
6086             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
6087             "OpReturn\n" +
6088             "OpFunctionEnd",
6089         9, true),
6090     // Test case 9: Replace first operand with a larger vector.
6091     InstructionFoldingCase<bool>(
6092         Header() +
6093             "; CHECK: OpVectorShuffle\n" +
6094             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
6095             "; CHECK: OpReturn\n" +
6096             "%main = OpFunction %void None %void_func\n" +
6097             "%main_lab = OpLabel\n" +
6098             "%2 = OpVariable %_ptr_v4double Function\n" +
6099             "%3 = OpVariable %_ptr_v4double Function\n" +
6100             "%4 = OpVariable %_ptr_v4double Function\n" +
6101             "%5 = OpLoad %v4double %2\n" +
6102             "%6 = OpLoad %v4double %3\n" +
6103             "%7 = OpLoad %v4double %4\n" +
6104             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
6105             "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
6106             "OpReturn\n" +
6107             "OpFunctionEnd",
6108         9, true),
6109     // Test case 10: Replace unused operand with null.
6110     InstructionFoldingCase<bool>(
6111         Header() +
6112             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6113             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6114             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
6115             "; CHECK: OpVectorShuffle\n" +
6116             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
6117             "; CHECK: OpReturn\n" +
6118             "%main = OpFunction %void None %void_func\n" +
6119             "%main_lab = OpLabel\n" +
6120             "%2 = OpVariable %_ptr_v4double Function\n" +
6121             "%3 = OpVariable %_ptr_v4double Function\n" +
6122             "%4 = OpVariable %_ptr_v4double Function\n" +
6123             "%5 = OpLoad %v4double %2\n" +
6124             "%6 = OpLoad %v4double %3\n" +
6125             "%7 = OpLoad %v4double %4\n" +
6126             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
6127             "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
6128             "OpReturn\n" +
6129             "OpFunctionEnd",
6130         9, true),
6131     // Test case 11: Replace unused operand with null.
6132     InstructionFoldingCase<bool>(
6133         Header() +
6134             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6135             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6136             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
6137             "; CHECK: OpVectorShuffle\n" +
6138             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
6139             "; CHECK: OpReturn\n" +
6140             "%main = OpFunction %void None %void_func\n" +
6141             "%main_lab = OpLabel\n" +
6142             "%2 = OpVariable %_ptr_v4double Function\n" +
6143             "%3 = OpVariable %_ptr_v4double Function\n" +
6144             "%5 = OpLoad %v4double %2\n" +
6145             "%6 = OpLoad %v4double %3\n" +
6146             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
6147             "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
6148             "OpReturn\n" +
6149             "OpFunctionEnd",
6150         9, true),
6151     // Test case 12: Replace unused operand with null.
6152     InstructionFoldingCase<bool>(
6153         Header() +
6154             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6155             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6156             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
6157             "; CHECK: OpVectorShuffle\n" +
6158             "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
6159             "; CHECK: OpReturn\n" +
6160             "%main = OpFunction %void None %void_func\n" +
6161             "%main_lab = OpLabel\n" +
6162             "%2 = OpVariable %_ptr_v4double Function\n" +
6163             "%3 = OpVariable %_ptr_v4double Function\n" +
6164             "%4 = OpVariable %_ptr_v4double Function\n" +
6165             "%5 = OpLoad %v4double %2\n" +
6166             "%6 = OpLoad %v4double %3\n" +
6167             "%7 = OpLoad %v4double %4\n" +
6168             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
6169             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
6170             "OpReturn\n" +
6171             "OpFunctionEnd",
6172         9, true),
6173     // Test case 13: Shuffle with undef literal.
6174     InstructionFoldingCase<bool>(
6175         Header() +
6176             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6177             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6178             "; CHECK: OpVectorShuffle\n" +
6179             "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
6180             "; CHECK: OpReturn\n" +
6181             "%main = OpFunction %void None %void_func\n" +
6182             "%main_lab = OpLabel\n" +
6183             "%2 = OpVariable %_ptr_v4double Function\n" +
6184             "%3 = OpVariable %_ptr_v4double Function\n" +
6185             "%4 = OpVariable %_ptr_v4double Function\n" +
6186             "%5 = OpLoad %v4double %2\n" +
6187             "%6 = OpLoad %v4double %3\n" +
6188             "%7 = OpLoad %v4double %4\n" +
6189             "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
6190             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
6191             "OpReturn\n" +
6192             "OpFunctionEnd",
6193         9, true)
6194 ));
6195 
6196 }  // namespace
6197 }  // namespace opt
6198 }  // namespace spvtools
6199