Add dependency for SPIRV-Headers
[platform/upstream/SPIRV-Tools.git] / test / opt / fold_test.cpp
1 // Copyright (c) 2016 Google Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 #include <memory>
15 #include <unordered_set>
16
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <opt/fold.h>
20
21 #ifdef SPIRV_EFFCEE
22 #include "effcee/effcee.h"
23 #endif
24
25 #include "opt/build_module.h"
26 #include "opt/def_use_manager.h"
27 #include "opt/ir_context.h"
28 #include "opt/module.h"
29 #include "pass_utils.h"
30 #include "spirv-tools/libspirv.hpp"
31
32 namespace {
33
34 using ::testing::Contains;
35
36 using namespace spvtools;
37 using spvtools::opt::analysis::DefUseManager;
38
39 #ifdef SPIRV_EFFCEE
40 std::string Disassemble(const std::string& original, ir::IRContext* context,
41                         uint32_t disassemble_options = 0) {
42   std::vector<uint32_t> optimized_bin;
43   context->module()->ToBinary(&optimized_bin, true);
44   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
45   SpirvTools tools(target_env);
46   std::string optimized_asm;
47   EXPECT_TRUE(
48       tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
49       << "Disassembling failed for shader:\n"
50       << original << std::endl;
51   return optimized_asm;
52 }
53
54 void Match(const std::string& original, ir::IRContext* context,
55            uint32_t disassemble_options = 0) {
56   std::string disassembly = Disassemble(original, context, disassemble_options);
57   auto match_result = effcee::Match(disassembly, original);
58   EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
59       << match_result.message() << "\nChecking result:\n"
60       << disassembly;
61 }
62 #endif
63
64 template <class ResultType>
65 struct InstructionFoldingCase {
66   InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
67       : test_body(tb), id_to_fold(id), expected_result(result) {}
68
69   std::string test_body;
70   uint32_t id_to_fold;
71   ResultType expected_result;
72 };
73
74 using IntegerInstructionFoldingTest =
75     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
76
77 TEST_P(IntegerInstructionFoldingTest, Case) {
78   const auto& tc = GetParam();
79
80   // Build module.
81   std::unique_ptr<ir::IRContext> context =
82       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
83                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
84   ASSERT_NE(nullptr, context);
85
86   // Fold the instruction to test.
87   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
88   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
89   bool succeeded = opt::FoldInstruction(inst);
90
91   // Make sure the instruction folded as expected.
92   EXPECT_TRUE(succeeded);
93   if (inst != nullptr) {
94     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
95     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
96     EXPECT_EQ(inst->opcode(), SpvOpConstant);
97     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
98     const opt::analysis::IntConstant* result =
99         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
100     EXPECT_NE(result, nullptr);
101     if (result != nullptr) {
102       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
103     }
104   }
105 }
106
107 // Returns a common SPIR-V header for all of the test that follow.
108 #define INT_0_ID 100
109 #define TRUE_ID 101
110 #define VEC2_0_ID 102
111 #define INT_7_ID 103
112 #define FLOAT_0_ID 104
113 #define DOUBLE_0_ID 105
114 #define VEC4_0_ID 106
115 #define DVEC4_0_ID 106
116 #define HALF_0_ID 108
117 const std::string& Header() {
118   static const std::string header = R"(OpCapability Shader
119 OpCapability Float16
120 %1 = OpExtInstImport "GLSL.std.450"
121 OpMemoryModel Logical GLSL450
122 OpEntryPoint Fragment %main "main"
123 OpExecutionMode %main OriginUpperLeft
124 OpSource GLSL 140
125 OpName %main "main"
126 %void = OpTypeVoid
127 %void_func = OpTypeFunction %void
128 %bool = OpTypeBool
129 %float16 = OpTypeFloat 16
130 %float = OpTypeFloat 32
131 %double = OpTypeFloat 64
132 %half = OpTypeFloat 16
133 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
134 %true = OpConstantTrue %bool
135 %false = OpConstantFalse %bool
136 %bool_null = OpConstantNull %bool
137 %short = OpTypeInt 16 1
138 %int = OpTypeInt 32 1
139 %long = OpTypeInt 64 1
140 %uint = OpTypeInt 32 0
141 %v2int = OpTypeVector %int 2
142 %v4int = OpTypeVector %int 4
143 %v4float = OpTypeVector %float 4
144 %v4double = OpTypeVector %double 4
145 %v2float = OpTypeVector %float 2
146 %v2bool = OpTypeVector %bool 2
147 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
148 %_ptr_int = OpTypePointer Function %int
149 %_ptr_uint = OpTypePointer Function %uint
150 %_ptr_bool = OpTypePointer Function %bool
151 %_ptr_float = OpTypePointer Function %float
152 %_ptr_double = OpTypePointer Function %double
153 %_ptr_half = OpTypePointer Function %half
154 %_ptr_long = OpTypePointer Function %long
155 %_ptr_v2int = OpTypePointer Function %v2int
156 %_ptr_v4int = OpTypePointer Function %v4int
157 %_ptr_v4float = OpTypePointer Function %v4float
158 %_ptr_v4double = OpTypePointer Function %v4double
159 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
160 %_ptr_v2float = OpTypePointer Function %v2float
161 %short_0 = OpConstant %short 0
162 %short_3 = OpConstant %short 3
163 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
164 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
165 %int_0 = OpConstant %int 0
166 %int_1 = OpConstant %int 1
167 %int_2 = OpConstant %int 2
168 %int_3 = OpConstant %int 3
169 %int_4 = OpConstant %int 4
170 %int_min = OpConstant %int -2147483648
171 %int_max = OpConstant %int 2147483647
172 %long_0 = OpConstant %long 0
173 %long_2 = OpConstant %long 2
174 %long_3 = OpConstant %long 3
175 %uint_0 = OpConstant %uint 0
176 %uint_2 = OpConstant %uint 2
177 %uint_3 = OpConstant %uint 3
178 %uint_4 = OpConstant %uint 4
179 %uint_32 = OpConstant %uint 32
180 %uint_max = OpConstant %uint 4294967295
181 %v2int_undef = OpUndef %v2int
182 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
183 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
184 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
185 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
186 %v2bool_null = OpConstantNull %v2bool
187 %v2bool_true_false = OpConstantComposite %v2bool %true %false
188 %v2bool_false_true = OpConstantComposite %v2bool %false %true
189 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
190 %v2int_null = OpConstantNull %v2int
191 %102 = OpConstantComposite %v2int %103 %103
192 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
193 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
194 %float16_0 = OpConstant %float16 0
195 %float16_1 = OpConstant %float16 1
196 %float16_2 = OpConstant %float16 2
197 %float_n1 = OpConstant %float -1
198 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
199 %float_0 = OpConstant %float 0
200 %float_half = OpConstant %float 0.5
201 %float_1 = OpConstant %float 1
202 %float_2 = OpConstant %float 2
203 %float_3 = OpConstant %float 3
204 %float_4 = OpConstant %float 4
205 %float_0p5 = OpConstant %float 0.5
206 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
207 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
208 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
209 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
210 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
211 %v2float_null = OpConstantNull %v2float
212 %double_n1 = OpConstant %double -1
213 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
214 %double_0 = OpConstant %double 0
215 %double_1 = OpConstant %double 1
216 %double_2 = OpConstant %double 2
217 %double_3 = OpConstant %double 3
218 %float_nan = OpConstant %float -0x1.8p+128
219 %double_nan = OpConstant %double -0x1.8p+1024
220 %108 = OpConstant %half 0
221 %half_1 = OpConstant %half 1
222 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
223 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
224 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
225 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
226 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
227 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
228 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
229 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
230 )";
231
232   return header;
233 }
234
235 // clang-format off
236 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
237                         ::testing::Values(
238   // Test case 0: fold 0*n
239   InstructionFoldingCase<uint32_t>(
240     Header() + "%main = OpFunction %void None %void_func\n" +
241     "%main_lab = OpLabel\n" +
242            "%n = OpVariable %_ptr_int Function\n" +
243         "%load = OpLoad %int %n\n" +
244            "%2 = OpIMul %int %int_0 %load\n" +
245                 "OpReturn\n" +
246                 "OpFunctionEnd",
247     2, 0),
248   // Test case 1: fold n*0
249   InstructionFoldingCase<uint32_t>(
250     Header() + "%main = OpFunction %void None %void_func\n" +
251         "%main_lab = OpLabel\n" +
252         "%n = OpVariable %_ptr_int Function\n" +
253         "%load = OpLoad %int %n\n" +
254         "%2 = OpIMul %int %load %int_0\n" +
255         "OpReturn\n" +
256         "OpFunctionEnd",
257     2, 0),
258   // Test case 2: fold 0/n (signed)
259   InstructionFoldingCase<uint32_t>(
260     Header() + "%main = OpFunction %void None %void_func\n" +
261         "%main_lab = OpLabel\n" +
262         "%n = OpVariable %_ptr_int Function\n" +
263         "%load = OpLoad %int %n\n" +
264         "%2 = OpSDiv %int %int_0 %load\n" +
265         "OpReturn\n" +
266         "OpFunctionEnd",
267         2, 0),
268   // Test case 3: fold n/0 (signed)
269   InstructionFoldingCase<uint32_t>(
270     Header() + "%main = OpFunction %void None %void_func\n" +
271         "%main_lab = OpLabel\n" +
272         "%n = OpVariable %_ptr_int Function\n" +
273         "%load = OpLoad %int %n\n" +
274         "%2 = OpSDiv %int %load %int_0\n" +
275         "OpReturn\n" +
276         "OpFunctionEnd",
277     2, 0),
278   // Test case 4: fold 0/n (unsigned)
279   InstructionFoldingCase<uint32_t>(
280     Header() + "%main = OpFunction %void None %void_func\n" +
281         "%main_lab = OpLabel\n" +
282         "%n = OpVariable %_ptr_uint Function\n" +
283         "%load = OpLoad %uint %n\n" +
284         "%2 = OpUDiv %uint %uint_0 %load\n" +
285         "OpReturn\n" +
286         "OpFunctionEnd",
287     2, 0),
288   // Test case 5: fold n/0 (unsigned)
289   InstructionFoldingCase<uint32_t>(
290     Header() + "%main = OpFunction %void None %void_func\n" +
291         "%main_lab = OpLabel\n" +
292         "%n = OpVariable %_ptr_int Function\n" +
293         "%load = OpLoad %int %n\n" +
294         "%2 = OpSDiv %int %load %int_0\n" +
295         "OpReturn\n" +
296         "OpFunctionEnd",
297     2, 0),
298   // Test case 6: fold 0 remainder n
299   InstructionFoldingCase<uint32_t>(
300     Header() + "%main = OpFunction %void None %void_func\n" +
301         "%main_lab = OpLabel\n" +
302         "%n = OpVariable %_ptr_int Function\n" +
303         "%load = OpLoad %int %n\n" +
304         "%2 = OpSRem %int %int_0 %load\n" +
305         "OpReturn\n" +
306         "OpFunctionEnd",
307     2, 0),
308   // Test case 7: fold n remainder 0
309   InstructionFoldingCase<uint32_t>(
310     Header() + "%main = OpFunction %void None %void_func\n" +
311         "%main_lab = OpLabel\n" +
312         "%n = OpVariable %_ptr_int Function\n" +
313         "%load = OpLoad %int %n\n" +
314         "%2 = OpSRem %int %load %int_0\n" +
315         "OpReturn\n" +
316         "OpFunctionEnd",
317     2, 0),
318   // Test case 8: fold 0%n (signed)
319   InstructionFoldingCase<uint32_t>(
320     Header() + "%main = OpFunction %void None %void_func\n" +
321         "%main_lab = OpLabel\n" +
322         "%n = OpVariable %_ptr_int Function\n" +
323         "%load = OpLoad %int %n\n" +
324         "%2 = OpSMod %int %int_0 %load\n" +
325         "OpReturn\n" +
326         "OpFunctionEnd",
327     2, 0),
328   // Test case 9: fold n%0 (signed)
329   InstructionFoldingCase<uint32_t>(
330     Header() + "%main = OpFunction %void None %void_func\n" +
331         "%main_lab = OpLabel\n" +
332         "%n = OpVariable %_ptr_int Function\n" +
333         "%load = OpLoad %int %n\n" +
334         "%2 = OpSMod %int %load %int_0\n" +
335         "OpReturn\n" +
336         "OpFunctionEnd",
337     2, 0),
338   // Test case 10: fold 0%n (unsigned)
339   InstructionFoldingCase<uint32_t>(
340     Header() + "%main = OpFunction %void None %void_func\n" +
341         "%main_lab = OpLabel\n" +
342         "%n = OpVariable %_ptr_uint Function\n" +
343         "%load = OpLoad %uint %n\n" +
344         "%2 = OpUMod %uint %uint_0 %load\n" +
345         "OpReturn\n" +
346         "OpFunctionEnd",
347     2, 0),
348   // Test case 11: fold n%0 (unsigned)
349   InstructionFoldingCase<uint32_t>(
350     Header() + "%main = OpFunction %void None %void_func\n" +
351         "%main_lab = OpLabel\n" +
352         "%n = OpVariable %_ptr_uint Function\n" +
353         "%load = OpLoad %uint %n\n" +
354         "%2 = OpUMod %uint %load %uint_0\n" +
355         "OpReturn\n" +
356         "OpFunctionEnd",
357     2, 0),
358   // Test case 12: fold n << 32
359   InstructionFoldingCase<uint32_t>(
360       Header() + "%main = OpFunction %void None %void_func\n" +
361           "%main_lab = OpLabel\n" +
362           "%n = OpVariable %_ptr_uint Function\n" +
363           "%load = OpLoad %uint %n\n" +
364           "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
365           "OpReturn\n" +
366           "OpFunctionEnd",
367       2, 0),
368   // Test case 13: fold n >> 32
369   InstructionFoldingCase<uint32_t>(
370       Header() + "%main = OpFunction %void None %void_func\n" +
371           "%main_lab = OpLabel\n" +
372           "%n = OpVariable %_ptr_uint Function\n" +
373           "%load = OpLoad %uint %n\n" +
374           "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
375           "OpReturn\n" +
376           "OpFunctionEnd",
377       2, 0),
378   // Test case 14: fold n | 0xFFFFFFFF
379   InstructionFoldingCase<uint32_t>(
380       Header() + "%main = OpFunction %void None %void_func\n" +
381   "%main_lab = OpLabel\n" +
382   "%n = OpVariable %_ptr_uint Function\n" +
383   "%load = OpLoad %uint %n\n" +
384   "%2 = OpBitwiseOr %uint %load %uint_max\n" +
385   "OpReturn\n" +
386   "OpFunctionEnd",
387   2, 0xFFFFFFFF),
388   // Test case 15: fold 0xFFFFFFFF | n
389   InstructionFoldingCase<uint32_t>(
390       Header() + "%main = OpFunction %void None %void_func\n" +
391           "%main_lab = OpLabel\n" +
392           "%n = OpVariable %_ptr_uint Function\n" +
393           "%load = OpLoad %uint %n\n" +
394           "%2 = OpBitwiseOr %uint %uint_max %load\n" +
395           "OpReturn\n" +
396           "OpFunctionEnd",
397       2, 0xFFFFFFFF),
398   // Test case 16: fold n & 0
399   InstructionFoldingCase<uint32_t>(
400       Header() + "%main = OpFunction %void None %void_func\n" +
401           "%main_lab = OpLabel\n" +
402           "%n = OpVariable %_ptr_uint Function\n" +
403           "%load = OpLoad %uint %n\n" +
404           "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
405           "OpReturn\n" +
406           "OpFunctionEnd",
407       2, 0)
408 ));
409 // clang-format on
410
411 using IntVectorInstructionFoldingTest =
412     ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
413
414 TEST_P(IntVectorInstructionFoldingTest, Case) {
415   const auto& tc = GetParam();
416
417   // Build module.
418   std::unique_ptr<ir::IRContext> context =
419       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
420                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
421   ASSERT_NE(nullptr, context);
422
423   // Fold the instruction to test.
424   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
425   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
426   bool succeeded = opt::FoldInstruction(inst);
427
428   // Make sure the instruction folded as expected.
429   EXPECT_TRUE(succeeded);
430   if (inst != nullptr) {
431     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
432     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
433     std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
434     EXPECT_THAT(opcodes, Contains(inst->opcode()));
435     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
436     const opt::analysis::Constant* result =
437         const_mrg->GetConstantFromInst(inst);
438     EXPECT_NE(result, nullptr);
439     if (result != nullptr) {
440       const std::vector<const opt::analysis::Constant*>& componenets =
441           result->AsVectorConstant()->GetComponents();
442       EXPECT_EQ(componenets.size(), tc.expected_result.size());
443       for (size_t i = 0; i < componenets.size(); i++) {
444         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
445       }
446     }
447   }
448 }
449
450 // clang-format off
451 INSTANTIATE_TEST_CASE_P(TestCase, IntVectorInstructionFoldingTest,
452 ::testing::Values(
453     // Test case 0: fold 0*n
454     InstructionFoldingCase<std::vector<uint32_t>>(
455         Header() + "%main = OpFunction %void None %void_func\n" +
456             "%main_lab = OpLabel\n" +
457             "%n = OpVariable %_ptr_int Function\n" +
458             "%load = OpLoad %int %n\n" +
459             "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
460             "OpReturn\n" +
461             "OpFunctionEnd",
462         2, {2,3}),
463     InstructionFoldingCase<std::vector<uint32_t>>(
464       Header() + "%main = OpFunction %void None %void_func\n" +
465           "%main_lab = OpLabel\n" +
466           "%n = OpVariable %_ptr_int Function\n" +
467           "%load = OpLoad %int %n\n" +
468           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
469           "OpReturn\n" +
470           "OpFunctionEnd",
471       2, {0,3})
472 ));
473 // clang-format on
474
475 using BooleanInstructionFoldingTest =
476     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
477
478 TEST_P(BooleanInstructionFoldingTest, Case) {
479   const auto& tc = GetParam();
480
481   // Build module.
482   std::unique_ptr<ir::IRContext> context =
483       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
484                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
485   ASSERT_NE(nullptr, context);
486
487   // Fold the instruction to test.
488   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
489   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
490   bool succeeded = opt::FoldInstruction(inst);
491
492   // Make sure the instruction folded as expected.
493   EXPECT_TRUE(succeeded);
494   if (inst != nullptr) {
495     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
496     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
497     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
498     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
499     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
500     const opt::analysis::BoolConstant* result =
501         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
502     EXPECT_NE(result, nullptr);
503     if (result != nullptr) {
504       EXPECT_EQ(result->value(), tc.expected_result);
505     }
506   }
507 }
508
509 // clang-format off
510 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest,
511                         ::testing::Values(
512   // Test case 0: fold true || n
513   InstructionFoldingCase<bool>(
514       Header() + "%main = OpFunction %void None %void_func\n" +
515           "%main_lab = OpLabel\n" +
516           "%n = OpVariable %_ptr_bool Function\n" +
517           "%load = OpLoad %bool %n\n" +
518           "%2 = OpLogicalOr %bool %true %load\n" +
519           "OpReturn\n" +
520           "OpFunctionEnd",
521       2, true),
522   // Test case 1: fold n || true
523   InstructionFoldingCase<bool>(
524       Header() + "%main = OpFunction %void None %void_func\n" +
525           "%main_lab = OpLabel\n" +
526           "%n = OpVariable %_ptr_bool Function\n" +
527           "%load = OpLoad %bool %n\n" +
528           "%2 = OpLogicalOr %bool %load %true\n" +
529           "OpReturn\n" +
530           "OpFunctionEnd",
531       2, true),
532   // Test case 2: fold false && n
533   InstructionFoldingCase<bool>(
534       Header() + "%main = OpFunction %void None %void_func\n" +
535           "%main_lab = OpLabel\n" +
536           "%n = OpVariable %_ptr_bool Function\n" +
537           "%load = OpLoad %bool %n\n" +
538           "%2 = OpLogicalAnd %bool %false %load\n" +
539           "OpReturn\n" +
540           "OpFunctionEnd",
541       2, false),
542   // Test case 3: fold n && false
543   InstructionFoldingCase<bool>(
544       Header() + "%main = OpFunction %void None %void_func\n" +
545           "%main_lab = OpLabel\n" +
546           "%n = OpVariable %_ptr_bool Function\n" +
547           "%load = OpLoad %bool %n\n" +
548           "%2 = OpLogicalAnd %bool %load %false\n" +
549           "OpReturn\n" +
550           "OpFunctionEnd",
551       2, false),
552   // Test case 4: fold n < 0 (unsigned)
553   InstructionFoldingCase<bool>(
554       Header() + "%main = OpFunction %void None %void_func\n" +
555           "%main_lab = OpLabel\n" +
556           "%n = OpVariable %_ptr_uint Function\n" +
557           "%load = OpLoad %uint %n\n" +
558           "%2 = OpULessThan %bool %load %uint_0\n" +
559           "OpReturn\n" +
560           "OpFunctionEnd",
561       2, false),
562   // Test case 5: fold UINT_MAX < n (unsigned)
563   InstructionFoldingCase<bool>(
564       Header() + "%main = OpFunction %void None %void_func\n" +
565           "%main_lab = OpLabel\n" +
566           "%n = OpVariable %_ptr_uint Function\n" +
567           "%load = OpLoad %uint %n\n" +
568           "%2 = OpULessThan %bool %uint_max %load\n" +
569           "OpReturn\n" +
570           "OpFunctionEnd",
571       2, false),
572   // Test case 6: fold INT_MAX < n (signed)
573   InstructionFoldingCase<bool>(
574       Header() + "%main = OpFunction %void None %void_func\n" +
575           "%main_lab = OpLabel\n" +
576           "%n = OpVariable %_ptr_int Function\n" +
577           "%load = OpLoad %int %n\n" +
578           "%2 = OpSLessThan %bool %int_max %load\n" +
579           "OpReturn\n" +
580           "OpFunctionEnd",
581       2, false),
582   // Test case 7: fold n < INT_MIN (signed)
583   InstructionFoldingCase<bool>(
584       Header() + "%main = OpFunction %void None %void_func\n" +
585           "%main_lab = OpLabel\n" +
586           "%n = OpVariable %_ptr_int Function\n" +
587           "%load = OpLoad %int %n\n" +
588           "%2 = OpSLessThan %bool %load %int_min\n" +
589           "OpReturn\n" +
590           "OpFunctionEnd",
591       2, false),
592   // Test case 8: fold 0 > n (unsigned)
593   InstructionFoldingCase<bool>(
594       Header() + "%main = OpFunction %void None %void_func\n" +
595           "%main_lab = OpLabel\n" +
596           "%n = OpVariable %_ptr_uint Function\n" +
597           "%load = OpLoad %uint %n\n" +
598           "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
599           "OpReturn\n" +
600           "OpFunctionEnd",
601       2, false),
602   // Test case 9: fold n > UINT_MAX (unsigned)
603   InstructionFoldingCase<bool>(
604       Header() + "%main = OpFunction %void None %void_func\n" +
605           "%main_lab = OpLabel\n" +
606           "%n = OpVariable %_ptr_uint Function\n" +
607           "%load = OpLoad %uint %n\n" +
608           "%2 = OpUGreaterThan %bool %load %uint_max\n" +
609           "OpReturn\n" +
610           "OpFunctionEnd",
611       2, false),
612   // Test case 10: fold n > INT_MAX (signed)
613   InstructionFoldingCase<bool>(
614       Header() + "%main = OpFunction %void None %void_func\n" +
615           "%main_lab = OpLabel\n" +
616           "%n = OpVariable %_ptr_int Function\n" +
617           "%load = OpLoad %int %n\n" +
618           "%2 = OpSGreaterThan %bool %load %int_max\n" +
619           "OpReturn\n" +
620           "OpFunctionEnd",
621       2, false),
622   // Test case 11: fold INT_MIN > n (signed)
623   InstructionFoldingCase<bool>(
624       Header() + "%main = OpFunction %void None %void_func\n" +
625           "%main_lab = OpLabel\n" +
626           "%n = OpVariable %_ptr_uint Function\n" +
627           "%load = OpLoad %uint %n\n" +
628           "%2 = OpSGreaterThan %bool %int_min %load\n" +
629           "OpReturn\n" +
630           "OpFunctionEnd",
631       2, false),
632   // Test case 12: fold 0 <= n (unsigned)
633   InstructionFoldingCase<bool>(
634       Header() + "%main = OpFunction %void None %void_func\n" +
635           "%main_lab = OpLabel\n" +
636           "%n = OpVariable %_ptr_uint Function\n" +
637           "%load = OpLoad %uint %n\n" +
638           "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
639           "OpReturn\n" +
640           "OpFunctionEnd",
641       2, true),
642   // Test case 13: fold n <= UINT_MAX (unsigned)
643   InstructionFoldingCase<bool>(
644       Header() + "%main = OpFunction %void None %void_func\n" +
645           "%main_lab = OpLabel\n" +
646           "%n = OpVariable %_ptr_uint Function\n" +
647           "%load = OpLoad %uint %n\n" +
648           "%2 = OpULessThanEqual %bool %load %uint_max\n" +
649           "OpReturn\n" +
650           "OpFunctionEnd",
651       2, true),
652   // Test case 14: fold INT_MIN <= n (signed)
653   InstructionFoldingCase<bool>(
654       Header() + "%main = OpFunction %void None %void_func\n" +
655           "%main_lab = OpLabel\n" +
656           "%n = OpVariable %_ptr_int Function\n" +
657           "%load = OpLoad %int %n\n" +
658           "%2 = OpSLessThanEqual %bool %int_min %load\n" +
659           "OpReturn\n" +
660           "OpFunctionEnd",
661       2, true),
662   // Test case 15: fold n <= INT_MAX (signed)
663   InstructionFoldingCase<bool>(
664       Header() + "%main = OpFunction %void None %void_func\n" +
665           "%main_lab = OpLabel\n" +
666           "%n = OpVariable %_ptr_int Function\n" +
667           "%load = OpLoad %int %n\n" +
668           "%2 = OpSLessThanEqual %bool %load %int_max\n" +
669           "OpReturn\n" +
670           "OpFunctionEnd",
671       2, true),
672   // Test case 16: fold n >= 0 (unsigned)
673   InstructionFoldingCase<bool>(
674       Header() + "%main = OpFunction %void None %void_func\n" +
675           "%main_lab = OpLabel\n" +
676           "%n = OpVariable %_ptr_uint Function\n" +
677           "%load = OpLoad %uint %n\n" +
678           "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
679           "OpReturn\n" +
680           "OpFunctionEnd",
681       2, true),
682   // Test case 17: fold UINT_MAX >= n (unsigned)
683   InstructionFoldingCase<bool>(
684       Header() + "%main = OpFunction %void None %void_func\n" +
685           "%main_lab = OpLabel\n" +
686           "%n = OpVariable %_ptr_uint Function\n" +
687           "%load = OpLoad %uint %n\n" +
688           "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
689           "OpReturn\n" +
690           "OpFunctionEnd",
691       2, true),
692   // Test case 18: fold n >= INT_MIN (signed)
693   InstructionFoldingCase<bool>(
694       Header() + "%main = OpFunction %void None %void_func\n" +
695           "%main_lab = OpLabel\n" +
696           "%n = OpVariable %_ptr_int Function\n" +
697           "%load = OpLoad %int %n\n" +
698           "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
699           "OpReturn\n" +
700           "OpFunctionEnd",
701       2, true),
702   // Test case 19: fold INT_MAX >= n (signed)
703   InstructionFoldingCase<bool>(
704       Header() + "%main = OpFunction %void None %void_func\n" +
705           "%main_lab = OpLabel\n" +
706           "%n = OpVariable %_ptr_int Function\n" +
707           "%load = OpLoad %int %n\n" +
708           "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
709           "OpReturn\n" +
710           "OpFunctionEnd",
711       2, true)
712 ));
713 // clang-format on
714
715 using FloatInstructionFoldingTest =
716     ::testing::TestWithParam<InstructionFoldingCase<float>>;
717
718 TEST_P(FloatInstructionFoldingTest, Case) {
719   const auto& tc = GetParam();
720
721   // Build module.
722   std::unique_ptr<ir::IRContext> context =
723       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
724                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
725   ASSERT_NE(nullptr, context);
726
727   // Fold the instruction to test.
728   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
729   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
730   bool succeeded = opt::FoldInstruction(inst);
731
732   // Make sure the instruction folded as expected.
733   EXPECT_TRUE(succeeded);
734   if (inst != nullptr) {
735     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
736     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
737     EXPECT_EQ(inst->opcode(), SpvOpConstant);
738     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
739     const opt::analysis::FloatConstant* result =
740         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
741     EXPECT_NE(result, nullptr);
742     if (result != nullptr) {
743       EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
744     }
745   }
746 }
747
748 // Not testing NaNs because there are no expectations concerning NaNs according
749 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
750 // specification.
751
752 // clang-format off
753 INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
754 ::testing::Values(
755     // Test case 0: Fold 2.0 - 1.0
756     InstructionFoldingCase<float>(
757         Header() + "%main = OpFunction %void None %void_func\n" +
758             "%main_lab = OpLabel\n" +
759             "%2 = OpFSub %float %float_2 %float_1\n" +
760             "OpReturn\n" +
761             "OpFunctionEnd",
762         2, 1.0),
763     // Test case 1: Fold 2.0 + 1.0
764     InstructionFoldingCase<float>(
765         Header() + "%main = OpFunction %void None %void_func\n" +
766             "%main_lab = OpLabel\n" +
767             "%2 = OpFAdd %float %float_2 %float_1\n" +
768             "OpReturn\n" +
769             "OpFunctionEnd",
770         2, 3.0),
771     // Test case 2: Fold 3.0 * 2.0
772     InstructionFoldingCase<float>(
773         Header() + "%main = OpFunction %void None %void_func\n" +
774             "%main_lab = OpLabel\n" +
775             "%2 = OpFMul %float %float_3 %float_2\n" +
776             "OpReturn\n" +
777             "OpFunctionEnd",
778         2, 6.0),
779     // Test case 3: Fold 1.0 / 2.0
780     InstructionFoldingCase<float>(
781         Header() + "%main = OpFunction %void None %void_func\n" +
782             "%main_lab = OpLabel\n" +
783             "%2 = OpFDiv %float %float_1 %float_2\n" +
784             "OpReturn\n" +
785             "OpFunctionEnd",
786         2, 0.5),
787     // Test case 4: Fold 1.0 / 0.0
788     InstructionFoldingCase<float>(
789         Header() + "%main = OpFunction %void None %void_func\n" +
790             "%main_lab = OpLabel\n" +
791             "%2 = OpFDiv %float %float_1 %float_0\n" +
792             "OpReturn\n" +
793             "OpFunctionEnd",
794         2, std::numeric_limits<float>::infinity()),
795     // Test case 5: Fold -1.0 / 0.0
796     InstructionFoldingCase<float>(
797         Header() + "%main = OpFunction %void None %void_func\n" +
798             "%main_lab = OpLabel\n" +
799             "%2 = OpFDiv %float %float_n1 %float_0\n" +
800             "OpReturn\n" +
801             "OpFunctionEnd",
802         2, -std::numeric_limits<float>::infinity())
803 ));
804 // clang-format on
805
806 using DoubleInstructionFoldingTest =
807     ::testing::TestWithParam<InstructionFoldingCase<double>>;
808
809 TEST_P(DoubleInstructionFoldingTest, Case) {
810   const auto& tc = GetParam();
811
812   // Build module.
813   std::unique_ptr<ir::IRContext> context =
814       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
815                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
816   ASSERT_NE(nullptr, context);
817
818   // Fold the instruction to test.
819   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
820   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
821   bool succeeded = opt::FoldInstruction(inst);
822
823   // Make sure the instruction folded as expected.
824   EXPECT_TRUE(succeeded);
825   if (inst != nullptr) {
826     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
827     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
828     EXPECT_EQ(inst->opcode(), SpvOpConstant);
829     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
830     const opt::analysis::FloatConstant* result =
831         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
832     EXPECT_NE(result, nullptr);
833     if (result != nullptr) {
834       EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
835     }
836   }
837 }
838
839 // clang-format off
840 INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
841 ::testing::Values(
842     // Test case 0: Fold 2.0 - 1.0
843     InstructionFoldingCase<double>(
844         Header() + "%main = OpFunction %void None %void_func\n" +
845             "%main_lab = OpLabel\n" +
846             "%2 = OpFSub %double %double_2 %double_1\n" +
847             "OpReturn\n" +
848             "OpFunctionEnd",
849         2, 1.0),
850         // Test case 1: Fold 2.0 + 1.0
851         InstructionFoldingCase<double>(
852             Header() + "%main = OpFunction %void None %void_func\n" +
853                 "%main_lab = OpLabel\n" +
854                 "%2 = OpFAdd %double %double_2 %double_1\n" +
855                 "OpReturn\n" +
856                 "OpFunctionEnd",
857             2, 3.0),
858         // Test case 2: Fold 3.0 * 2.0
859         InstructionFoldingCase<double>(
860             Header() + "%main = OpFunction %void None %void_func\n" +
861                 "%main_lab = OpLabel\n" +
862                 "%2 = OpFMul %double %double_3 %double_2\n" +
863                 "OpReturn\n" +
864                 "OpFunctionEnd",
865             2, 6.0),
866         // Test case 3: Fold 1.0 / 2.0
867         InstructionFoldingCase<double>(
868             Header() + "%main = OpFunction %void None %void_func\n" +
869                 "%main_lab = OpLabel\n" +
870                 "%2 = OpFDiv %double %double_1 %double_2\n" +
871                 "OpReturn\n" +
872                 "OpFunctionEnd",
873             2, 0.5),
874         // Test case 4: Fold 1.0 / 0.0
875         InstructionFoldingCase<double>(
876             Header() + "%main = OpFunction %void None %void_func\n" +
877                 "%main_lab = OpLabel\n" +
878                 "%2 = OpFDiv %double %double_1 %double_0\n" +
879                 "OpReturn\n" +
880                 "OpFunctionEnd",
881             2, std::numeric_limits<double>::infinity()),
882         // Test case 4: Fold -1.0 / 0.0
883         InstructionFoldingCase<double>(
884             Header() + "%main = OpFunction %void None %void_func\n" +
885                 "%main_lab = OpLabel\n" +
886                 "%2 = OpFDiv %double %double_n1 %double_0\n" +
887                 "OpReturn\n" +
888                 "OpFunctionEnd",
889             2, -std::numeric_limits<double>::infinity())
890 ));
891 // clang-format on
892
893 // clang-format off
894 INSTANTIATE_TEST_CASE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
895                         ::testing::Values(
896   // Test case 0: fold 1.0 == 2.0
897   InstructionFoldingCase<bool>(
898       Header() + "%main = OpFunction %void None %void_func\n" +
899           "%main_lab = OpLabel\n" +
900           "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
901           "OpReturn\n" +
902           "OpFunctionEnd",
903       2, false),
904   // Test case 1: fold 1.0 != 2.0
905   InstructionFoldingCase<bool>(
906       Header() + "%main = OpFunction %void None %void_func\n" +
907           "%main_lab = OpLabel\n" +
908           "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
909           "OpReturn\n" +
910           "OpFunctionEnd",
911       2, true),
912   // Test case 2: fold 1.0 < 2.0
913   InstructionFoldingCase<bool>(
914       Header() + "%main = OpFunction %void None %void_func\n" +
915           "%main_lab = OpLabel\n" +
916           "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
917           "OpReturn\n" +
918           "OpFunctionEnd",
919       2, true),
920   // Test case 3: fold 1.0 > 2.0
921   InstructionFoldingCase<bool>(
922       Header() + "%main = OpFunction %void None %void_func\n" +
923           "%main_lab = OpLabel\n" +
924           "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
925           "OpReturn\n" +
926           "OpFunctionEnd",
927       2, false),
928   // Test case 4: fold 1.0 <= 2.0
929   InstructionFoldingCase<bool>(
930       Header() + "%main = OpFunction %void None %void_func\n" +
931           "%main_lab = OpLabel\n" +
932           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
933           "OpReturn\n" +
934           "OpFunctionEnd",
935       2, true),
936   // Test case 5: fold 1.0 >= 2.0
937   InstructionFoldingCase<bool>(
938       Header() + "%main = OpFunction %void None %void_func\n" +
939           "%main_lab = OpLabel\n" +
940           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
941           "OpReturn\n" +
942           "OpFunctionEnd",
943       2, false),
944   // Test case 6: fold 1.0 == 1.0
945   InstructionFoldingCase<bool>(
946       Header() + "%main = OpFunction %void None %void_func\n" +
947           "%main_lab = OpLabel\n" +
948           "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
949           "OpReturn\n" +
950           "OpFunctionEnd",
951       2, true),
952   // Test case 7: fold 1.0 != 1.0
953   InstructionFoldingCase<bool>(
954       Header() + "%main = OpFunction %void None %void_func\n" +
955           "%main_lab = OpLabel\n" +
956           "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
957           "OpReturn\n" +
958           "OpFunctionEnd",
959       2, false),
960   // Test case 8: fold 1.0 < 1.0
961   InstructionFoldingCase<bool>(
962       Header() + "%main = OpFunction %void None %void_func\n" +
963           "%main_lab = OpLabel\n" +
964           "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
965           "OpReturn\n" +
966           "OpFunctionEnd",
967       2, false),
968   // Test case 9: fold 1.0 > 1.0
969   InstructionFoldingCase<bool>(
970       Header() + "%main = OpFunction %void None %void_func\n" +
971           "%main_lab = OpLabel\n" +
972           "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
973           "OpReturn\n" +
974           "OpFunctionEnd",
975       2, false),
976   // Test case 10: fold 1.0 <= 1.0
977   InstructionFoldingCase<bool>(
978       Header() + "%main = OpFunction %void None %void_func\n" +
979           "%main_lab = OpLabel\n" +
980           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
981           "OpReturn\n" +
982           "OpFunctionEnd",
983       2, true),
984   // Test case 11: fold 1.0 >= 1.0
985   InstructionFoldingCase<bool>(
986       Header() + "%main = OpFunction %void None %void_func\n" +
987           "%main_lab = OpLabel\n" +
988           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
989           "OpReturn\n" +
990           "OpFunctionEnd",
991       2, true),
992   // Test case 12: fold 2.0 < 1.0
993   InstructionFoldingCase<bool>(
994       Header() + "%main = OpFunction %void None %void_func\n" +
995           "%main_lab = OpLabel\n" +
996           "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
997           "OpReturn\n" +
998           "OpFunctionEnd",
999       2, false),
1000   // Test case 13: fold 2.0 > 1.0
1001   InstructionFoldingCase<bool>(
1002       Header() + "%main = OpFunction %void None %void_func\n" +
1003           "%main_lab = OpLabel\n" +
1004           "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
1005           "OpReturn\n" +
1006           "OpFunctionEnd",
1007       2, true),
1008   // Test case 14: fold 2.0 <= 1.0
1009   InstructionFoldingCase<bool>(
1010       Header() + "%main = OpFunction %void None %void_func\n" +
1011           "%main_lab = OpLabel\n" +
1012           "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
1013           "OpReturn\n" +
1014           "OpFunctionEnd",
1015       2, false),
1016   // Test case 15: fold 2.0 >= 1.0
1017   InstructionFoldingCase<bool>(
1018       Header() + "%main = OpFunction %void None %void_func\n" +
1019           "%main_lab = OpLabel\n" +
1020           "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
1021           "OpReturn\n" +
1022           "OpFunctionEnd",
1023       2, true)
1024 ));
1025
1026 INSTANTIATE_TEST_CASE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1027                         ::testing::Values(
1028   // Test case 0: fold 1.0 == 2.0
1029   InstructionFoldingCase<bool>(
1030       Header() + "%main = OpFunction %void None %void_func\n" +
1031           "%main_lab = OpLabel\n" +
1032           "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
1033           "OpReturn\n" +
1034           "OpFunctionEnd",
1035       2, false),
1036   // Test case 1: fold 1.0 != 2.0
1037   InstructionFoldingCase<bool>(
1038       Header() + "%main = OpFunction %void None %void_func\n" +
1039           "%main_lab = OpLabel\n" +
1040           "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
1041           "OpReturn\n" +
1042           "OpFunctionEnd",
1043       2, true),
1044   // Test case 2: fold 1.0 < 2.0
1045   InstructionFoldingCase<bool>(
1046       Header() + "%main = OpFunction %void None %void_func\n" +
1047           "%main_lab = OpLabel\n" +
1048           "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
1049           "OpReturn\n" +
1050           "OpFunctionEnd",
1051       2, true),
1052   // Test case 3: fold 1.0 > 2.0
1053   InstructionFoldingCase<bool>(
1054       Header() + "%main = OpFunction %void None %void_func\n" +
1055           "%main_lab = OpLabel\n" +
1056           "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
1057           "OpReturn\n" +
1058           "OpFunctionEnd",
1059       2, false),
1060   // Test case 4: fold 1.0 <= 2.0
1061   InstructionFoldingCase<bool>(
1062       Header() + "%main = OpFunction %void None %void_func\n" +
1063           "%main_lab = OpLabel\n" +
1064           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
1065           "OpReturn\n" +
1066           "OpFunctionEnd",
1067       2, true),
1068   // Test case 5: fold 1.0 >= 2.0
1069   InstructionFoldingCase<bool>(
1070       Header() + "%main = OpFunction %void None %void_func\n" +
1071           "%main_lab = OpLabel\n" +
1072           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
1073           "OpReturn\n" +
1074           "OpFunctionEnd",
1075       2, false),
1076   // Test case 6: fold 1.0 == 1.0
1077   InstructionFoldingCase<bool>(
1078       Header() + "%main = OpFunction %void None %void_func\n" +
1079           "%main_lab = OpLabel\n" +
1080           "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
1081           "OpReturn\n" +
1082           "OpFunctionEnd",
1083       2, true),
1084   // Test case 7: fold 1.0 != 1.0
1085   InstructionFoldingCase<bool>(
1086       Header() + "%main = OpFunction %void None %void_func\n" +
1087           "%main_lab = OpLabel\n" +
1088           "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
1089           "OpReturn\n" +
1090           "OpFunctionEnd",
1091       2, false),
1092   // Test case 8: fold 1.0 < 1.0
1093   InstructionFoldingCase<bool>(
1094       Header() + "%main = OpFunction %void None %void_func\n" +
1095           "%main_lab = OpLabel\n" +
1096           "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
1097           "OpReturn\n" +
1098           "OpFunctionEnd",
1099       2, false),
1100   // Test case 9: fold 1.0 > 1.0
1101   InstructionFoldingCase<bool>(
1102       Header() + "%main = OpFunction %void None %void_func\n" +
1103           "%main_lab = OpLabel\n" +
1104           "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
1105           "OpReturn\n" +
1106           "OpFunctionEnd",
1107       2, false),
1108   // Test case 10: fold 1.0 <= 1.0
1109   InstructionFoldingCase<bool>(
1110       Header() + "%main = OpFunction %void None %void_func\n" +
1111           "%main_lab = OpLabel\n" +
1112           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
1113           "OpReturn\n" +
1114           "OpFunctionEnd",
1115       2, true),
1116   // Test case 11: fold 1.0 >= 1.0
1117   InstructionFoldingCase<bool>(
1118       Header() + "%main = OpFunction %void None %void_func\n" +
1119           "%main_lab = OpLabel\n" +
1120           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
1121           "OpReturn\n" +
1122           "OpFunctionEnd",
1123       2, true),
1124   // Test case 12: fold 2.0 < 1.0
1125   InstructionFoldingCase<bool>(
1126       Header() + "%main = OpFunction %void None %void_func\n" +
1127           "%main_lab = OpLabel\n" +
1128           "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
1129           "OpReturn\n" +
1130           "OpFunctionEnd",
1131       2, false),
1132   // Test case 13: fold 2.0 > 1.0
1133   InstructionFoldingCase<bool>(
1134       Header() + "%main = OpFunction %void None %void_func\n" +
1135           "%main_lab = OpLabel\n" +
1136           "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
1137           "OpReturn\n" +
1138           "OpFunctionEnd",
1139       2, true),
1140   // Test case 14: fold 2.0 <= 1.0
1141   InstructionFoldingCase<bool>(
1142       Header() + "%main = OpFunction %void None %void_func\n" +
1143           "%main_lab = OpLabel\n" +
1144           "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
1145           "OpReturn\n" +
1146           "OpFunctionEnd",
1147       2, false),
1148   // Test case 15: fold 2.0 >= 1.0
1149   InstructionFoldingCase<bool>(
1150       Header() + "%main = OpFunction %void None %void_func\n" +
1151           "%main_lab = OpLabel\n" +
1152           "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
1153           "OpReturn\n" +
1154           "OpFunctionEnd",
1155       2, true)
1156 ));
1157
1158 INSTANTIATE_TEST_CASE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1159                         ::testing::Values(
1160   // Test case 0: fold 1.0 == 2.0
1161   InstructionFoldingCase<bool>(
1162       Header() + "%main = OpFunction %void None %void_func\n" +
1163           "%main_lab = OpLabel\n" +
1164           "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
1165           "OpReturn\n" +
1166           "OpFunctionEnd",
1167       2, false),
1168   // Test case 1: fold 1.0 != 2.0
1169   InstructionFoldingCase<bool>(
1170       Header() + "%main = OpFunction %void None %void_func\n" +
1171           "%main_lab = OpLabel\n" +
1172           "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
1173           "OpReturn\n" +
1174           "OpFunctionEnd",
1175       2, true),
1176   // Test case 2: fold 1.0 < 2.0
1177   InstructionFoldingCase<bool>(
1178       Header() + "%main = OpFunction %void None %void_func\n" +
1179           "%main_lab = OpLabel\n" +
1180           "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
1181           "OpReturn\n" +
1182           "OpFunctionEnd",
1183       2, true),
1184   // Test case 3: fold 1.0 > 2.0
1185   InstructionFoldingCase<bool>(
1186       Header() + "%main = OpFunction %void None %void_func\n" +
1187           "%main_lab = OpLabel\n" +
1188           "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
1189           "OpReturn\n" +
1190           "OpFunctionEnd",
1191       2, false),
1192   // Test case 4: fold 1.0 <= 2.0
1193   InstructionFoldingCase<bool>(
1194       Header() + "%main = OpFunction %void None %void_func\n" +
1195           "%main_lab = OpLabel\n" +
1196           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
1197           "OpReturn\n" +
1198           "OpFunctionEnd",
1199       2, true),
1200   // Test case 5: fold 1.0 >= 2.0
1201   InstructionFoldingCase<bool>(
1202       Header() + "%main = OpFunction %void None %void_func\n" +
1203           "%main_lab = OpLabel\n" +
1204           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
1205           "OpReturn\n" +
1206           "OpFunctionEnd",
1207       2, false),
1208   // Test case 6: fold 1.0 == 1.0
1209   InstructionFoldingCase<bool>(
1210       Header() + "%main = OpFunction %void None %void_func\n" +
1211           "%main_lab = OpLabel\n" +
1212           "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
1213           "OpReturn\n" +
1214           "OpFunctionEnd",
1215       2, true),
1216   // Test case 7: fold 1.0 != 1.0
1217   InstructionFoldingCase<bool>(
1218       Header() + "%main = OpFunction %void None %void_func\n" +
1219           "%main_lab = OpLabel\n" +
1220           "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
1221           "OpReturn\n" +
1222           "OpFunctionEnd",
1223       2, false),
1224   // Test case 8: fold 1.0 < 1.0
1225   InstructionFoldingCase<bool>(
1226       Header() + "%main = OpFunction %void None %void_func\n" +
1227           "%main_lab = OpLabel\n" +
1228           "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
1229           "OpReturn\n" +
1230           "OpFunctionEnd",
1231       2, false),
1232   // Test case 9: fold 1.0 > 1.0
1233   InstructionFoldingCase<bool>(
1234       Header() + "%main = OpFunction %void None %void_func\n" +
1235           "%main_lab = OpLabel\n" +
1236           "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
1237           "OpReturn\n" +
1238           "OpFunctionEnd",
1239       2, false),
1240   // Test case 10: fold 1.0 <= 1.0
1241   InstructionFoldingCase<bool>(
1242       Header() + "%main = OpFunction %void None %void_func\n" +
1243           "%main_lab = OpLabel\n" +
1244           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
1245           "OpReturn\n" +
1246           "OpFunctionEnd",
1247       2, true),
1248   // Test case 11: fold 1.0 >= 1.0
1249   InstructionFoldingCase<bool>(
1250       Header() + "%main = OpFunction %void None %void_func\n" +
1251           "%main_lab = OpLabel\n" +
1252           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
1253           "OpReturn\n" +
1254           "OpFunctionEnd",
1255       2, true),
1256   // Test case 12: fold 2.0 < 1.0
1257   InstructionFoldingCase<bool>(
1258       Header() + "%main = OpFunction %void None %void_func\n" +
1259           "%main_lab = OpLabel\n" +
1260           "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
1261           "OpReturn\n" +
1262           "OpFunctionEnd",
1263       2, false),
1264   // Test case 13: fold 2.0 > 1.0
1265   InstructionFoldingCase<bool>(
1266       Header() + "%main = OpFunction %void None %void_func\n" +
1267           "%main_lab = OpLabel\n" +
1268           "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
1269           "OpReturn\n" +
1270           "OpFunctionEnd",
1271       2, true),
1272   // Test case 14: fold 2.0 <= 1.0
1273   InstructionFoldingCase<bool>(
1274       Header() + "%main = OpFunction %void None %void_func\n" +
1275           "%main_lab = OpLabel\n" +
1276           "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
1277           "OpReturn\n" +
1278           "OpFunctionEnd",
1279       2, false),
1280   // Test case 15: fold 2.0 >= 1.0
1281   InstructionFoldingCase<bool>(
1282       Header() + "%main = OpFunction %void None %void_func\n" +
1283           "%main_lab = OpLabel\n" +
1284           "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
1285           "OpReturn\n" +
1286           "OpFunctionEnd",
1287       2, true)
1288 ));
1289
1290 INSTANTIATE_TEST_CASE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1291                         ::testing::Values(
1292   // Test case 0: fold 1.0 == 2.0
1293   InstructionFoldingCase<bool>(
1294       Header() + "%main = OpFunction %void None %void_func\n" +
1295           "%main_lab = OpLabel\n" +
1296           "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
1297           "OpReturn\n" +
1298           "OpFunctionEnd",
1299       2, false),
1300   // Test case 1: fold 1.0 != 2.0
1301   InstructionFoldingCase<bool>(
1302       Header() + "%main = OpFunction %void None %void_func\n" +
1303           "%main_lab = OpLabel\n" +
1304           "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
1305           "OpReturn\n" +
1306           "OpFunctionEnd",
1307       2, true),
1308   // Test case 2: fold 1.0 < 2.0
1309   InstructionFoldingCase<bool>(
1310       Header() + "%main = OpFunction %void None %void_func\n" +
1311           "%main_lab = OpLabel\n" +
1312           "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
1313           "OpReturn\n" +
1314           "OpFunctionEnd",
1315       2, true),
1316   // Test case 3: fold 1.0 > 2.0
1317   InstructionFoldingCase<bool>(
1318       Header() + "%main = OpFunction %void None %void_func\n" +
1319           "%main_lab = OpLabel\n" +
1320           "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
1321           "OpReturn\n" +
1322           "OpFunctionEnd",
1323       2, false),
1324   // Test case 4: fold 1.0 <= 2.0
1325   InstructionFoldingCase<bool>(
1326       Header() + "%main = OpFunction %void None %void_func\n" +
1327           "%main_lab = OpLabel\n" +
1328           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
1329           "OpReturn\n" +
1330           "OpFunctionEnd",
1331       2, true),
1332   // Test case 5: fold 1.0 >= 2.0
1333   InstructionFoldingCase<bool>(
1334       Header() + "%main = OpFunction %void None %void_func\n" +
1335           "%main_lab = OpLabel\n" +
1336           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
1337           "OpReturn\n" +
1338           "OpFunctionEnd",
1339       2, false),
1340   // Test case 6: fold 1.0 == 1.0
1341   InstructionFoldingCase<bool>(
1342       Header() + "%main = OpFunction %void None %void_func\n" +
1343           "%main_lab = OpLabel\n" +
1344           "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
1345           "OpReturn\n" +
1346           "OpFunctionEnd",
1347       2, true),
1348   // Test case 7: fold 1.0 != 1.0
1349   InstructionFoldingCase<bool>(
1350       Header() + "%main = OpFunction %void None %void_func\n" +
1351           "%main_lab = OpLabel\n" +
1352           "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
1353           "OpReturn\n" +
1354           "OpFunctionEnd",
1355       2, false),
1356   // Test case 8: fold 1.0 < 1.0
1357   InstructionFoldingCase<bool>(
1358       Header() + "%main = OpFunction %void None %void_func\n" +
1359           "%main_lab = OpLabel\n" +
1360           "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
1361           "OpReturn\n" +
1362           "OpFunctionEnd",
1363       2, false),
1364   // Test case 9: fold 1.0 > 1.0
1365   InstructionFoldingCase<bool>(
1366       Header() + "%main = OpFunction %void None %void_func\n" +
1367           "%main_lab = OpLabel\n" +
1368           "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
1369           "OpReturn\n" +
1370           "OpFunctionEnd",
1371       2, false),
1372   // Test case 10: fold 1.0 <= 1.0
1373   InstructionFoldingCase<bool>(
1374       Header() + "%main = OpFunction %void None %void_func\n" +
1375           "%main_lab = OpLabel\n" +
1376           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
1377           "OpReturn\n" +
1378           "OpFunctionEnd",
1379       2, true),
1380   // Test case 11: fold 1.0 >= 1.0
1381   InstructionFoldingCase<bool>(
1382       Header() + "%main = OpFunction %void None %void_func\n" +
1383           "%main_lab = OpLabel\n" +
1384           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
1385           "OpReturn\n" +
1386           "OpFunctionEnd",
1387       2, true),
1388   // Test case 12: fold 2.0 < 1.0
1389   InstructionFoldingCase<bool>(
1390       Header() + "%main = OpFunction %void None %void_func\n" +
1391           "%main_lab = OpLabel\n" +
1392           "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
1393           "OpReturn\n" +
1394           "OpFunctionEnd",
1395       2, false),
1396   // Test case 13: fold 2.0 > 1.0
1397   InstructionFoldingCase<bool>(
1398       Header() + "%main = OpFunction %void None %void_func\n" +
1399           "%main_lab = OpLabel\n" +
1400           "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
1401           "OpReturn\n" +
1402           "OpFunctionEnd",
1403       2, true),
1404   // Test case 14: fold 2.0 <= 1.0
1405   InstructionFoldingCase<bool>(
1406       Header() + "%main = OpFunction %void None %void_func\n" +
1407           "%main_lab = OpLabel\n" +
1408           "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
1409           "OpReturn\n" +
1410           "OpFunctionEnd",
1411       2, false),
1412   // Test case 15: fold 2.0 >= 1.0
1413   InstructionFoldingCase<bool>(
1414       Header() + "%main = OpFunction %void None %void_func\n" +
1415           "%main_lab = OpLabel\n" +
1416           "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
1417           "OpReturn\n" +
1418           "OpFunctionEnd",
1419       2, true)
1420 ));
1421
1422 INSTANTIATE_TEST_CASE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1423                         ::testing::Values(
1424   // Test case 0: fold NaN == 0 (ord)
1425   InstructionFoldingCase<bool>(
1426       Header() + "%main = OpFunction %void None %void_func\n" +
1427           "%main_lab = OpLabel\n" +
1428           "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
1429           "OpReturn\n" +
1430           "OpFunctionEnd",
1431       2, false),
1432   // Test case 1: fold NaN == NaN (unord)
1433   InstructionFoldingCase<bool>(
1434       Header() + "%main = OpFunction %void None %void_func\n" +
1435           "%main_lab = OpLabel\n" +
1436           "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
1437           "OpReturn\n" +
1438           "OpFunctionEnd",
1439       2, true),
1440   // Test case 2: fold NaN != NaN (ord)
1441   InstructionFoldingCase<bool>(
1442       Header() + "%main = OpFunction %void None %void_func\n" +
1443           "%main_lab = OpLabel\n" +
1444           "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
1445           "OpReturn\n" +
1446           "OpFunctionEnd",
1447       2, false),
1448   // Test case 3: fold NaN != NaN (unord)
1449   InstructionFoldingCase<bool>(
1450       Header() + "%main = OpFunction %void None %void_func\n" +
1451           "%main_lab = OpLabel\n" +
1452           "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
1453           "OpReturn\n" +
1454           "OpFunctionEnd",
1455       2, true)
1456 ));
1457
1458 INSTANTIATE_TEST_CASE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
1459                         ::testing::Values(
1460   // Test case 0: fold NaN == 0 (ord)
1461   InstructionFoldingCase<bool>(
1462       Header() + "%main = OpFunction %void None %void_func\n" +
1463           "%main_lab = OpLabel\n" +
1464           "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
1465           "OpReturn\n" +
1466           "OpFunctionEnd",
1467       2, false),
1468   // Test case 1: fold NaN == NaN (unord)
1469   InstructionFoldingCase<bool>(
1470       Header() + "%main = OpFunction %void None %void_func\n" +
1471           "%main_lab = OpLabel\n" +
1472           "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
1473           "OpReturn\n" +
1474           "OpFunctionEnd",
1475       2, true),
1476   // Test case 2: fold NaN != NaN (ord)
1477   InstructionFoldingCase<bool>(
1478       Header() + "%main = OpFunction %void None %void_func\n" +
1479           "%main_lab = OpLabel\n" +
1480           "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
1481           "OpReturn\n" +
1482           "OpFunctionEnd",
1483       2, false),
1484   // Test case 3: fold NaN != NaN (unord)
1485   InstructionFoldingCase<bool>(
1486       Header() + "%main = OpFunction %void None %void_func\n" +
1487           "%main_lab = OpLabel\n" +
1488           "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
1489           "OpReturn\n" +
1490           "OpFunctionEnd",
1491       2, true)
1492 ));
1493 // clang-format on
1494
1495 template <class ResultType>
1496 struct InstructionFoldingCaseWithMap {
1497   InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
1498                                 ResultType result,
1499                                 std::function<uint32_t(uint32_t)> map)
1500       : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
1501
1502   std::string test_body;
1503   uint32_t id_to_fold;
1504   ResultType expected_result;
1505   std::function<uint32_t(uint32_t)> id_map;
1506 };
1507
1508 using IntegerInstructionFoldingTestWithMap =
1509     ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
1510
1511 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
1512   const auto& tc = GetParam();
1513
1514   // Build module.
1515   std::unique_ptr<ir::IRContext> context =
1516       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1517                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1518   ASSERT_NE(nullptr, context);
1519
1520   // Fold the instruction to test.
1521   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1522   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1523   inst = opt::FoldInstructionToConstant(inst, tc.id_map);
1524
1525   // Make sure the instruction folded as expected.
1526   EXPECT_NE(inst, nullptr);
1527   if (inst != nullptr) {
1528     EXPECT_EQ(inst->opcode(), SpvOpConstant);
1529     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1530     const opt::analysis::IntConstant* result =
1531         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
1532     EXPECT_NE(result, nullptr);
1533     if (result != nullptr) {
1534       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
1535     }
1536   }
1537 }
1538 // clang-format off
1539 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap,
1540   ::testing::Values(
1541       // Test case 0: fold %3 = 0; %3 * n
1542       InstructionFoldingCaseWithMap<uint32_t>(
1543           Header() + "%main = OpFunction %void None %void_func\n" +
1544               "%main_lab = OpLabel\n" +
1545               "%n = OpVariable %_ptr_int Function\n" +
1546               "%load = OpLoad %int %n\n" +
1547               "%3 = OpCopyObject %int %int_0\n"
1548               "%2 = OpIMul %int %3 %load\n" +
1549               "OpReturn\n" +
1550               "OpFunctionEnd",
1551           2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
1552   ));
1553 // clang-format on
1554
1555 using BooleanInstructionFoldingTestWithMap =
1556     ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
1557
1558 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
1559   const auto& tc = GetParam();
1560
1561   // Build module.
1562   std::unique_ptr<ir::IRContext> context =
1563       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1564                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1565   ASSERT_NE(nullptr, context);
1566
1567   // Fold the instruction to test.
1568   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1569   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1570   inst = opt::FoldInstructionToConstant(inst, tc.id_map);
1571
1572   // Make sure the instruction folded as expected.
1573   EXPECT_NE(inst, nullptr);
1574   if (inst != nullptr) {
1575     std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
1576     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
1577     opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1578     const opt::analysis::BoolConstant* result =
1579         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
1580     EXPECT_NE(result, nullptr);
1581     if (result != nullptr) {
1582       EXPECT_EQ(result->value(), tc.expected_result);
1583     }
1584   }
1585 }
1586
1587 // clang-format off
1588 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap,
1589   ::testing::Values(
1590       // Test case 0: fold %3 = true; %3 || n
1591       InstructionFoldingCaseWithMap<bool>(
1592           Header() + "%main = OpFunction %void None %void_func\n" +
1593               "%main_lab = OpLabel\n" +
1594               "%n = OpVariable %_ptr_bool Function\n" +
1595               "%load = OpLoad %bool %n\n" +
1596               "%3 = OpCopyObject %bool %true\n" +
1597               "%2 = OpLogicalOr %bool %3 %load\n" +
1598               "OpReturn\n" +
1599               "OpFunctionEnd",
1600           2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
1601   ));
1602 // clang-format on
1603
1604 using GeneralInstructionFoldingTest =
1605     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
1606
1607 TEST_P(GeneralInstructionFoldingTest, Case) {
1608   const auto& tc = GetParam();
1609
1610   // Build module.
1611   std::unique_ptr<ir::IRContext> context =
1612       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1613                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1614   ASSERT_NE(nullptr, context);
1615
1616   // Fold the instruction to test.
1617   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1618   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1619   std::unique_ptr<ir::Instruction> original_inst(inst->Clone(context.get()));
1620   bool succeeded = opt::FoldInstruction(inst);
1621
1622   // Make sure the instruction folded as expected.
1623   EXPECT_EQ(inst->result_id(), original_inst->result_id());
1624   EXPECT_EQ(inst->type_id(), original_inst->type_id());
1625   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
1626   if (succeeded) {
1627     EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1628     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
1629   } else {
1630     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
1631     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
1632       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
1633     }
1634   }
1635 }
1636
1637 // clang-format off
1638 INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
1639                         ::testing::Values(
1640     // Test case 0: Don't fold n * m
1641     InstructionFoldingCase<uint32_t>(
1642         Header() + "%main = OpFunction %void None %void_func\n" +
1643             "%main_lab = OpLabel\n" +
1644             "%n = OpVariable %_ptr_int Function\n" +
1645             "%m = OpVariable %_ptr_int Function\n" +
1646             "%load_n = OpLoad %int %n\n" +
1647             "%load_m = OpLoad %int %m\n" +
1648             "%2 = OpIMul %int %load_n %load_m\n" +
1649             "OpReturn\n" +
1650             "OpFunctionEnd",
1651         2, 0),
1652     // Test case 1: Don't fold n / m (unsigned)
1653     InstructionFoldingCase<uint32_t>(
1654         Header() + "%main = OpFunction %void None %void_func\n" +
1655             "%main_lab = OpLabel\n" +
1656             "%n = OpVariable %_ptr_uint Function\n" +
1657             "%m = OpVariable %_ptr_uint Function\n" +
1658             "%load_n = OpLoad %uint %n\n" +
1659             "%load_m = OpLoad %uint %m\n" +
1660             "%2 = OpUDiv %uint %load_n %load_m\n" +
1661             "OpReturn\n" +
1662             "OpFunctionEnd",
1663         2, 0),
1664     // Test case 2: Don't fold n / m (signed)
1665     InstructionFoldingCase<uint32_t>(
1666         Header() + "%main = OpFunction %void None %void_func\n" +
1667             "%main_lab = OpLabel\n" +
1668             "%n = OpVariable %_ptr_int Function\n" +
1669             "%m = OpVariable %_ptr_int Function\n" +
1670             "%load_n = OpLoad %int %n\n" +
1671             "%load_m = OpLoad %int %m\n" +
1672             "%2 = OpSDiv %int %load_n %load_m\n" +
1673             "OpReturn\n" +
1674             "OpFunctionEnd",
1675         2, 0),
1676     // Test case 3: Don't fold n remainder m
1677     InstructionFoldingCase<uint32_t>(
1678         Header() + "%main = OpFunction %void None %void_func\n" +
1679             "%main_lab = OpLabel\n" +
1680             "%n = OpVariable %_ptr_int Function\n" +
1681             "%m = OpVariable %_ptr_int Function\n" +
1682             "%load_n = OpLoad %int %n\n" +
1683             "%load_m = OpLoad %int %m\n" +
1684             "%2 = OpSRem %int %load_n %load_m\n" +
1685             "OpReturn\n" +
1686             "OpFunctionEnd",
1687         2, 0),
1688     // Test case 4: Don't fold n % m (signed)
1689     InstructionFoldingCase<uint32_t>(
1690         Header() + "%main = OpFunction %void None %void_func\n" +
1691             "%main_lab = OpLabel\n" +
1692             "%n = OpVariable %_ptr_int Function\n" +
1693             "%m = OpVariable %_ptr_int Function\n" +
1694             "%load_n = OpLoad %int %n\n" +
1695             "%load_m = OpLoad %int %m\n" +
1696             "%2 = OpSMod %int %load_n %load_m\n" +
1697             "OpReturn\n" +
1698             "OpFunctionEnd",
1699         2, 0),
1700     // Test case 5: Don't fold n % m (unsigned)
1701     InstructionFoldingCase<uint32_t>(
1702         Header() + "%main = OpFunction %void None %void_func\n" +
1703             "%main_lab = OpLabel\n" +
1704             "%n = OpVariable %_ptr_uint Function\n" +
1705             "%m = OpVariable %_ptr_uint Function\n" +
1706             "%load_n = OpLoad %uint %n\n" +
1707             "%load_m = OpLoad %uint %m\n" +
1708             "%2 = OpUMod %int %load_n %load_m\n" +
1709             "OpReturn\n" +
1710             "OpFunctionEnd",
1711         2, 0),
1712     // Test case 6: Don't fold n << m
1713     InstructionFoldingCase<uint32_t>(
1714         Header() + "%main = OpFunction %void None %void_func\n" +
1715             "%main_lab = OpLabel\n" +
1716             "%n = OpVariable %_ptr_uint Function\n" +
1717             "%m = OpVariable %_ptr_uint Function\n" +
1718             "%load_n = OpLoad %uint %n\n" +
1719             "%load_m = OpLoad %uint %m\n" +
1720             "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
1721             "OpReturn\n" +
1722             "OpFunctionEnd",
1723         2, 0),
1724     // Test case 7: Don't fold n >> m
1725     InstructionFoldingCase<uint32_t>(
1726         Header() + "%main = OpFunction %void None %void_func\n" +
1727             "%main_lab = OpLabel\n" +
1728             "%n = OpVariable %_ptr_uint Function\n" +
1729             "%m = OpVariable %_ptr_uint Function\n" +
1730             "%load_n = OpLoad %uint %n\n" +
1731             "%load_m = OpLoad %uint %m\n" +
1732             "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
1733             "OpReturn\n" +
1734             "OpFunctionEnd",
1735         2, 0),
1736     // Test case 8: Don't fold n | m
1737     InstructionFoldingCase<uint32_t>(
1738         Header() + "%main = OpFunction %void None %void_func\n" +
1739             "%main_lab = OpLabel\n" +
1740             "%n = OpVariable %_ptr_uint Function\n" +
1741             "%m = OpVariable %_ptr_uint Function\n" +
1742             "%load_n = OpLoad %uint %n\n" +
1743             "%load_m = OpLoad %uint %m\n" +
1744             "%2 = OpBitwiseOr %int %load_n %load_m\n" +
1745             "OpReturn\n" +
1746             "OpFunctionEnd",
1747         2, 0),
1748     // Test case 9: Don't fold n & m
1749     InstructionFoldingCase<uint32_t>(
1750         Header() + "%main = OpFunction %void None %void_func\n" +
1751             "%main_lab = OpLabel\n" +
1752             "%n = OpVariable %_ptr_uint Function\n" +
1753             "%m = OpVariable %_ptr_uint Function\n" +
1754             "%load_n = OpLoad %uint %n\n" +
1755             "%load_m = OpLoad %uint %m\n" +
1756             "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
1757             "OpReturn\n" +
1758             "OpFunctionEnd",
1759         2, 0),
1760     // Test case 10: Don't fold n < m (unsigned)
1761     InstructionFoldingCase<uint32_t>(
1762         Header() + "%main = OpFunction %void None %void_func\n" +
1763             "%main_lab = OpLabel\n" +
1764             "%n = OpVariable %_ptr_uint Function\n" +
1765             "%m = OpVariable %_ptr_uint Function\n" +
1766             "%load_n = OpLoad %uint %n\n" +
1767             "%load_m = OpLoad %uint %m\n" +
1768             "%2 = OpULessThan %bool %load_n %load_m\n" +
1769             "OpReturn\n" +
1770             "OpFunctionEnd",
1771         2, 0),
1772     // Test case 11: Don't fold n > m (unsigned)
1773     InstructionFoldingCase<uint32_t>(
1774         Header() + "%main = OpFunction %void None %void_func\n" +
1775             "%main_lab = OpLabel\n" +
1776             "%n = OpVariable %_ptr_uint Function\n" +
1777             "%m = OpVariable %_ptr_uint Function\n" +
1778             "%load_n = OpLoad %uint %n\n" +
1779             "%load_m = OpLoad %uint %m\n" +
1780             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1781             "OpReturn\n" +
1782             "OpFunctionEnd",
1783         2, 0),
1784     // Test case 12: Don't fold n <= m (unsigned)
1785     InstructionFoldingCase<uint32_t>(
1786         Header() + "%main = OpFunction %void None %void_func\n" +
1787             "%main_lab = OpLabel\n" +
1788             "%n = OpVariable %_ptr_uint Function\n" +
1789             "%m = OpVariable %_ptr_uint Function\n" +
1790             "%load_n = OpLoad %uint %n\n" +
1791             "%load_m = OpLoad %uint %m\n" +
1792             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1793             "OpReturn\n" +
1794             "OpFunctionEnd",
1795         2, 0),
1796     // Test case 13: Don't fold n >= m (unsigned)
1797     InstructionFoldingCase<uint32_t>(
1798         Header() + "%main = OpFunction %void None %void_func\n" +
1799             "%main_lab = OpLabel\n" +
1800             "%n = OpVariable %_ptr_uint Function\n" +
1801             "%m = OpVariable %_ptr_uint Function\n" +
1802             "%load_n = OpLoad %uint %n\n" +
1803             "%load_m = OpLoad %uint %m\n" +
1804             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1805             "OpReturn\n" +
1806             "OpFunctionEnd",
1807         2, 0),
1808     // Test case 14: Don't fold n < m (signed)
1809     InstructionFoldingCase<uint32_t>(
1810         Header() + "%main = OpFunction %void None %void_func\n" +
1811             "%main_lab = OpLabel\n" +
1812             "%n = OpVariable %_ptr_int Function\n" +
1813             "%m = OpVariable %_ptr_int Function\n" +
1814             "%load_n = OpLoad %int %n\n" +
1815             "%load_m = OpLoad %int %m\n" +
1816             "%2 = OpULessThan %bool %load_n %load_m\n" +
1817             "OpReturn\n" +
1818             "OpFunctionEnd",
1819         2, 0),
1820     // Test case 15: Don't fold n > m (signed)
1821     InstructionFoldingCase<uint32_t>(
1822         Header() + "%main = OpFunction %void None %void_func\n" +
1823             "%main_lab = OpLabel\n" +
1824             "%n = OpVariable %_ptr_int Function\n" +
1825             "%m = OpVariable %_ptr_int Function\n" +
1826             "%load_n = OpLoad %int %n\n" +
1827             "%load_m = OpLoad %int %m\n" +
1828             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1829             "OpReturn\n" +
1830             "OpFunctionEnd",
1831         2, 0),
1832     // Test case 16: Don't fold n <= m (signed)
1833     InstructionFoldingCase<uint32_t>(
1834         Header() + "%main = OpFunction %void None %void_func\n" +
1835             "%main_lab = OpLabel\n" +
1836             "%n = OpVariable %_ptr_int Function\n" +
1837             "%m = OpVariable %_ptr_int Function\n" +
1838             "%load_n = OpLoad %int %n\n" +
1839             "%load_m = OpLoad %int %m\n" +
1840             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1841             "OpReturn\n" +
1842             "OpFunctionEnd",
1843         2, 0),
1844     // Test case 17: Don't fold n >= m (signed)
1845     InstructionFoldingCase<uint32_t>(
1846         Header() + "%main = OpFunction %void None %void_func\n" +
1847             "%main_lab = OpLabel\n" +
1848             "%n = OpVariable %_ptr_int Function\n" +
1849             "%m = OpVariable %_ptr_int Function\n" +
1850             "%load_n = OpLoad %int %n\n" +
1851             "%load_m = OpLoad %int %m\n" +
1852             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1853             "OpReturn\n" +
1854             "OpFunctionEnd",
1855         2, 0),
1856     // Test case 18: Don't fold n || m
1857     InstructionFoldingCase<uint32_t>(
1858         Header() + "%main = OpFunction %void None %void_func\n" +
1859             "%main_lab = OpLabel\n" +
1860             "%n = OpVariable %_ptr_bool Function\n" +
1861             "%m = OpVariable %_ptr_bool Function\n" +
1862             "%load_n = OpLoad %bool %n\n" +
1863             "%load_m = OpLoad %bool %m\n" +
1864             "%2 = OpLogicalOr %bool %load_n %load_m\n" +
1865             "OpReturn\n" +
1866             "OpFunctionEnd",
1867         2, 0),
1868     // Test case 19: Don't fold n && m
1869     InstructionFoldingCase<uint32_t>(
1870         Header() + "%main = OpFunction %void None %void_func\n" +
1871             "%main_lab = OpLabel\n" +
1872             "%n = OpVariable %_ptr_bool Function\n" +
1873             "%m = OpVariable %_ptr_bool Function\n" +
1874             "%load_n = OpLoad %bool %n\n" +
1875             "%load_m = OpLoad %bool %m\n" +
1876             "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
1877             "OpReturn\n" +
1878             "OpFunctionEnd",
1879         2, 0),
1880     // Test case 20: Don't fold n * 3
1881     InstructionFoldingCase<uint32_t>(
1882         Header() + "%main = OpFunction %void None %void_func\n" +
1883             "%main_lab = OpLabel\n" +
1884             "%n = OpVariable %_ptr_int Function\n" +
1885             "%load_n = OpLoad %int %n\n" +
1886             "%2 = OpIMul %int %load_n %int_3\n" +
1887             "OpReturn\n" +
1888             "OpFunctionEnd",
1889         2, 0),
1890     // Test case 21: Don't fold n / 3 (unsigned)
1891     InstructionFoldingCase<uint32_t>(
1892         Header() + "%main = OpFunction %void None %void_func\n" +
1893             "%main_lab = OpLabel\n" +
1894             "%n = OpVariable %_ptr_uint Function\n" +
1895             "%load_n = OpLoad %uint %n\n" +
1896             "%2 = OpUDiv %uint %load_n %uint_3\n" +
1897             "OpReturn\n" +
1898             "OpFunctionEnd",
1899         2, 0),
1900     // Test case 22: Don't fold n / 3 (signed)
1901     InstructionFoldingCase<uint32_t>(
1902         Header() + "%main = OpFunction %void None %void_func\n" +
1903             "%main_lab = OpLabel\n" +
1904             "%n = OpVariable %_ptr_int Function\n" +
1905             "%load_n = OpLoad %int %n\n" +
1906             "%2 = OpSDiv %int %load_n %int_3\n" +
1907             "OpReturn\n" +
1908             "OpFunctionEnd",
1909         2, 0),
1910     // Test case 23: Don't fold n remainder 3
1911     InstructionFoldingCase<uint32_t>(
1912         Header() + "%main = OpFunction %void None %void_func\n" +
1913             "%main_lab = OpLabel\n" +
1914             "%n = OpVariable %_ptr_int Function\n" +
1915             "%load_n = OpLoad %int %n\n" +
1916             "%2 = OpSRem %int %load_n %int_3\n" +
1917             "OpReturn\n" +
1918             "OpFunctionEnd",
1919         2, 0),
1920     // Test case 24: Don't fold n % 3 (signed)
1921     InstructionFoldingCase<uint32_t>(
1922         Header() + "%main = OpFunction %void None %void_func\n" +
1923             "%main_lab = OpLabel\n" +
1924             "%n = OpVariable %_ptr_int Function\n" +
1925             "%load_n = OpLoad %int %n\n" +
1926             "%2 = OpSMod %int %load_n %int_3\n" +
1927             "OpReturn\n" +
1928             "OpFunctionEnd",
1929         2, 0),
1930     // Test case 25: Don't fold n % 3 (unsigned)
1931     InstructionFoldingCase<uint32_t>(
1932         Header() + "%main = OpFunction %void None %void_func\n" +
1933             "%main_lab = OpLabel\n" +
1934             "%n = OpVariable %_ptr_uint Function\n" +
1935             "%load_n = OpLoad %uint %n\n" +
1936             "%2 = OpUMod %int %load_n %int_3\n" +
1937             "OpReturn\n" +
1938             "OpFunctionEnd",
1939         2, 0),
1940     // Test case 26: Don't fold n << 3
1941     InstructionFoldingCase<uint32_t>(
1942         Header() + "%main = OpFunction %void None %void_func\n" +
1943             "%main_lab = OpLabel\n" +
1944             "%n = OpVariable %_ptr_uint Function\n" +
1945             "%load_n = OpLoad %uint %n\n" +
1946             "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
1947             "OpReturn\n" +
1948             "OpFunctionEnd",
1949         2, 0),
1950     // Test case 27: Don't fold n >> 3
1951     InstructionFoldingCase<uint32_t>(
1952         Header() + "%main = OpFunction %void None %void_func\n" +
1953             "%main_lab = OpLabel\n" +
1954             "%n = OpVariable %_ptr_uint Function\n" +
1955             "%load_n = OpLoad %uint %n\n" +
1956             "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
1957             "OpReturn\n" +
1958             "OpFunctionEnd",
1959         2, 0),
1960     // Test case 28: Don't fold n | 3
1961     InstructionFoldingCase<uint32_t>(
1962         Header() + "%main = OpFunction %void None %void_func\n" +
1963             "%main_lab = OpLabel\n" +
1964             "%n = OpVariable %_ptr_uint Function\n" +
1965             "%load_n = OpLoad %uint %n\n" +
1966             "%2 = OpBitwiseOr %int %load_n %int_3\n" +
1967             "OpReturn\n" +
1968             "OpFunctionEnd",
1969         2, 0),
1970     // Test case 29: Don't fold n & 3
1971     InstructionFoldingCase<uint32_t>(
1972         Header() + "%main = OpFunction %void None %void_func\n" +
1973             "%main_lab = OpLabel\n" +
1974             "%n = OpVariable %_ptr_uint Function\n" +
1975             "%load_n = OpLoad %uint %n\n" +
1976             "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
1977             "OpReturn\n" +
1978             "OpFunctionEnd",
1979         2, 0),
1980     // Test case 30: Don't fold n < 3 (unsigned)
1981     InstructionFoldingCase<uint32_t>(
1982         Header() + "%main = OpFunction %void None %void_func\n" +
1983             "%main_lab = OpLabel\n" +
1984             "%n = OpVariable %_ptr_uint Function\n" +
1985             "%load_n = OpLoad %uint %n\n" +
1986             "%2 = OpULessThan %bool %load_n %uint_3\n" +
1987             "OpReturn\n" +
1988             "OpFunctionEnd",
1989         2, 0),
1990     // Test case 31: Don't fold n > 3 (unsigned)
1991     InstructionFoldingCase<uint32_t>(
1992         Header() + "%main = OpFunction %void None %void_func\n" +
1993             "%main_lab = OpLabel\n" +
1994             "%n = OpVariable %_ptr_uint Function\n" +
1995             "%load_n = OpLoad %uint %n\n" +
1996             "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
1997             "OpReturn\n" +
1998             "OpFunctionEnd",
1999         2, 0),
2000     // Test case 32: Don't fold n <= 3 (unsigned)
2001     InstructionFoldingCase<uint32_t>(
2002         Header() + "%main = OpFunction %void None %void_func\n" +
2003             "%main_lab = OpLabel\n" +
2004             "%n = OpVariable %_ptr_uint Function\n" +
2005             "%load_n = OpLoad %uint %n\n" +
2006             "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
2007             "OpReturn\n" +
2008             "OpFunctionEnd",
2009         2, 0),
2010     // Test case 33: Don't fold n >= 3 (unsigned)
2011     InstructionFoldingCase<uint32_t>(
2012         Header() + "%main = OpFunction %void None %void_func\n" +
2013             "%main_lab = OpLabel\n" +
2014             "%n = OpVariable %_ptr_uint Function\n" +
2015             "%load_n = OpLoad %uint %n\n" +
2016             "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
2017             "OpReturn\n" +
2018             "OpFunctionEnd",
2019         2, 0),
2020     // Test case 34: Don't fold n < 3 (signed)
2021     InstructionFoldingCase<uint32_t>(
2022         Header() + "%main = OpFunction %void None %void_func\n" +
2023             "%main_lab = OpLabel\n" +
2024             "%n = OpVariable %_ptr_int Function\n" +
2025             "%load_n = OpLoad %int %n\n" +
2026             "%2 = OpULessThan %bool %load_n %int_3\n" +
2027             "OpReturn\n" +
2028             "OpFunctionEnd",
2029         2, 0),
2030     // Test case 35: Don't fold n > 3 (signed)
2031     InstructionFoldingCase<uint32_t>(
2032         Header() + "%main = OpFunction %void None %void_func\n" +
2033             "%main_lab = OpLabel\n" +
2034             "%n = OpVariable %_ptr_int Function\n" +
2035             "%load_n = OpLoad %int %n\n" +
2036             "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
2037             "OpReturn\n" +
2038             "OpFunctionEnd",
2039         2, 0),
2040     // Test case 36: Don't fold n <= 3 (signed)
2041     InstructionFoldingCase<uint32_t>(
2042         Header() + "%main = OpFunction %void None %void_func\n" +
2043             "%main_lab = OpLabel\n" +
2044             "%n = OpVariable %_ptr_int Function\n" +
2045             "%load_n = OpLoad %int %n\n" +
2046             "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
2047             "OpReturn\n" +
2048             "OpFunctionEnd",
2049         2, 0),
2050     // Test case 37: Don't fold n >= 3 (signed)
2051     InstructionFoldingCase<uint32_t>(
2052         Header() + "%main = OpFunction %void None %void_func\n" +
2053             "%main_lab = OpLabel\n" +
2054             "%n = OpVariable %_ptr_int Function\n" +
2055             "%load_n = OpLoad %int %n\n" +
2056             "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
2057             "OpReturn\n" +
2058             "OpFunctionEnd",
2059         2, 0),
2060     // Test case 38: Don't fold 0 + 3 (long), bad length
2061     InstructionFoldingCase<uint32_t>(
2062         Header() + "%main = OpFunction %void None %void_func\n" +
2063             "%main_lab = OpLabel\n" +
2064             "%2 = OpIAdd %long %long_0 %long_3\n" +
2065             "OpReturn\n" +
2066             "OpFunctionEnd",
2067         2, 0),
2068     // Test case 39: Don't fold 0 + 3 (short), bad length
2069     InstructionFoldingCase<uint32_t>(
2070         Header() + "%main = OpFunction %void None %void_func\n" +
2071             "%main_lab = OpLabel\n" +
2072             "%2 = OpIAdd %short %short_0 %short_3\n" +
2073             "OpReturn\n" +
2074             "OpFunctionEnd",
2075         2, 0),
2076     // Test case 40: fold 1*n
2077     InstructionFoldingCase<uint32_t>(
2078         Header() + "%main = OpFunction %void None %void_func\n" +
2079             "%main_lab = OpLabel\n" +
2080             "%n = OpVariable %_ptr_int Function\n" +
2081             "%3 = OpLoad %int %n\n" +
2082             "%2 = OpIMul %int %int_1 %3\n" +
2083             "OpReturn\n" +
2084             "OpFunctionEnd",
2085         2, 3),
2086     // Test case 41: fold n*1
2087     InstructionFoldingCase<uint32_t>(
2088         Header() + "%main = OpFunction %void None %void_func\n" +
2089             "%main_lab = OpLabel\n" +
2090             "%n = OpVariable %_ptr_int Function\n" +
2091             "%3 = OpLoad %int %n\n" +
2092             "%2 = OpIMul %int %3 %int_1\n" +
2093             "OpReturn\n" +
2094             "OpFunctionEnd",
2095         2, 3)
2096 ));
2097
2098 INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
2099 ::testing::Values(
2100     // Test case 0: fold Insert feeding extract
2101     InstructionFoldingCase<uint32_t>(
2102         Header() + "%main = OpFunction %void None %void_func\n" +
2103             "%main_lab = OpLabel\n" +
2104             "%n = OpVariable %_ptr_int Function\n" +
2105             "%2 = OpLoad %int %n\n" +
2106             "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
2107             "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
2108             "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
2109             "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
2110             "%7 = OpCompositeExtract %int %6 0\n" +
2111             "OpReturn\n" +
2112             "OpFunctionEnd",
2113         7, 2),
2114     // Test case 1: fold Composite construct feeding extract (position 0)
2115     InstructionFoldingCase<uint32_t>(
2116         Header() + "%main = OpFunction %void None %void_func\n" +
2117             "%main_lab = OpLabel\n" +
2118             "%n = OpVariable %_ptr_int Function\n" +
2119             "%2 = OpLoad %int %n\n" +
2120             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
2121             "%4 = OpCompositeExtract %int %3 0\n" +
2122             "OpReturn\n" +
2123             "OpFunctionEnd",
2124         4, 2),
2125     // Test case 2: fold Composite construct feeding extract (position 3)
2126     InstructionFoldingCase<uint32_t>(
2127         Header() + "%main = OpFunction %void None %void_func\n" +
2128             "%main_lab = OpLabel\n" +
2129             "%n = OpVariable %_ptr_int Function\n" +
2130             "%2 = OpLoad %int %n\n" +
2131             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
2132             "%4 = OpCompositeExtract %int %3 3\n" +
2133             "OpReturn\n" +
2134             "OpFunctionEnd",
2135         4, INT_0_ID),
2136     // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
2137     InstructionFoldingCase<uint32_t>(
2138         Header() + "%main = OpFunction %void None %void_func\n" +
2139             "%main_lab = OpLabel\n" +
2140             "%n = OpVariable %_ptr_int Function\n" +
2141             "%2 = OpLoad %int %n\n" +
2142             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
2143             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2144             "%5 = OpCompositeExtract %int %4 3\n" +
2145             "OpReturn\n" +
2146             "OpFunctionEnd",
2147         5, INT_0_ID),
2148     // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
2149     InstructionFoldingCase<uint32_t>(
2150         Header() + "%main = OpFunction %void None %void_func\n" +
2151             "%main_lab = OpLabel\n" +
2152             "%n = OpVariable %_ptr_int Function\n" +
2153             "%2 = OpLoad %int %n\n" +
2154             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
2155             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2156             "%5 = OpCompositeExtract %int %4 0\n" +
2157             "OpReturn\n" +
2158             "OpFunctionEnd",
2159         5, 2),
2160     // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
2161     InstructionFoldingCase<uint32_t>(
2162         Header() + "%main = OpFunction %void None %void_func\n" +
2163             "%main_lab = OpLabel\n" +
2164             "%n = OpVariable %_ptr_int Function\n" +
2165             "%2 = OpLoad %int %n\n" +
2166             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
2167             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
2168             "%5 = OpCompositeExtract %int %4 1\n" +
2169             "OpReturn\n" +
2170             "OpFunctionEnd",
2171         5, 2),
2172     // Test case 6: fold Composite construct with multiple indices.
2173     InstructionFoldingCase<uint32_t>(
2174         Header() + "%main = OpFunction %void None %void_func\n" +
2175             "%main_lab = OpLabel\n" +
2176             "%n = OpVariable %_ptr_int Function\n" +
2177             "%2 = OpLoad %int %n\n" +
2178             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
2179             "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
2180             "%5 = OpCompositeExtract %int %4 0 1\n" +
2181             "OpReturn\n" +
2182             "OpFunctionEnd",
2183         5, 2),
2184     // Test case 7: fold constant extract.
2185     InstructionFoldingCase<uint32_t>(
2186         Header() + "%main = OpFunction %void None %void_func\n" +
2187             "%main_lab = OpLabel\n" +
2188             "%2 = OpCompositeExtract %int %102 1\n" +
2189             "OpReturn\n" +
2190             "OpFunctionEnd",
2191         2, INT_7_ID),
2192     // Test case 8: constant struct has OpUndef
2193     InstructionFoldingCase<uint32_t>(
2194         Header() + "%main = OpFunction %void None %void_func\n" +
2195             "%main_lab = OpLabel\n" +
2196             "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
2197             "OpReturn\n" +
2198             "OpFunctionEnd",
2199         2, 0),
2200     // Test case 9: Extracting a member of element inserted via Insert
2201     InstructionFoldingCase<uint32_t>(
2202         Header() + "%main = OpFunction %void None %void_func\n" +
2203             "%main_lab = OpLabel\n" +
2204             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
2205             "%2 = OpLoad %struct_v2int_int_int %n\n" +
2206             "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
2207             "%4 = OpCompositeExtract %int %3 0 1\n" +
2208             "OpReturn\n" +
2209             "OpFunctionEnd",
2210         4, 103),
2211     // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
2212     InstructionFoldingCase<uint32_t>(
2213         Header() + "%main = OpFunction %void None %void_func\n" +
2214             "%main_lab = OpLabel\n" +
2215             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
2216             "%2 = OpLoad %struct_v2int_int_int %n\n" +
2217             "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
2218             "%4 = OpCompositeExtract %v2int %3 0\n" +
2219             "OpReturn\n" +
2220             "OpFunctionEnd",
2221         4, 0),
2222     // Test case 11: Extracting from result of vector shuffle (first input)
2223     InstructionFoldingCase<uint32_t>(
2224         Header() + "%main = OpFunction %void None %void_func\n" +
2225             "%main_lab = OpLabel\n" +
2226             "%n = OpVariable %_ptr_v2int Function\n" +
2227             "%2 = OpLoad %v2int %n\n" +
2228             "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
2229             "%4 = OpCompositeExtract %int %3 1\n" +
2230             "OpReturn\n" +
2231             "OpFunctionEnd",
2232         4, INT_7_ID),
2233     // Test case 12: Extracting from result of vector shuffle (second input)
2234     InstructionFoldingCase<uint32_t>(
2235         Header() + "%main = OpFunction %void None %void_func\n" +
2236             "%main_lab = OpLabel\n" +
2237             "%n = OpVariable %_ptr_v2int Function\n" +
2238             "%2 = OpLoad %v2int %n\n" +
2239             "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
2240             "%4 = OpCompositeExtract %int %3 0\n" +
2241             "OpReturn\n" +
2242             "OpFunctionEnd",
2243         4, INT_7_ID)
2244 ));
2245
2246 INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
2247 ::testing::Values(
2248     // Test case 0: fold Extracts feeding construct
2249     InstructionFoldingCase<uint32_t>(
2250         Header() + "%main = OpFunction %void None %void_func\n" +
2251             "%main_lab = OpLabel\n" +
2252             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2253             "%3 = OpCompositeExtract %int %2 0\n" +
2254             "%4 = OpCompositeExtract %int %2 1\n" +
2255             "%5 = OpCompositeExtract %int %2 2\n" +
2256             "%6 = OpCompositeExtract %int %2 3\n" +
2257             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2258             "OpReturn\n" +
2259             "OpFunctionEnd",
2260         7, 2),
2261     // Test case 1: Don't fold Extracts feeding construct (Different source)
2262     InstructionFoldingCase<uint32_t>(
2263         Header() + "%main = OpFunction %void None %void_func\n" +
2264             "%main_lab = OpLabel\n" +
2265             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2266             "%3 = OpCompositeExtract %int %2 0\n" +
2267             "%4 = OpCompositeExtract %int %2 1\n" +
2268             "%5 = OpCompositeExtract %int %2 2\n" +
2269             "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
2270             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2271             "OpReturn\n" +
2272             "OpFunctionEnd",
2273         7, 0),
2274     // Test case 2: Don't fold Extracts feeding construct (bad indices)
2275     InstructionFoldingCase<uint32_t>(
2276         Header() + "%main = OpFunction %void None %void_func\n" +
2277             "%main_lab = OpLabel\n" +
2278             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
2279             "%3 = OpCompositeExtract %int %2 0\n" +
2280             "%4 = OpCompositeExtract %int %2 0\n" +
2281             "%5 = OpCompositeExtract %int %2 2\n" +
2282             "%6 = OpCompositeExtract %int %2 3\n" +
2283             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
2284             "OpReturn\n" +
2285             "OpFunctionEnd",
2286         7, 0),
2287     // Test case 3: Don't fold Extracts feeding construct (different type)
2288     InstructionFoldingCase<uint32_t>(
2289         Header() + "%main = OpFunction %void None %void_func\n" +
2290             "%main_lab = OpLabel\n" +
2291             "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
2292             "%3 = OpCompositeExtract %v2int %2 0\n" +
2293             "%4 = OpCompositeExtract %int %2 1\n" +
2294             "%5 = OpCompositeExtract %int %2 2\n" +
2295             "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
2296             "OpReturn\n" +
2297             "OpFunctionEnd",
2298         7, 0),
2299     // Test case 4: Fold construct with constants to constant.
2300     InstructionFoldingCase<uint32_t>(
2301         Header() + "%main = OpFunction %void None %void_func\n" +
2302             "%main_lab = OpLabel\n" +
2303             "%2 = OpCompositeConstruct %v2int %103 %103\n" +
2304             "OpReturn\n" +
2305             "OpFunctionEnd",
2306         2, VEC2_0_ID)
2307 ));
2308
2309 INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
2310 ::testing::Values(
2311   // Test case 0: Fold phi with the same values for all edges.
2312   InstructionFoldingCase<uint32_t>(
2313       Header() + "%main = OpFunction %void None %void_func\n" +
2314           "%main_lab = OpLabel\n" +
2315           "            OpBranchConditional %true %l1 %l2\n" +
2316           "%l1 = OpLabel\n" +
2317           "      OpBranch %merge_lab\n" +
2318           "%l2 = OpLabel\n" +
2319           "      OpBranch %merge_lab\n" +
2320           "%merge_lab = OpLabel\n" +
2321           "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
2322           "OpReturn\n" +
2323           "OpFunctionEnd",
2324       2, INT_0_ID),
2325   // Test case 1: Fold phi in pass through loop.
2326   InstructionFoldingCase<uint32_t>(
2327       Header() + "%main = OpFunction %void None %void_func\n" +
2328           "%main_lab = OpLabel\n" +
2329           "            OpBranch %l1\n" +
2330           "%l1 = OpLabel\n" +
2331           "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
2332           "      OpBranchConditional %true %l1 %merge_lab\n" +
2333           "%merge_lab = OpLabel\n" +
2334           "OpReturn\n" +
2335           "OpFunctionEnd",
2336       2, INT_0_ID),
2337   // Test case 2: Don't Fold phi because of different values.
2338   InstructionFoldingCase<uint32_t>(
2339       Header() + "%main = OpFunction %void None %void_func\n" +
2340           "%main_lab = OpLabel\n" +
2341           "            OpBranch %l1\n" +
2342           "%l1 = OpLabel\n" +
2343           "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
2344           "      OpBranchConditional %true %l1 %merge_lab\n" +
2345           "%merge_lab = OpLabel\n" +
2346           "OpReturn\n" +
2347           "OpFunctionEnd",
2348       2, 0)
2349 ));
2350
2351 INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
2352                         ::testing::Values(
2353     // Test case 0: Don't fold n + 1.0
2354     InstructionFoldingCase<uint32_t>(
2355         Header() + "%main = OpFunction %void None %void_func\n" +
2356             "%main_lab = OpLabel\n" +
2357             "%n = OpVariable %_ptr_float Function\n" +
2358             "%3 = OpLoad %float %n\n" +
2359             "%2 = OpFAdd %float %3 %float_2\n" +
2360             "OpReturn\n" +
2361             "OpFunctionEnd",
2362         2, 0),
2363     // Test case 1: Don't fold n - 1.0
2364     InstructionFoldingCase<uint32_t>(
2365         Header() + "%main = OpFunction %void None %void_func\n" +
2366             "%main_lab = OpLabel\n" +
2367             "%n = OpVariable %_ptr_float Function\n" +
2368             "%3 = OpLoad %float %n\n" +
2369             "%2 = OpFSub %float %3 %float_2\n" +
2370             "OpReturn\n" +
2371             "OpFunctionEnd",
2372         2, 0),
2373     // Test case 2: Don't fold n * 2.0
2374     InstructionFoldingCase<uint32_t>(
2375         Header() + "%main = OpFunction %void None %void_func\n" +
2376             "%main_lab = OpLabel\n" +
2377             "%n = OpVariable %_ptr_float Function\n" +
2378             "%3 = OpLoad %float %n\n" +
2379             "%2 = OpFMul %float %3 %float_2\n" +
2380             "OpReturn\n" +
2381             "OpFunctionEnd",
2382         2, 0),
2383     // Test case 3: Fold n + 0.0
2384     InstructionFoldingCase<uint32_t>(
2385         Header() + "%main = OpFunction %void None %void_func\n" +
2386             "%main_lab = OpLabel\n" +
2387             "%n = OpVariable %_ptr_float Function\n" +
2388             "%3 = OpLoad %float %n\n" +
2389             "%2 = OpFAdd %float %3 %float_0\n" +
2390             "OpReturn\n" +
2391             "OpFunctionEnd",
2392         2, 3),
2393     // Test case 4: Fold 0.0 + n
2394     InstructionFoldingCase<uint32_t>(
2395         Header() + "%main = OpFunction %void None %void_func\n" +
2396             "%main_lab = OpLabel\n" +
2397             "%n = OpVariable %_ptr_float Function\n" +
2398             "%3 = OpLoad %float %n\n" +
2399             "%2 = OpFAdd %float %float_0 %3\n" +
2400             "OpReturn\n" +
2401             "OpFunctionEnd",
2402         2, 3),
2403     // Test case 5: Fold n - 0.0
2404     InstructionFoldingCase<uint32_t>(
2405         Header() + "%main = OpFunction %void None %void_func\n" +
2406             "%main_lab = OpLabel\n" +
2407             "%n = OpVariable %_ptr_float Function\n" +
2408             "%3 = OpLoad %float %n\n" +
2409             "%2 = OpFSub %float %3 %float_0\n" +
2410             "OpReturn\n" +
2411             "OpFunctionEnd",
2412         2, 3),
2413     // Test case 6: Fold n * 1.0
2414     InstructionFoldingCase<uint32_t>(
2415         Header() + "%main = OpFunction %void None %void_func\n" +
2416             "%main_lab = OpLabel\n" +
2417             "%n = OpVariable %_ptr_float Function\n" +
2418             "%3 = OpLoad %float %n\n" +
2419             "%2 = OpFMul %float %3 %float_1\n" +
2420             "OpReturn\n" +
2421             "OpFunctionEnd",
2422         2, 3),
2423     // Test case 7: Fold 1.0 * n
2424     InstructionFoldingCase<uint32_t>(
2425         Header() + "%main = OpFunction %void None %void_func\n" +
2426             "%main_lab = OpLabel\n" +
2427             "%n = OpVariable %_ptr_float Function\n" +
2428             "%3 = OpLoad %float %n\n" +
2429             "%2 = OpFMul %float %float_1 %3\n" +
2430             "OpReturn\n" +
2431             "OpFunctionEnd",
2432         2, 3),
2433     // Test case 8: Fold n / 1.0
2434     InstructionFoldingCase<uint32_t>(
2435         Header() + "%main = OpFunction %void None %void_func\n" +
2436             "%main_lab = OpLabel\n" +
2437             "%n = OpVariable %_ptr_float Function\n" +
2438             "%3 = OpLoad %float %n\n" +
2439             "%2 = OpFDiv %float %3 %float_1\n" +
2440             "OpReturn\n" +
2441             "OpFunctionEnd",
2442         2, 3),
2443     // Test case 9: Fold n * 0.0
2444     InstructionFoldingCase<uint32_t>(
2445         Header() + "%main = OpFunction %void None %void_func\n" +
2446             "%main_lab = OpLabel\n" +
2447             "%n = OpVariable %_ptr_float Function\n" +
2448             "%3 = OpLoad %float %n\n" +
2449             "%2 = OpFMul %float %3 %104\n" +
2450             "OpReturn\n" +
2451             "OpFunctionEnd",
2452         2, FLOAT_0_ID),
2453     // Test case 10: Fold 0.0 * n
2454     InstructionFoldingCase<uint32_t>(
2455         Header() + "%main = OpFunction %void None %void_func\n" +
2456             "%main_lab = OpLabel\n" +
2457             "%n = OpVariable %_ptr_float Function\n" +
2458             "%3 = OpLoad %float %n\n" +
2459             "%2 = OpFMul %float %104 %3\n" +
2460             "OpReturn\n" +
2461             "OpFunctionEnd",
2462         2, FLOAT_0_ID),
2463     // Test case 11: Fold 0.0 / n
2464     InstructionFoldingCase<uint32_t>(
2465         Header() + "%main = OpFunction %void None %void_func\n" +
2466             "%main_lab = OpLabel\n" +
2467             "%n = OpVariable %_ptr_float Function\n" +
2468             "%3 = OpLoad %float %n\n" +
2469             "%2 = OpFDiv %float %104 %3\n" +
2470             "OpReturn\n" +
2471             "OpFunctionEnd",
2472         2, FLOAT_0_ID),
2473     // Test case 12: Don't fold mix(a, b, 2.0)
2474     InstructionFoldingCase<uint32_t>(
2475         Header() + "%main = OpFunction %void None %void_func\n" +
2476             "%main_lab = OpLabel\n" +
2477             "%a = OpVariable %_ptr_float Function\n" +
2478             "%b = OpVariable %_ptr_float Function\n" +
2479             "%3 = OpLoad %float %a\n" +
2480             "%4 = OpLoad %float %b\n" +
2481             "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
2482             "OpReturn\n" +
2483             "OpFunctionEnd",
2484         2, 0),
2485     // Test case 13: Fold mix(a, b, 0.0)
2486     InstructionFoldingCase<uint32_t>(
2487         Header() + "%main = OpFunction %void None %void_func\n" +
2488             "%main_lab = OpLabel\n" +
2489             "%a = OpVariable %_ptr_float Function\n" +
2490             "%b = OpVariable %_ptr_float Function\n" +
2491             "%3 = OpLoad %float %a\n" +
2492             "%4 = OpLoad %float %b\n" +
2493             "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
2494             "OpReturn\n" +
2495             "OpFunctionEnd",
2496         2, 3),
2497     // Test case 14: Fold mix(a, b, 1.0)
2498     InstructionFoldingCase<uint32_t>(
2499         Header() + "%main = OpFunction %void None %void_func\n" +
2500             "%main_lab = OpLabel\n" +
2501             "%a = OpVariable %_ptr_float Function\n" +
2502             "%b = OpVariable %_ptr_float Function\n" +
2503             "%3 = OpLoad %float %a\n" +
2504             "%4 = OpLoad %float %b\n" +
2505             "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
2506             "OpReturn\n" +
2507             "OpFunctionEnd",
2508         2, 4),
2509     // Test case 15: Fold vector fadd with null
2510     InstructionFoldingCase<uint32_t>(
2511         Header() + "%main = OpFunction %void None %void_func\n" +
2512             "%main_lab = OpLabel\n" +
2513             "%a = OpVariable %_ptr_v2float Function\n" +
2514             "%2 = OpLoad %v2float %a\n" +
2515             "%3 = OpFAdd %v2float %2 %v2float_null\n" +
2516             "OpReturn\n" +
2517             "OpFunctionEnd",
2518         3, 2),
2519     // Test case 16: Fold vector fadd with null
2520     InstructionFoldingCase<uint32_t>(
2521         Header() + "%main = OpFunction %void None %void_func\n" +
2522             "%main_lab = OpLabel\n" +
2523             "%a = OpVariable %_ptr_v2float Function\n" +
2524             "%2 = OpLoad %v2float %a\n" +
2525             "%3 = OpFAdd %v2float %v2float_null %2\n" +
2526             "OpReturn\n" +
2527             "OpFunctionEnd",
2528         3, 2),
2529     // Test case 15: Fold vector fsub with null
2530     InstructionFoldingCase<uint32_t>(
2531         Header() + "%main = OpFunction %void None %void_func\n" +
2532             "%main_lab = OpLabel\n" +
2533             "%a = OpVariable %_ptr_v2float Function\n" +
2534             "%2 = OpLoad %v2float %a\n" +
2535             "%3 = OpFSub %v2float %2 %v2float_null\n" +
2536             "OpReturn\n" +
2537             "OpFunctionEnd",
2538         3, 2),
2539     // Test case 16: Fold 0.0(half) * n
2540     InstructionFoldingCase<uint32_t>(
2541         Header() + "%main = OpFunction %void None %void_func\n" +
2542             "%main_lab = OpLabel\n" +
2543             "%n = OpVariable %_ptr_half Function\n" +
2544             "%3 = OpLoad %half %n\n" +
2545             "%2 = OpFMul %half %108 %3\n" +
2546             "OpReturn\n" +
2547             "OpFunctionEnd",
2548         2, HALF_0_ID),
2549     // Test case 17: Don't fold 1.0(half) * n
2550     InstructionFoldingCase<uint32_t>(
2551         Header() + "%main = OpFunction %void None %void_func\n" +
2552             "%main_lab = OpLabel\n" +
2553             "%n = OpVariable %_ptr_half Function\n" +
2554             "%3 = OpLoad %half %n\n" +
2555             "%2 = OpFMul %half %half_1 %3\n" +
2556             "OpReturn\n" +
2557             "OpFunctionEnd",
2558         2, 0),
2559     // Test case 18: Don't fold 1.0 * 1.0 (half)
2560     InstructionFoldingCase<uint32_t>(
2561         Header() + "%main = OpFunction %void None %void_func\n" +
2562             "%main_lab = OpLabel\n" +
2563             "%2 = OpFMul %half %half_1 %half_1\n" +
2564             "OpReturn\n" +
2565             "OpFunctionEnd",
2566         2, 0)
2567 ));
2568
2569 INSTANTIATE_TEST_CASE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
2570                         ::testing::Values(
2571     // Test case 0: Don't fold n + 1.0
2572     InstructionFoldingCase<uint32_t>(
2573         Header() + "%main = OpFunction %void None %void_func\n" +
2574             "%main_lab = OpLabel\n" +
2575             "%n = OpVariable %_ptr_double Function\n" +
2576             "%3 = OpLoad %double %n\n" +
2577             "%2 = OpFAdd %double %3 %double_2\n" +
2578             "OpReturn\n" +
2579             "OpFunctionEnd",
2580         2, 0),
2581     // Test case 1: Don't fold n - 1.0
2582     InstructionFoldingCase<uint32_t>(
2583         Header() + "%main = OpFunction %void None %void_func\n" +
2584             "%main_lab = OpLabel\n" +
2585             "%n = OpVariable %_ptr_double Function\n" +
2586             "%3 = OpLoad %double %n\n" +
2587             "%2 = OpFSub %double %3 %double_2\n" +
2588             "OpReturn\n" +
2589             "OpFunctionEnd",
2590         2, 0),
2591     // Test case 2: Don't fold n * 2.0
2592     InstructionFoldingCase<uint32_t>(
2593         Header() + "%main = OpFunction %void None %void_func\n" +
2594             "%main_lab = OpLabel\n" +
2595             "%n = OpVariable %_ptr_double Function\n" +
2596             "%3 = OpLoad %double %n\n" +
2597             "%2 = OpFMul %double %3 %double_2\n" +
2598             "OpReturn\n" +
2599             "OpFunctionEnd",
2600         2, 0),
2601     // Test case 3: Fold n + 0.0
2602     InstructionFoldingCase<uint32_t>(
2603         Header() + "%main = OpFunction %void None %void_func\n" +
2604             "%main_lab = OpLabel\n" +
2605             "%n = OpVariable %_ptr_double Function\n" +
2606             "%3 = OpLoad %double %n\n" +
2607             "%2 = OpFAdd %double %3 %double_0\n" +
2608             "OpReturn\n" +
2609             "OpFunctionEnd",
2610         2, 3),
2611     // Test case 4: Fold 0.0 + n
2612     InstructionFoldingCase<uint32_t>(
2613         Header() + "%main = OpFunction %void None %void_func\n" +
2614             "%main_lab = OpLabel\n" +
2615             "%n = OpVariable %_ptr_double Function\n" +
2616             "%3 = OpLoad %double %n\n" +
2617             "%2 = OpFAdd %double %double_0 %3\n" +
2618             "OpReturn\n" +
2619             "OpFunctionEnd",
2620         2, 3),
2621     // Test case 5: Fold n - 0.0
2622     InstructionFoldingCase<uint32_t>(
2623         Header() + "%main = OpFunction %void None %void_func\n" +
2624             "%main_lab = OpLabel\n" +
2625             "%n = OpVariable %_ptr_double Function\n" +
2626             "%3 = OpLoad %double %n\n" +
2627             "%2 = OpFSub %double %3 %double_0\n" +
2628             "OpReturn\n" +
2629             "OpFunctionEnd",
2630         2, 3),
2631     // Test case 6: Fold n * 1.0
2632     InstructionFoldingCase<uint32_t>(
2633         Header() + "%main = OpFunction %void None %void_func\n" +
2634             "%main_lab = OpLabel\n" +
2635             "%n = OpVariable %_ptr_double Function\n" +
2636             "%3 = OpLoad %double %n\n" +
2637             "%2 = OpFMul %double %3 %double_1\n" +
2638             "OpReturn\n" +
2639             "OpFunctionEnd",
2640         2, 3),
2641     // Test case 7: Fold 1.0 * n
2642     InstructionFoldingCase<uint32_t>(
2643         Header() + "%main = OpFunction %void None %void_func\n" +
2644             "%main_lab = OpLabel\n" +
2645             "%n = OpVariable %_ptr_double Function\n" +
2646             "%3 = OpLoad %double %n\n" +
2647             "%2 = OpFMul %double %double_1 %3\n" +
2648             "OpReturn\n" +
2649             "OpFunctionEnd",
2650         2, 3),
2651     // Test case 8: Fold n / 1.0
2652     InstructionFoldingCase<uint32_t>(
2653         Header() + "%main = OpFunction %void None %void_func\n" +
2654             "%main_lab = OpLabel\n" +
2655             "%n = OpVariable %_ptr_double Function\n" +
2656             "%3 = OpLoad %double %n\n" +
2657             "%2 = OpFDiv %double %3 %double_1\n" +
2658             "OpReturn\n" +
2659             "OpFunctionEnd",
2660         2, 3),
2661     // Test case 9: Fold n * 0.0
2662     InstructionFoldingCase<uint32_t>(
2663         Header() + "%main = OpFunction %void None %void_func\n" +
2664             "%main_lab = OpLabel\n" +
2665             "%n = OpVariable %_ptr_double Function\n" +
2666             "%3 = OpLoad %double %n\n" +
2667             "%2 = OpFMul %double %3 %105\n" +
2668             "OpReturn\n" +
2669             "OpFunctionEnd",
2670         2, DOUBLE_0_ID),
2671     // Test case 10: Fold 0.0 * n
2672     InstructionFoldingCase<uint32_t>(
2673         Header() + "%main = OpFunction %void None %void_func\n" +
2674             "%main_lab = OpLabel\n" +
2675             "%n = OpVariable %_ptr_double Function\n" +
2676             "%3 = OpLoad %double %n\n" +
2677             "%2 = OpFMul %double %105 %3\n" +
2678             "OpReturn\n" +
2679             "OpFunctionEnd",
2680         2, DOUBLE_0_ID),
2681     // Test case 11: Fold 0.0 / n
2682     InstructionFoldingCase<uint32_t>(
2683         Header() + "%main = OpFunction %void None %void_func\n" +
2684             "%main_lab = OpLabel\n" +
2685             "%n = OpVariable %_ptr_double Function\n" +
2686             "%3 = OpLoad %double %n\n" +
2687             "%2 = OpFDiv %double %105 %3\n" +
2688             "OpReturn\n" +
2689             "OpFunctionEnd",
2690         2, DOUBLE_0_ID),
2691     // Test case 12: Don't fold mix(a, b, 2.0)
2692     InstructionFoldingCase<uint32_t>(
2693         Header() + "%main = OpFunction %void None %void_func\n" +
2694             "%main_lab = OpLabel\n" +
2695             "%a = OpVariable %_ptr_double Function\n" +
2696             "%b = OpVariable %_ptr_double Function\n" +
2697             "%3 = OpLoad %double %a\n" +
2698             "%4 = OpLoad %double %b\n" +
2699             "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
2700             "OpReturn\n" +
2701             "OpFunctionEnd",
2702         2, 0),
2703     // Test case 13: Fold mix(a, b, 0.0)
2704     InstructionFoldingCase<uint32_t>(
2705         Header() + "%main = OpFunction %void None %void_func\n" +
2706             "%main_lab = OpLabel\n" +
2707             "%a = OpVariable %_ptr_double Function\n" +
2708             "%b = OpVariable %_ptr_double Function\n" +
2709             "%3 = OpLoad %double %a\n" +
2710             "%4 = OpLoad %double %b\n" +
2711             "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
2712             "OpReturn\n" +
2713             "OpFunctionEnd",
2714         2, 3),
2715     // Test case 14: Fold mix(a, b, 1.0)
2716     InstructionFoldingCase<uint32_t>(
2717         Header() + "%main = OpFunction %void None %void_func\n" +
2718             "%main_lab = OpLabel\n" +
2719             "%a = OpVariable %_ptr_double Function\n" +
2720             "%b = OpVariable %_ptr_double Function\n" +
2721             "%3 = OpLoad %double %a\n" +
2722             "%4 = OpLoad %double %b\n" +
2723             "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
2724             "OpReturn\n" +
2725             "OpFunctionEnd",
2726         2, 4)
2727 ));
2728
2729 INSTANTIATE_TEST_CASE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
2730                         ::testing::Values(
2731     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
2732     InstructionFoldingCase<uint32_t>(
2733         Header() + "%main = OpFunction %void None %void_func\n" +
2734             "%main_lab = OpLabel\n" +
2735             "%n = OpVariable %_ptr_v4float Function\n" +
2736             "%3 = OpLoad %v4float %n\n" +
2737             "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
2738             "OpReturn\n" +
2739             "OpFunctionEnd",
2740         2, 0),
2741     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
2742     InstructionFoldingCase<uint32_t>(
2743         Header() + "%main = OpFunction %void None %void_func\n" +
2744             "%main_lab = OpLabel\n" +
2745             "%n = OpVariable %_ptr_v4float Function\n" +
2746             "%3 = OpLoad %v4float %n\n" +
2747             "%2 = OpFMul %v4float %3 %106\n" +
2748             "OpReturn\n" +
2749             "OpFunctionEnd",
2750         2, VEC4_0_ID),
2751     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
2752     InstructionFoldingCase<uint32_t>(
2753         Header() + "%main = OpFunction %void None %void_func\n" +
2754             "%main_lab = OpLabel\n" +
2755             "%n = OpVariable %_ptr_v4float Function\n" +
2756             "%3 = OpLoad %v4float %n\n" +
2757             "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
2758             "OpReturn\n" +
2759             "OpFunctionEnd",
2760         2, 3)
2761 ));
2762
2763 INSTANTIATE_TEST_CASE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
2764                         ::testing::Values(
2765     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
2766     InstructionFoldingCase<uint32_t>(
2767         Header() + "%main = OpFunction %void None %void_func\n" +
2768             "%main_lab = OpLabel\n" +
2769             "%n = OpVariable %_ptr_v4double Function\n" +
2770             "%3 = OpLoad %v4double %n\n" +
2771             "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
2772             "OpReturn\n" +
2773             "OpFunctionEnd",
2774         2, 0),
2775     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
2776     InstructionFoldingCase<uint32_t>(
2777         Header() + "%main = OpFunction %void None %void_func\n" +
2778             "%main_lab = OpLabel\n" +
2779             "%n = OpVariable %_ptr_v4double Function\n" +
2780             "%3 = OpLoad %v4double %n\n" +
2781             "%2 = OpFMul %v4double %3 %106\n" +
2782             "OpReturn\n" +
2783             "OpFunctionEnd",
2784         2, DVEC4_0_ID),
2785     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
2786     InstructionFoldingCase<uint32_t>(
2787         Header() + "%main = OpFunction %void None %void_func\n" +
2788             "%main_lab = OpLabel\n" +
2789             "%n = OpVariable %_ptr_v4double Function\n" +
2790             "%3 = OpLoad %v4double %n\n" +
2791             "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
2792             "OpReturn\n" +
2793             "OpFunctionEnd",
2794         2, 3)
2795 ));
2796
2797 INSTANTIATE_TEST_CASE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
2798                         ::testing::Values(
2799     // Test case 0: Fold int(3.0)
2800     InstructionFoldingCase<uint32_t>(
2801         Header() + "%main = OpFunction %void None %void_func\n" +
2802             "%main_lab = OpLabel\n" +
2803             "%2 = OpConvertFToS %int %float_3\n" +
2804             "OpReturn\n" +
2805             "OpFunctionEnd",
2806         2, 3),
2807     // Test case 1: Fold uint(3.0)
2808     InstructionFoldingCase<uint32_t>(
2809         Header() + "%main = OpFunction %void None %void_func\n" +
2810             "%main_lab = OpLabel\n" +
2811             "%2 = OpConvertFToU %int %float_3\n" +
2812             "OpReturn\n" +
2813             "OpFunctionEnd",
2814         2, 3)
2815 ));
2816
2817 INSTANTIATE_TEST_CASE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
2818                         ::testing::Values(
2819     // Test case 0: Fold float(3)
2820     InstructionFoldingCase<float>(
2821         Header() + "%main = OpFunction %void None %void_func\n" +
2822             "%main_lab = OpLabel\n" +
2823             "%2 = OpConvertSToF %float %int_3\n" +
2824             "OpReturn\n" +
2825             "OpFunctionEnd",
2826         2, 3.0),
2827     // Test case 1: Fold float(3u)
2828     InstructionFoldingCase<float>(
2829         Header() + "%main = OpFunction %void None %void_func\n" +
2830             "%main_lab = OpLabel\n" +
2831             "%2 = OpConvertUToF %float %uint_3\n" +
2832             "OpReturn\n" +
2833             "OpFunctionEnd",
2834         2, 3.0)
2835 ));
2836 // clang-format on
2837
2838 using ToNegateFoldingTest =
2839     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
2840
2841 TEST_P(ToNegateFoldingTest, Case) {
2842   const auto& tc = GetParam();
2843
2844   // Build module.
2845   std::unique_ptr<ir::IRContext> context =
2846       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2847                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2848   ASSERT_NE(nullptr, context);
2849
2850   // Fold the instruction to test.
2851   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2852   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2853   std::unique_ptr<ir::Instruction> original_inst(inst->Clone(context.get()));
2854   bool succeeded = opt::FoldInstruction(inst);
2855
2856   // Make sure the instruction folded as expected.
2857   EXPECT_EQ(inst->result_id(), original_inst->result_id());
2858   EXPECT_EQ(inst->type_id(), original_inst->type_id());
2859   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
2860   if (succeeded) {
2861     EXPECT_EQ(inst->opcode(), SpvOpFNegate);
2862     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
2863   } else {
2864     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
2865     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
2866       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
2867     }
2868   }
2869 }
2870
2871 // clang-format off
2872 INSTANTIATE_TEST_CASE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
2873                         ::testing::Values(
2874     // Test case 0: Don't fold 1.0 - n
2875     InstructionFoldingCase<uint32_t>(
2876         Header() + "%main = OpFunction %void None %void_func\n" +
2877             "%main_lab = OpLabel\n" +
2878             "%n = OpVariable %_ptr_float Function\n" +
2879             "%3 = OpLoad %float %n\n" +
2880             "%2 = OpFSub %float %float_1 %3\n" +
2881             "OpReturn\n" +
2882             "OpFunctionEnd",
2883         2, 0),
2884     // Test case 1: Fold 0.0 - n
2885     InstructionFoldingCase<uint32_t>(
2886         Header() + "%main = OpFunction %void None %void_func\n" +
2887             "%main_lab = OpLabel\n" +
2888             "%n = OpVariable %_ptr_float Function\n" +
2889             "%3 = OpLoad %float %n\n" +
2890             "%2 = OpFSub %float %float_0 %3\n" +
2891             "OpReturn\n" +
2892             "OpFunctionEnd",
2893         2, 3),
2894         // Test case 2: Don't fold (0,0,0,1) - n
2895     InstructionFoldingCase<uint32_t>(
2896         Header() + "%main = OpFunction %void None %void_func\n" +
2897             "%main_lab = OpLabel\n" +
2898             "%n = OpVariable %_ptr_v4float Function\n" +
2899             "%3 = OpLoad %v4float %n\n" +
2900             "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
2901             "OpReturn\n" +
2902             "OpFunctionEnd",
2903         2, 0),
2904         // Test case 3: Fold (0,0,0,0) - n
2905     InstructionFoldingCase<uint32_t>(
2906         Header() + "%main = OpFunction %void None %void_func\n" +
2907             "%main_lab = OpLabel\n" +
2908             "%n = OpVariable %_ptr_v4float Function\n" +
2909             "%3 = OpLoad %v4float %n\n" +
2910             "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
2911             "OpReturn\n" +
2912             "OpFunctionEnd",
2913         2, 3)
2914 ));
2915
2916 INSTANTIATE_TEST_CASE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
2917                         ::testing::Values(
2918     // Test case 0: Don't fold 1.0 - n
2919     InstructionFoldingCase<uint32_t>(
2920         Header() + "%main = OpFunction %void None %void_func\n" +
2921             "%main_lab = OpLabel\n" +
2922             "%n = OpVariable %_ptr_double Function\n" +
2923             "%3 = OpLoad %double %n\n" +
2924             "%2 = OpFSub %double %double_1 %3\n" +
2925             "OpReturn\n" +
2926             "OpFunctionEnd",
2927         2, 0),
2928     // Test case 1: Fold 0.0 - n
2929     InstructionFoldingCase<uint32_t>(
2930         Header() + "%main = OpFunction %void None %void_func\n" +
2931             "%main_lab = OpLabel\n" +
2932             "%n = OpVariable %_ptr_double Function\n" +
2933             "%3 = OpLoad %double %n\n" +
2934             "%2 = OpFSub %double %double_0 %3\n" +
2935             "OpReturn\n" +
2936             "OpFunctionEnd",
2937         2, 3),
2938         // Test case 2: Don't fold (0,0,0,1) - n
2939     InstructionFoldingCase<uint32_t>(
2940         Header() + "%main = OpFunction %void None %void_func\n" +
2941             "%main_lab = OpLabel\n" +
2942             "%n = OpVariable %_ptr_v4double Function\n" +
2943             "%3 = OpLoad %v4double %n\n" +
2944             "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
2945             "OpReturn\n" +
2946             "OpFunctionEnd",
2947         2, 0),
2948         // Test case 3: Fold (0,0,0,0) - n
2949     InstructionFoldingCase<uint32_t>(
2950         Header() + "%main = OpFunction %void None %void_func\n" +
2951             "%main_lab = OpLabel\n" +
2952             "%n = OpVariable %_ptr_v4double Function\n" +
2953             "%3 = OpLoad %v4double %n\n" +
2954             "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
2955             "OpReturn\n" +
2956             "OpFunctionEnd",
2957         2, 3)
2958 ));
2959
2960 #ifdef SPIRV_EFFCEE
2961 using MatchingInstructionFoldingTest =
2962     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
2963
2964 TEST_P(MatchingInstructionFoldingTest, Case) {
2965   const auto& tc = GetParam();
2966
2967   // Build module.
2968   std::unique_ptr<ir::IRContext> context =
2969       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2970                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2971   ASSERT_NE(nullptr, context);
2972
2973   // Fold the instruction to test.
2974   opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2975   ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2976   std::unique_ptr<ir::Instruction> original_inst(inst->Clone(context.get()));
2977   bool succeeded = opt::FoldInstruction(inst);
2978   EXPECT_EQ(succeeded, tc.expected_result);
2979   if (succeeded) {
2980     Match(tc.test_body, context.get());
2981   }
2982 }
2983
2984 INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest,
2985 ::testing::Values(
2986   // Test case 0: fold consecutive fnegate
2987   // -(-x) = x
2988   InstructionFoldingCase<bool>(
2989     Header() +
2990       "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
2991       "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
2992       "%main = OpFunction %void None %void_func\n" +
2993       "%main_lab = OpLabel\n" +
2994       "%var = OpVariable %_ptr_float Function\n" +
2995       "%2 = OpLoad %float %var\n" +
2996       "%3 = OpFNegate %float %2\n" +
2997       "%4 = OpFNegate %float %3\n" +
2998       "OpReturn\n" +
2999       "OpFunctionEnd",
3000     4, true),
3001   // Test case 1: fold fnegate(fmul with const).
3002   // -(x * 2.0) = x * -2.0
3003   InstructionFoldingCase<bool>(
3004     Header() +
3005       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3006       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
3007       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3008       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
3009       "%main = OpFunction %void None %void_func\n" +
3010       "%main_lab = OpLabel\n" +
3011       "%var = OpVariable %_ptr_float Function\n" +
3012       "%2 = OpLoad %float %var\n" +
3013       "%3 = OpFMul %float %2 %float_2\n" +
3014       "%4 = OpFNegate %float %3\n" +
3015       "OpReturn\n" +
3016       "OpFunctionEnd",
3017     4, true),
3018   // Test case 2: fold fnegate(fmul with const).
3019   // -(2.0 * x) = x * 2.0
3020   InstructionFoldingCase<bool>(
3021     Header() +
3022       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3023       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
3024       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3025       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
3026       "%main = OpFunction %void None %void_func\n" +
3027       "%main_lab = OpLabel\n" +
3028       "%var = OpVariable %_ptr_float Function\n" +
3029       "%2 = OpLoad %float %var\n" +
3030       "%3 = OpFMul %float %float_2 %2\n" +
3031       "%4 = OpFNegate %float %3\n" +
3032       "OpReturn\n" +
3033       "OpFunctionEnd",
3034     4, true),
3035   // Test case 3: fold fnegate(fdiv with const).
3036   // -(x / 2.0) = x * -0.5
3037   InstructionFoldingCase<bool>(
3038     Header() +
3039       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3040       "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
3041       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3042       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
3043       "%main = OpFunction %void None %void_func\n" +
3044       "%main_lab = OpLabel\n" +
3045       "%var = OpVariable %_ptr_float Function\n" +
3046       "%2 = OpLoad %float %var\n" +
3047       "%3 = OpFDiv %float %2 %float_2\n" +
3048       "%4 = OpFNegate %float %3\n" +
3049       "OpReturn\n" +
3050       "OpFunctionEnd",
3051     4, true),
3052   // Test case 4: fold fnegate(fdiv with const).
3053   // -(2.0 / x) = -2.0 / x
3054   InstructionFoldingCase<bool>(
3055     Header() +
3056       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3057       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
3058       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3059       "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
3060       "%main = OpFunction %void None %void_func\n" +
3061       "%main_lab = OpLabel\n" +
3062       "%var = OpVariable %_ptr_float Function\n" +
3063       "%2 = OpLoad %float %var\n" +
3064       "%3 = OpFDiv %float %float_2 %2\n" +
3065       "%4 = OpFNegate %float %3\n" +
3066       "OpReturn\n" +
3067       "OpFunctionEnd",
3068     4, true),
3069   // Test case 5: fold fnegate(fadd with const).
3070   // -(2.0 + x) = -2.0 - x
3071   InstructionFoldingCase<bool>(
3072     Header() +
3073       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3074       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
3075       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3076       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
3077       "%main = OpFunction %void None %void_func\n" +
3078       "%main_lab = OpLabel\n" +
3079       "%var = OpVariable %_ptr_float Function\n" +
3080       "%2 = OpLoad %float %var\n" +
3081       "%3 = OpFAdd %float %float_2 %2\n" +
3082       "%4 = OpFNegate %float %3\n" +
3083       "OpReturn\n" +
3084       "OpFunctionEnd",
3085     4, true),
3086   // Test case 6: fold fnegate(fadd with const).
3087   // -(x + 2.0) = -2.0 - x
3088   InstructionFoldingCase<bool>(
3089     Header() +
3090       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3091       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
3092       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3093       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
3094       "%main = OpFunction %void None %void_func\n" +
3095       "%main_lab = OpLabel\n" +
3096       "%var = OpVariable %_ptr_float Function\n" +
3097       "%2 = OpLoad %float %var\n" +
3098       "%3 = OpFAdd %float %2 %float_2\n" +
3099       "%4 = OpFNegate %float %3\n" +
3100       "OpReturn\n" +
3101       "OpFunctionEnd",
3102     4, true),
3103   // Test case 7: fold fnegate(fsub with const).
3104   // -(2.0 - x) = x - 2.0
3105   InstructionFoldingCase<bool>(
3106     Header() +
3107       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3108       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3109       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3110       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
3111       "%main = OpFunction %void None %void_func\n" +
3112       "%main_lab = OpLabel\n" +
3113       "%var = OpVariable %_ptr_float Function\n" +
3114       "%2 = OpLoad %float %var\n" +
3115       "%3 = OpFSub %float %float_2 %2\n" +
3116       "%4 = OpFNegate %float %3\n" +
3117       "OpReturn\n" +
3118       "OpFunctionEnd",
3119     4, true),
3120   // Test case 8: fold fnegate(fsub with const).
3121   // -(x - 2.0) = 2.0 - x
3122   InstructionFoldingCase<bool>(
3123     Header() +
3124       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3125       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3126       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3127       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
3128       "%main = OpFunction %void None %void_func\n" +
3129       "%main_lab = OpLabel\n" +
3130       "%var = OpVariable %_ptr_float Function\n" +
3131       "%2 = OpLoad %float %var\n" +
3132       "%3 = OpFSub %float %2 %float_2\n" +
3133       "%4 = OpFNegate %float %3\n" +
3134       "OpReturn\n" +
3135       "OpFunctionEnd",
3136     4, true),
3137   // Test case 9: fold consecutive snegate
3138   // -(-x) = x
3139   InstructionFoldingCase<bool>(
3140     Header() +
3141       "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
3142       "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
3143       "%main = OpFunction %void None %void_func\n" +
3144       "%main_lab = OpLabel\n" +
3145       "%var = OpVariable %_ptr_int Function\n" +
3146       "%2 = OpLoad %int %var\n" +
3147       "%3 = OpSNegate %int %2\n" +
3148       "%4 = OpSNegate %int %3\n" +
3149       "OpReturn\n" +
3150       "OpFunctionEnd",
3151     4, true),
3152   // Test case 10: fold consecutive vector negate
3153   // -(-x) = x
3154   InstructionFoldingCase<bool>(
3155     Header() +
3156       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
3157       "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
3158       "%main = OpFunction %void None %void_func\n" +
3159       "%main_lab = OpLabel\n" +
3160       "%var = OpVariable %_ptr_v2float Function\n" +
3161       "%2 = OpLoad %v2float %var\n" +
3162       "%3 = OpFNegate %v2float %2\n" +
3163       "%4 = OpFNegate %v2float %3\n" +
3164       "OpReturn\n" +
3165       "OpFunctionEnd",
3166     4, true),
3167   // Test case 11: fold snegate(iadd with const).
3168   // -(2 + x) = -2 - x
3169   InstructionFoldingCase<bool>(
3170     Header() +
3171       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3172       "; CHECK: OpConstant [[int]] -2147483648\n" +
3173       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3174       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3175       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
3176       "%main = OpFunction %void None %void_func\n" +
3177       "%main_lab = OpLabel\n" +
3178       "%var = OpVariable %_ptr_int Function\n" +
3179       "%2 = OpLoad %int %var\n" +
3180       "%3 = OpIAdd %int %int_2 %2\n" +
3181       "%4 = OpSNegate %int %3\n" +
3182       "OpReturn\n" +
3183       "OpFunctionEnd",
3184     4, true),
3185   // Test case 12: fold snegate(iadd with const).
3186   // -(x + 2) = -2 - x
3187   InstructionFoldingCase<bool>(
3188     Header() +
3189       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3190       "; CHECK: OpConstant [[int]] -2147483648\n" +
3191       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3192       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3193       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
3194       "%main = OpFunction %void None %void_func\n" +
3195       "%main_lab = OpLabel\n" +
3196       "%var = OpVariable %_ptr_int Function\n" +
3197       "%2 = OpLoad %int %var\n" +
3198       "%3 = OpIAdd %int %2 %int_2\n" +
3199       "%4 = OpSNegate %int %3\n" +
3200       "OpReturn\n" +
3201       "OpFunctionEnd",
3202     4, true),
3203   // Test case 13: fold snegate(isub with const).
3204   // -(2 - x) = x - 2
3205   InstructionFoldingCase<bool>(
3206     Header() +
3207       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3208       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
3209       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3210       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
3211       "%main = OpFunction %void None %void_func\n" +
3212       "%main_lab = OpLabel\n" +
3213       "%var = OpVariable %_ptr_int Function\n" +
3214       "%2 = OpLoad %int %var\n" +
3215       "%3 = OpISub %int %int_2 %2\n" +
3216       "%4 = OpSNegate %int %3\n" +
3217       "OpReturn\n" +
3218       "OpFunctionEnd",
3219     4, true),
3220   // Test case 14: fold snegate(isub with const).
3221   // -(x - 2) = 2 - x
3222   InstructionFoldingCase<bool>(
3223     Header() +
3224       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3225       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
3226       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3227       "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
3228       "%main = OpFunction %void None %void_func\n" +
3229       "%main_lab = OpLabel\n" +
3230       "%var = OpVariable %_ptr_int Function\n" +
3231       "%2 = OpLoad %int %var\n" +
3232       "%3 = OpISub %int %2 %int_2\n" +
3233       "%4 = OpSNegate %int %3\n" +
3234       "OpReturn\n" +
3235       "OpFunctionEnd",
3236     4, true),
3237   // Test case 15: fold snegate(iadd with const).
3238   // -(x + 2) = -2 - x
3239   InstructionFoldingCase<bool>(
3240     Header() +
3241       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
3242       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
3243       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3244       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
3245       "%main = OpFunction %void None %void_func\n" +
3246       "%main_lab = OpLabel\n" +
3247       "%var = OpVariable %_ptr_long Function\n" +
3248       "%2 = OpLoad %long %var\n" +
3249       "%3 = OpIAdd %long %2 %long_2\n" +
3250       "%4 = OpSNegate %long %3\n" +
3251       "OpReturn\n" +
3252       "OpFunctionEnd",
3253     4, true),
3254   // Test case 16: fold snegate(isub with const).
3255   // -(2 - x) = x - 2
3256   InstructionFoldingCase<bool>(
3257     Header() +
3258       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
3259       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
3260       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3261       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
3262       "%main = OpFunction %void None %void_func\n" +
3263       "%main_lab = OpLabel\n" +
3264       "%var = OpVariable %_ptr_long Function\n" +
3265       "%2 = OpLoad %long %var\n" +
3266       "%3 = OpISub %long %long_2 %2\n" +
3267       "%4 = OpSNegate %long %3\n" +
3268       "OpReturn\n" +
3269       "OpFunctionEnd",
3270     4, true),
3271   // Test case 17: fold snegate(isub with const).
3272   // -(x - 2) = 2 - x
3273   InstructionFoldingCase<bool>(
3274     Header() +
3275       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
3276       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
3277       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3278       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
3279       "%main = OpFunction %void None %void_func\n" +
3280       "%main_lab = OpLabel\n" +
3281       "%var = OpVariable %_ptr_long Function\n" +
3282       "%2 = OpLoad %long %var\n" +
3283       "%3 = OpISub %long %2 %long_2\n" +
3284       "%4 = OpSNegate %long %3\n" +
3285       "OpReturn\n" +
3286       "OpFunctionEnd",
3287     4, true)
3288 ));
3289
3290 INSTANTIATE_TEST_CASE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
3291 ::testing::Values(
3292   // Test case 0: scalar reicprocal
3293   // x / 0.5 = x * 2.0
3294   InstructionFoldingCase<bool>(
3295     Header() +
3296       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3297       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3298       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3299       "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
3300       "%main = OpFunction %void None %void_func\n" +
3301       "%main_lab = OpLabel\n" +
3302       "%var = OpVariable %_ptr_float Function\n" +
3303       "%2 = OpLoad %float %var\n" +
3304       "%3 = OpFDiv %float %2 %float_0p5\n" +
3305       "OpReturn\n" +
3306       "OpFunctionEnd\n",
3307     3, true),
3308   // Test case 1: Unfoldable
3309   InstructionFoldingCase<bool>(
3310     Header() +
3311       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3312       "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
3313       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3314       "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
3315       "%main = OpFunction %void None %void_func\n" +
3316       "%main_lab = OpLabel\n" +
3317       "%var = OpVariable %_ptr_float Function\n" +
3318       "%2 = OpLoad %float %var\n" +
3319       "%3 = OpFDiv %float %2 %104\n" +
3320       "OpReturn\n" +
3321       "OpFunctionEnd\n",
3322     3, false),
3323   // Test case 2: Vector reciprocal
3324   // x / {2.0, 0.5} = x * {0.5, 2.0}
3325   InstructionFoldingCase<bool>(
3326     Header() +
3327       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3328       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
3329       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3330       "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
3331       "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
3332       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
3333       "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
3334       "%main = OpFunction %void None %void_func\n" +
3335       "%main_lab = OpLabel\n" +
3336       "%var = OpVariable %_ptr_v2float Function\n" +
3337       "%2 = OpLoad %v2float %var\n" +
3338       "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
3339       "OpReturn\n" +
3340       "OpFunctionEnd\n",
3341     3, true),
3342   // Test case 3: double reciprocal
3343   // x / 2.0 = x * 0.5
3344   InstructionFoldingCase<bool>(
3345     Header() +
3346       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
3347       "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
3348       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
3349       "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
3350       "%main = OpFunction %void None %void_func\n" +
3351       "%main_lab = OpLabel\n" +
3352       "%var = OpVariable %_ptr_double Function\n" +
3353       "%2 = OpLoad %double %var\n" +
3354       "%3 = OpFDiv %double %2 %double_2\n" +
3355       "OpReturn\n" +
3356       "OpFunctionEnd\n",
3357     3, true),
3358   // Test case 4: don't fold x / 0.
3359   InstructionFoldingCase<bool>(
3360     Header() +
3361       "%main = OpFunction %void None %void_func\n" +
3362       "%main_lab = OpLabel\n" +
3363       "%var = OpVariable %_ptr_v2float Function\n" +
3364       "%2 = OpLoad %v2float %var\n" +
3365       "%3 = OpFDiv %v2float %2 %v2float_null\n" +
3366       "OpReturn\n" +
3367       "OpFunctionEnd\n",
3368     3, false)
3369 ));
3370
3371 INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest,
3372 ::testing::Values(
3373   // Test case 0: fold consecutive fmuls
3374   // (x * 3.0) * 2.0 = x * 6.0
3375   InstructionFoldingCase<bool>(
3376     Header() +
3377       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3378       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
3379       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3380       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
3381       "%main = OpFunction %void None %void_func\n" +
3382       "%main_lab = OpLabel\n" +
3383       "%var = OpVariable %_ptr_float Function\n" +
3384       "%2 = OpLoad %float %var\n" +
3385       "%3 = OpFMul %float %2 %float_3\n" +
3386       "%4 = OpFMul %float %3 %float_2\n" +
3387       "OpReturn\n" +
3388       "OpFunctionEnd\n",
3389     4, true),
3390   // Test case 1: fold consecutive fmuls
3391   // 2.0 * (x * 3.0) = x * 6.0
3392   InstructionFoldingCase<bool>(
3393     Header() +
3394       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3395       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
3396       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3397       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
3398       "%main = OpFunction %void None %void_func\n" +
3399       "%main_lab = OpLabel\n" +
3400       "%var = OpVariable %_ptr_float Function\n" +
3401       "%2 = OpLoad %float %var\n" +
3402       "%3 = OpFMul %float %2 %float_3\n" +
3403       "%4 = OpFMul %float %float_2 %3\n" +
3404       "OpReturn\n" +
3405       "OpFunctionEnd\n",
3406     4, true),
3407   // Test case 2: fold consecutive fmuls
3408   // (3.0 * x) * 2.0 = x * 6.0
3409   InstructionFoldingCase<bool>(
3410     Header() +
3411       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3412       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
3413       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3414       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
3415       "%main = OpFunction %void None %void_func\n" +
3416       "%main_lab = OpLabel\n" +
3417       "%var = OpVariable %_ptr_float Function\n" +
3418       "%2 = OpLoad %float %var\n" +
3419       "%3 = OpFMul %float %float_3 %2\n" +
3420       "%4 = OpFMul %float %float_2 %3\n" +
3421       "OpReturn\n" +
3422       "OpFunctionEnd\n",
3423     4, true),
3424   // Test case 3: fold vector fmul
3425   InstructionFoldingCase<bool>(
3426     Header() +
3427       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3428       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
3429       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
3430       "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
3431       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
3432       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
3433       "%main = OpFunction %void None %void_func\n" +
3434       "%main_lab = OpLabel\n" +
3435       "%var = OpVariable %_ptr_v2float Function\n" +
3436       "%2 = OpLoad %v2float %var\n" +
3437       "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
3438       "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
3439       "OpReturn\n" +
3440       "OpFunctionEnd\n",
3441     4, true),
3442   // Test case 4: fold double fmuls
3443   // (x * 3.0) * 2.0 = x * 6.0
3444   InstructionFoldingCase<bool>(
3445     Header() +
3446       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
3447       "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
3448       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
3449       "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
3450       "%main = OpFunction %void None %void_func\n" +
3451       "%main_lab = OpLabel\n" +
3452       "%var = OpVariable %_ptr_double Function\n" +
3453       "%2 = OpLoad %double %var\n" +
3454       "%3 = OpFMul %double %2 %double_3\n" +
3455       "%4 = OpFMul %double %3 %double_2\n" +
3456       "OpReturn\n" +
3457       "OpFunctionEnd\n",
3458     4, true),
3459   // Test case 5: fold 32 bit imuls
3460   // (x * 3) * 2 = x * 6
3461   InstructionFoldingCase<bool>(
3462     Header() +
3463       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3464       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
3465       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3466       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
3467       "%main = OpFunction %void None %void_func\n" +
3468       "%main_lab = OpLabel\n" +
3469       "%var = OpVariable %_ptr_int Function\n" +
3470       "%2 = OpLoad %int %var\n" +
3471       "%3 = OpIMul %int %2 %int_3\n" +
3472       "%4 = OpIMul %int %3 %int_2\n" +
3473       "OpReturn\n" +
3474       "OpFunctionEnd\n",
3475     4, true),
3476   // Test case 6: fold 64 bit imuls
3477   // (x * 3) * 2 = x * 6
3478   InstructionFoldingCase<bool>(
3479     Header() +
3480       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
3481       "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
3482       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3483       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
3484       "%main = OpFunction %void None %void_func\n" +
3485       "%main_lab = OpLabel\n" +
3486       "%var = OpVariable %_ptr_long Function\n" +
3487       "%2 = OpLoad %long %var\n" +
3488       "%3 = OpIMul %long %2 %long_3\n" +
3489       "%4 = OpIMul %long %3 %long_2\n" +
3490       "OpReturn\n" +
3491       "OpFunctionEnd\n",
3492     4, true),
3493   // Test case 7: merge vector integer mults
3494   InstructionFoldingCase<bool>(
3495     Header() +
3496       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3497       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
3498       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
3499       "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
3500       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
3501       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
3502       "%main = OpFunction %void None %void_func\n" +
3503       "%main_lab = OpLabel\n" +
3504       "%var = OpVariable %_ptr_v2int Function\n" +
3505       "%2 = OpLoad %v2int %var\n" +
3506       "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
3507       "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
3508       "OpReturn\n" +
3509       "OpFunctionEnd\n",
3510     4, true),
3511   // Test case 8: merge fmul of fdiv
3512   // 2.0 * (2.0 / x) = 4.0 / x
3513   InstructionFoldingCase<bool>(
3514     Header() +
3515       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3516       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
3517       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3518       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
3519       "%main = OpFunction %void None %void_func\n" +
3520       "%main_lab = OpLabel\n" +
3521       "%var = OpVariable %_ptr_float Function\n" +
3522       "%2 = OpLoad %float %var\n" +
3523       "%3 = OpFDiv %float %float_2 %2\n" +
3524       "%4 = OpFMul %float %float_2 %3\n" +
3525       "OpReturn\n" +
3526       "OpFunctionEnd\n",
3527     4, true),
3528   // Test case 9: merge fmul of fdiv
3529   // (2.0 / x) * 2.0 = 4.0 / x
3530   InstructionFoldingCase<bool>(
3531     Header() +
3532       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3533       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
3534       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3535       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
3536       "%main = OpFunction %void None %void_func\n" +
3537       "%main_lab = OpLabel\n" +
3538       "%var = OpVariable %_ptr_float Function\n" +
3539       "%2 = OpLoad %float %var\n" +
3540       "%3 = OpFDiv %float %float_2 %2\n" +
3541       "%4 = OpFMul %float %3 %float_2\n" +
3542       "OpReturn\n" +
3543       "OpFunctionEnd\n",
3544     4, true),
3545   // Test case 10: Do not merge imul of sdiv
3546   // 4 * (x / 2)
3547   InstructionFoldingCase<bool>(
3548     Header() +
3549       "%main = OpFunction %void None %void_func\n" +
3550       "%main_lab = OpLabel\n" +
3551       "%var = OpVariable %_ptr_int Function\n" +
3552       "%2 = OpLoad %int %var\n" +
3553       "%3 = OpSDiv %int %2 %int_2\n" +
3554       "%4 = OpIMul %int %int_4 %3\n" +
3555       "OpReturn\n" +
3556       "OpFunctionEnd\n",
3557     4, false),
3558   // Test case 11: Do not merge imul of sdiv
3559   // (x / 2) * 4
3560   InstructionFoldingCase<bool>(
3561     Header() +
3562       "%main = OpFunction %void None %void_func\n" +
3563       "%main_lab = OpLabel\n" +
3564       "%var = OpVariable %_ptr_int Function\n" +
3565       "%2 = OpLoad %int %var\n" +
3566       "%3 = OpSDiv %int %2 %int_2\n" +
3567       "%4 = OpIMul %int %3 %int_4\n" +
3568       "OpReturn\n" +
3569       "OpFunctionEnd\n",
3570     4, false),
3571   // Test case 12: Do not merge imul of udiv
3572   // 4 * (x / 2)
3573   InstructionFoldingCase<bool>(
3574     Header() +
3575       "%main = OpFunction %void None %void_func\n" +
3576       "%main_lab = OpLabel\n" +
3577       "%var = OpVariable %_ptr_uint Function\n" +
3578       "%2 = OpLoad %uint %var\n" +
3579       "%3 = OpUDiv %uint %2 %uint_2\n" +
3580       "%4 = OpIMul %uint %uint_4 %3\n" +
3581       "OpReturn\n" +
3582       "OpFunctionEnd\n",
3583     4, false),
3584   // Test case 13: Do not merge imul of udiv
3585   // (x / 2) * 4
3586   InstructionFoldingCase<bool>(
3587     Header() +
3588       "%main = OpFunction %void None %void_func\n" +
3589       "%main_lab = OpLabel\n" +
3590       "%var = OpVariable %_ptr_uint Function\n" +
3591       "%2 = OpLoad %uint %var\n" +
3592       "%3 = OpUDiv %uint %2 %uint_2\n" +
3593       "%4 = OpIMul %uint %3 %uint_4\n" +
3594       "OpReturn\n" +
3595       "OpFunctionEnd\n",
3596     4, false),
3597   // Test case 14: Don't fold
3598   // (x / 3) * 4
3599   InstructionFoldingCase<bool>(
3600     Header() +
3601       "%main = OpFunction %void None %void_func\n" +
3602       "%main_lab = OpLabel\n" +
3603       "%var = OpVariable %_ptr_uint Function\n" +
3604       "%2 = OpLoad %uint %var\n" +
3605       "%3 = OpUDiv %uint %2 %uint_3\n" +
3606       "%4 = OpIMul %uint %3 %uint_4\n" +
3607       "OpReturn\n" +
3608       "OpFunctionEnd\n",
3609     4, false),
3610   // Test case 15: merge vector fmul of fdiv
3611   // (x / {2,2}) * {4,4} = x * {2,2}
3612   InstructionFoldingCase<bool>(
3613     Header() +
3614       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3615       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
3616       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3617       "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
3618       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
3619       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
3620       "%main = OpFunction %void None %void_func\n" +
3621       "%main_lab = OpLabel\n" +
3622       "%var = OpVariable %_ptr_v2float Function\n" +
3623       "%2 = OpLoad %v2float %var\n" +
3624       "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
3625       "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
3626       "OpReturn\n" +
3627       "OpFunctionEnd\n",
3628     4, true),
3629   // Test case 16: merge vector imul of snegate
3630   // (-x) * {2,2} = x * {-2,-2}
3631   InstructionFoldingCase<bool>(
3632     Header() +
3633       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3634       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
3635       "; CHECK: OpConstant [[int]] -2147483648\n" +
3636       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3637       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
3638       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
3639       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
3640       "%main = OpFunction %void None %void_func\n" +
3641       "%main_lab = OpLabel\n" +
3642       "%var = OpVariable %_ptr_v2int Function\n" +
3643       "%2 = OpLoad %v2int %var\n" +
3644       "%3 = OpSNegate %v2int %2\n" +
3645       "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
3646       "OpReturn\n" +
3647       "OpFunctionEnd\n",
3648     4, true),
3649   // Test case 17: merge vector imul of snegate
3650   // {2,2} * (-x) = x * {-2,-2}
3651   InstructionFoldingCase<bool>(
3652     Header() +
3653       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3654       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
3655       "; CHECK: OpConstant [[int]] -2147483648\n" +
3656       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3657       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
3658       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
3659       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
3660       "%main = OpFunction %void None %void_func\n" +
3661       "%main_lab = OpLabel\n" +
3662       "%var = OpVariable %_ptr_v2int Function\n" +
3663       "%2 = OpLoad %v2int %var\n" +
3664       "%3 = OpSNegate %v2int %2\n" +
3665       "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
3666       "OpReturn\n" +
3667       "OpFunctionEnd\n",
3668     4, true)
3669 ));
3670
3671 INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest,
3672 ::testing::Values(
3673   // Test case 0: merge consecutive fdiv
3674   // 4.0 / (2.0 / x) = 2.0 * x
3675   InstructionFoldingCase<bool>(
3676     Header() +
3677       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3678       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3679       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3680       "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
3681       "%main = OpFunction %void None %void_func\n" +
3682       "%main_lab = OpLabel\n" +
3683       "%var = OpVariable %_ptr_float Function\n" +
3684       "%2 = OpLoad %float %var\n" +
3685       "%3 = OpFDiv %float %float_2 %2\n" +
3686       "%4 = OpFDiv %float %float_4 %3\n" +
3687       "OpReturn\n" +
3688       "OpFunctionEnd\n",
3689     4, true),
3690   // Test case 1: merge consecutive fdiv
3691   // 4.0 / (x / 2.0) = 8.0 / x
3692   InstructionFoldingCase<bool>(
3693     Header() +
3694       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3695       "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
3696       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3697       "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
3698       "%main = OpFunction %void None %void_func\n" +
3699       "%main_lab = OpLabel\n" +
3700       "%var = OpVariable %_ptr_float Function\n" +
3701       "%2 = OpLoad %float %var\n" +
3702       "%3 = OpFDiv %float %2 %float_2\n" +
3703       "%4 = OpFDiv %float %float_4 %3\n" +
3704       "OpReturn\n" +
3705       "OpFunctionEnd\n",
3706     4, true),
3707   // Test case 2: merge consecutive fdiv
3708   // (4.0 / x) / 2.0 = 2.0 / x
3709   InstructionFoldingCase<bool>(
3710     Header() +
3711       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3712       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3713       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3714       "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
3715       "%main = OpFunction %void None %void_func\n" +
3716       "%main_lab = OpLabel\n" +
3717       "%var = OpVariable %_ptr_float Function\n" +
3718       "%2 = OpLoad %float %var\n" +
3719       "%3 = OpFDiv %float %float_4 %2\n" +
3720       "%4 = OpFDiv %float %3 %float_2\n" +
3721       "OpReturn\n" +
3722       "OpFunctionEnd\n",
3723     4, true),
3724   // Test case 3: Do not merge consecutive sdiv
3725   // 4 / (2 / x)
3726   InstructionFoldingCase<bool>(
3727     Header() +
3728       "%main = OpFunction %void None %void_func\n" +
3729       "%main_lab = OpLabel\n" +
3730       "%var = OpVariable %_ptr_int Function\n" +
3731       "%2 = OpLoad %int %var\n" +
3732       "%3 = OpSDiv %int %int_2 %2\n" +
3733       "%4 = OpSDiv %int %int_4 %3\n" +
3734       "OpReturn\n" +
3735       "OpFunctionEnd\n",
3736     4, false),
3737   // Test case 4: Do not merge consecutive sdiv
3738   // 4 / (x / 2)
3739   InstructionFoldingCase<bool>(
3740     Header() +
3741       "%main = OpFunction %void None %void_func\n" +
3742       "%main_lab = OpLabel\n" +
3743       "%var = OpVariable %_ptr_int Function\n" +
3744       "%2 = OpLoad %int %var\n" +
3745       "%3 = OpSDiv %int %2 %int_2\n" +
3746       "%4 = OpSDiv %int %int_4 %3\n" +
3747       "OpReturn\n" +
3748       "OpFunctionEnd\n",
3749     4, false),
3750   // Test case 5: Do not merge consecutive sdiv
3751   // (4 / x) / 2
3752   InstructionFoldingCase<bool>(
3753     Header() +
3754       "%main = OpFunction %void None %void_func\n" +
3755       "%main_lab = OpLabel\n" +
3756       "%var = OpVariable %_ptr_int Function\n" +
3757       "%2 = OpLoad %int %var\n" +
3758       "%3 = OpSDiv %int %int_4 %2\n" +
3759       "%4 = OpSDiv %int %3 %int_2\n" +
3760       "OpReturn\n" +
3761       "OpFunctionEnd\n",
3762     4, false),
3763   // Test case 6: Do not merge consecutive sdiv
3764   // (x / 4) / 2
3765   InstructionFoldingCase<bool>(
3766     Header() +
3767       "%main = OpFunction %void None %void_func\n" +
3768       "%main_lab = OpLabel\n" +
3769       "%var = OpVariable %_ptr_int Function\n" +
3770       "%2 = OpLoad %int %var\n" +
3771       "%3 = OpSDiv %int %2 %int_4\n" +
3772       "%4 = OpSDiv %int %3 %int_2\n" +
3773       "OpReturn\n" +
3774       "OpFunctionEnd\n",
3775     4, false),
3776   // Test case 7: Do not merge sdiv of imul
3777   // 4 / (2 * x)
3778   InstructionFoldingCase<bool>(
3779     Header() +
3780       "%main = OpFunction %void None %void_func\n" +
3781       "%main_lab = OpLabel\n" +
3782       "%var = OpVariable %_ptr_int Function\n" +
3783       "%2 = OpLoad %int %var\n" +
3784       "%3 = OpIMul %int %int_2 %2\n" +
3785       "%4 = OpSDiv %int %int_4 %3\n" +
3786       "OpReturn\n" +
3787       "OpFunctionEnd\n",
3788     4, false),
3789   // Test case 8: Do not merge sdiv of imul
3790   // 4 / (x * 2)
3791   InstructionFoldingCase<bool>(
3792     Header() +
3793       "%main = OpFunction %void None %void_func\n" +
3794       "%main_lab = OpLabel\n" +
3795       "%var = OpVariable %_ptr_int Function\n" +
3796       "%2 = OpLoad %int %var\n" +
3797       "%3 = OpIMul %int %2 %int_2\n" +
3798       "%4 = OpSDiv %int %int_4 %3\n" +
3799       "OpReturn\n" +
3800       "OpFunctionEnd\n",
3801     4, false),
3802   // Test case 9: Do not merge sdiv of imul
3803   // (4 * x) / 2
3804   InstructionFoldingCase<bool>(
3805     Header() +
3806       "%main = OpFunction %void None %void_func\n" +
3807       "%main_lab = OpLabel\n" +
3808       "%var = OpVariable %_ptr_int Function\n" +
3809       "%2 = OpLoad %int %var\n" +
3810       "%3 = OpIMul %int %int_4 %2\n" +
3811       "%4 = OpSDiv %int %3 %int_2\n" +
3812       "OpReturn\n" +
3813       "OpFunctionEnd\n",
3814     4, false),
3815   // Test case 10: Do not merge sdiv of imul
3816   // (x * 4) / 2
3817   InstructionFoldingCase<bool>(
3818     Header() +
3819       "%main = OpFunction %void None %void_func\n" +
3820       "%main_lab = OpLabel\n" +
3821       "%var = OpVariable %_ptr_int Function\n" +
3822       "%2 = OpLoad %int %var\n" +
3823       "%3 = OpIMul %int %2 %int_4\n" +
3824       "%4 = OpSDiv %int %3 %int_2\n" +
3825       "OpReturn\n" +
3826       "OpFunctionEnd\n",
3827     4, false),
3828   // Test case 11: merge sdiv of snegate
3829   // (-x) / 2 = x / -2
3830   InstructionFoldingCase<bool>(
3831     Header() +
3832       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3833       "; CHECK: OpConstant [[int]] -2147483648\n" +
3834       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3835       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3836       "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[int_n2]]\n" +
3837       "%main = OpFunction %void None %void_func\n" +
3838       "%main_lab = OpLabel\n" +
3839       "%var = OpVariable %_ptr_int Function\n" +
3840       "%2 = OpLoad %int %var\n" +
3841       "%3 = OpSNegate %int %2\n" +
3842       "%4 = OpSDiv %int %3 %int_2\n" +
3843       "OpReturn\n" +
3844       "OpFunctionEnd\n",
3845     4, true),
3846   // Test case 12: merge sdiv of snegate
3847   // 2 / (-x) = -2 / x
3848   InstructionFoldingCase<bool>(
3849     Header() +
3850       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
3851       "; CHECK: OpConstant [[int]] -2147483648\n" +
3852       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" +
3853       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
3854       "; CHECK: %4 = OpSDiv [[int]] [[int_n2]] [[ld]]\n" +
3855       "%main = OpFunction %void None %void_func\n" +
3856       "%main_lab = OpLabel\n" +
3857       "%var = OpVariable %_ptr_int Function\n" +
3858       "%2 = OpLoad %int %var\n" +
3859       "%3 = OpSNegate %int %2\n" +
3860       "%4 = OpSDiv %int %int_2 %3\n" +
3861       "OpReturn\n" +
3862       "OpFunctionEnd\n",
3863     4, true),
3864   // Test case 13: Don't merge
3865   // (x / {null}) / {null}
3866   InstructionFoldingCase<bool>(
3867     Header() +
3868       "%main = OpFunction %void None %void_func\n" +
3869       "%main_lab = OpLabel\n" +
3870       "%var = OpVariable %_ptr_v2float Function\n" +
3871       "%2 = OpLoad %float %var\n" +
3872       "%3 = OpFDiv %float %2 %v2float_null\n" +
3873       "%4 = OpFDiv %float %3 %v2float_null\n" +
3874       "OpReturn\n" +
3875       "OpFunctionEnd\n",
3876     4, false)
3877 ));
3878
3879 INSTANTIATE_TEST_CASE_P(MergeAddTest, MatchingInstructionFoldingTest,
3880 ::testing::Values(
3881   // Test case 0: merge add of negate
3882   // (-x) + 2 = 2 - x
3883   InstructionFoldingCase<bool>(
3884     Header() +
3885       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3886       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3887       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3888       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
3889       "%main = OpFunction %void None %void_func\n" +
3890       "%main_lab = OpLabel\n" +
3891       "%var = OpVariable %_ptr_float Function\n" +
3892       "%2 = OpLoad %float %var\n" +
3893       "%3 = OpFNegate %float %2\n" +
3894       "%4 = OpFAdd %float %3 %float_2\n" +
3895       "OpReturn\n" +
3896       "OpFunctionEnd\n",
3897     4, true),
3898   // Test case 1: merge add of negate
3899   // 2 + (-x) = 2 - x
3900   InstructionFoldingCase<bool>(
3901     Header() +
3902       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3903       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
3904       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3905       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
3906       "%main = OpFunction %void None %void_func\n" +
3907       "%main_lab = OpLabel\n" +
3908       "%var = OpVariable %_ptr_float Function\n" +
3909       "%2 = OpLoad %float %var\n" +
3910       "%3 = OpSNegate %float %2\n" +
3911       "%4 = OpIAdd %float %float_2 %3\n" +
3912       "OpReturn\n" +
3913       "OpFunctionEnd\n",
3914     4, true),
3915   // Test case 2: merge add of negate
3916   // (-x) + 2 = 2 - x
3917   InstructionFoldingCase<bool>(
3918     Header() +
3919       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
3920       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
3921       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3922       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
3923       "%main = OpFunction %void None %void_func\n" +
3924       "%main_lab = OpLabel\n" +
3925       "%var = OpVariable %_ptr_long Function\n" +
3926       "%2 = OpLoad %long %var\n" +
3927       "%3 = OpSNegate %long %2\n" +
3928       "%4 = OpIAdd %long %3 %long_2\n" +
3929       "OpReturn\n" +
3930       "OpFunctionEnd\n",
3931     4, true),
3932   // Test case 3: merge add of negate
3933   // 2 + (-x) = 2 - x
3934   InstructionFoldingCase<bool>(
3935     Header() +
3936       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
3937       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
3938       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
3939       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
3940       "%main = OpFunction %void None %void_func\n" +
3941       "%main_lab = OpLabel\n" +
3942       "%var = OpVariable %_ptr_long Function\n" +
3943       "%2 = OpLoad %long %var\n" +
3944       "%3 = OpSNegate %long %2\n" +
3945       "%4 = OpIAdd %long %long_2 %3\n" +
3946       "OpReturn\n" +
3947       "OpFunctionEnd\n",
3948     4, true),
3949   // Test case 4: merge add of subtract
3950   // (x - 1) + 2 = x + 1
3951   InstructionFoldingCase<bool>(
3952     Header() +
3953       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3954       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
3955       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3956       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
3957       "%main = OpFunction %void None %void_func\n" +
3958       "%main_lab = OpLabel\n" +
3959       "%var = OpVariable %_ptr_float Function\n" +
3960       "%2 = OpLoad %float %var\n" +
3961       "%3 = OpFSub %float %2 %float_1\n" +
3962       "%4 = OpFAdd %float %3 %float_2\n" +
3963       "OpReturn\n" +
3964       "OpFunctionEnd\n",
3965     4, true),
3966   // Test case 5: merge add of subtract
3967   // (1 - x) + 2 = 3 - x
3968   InstructionFoldingCase<bool>(
3969     Header() +
3970       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3971       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
3972       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3973       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
3974       "%main = OpFunction %void None %void_func\n" +
3975       "%main_lab = OpLabel\n" +
3976       "%var = OpVariable %_ptr_float Function\n" +
3977       "%2 = OpLoad %float %var\n" +
3978       "%3 = OpFSub %float %float_1 %2\n" +
3979       "%4 = OpFAdd %float %3 %float_2\n" +
3980       "OpReturn\n" +
3981       "OpFunctionEnd\n",
3982     4, true),
3983   // Test case 6: merge add of subtract
3984   // 2 + (x - 1) = x + 1
3985   InstructionFoldingCase<bool>(
3986     Header() +
3987       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
3988       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
3989       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
3990       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
3991       "%main = OpFunction %void None %void_func\n" +
3992       "%main_lab = OpLabel\n" +
3993       "%var = OpVariable %_ptr_float Function\n" +
3994       "%2 = OpLoad %float %var\n" +
3995       "%3 = OpFSub %float %2 %float_1\n" +
3996       "%4 = OpFAdd %float %float_2 %3\n" +
3997       "OpReturn\n" +
3998       "OpFunctionEnd\n",
3999     4, true),
4000   // Test case 7: merge add of subtract
4001   // 2 + (1 - x) = 3 - x
4002   InstructionFoldingCase<bool>(
4003     Header() +
4004       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4005       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4006       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4007       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
4008       "%main = OpFunction %void None %void_func\n" +
4009       "%main_lab = OpLabel\n" +
4010       "%var = OpVariable %_ptr_float Function\n" +
4011       "%2 = OpLoad %float %var\n" +
4012       "%3 = OpFSub %float %float_1 %2\n" +
4013       "%4 = OpFAdd %float %float_2 %3\n" +
4014       "OpReturn\n" +
4015       "OpFunctionEnd\n",
4016     4, true),
4017   // Test case 8: merge add of add
4018   // (x + 1) + 2 = x + 3
4019   InstructionFoldingCase<bool>(
4020     Header() +
4021       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4022       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4023       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4024       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
4025       "%main = OpFunction %void None %void_func\n" +
4026       "%main_lab = OpLabel\n" +
4027       "%var = OpVariable %_ptr_float Function\n" +
4028       "%2 = OpLoad %float %var\n" +
4029       "%3 = OpFAdd %float %2 %float_1\n" +
4030       "%4 = OpFAdd %float %3 %float_2\n" +
4031       "OpReturn\n" +
4032       "OpFunctionEnd\n",
4033     4, true),
4034   // Test case 9: merge add of add
4035   // (1 + x) + 2 = 3 + x
4036   InstructionFoldingCase<bool>(
4037     Header() +
4038       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4039       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4040       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4041       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
4042       "%main = OpFunction %void None %void_func\n" +
4043       "%main_lab = OpLabel\n" +
4044       "%var = OpVariable %_ptr_float Function\n" +
4045       "%2 = OpLoad %float %var\n" +
4046       "%3 = OpFAdd %float %float_1 %2\n" +
4047       "%4 = OpFAdd %float %3 %float_2\n" +
4048       "OpReturn\n" +
4049       "OpFunctionEnd\n",
4050     4, true),
4051   // Test case 10: merge add of add
4052   // 2 + (x + 1) = x + 1
4053   InstructionFoldingCase<bool>(
4054     Header() +
4055       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4056       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4057       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4058       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
4059       "%main = OpFunction %void None %void_func\n" +
4060       "%main_lab = OpLabel\n" +
4061       "%var = OpVariable %_ptr_float Function\n" +
4062       "%2 = OpLoad %float %var\n" +
4063       "%3 = OpFAdd %float %2 %float_1\n" +
4064       "%4 = OpFAdd %float %float_2 %3\n" +
4065       "OpReturn\n" +
4066       "OpFunctionEnd\n",
4067     4, true),
4068   // Test case 11: merge add of add
4069   // 2 + (1 + x) = 3 - x
4070   InstructionFoldingCase<bool>(
4071     Header() +
4072       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4073       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4074       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4075       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
4076       "%main = OpFunction %void None %void_func\n" +
4077       "%main_lab = OpLabel\n" +
4078       "%var = OpVariable %_ptr_float Function\n" +
4079       "%2 = OpLoad %float %var\n" +
4080       "%3 = OpFAdd %float %float_1 %2\n" +
4081       "%4 = OpFAdd %float %float_2 %3\n" +
4082       "OpReturn\n" +
4083       "OpFunctionEnd\n",
4084     4, true)
4085 ));
4086
4087 INSTANTIATE_TEST_CASE_P(MergeSubTest, MatchingInstructionFoldingTest,
4088 ::testing::Values(
4089   // Test case 0: merge sub of negate
4090   // (-x) - 2 = -2 - x
4091   InstructionFoldingCase<bool>(
4092     Header() +
4093       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4094       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" +
4095       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4096       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
4097       "%main = OpFunction %void None %void_func\n" +
4098       "%main_lab = OpLabel\n" +
4099       "%var = OpVariable %_ptr_float Function\n" +
4100       "%2 = OpLoad %float %var\n" +
4101       "%3 = OpFNegate %float %2\n" +
4102       "%4 = OpFSub %float %3 %float_2\n" +
4103       "OpReturn\n" +
4104       "OpFunctionEnd\n",
4105     4, true),
4106   // Test case 1: merge sub of negate
4107   // 2 - (-x) = x + 2
4108   InstructionFoldingCase<bool>(
4109     Header() +
4110       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4111       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4112       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4113       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
4114       "%main = OpFunction %void None %void_func\n" +
4115       "%main_lab = OpLabel\n" +
4116       "%var = OpVariable %_ptr_float Function\n" +
4117       "%2 = OpLoad %float %var\n" +
4118       "%3 = OpFNegate %float %2\n" +
4119       "%4 = OpFSub %float %float_2 %3\n" +
4120       "OpReturn\n" +
4121       "OpFunctionEnd\n",
4122     4, true),
4123   // Test case 2: merge sub of negate
4124   // (-x) - 2 = -2 - x
4125   InstructionFoldingCase<bool>(
4126     Header() +
4127       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
4128       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
4129       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4130       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
4131       "%main = OpFunction %void None %void_func\n" +
4132       "%main_lab = OpLabel\n" +
4133       "%var = OpVariable %_ptr_long Function\n" +
4134       "%2 = OpLoad %long %var\n" +
4135       "%3 = OpSNegate %long %2\n" +
4136       "%4 = OpISub %long %3 %long_2\n" +
4137       "OpReturn\n" +
4138       "OpFunctionEnd\n",
4139     4, true),
4140   // Test case 3: merge sub of negate
4141   // 2 - (-x) = x + 2
4142   InstructionFoldingCase<bool>(
4143     Header() +
4144       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
4145       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
4146       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
4147       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
4148       "%main = OpFunction %void None %void_func\n" +
4149       "%main_lab = OpLabel\n" +
4150       "%var = OpVariable %_ptr_long Function\n" +
4151       "%2 = OpLoad %long %var\n" +
4152       "%3 = OpSNegate %long %2\n" +
4153       "%4 = OpISub %long %long_2 %3\n" +
4154       "OpReturn\n" +
4155       "OpFunctionEnd\n",
4156     4, true),
4157   // Test case 4: merge add of subtract
4158   // (x + 2) - 1 = x + 1
4159   InstructionFoldingCase<bool>(
4160     Header() +
4161       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4162       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4163       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4164       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
4165       "%main = OpFunction %void None %void_func\n" +
4166       "%main_lab = OpLabel\n" +
4167       "%var = OpVariable %_ptr_float Function\n" +
4168       "%2 = OpLoad %float %var\n" +
4169       "%3 = OpFAdd %float %2 %float_2\n" +
4170       "%4 = OpFSub %float %3 %float_1\n" +
4171       "OpReturn\n" +
4172       "OpFunctionEnd\n",
4173     4, true),
4174   // Test case 5: merge add of subtract
4175   // (2 + x) - 1 = x + 1
4176   InstructionFoldingCase<bool>(
4177     Header() +
4178       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4179       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4180       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4181       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
4182       "%main = OpFunction %void None %void_func\n" +
4183       "%main_lab = OpLabel\n" +
4184       "%var = OpVariable %_ptr_float Function\n" +
4185       "%2 = OpLoad %float %var\n" +
4186       "%3 = OpFAdd %float %float_2 %2\n" +
4187       "%4 = OpFSub %float %3 %float_1\n" +
4188       "OpReturn\n" +
4189       "OpFunctionEnd\n",
4190     4, true),
4191   // Test case 6: merge add of subtract
4192   // 2 - (x + 1) = 1 - x
4193   InstructionFoldingCase<bool>(
4194     Header() +
4195       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4196       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4197       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4198       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
4199       "%main = OpFunction %void None %void_func\n" +
4200       "%main_lab = OpLabel\n" +
4201       "%var = OpVariable %_ptr_float Function\n" +
4202       "%2 = OpLoad %float %var\n" +
4203       "%3 = OpFAdd %float %2 %float_1\n" +
4204       "%4 = OpFSub %float %float_2 %3\n" +
4205       "OpReturn\n" +
4206       "OpFunctionEnd\n",
4207     4, true),
4208   // Test case 7: merge add of subtract
4209   // 2 - (1 + x) = 1 - x
4210   InstructionFoldingCase<bool>(
4211     Header() +
4212       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4213       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4214       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4215       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
4216       "%main = OpFunction %void None %void_func\n" +
4217       "%main_lab = OpLabel\n" +
4218       "%var = OpVariable %_ptr_float Function\n" +
4219       "%2 = OpLoad %float %var\n" +
4220       "%3 = OpFAdd %float %float_1 %2\n" +
4221       "%4 = OpFSub %float %float_2 %3\n" +
4222       "OpReturn\n" +
4223       "OpFunctionEnd\n",
4224     4, true),
4225   // Test case 8: merge subtract of subtract
4226   // (x - 2) - 1 = x - 3
4227   InstructionFoldingCase<bool>(
4228     Header() +
4229       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4230       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4231       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4232       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
4233       "%main = OpFunction %void None %void_func\n" +
4234       "%main_lab = OpLabel\n" +
4235       "%var = OpVariable %_ptr_float Function\n" +
4236       "%2 = OpLoad %float %var\n" +
4237       "%3 = OpFSub %float %2 %float_2\n" +
4238       "%4 = OpFSub %float %3 %float_1\n" +
4239       "OpReturn\n" +
4240       "OpFunctionEnd\n",
4241     4, true),
4242   // Test case 9: merge subtract of subtract
4243   // (2 - x) - 1 = 1 - x
4244   InstructionFoldingCase<bool>(
4245     Header() +
4246       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4247       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4248       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4249       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
4250       "%main = OpFunction %void None %void_func\n" +
4251       "%main_lab = OpLabel\n" +
4252       "%var = OpVariable %_ptr_float Function\n" +
4253       "%2 = OpLoad %float %var\n" +
4254       "%3 = OpFSub %float %float_2 %2\n" +
4255       "%4 = OpFSub %float %3 %float_1\n" +
4256       "OpReturn\n" +
4257       "OpFunctionEnd\n",
4258     4, true),
4259   // Test case 10: merge subtract of subtract
4260   // 2 - (x - 1) = 3 - x
4261   InstructionFoldingCase<bool>(
4262     Header() +
4263       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4264       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
4265       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4266       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
4267       "%main = OpFunction %void None %void_func\n" +
4268       "%main_lab = OpLabel\n" +
4269       "%var = OpVariable %_ptr_float Function\n" +
4270       "%2 = OpLoad %float %var\n" +
4271       "%3 = OpFSub %float %2 %float_1\n" +
4272       "%4 = OpFSub %float %float_2 %3\n" +
4273       "OpReturn\n" +
4274       "OpFunctionEnd\n",
4275     4, true),
4276   // Test case 11: merge subtract of subtract
4277   // 1 - (2 - x) = x + (-1)
4278   InstructionFoldingCase<bool>(
4279     Header() +
4280       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4281       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
4282       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4283       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
4284       "%main = OpFunction %void None %void_func\n" +
4285       "%main_lab = OpLabel\n" +
4286       "%var = OpVariable %_ptr_float Function\n" +
4287       "%2 = OpLoad %float %var\n" +
4288       "%3 = OpFSub %float %float_2 %2\n" +
4289       "%4 = OpFSub %float %float_1 %3\n" +
4290       "OpReturn\n" +
4291       "OpFunctionEnd\n",
4292     4, true),
4293   // Test case 12: merge subtract of subtract
4294   // 2 - (1 - x) = x + 1
4295   InstructionFoldingCase<bool>(
4296     Header() +
4297       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4298       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
4299       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4300       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
4301       "%main = OpFunction %void None %void_func\n" +
4302       "%main_lab = OpLabel\n" +
4303       "%var = OpVariable %_ptr_float Function\n" +
4304       "%2 = OpLoad %float %var\n" +
4305       "%3 = OpFSub %float %float_1 %2\n" +
4306       "%4 = OpFSub %float %float_2 %3\n" +
4307       "OpReturn\n" +
4308       "OpFunctionEnd\n",
4309     4, true)
4310 ));
4311
4312 INSTANTIATE_TEST_CASE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
4313 ::testing::Values(
4314   // Test case 0: Fold select with the same values for both sides
4315   InstructionFoldingCase<bool>(
4316       Header() +
4317           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4318           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
4319           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
4320           "%main = OpFunction %void None %void_func\n" +
4321           "%main_lab = OpLabel\n" +
4322           "%n = OpVariable %_ptr_bool Function\n" +
4323           "%load = OpLoad %bool %n\n" +
4324           "%2 = OpSelect %int %load %100 %100\n" +
4325           "OpReturn\n" +
4326           "OpFunctionEnd",
4327       2, true),
4328   // Test case 1: Fold select true to left side
4329   InstructionFoldingCase<bool>(
4330       Header() +
4331           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4332           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
4333           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
4334           "%main = OpFunction %void None %void_func\n" +
4335           "%main_lab = OpLabel\n" +
4336           "%n = OpVariable %_ptr_int Function\n" +
4337           "%load = OpLoad %bool %n\n" +
4338           "%2 = OpSelect %int %true %100 %n\n" +
4339           "OpReturn\n" +
4340           "OpFunctionEnd",
4341       2, true),
4342   // Test case 2: Fold select false to right side
4343   InstructionFoldingCase<bool>(
4344       Header() +
4345           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4346           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
4347           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
4348           "%main = OpFunction %void None %void_func\n" +
4349           "%main_lab = OpLabel\n" +
4350           "%n = OpVariable %_ptr_int Function\n" +
4351           "%load = OpLoad %bool %n\n" +
4352           "%2 = OpSelect %int %false %n %100\n" +
4353           "OpReturn\n" +
4354           "OpFunctionEnd",
4355       2, true),
4356   // Test case 3: Fold select null to right side
4357   InstructionFoldingCase<bool>(
4358       Header() +
4359           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4360           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
4361           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
4362           "%main = OpFunction %void None %void_func\n" +
4363           "%main_lab = OpLabel\n" +
4364           "%n = OpVariable %_ptr_int Function\n" +
4365           "%load = OpLoad %int %n\n" +
4366           "%2 = OpSelect %int %bool_null %load %100\n" +
4367           "OpReturn\n" +
4368           "OpFunctionEnd",
4369       2, true),
4370   // Test case 4: vector null
4371   InstructionFoldingCase<bool>(
4372       Header() +
4373           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4374           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4375           "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
4376           "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
4377           "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
4378           "%main = OpFunction %void None %void_func\n" +
4379           "%main_lab = OpLabel\n" +
4380           "%n = OpVariable %_ptr_v2int Function\n" +
4381           "%load = OpLoad %v2int %n\n" +
4382           "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
4383           "OpReturn\n" +
4384           "OpFunctionEnd",
4385       2, true),
4386   // Test case 5: vector select
4387   InstructionFoldingCase<bool>(
4388       Header() +
4389           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4390           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4391           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
4392           "%main = OpFunction %void None %void_func\n" +
4393           "%main_lab = OpLabel\n" +
4394           "%m = OpVariable %_ptr_v2int Function\n" +
4395           "%n = OpVariable %_ptr_v2int Function\n" +
4396           "%2 = OpLoad %v2int %n\n" +
4397           "%3 = OpLoad %v2int %n\n" +
4398           "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
4399           "OpReturn\n" +
4400           "OpFunctionEnd",
4401       4, true),
4402   // Test case 6: vector select
4403   InstructionFoldingCase<bool>(
4404       Header() +
4405           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4406           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
4407           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
4408           "%main = OpFunction %void None %void_func\n" +
4409           "%main_lab = OpLabel\n" +
4410           "%m = OpVariable %_ptr_v2int Function\n" +
4411           "%n = OpVariable %_ptr_v2int Function\n" +
4412           "%2 = OpLoad %v2int %n\n" +
4413           "%3 = OpLoad %v2int %n\n" +
4414           "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
4415           "OpReturn\n" +
4416           "OpFunctionEnd",
4417       4, true)
4418 ));
4419
4420 INSTANTIATE_TEST_CASE_P(CompositeExtractMatchingTest, MatchingInstructionFoldingTest,
4421 ::testing::Values(
4422     // Test case 0: Extracting from result of consecutive shuffles of differing
4423     // size.
4424     InstructionFoldingCase<bool>(
4425         Header() +
4426             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4427             "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
4428             "%main = OpFunction %void None %void_func\n" +
4429             "%main_lab = OpLabel\n" +
4430             "%n = OpVariable %_ptr_v4int Function\n" +
4431             "%2 = OpLoad %v4int %n\n" +
4432             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
4433             "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
4434             "%5 = OpCompositeExtract %int %4 1\n" +
4435             "OpReturn\n" +
4436             "OpFunctionEnd",
4437         5, true),
4438     // Test case 1: Extracting from result of vector shuffle of differing
4439     // input and result sizes.
4440     InstructionFoldingCase<bool>(
4441         Header() +
4442             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4443             "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
4444             "%main = OpFunction %void None %void_func\n" +
4445             "%main_lab = OpLabel\n" +
4446             "%n = OpVariable %_ptr_v4int Function\n" +
4447             "%2 = OpLoad %v4int %n\n" +
4448             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
4449             "%4 = OpCompositeExtract %int %3 0\n" +
4450             "OpReturn\n" +
4451             "OpFunctionEnd",
4452         4, true),
4453     // Test case 2: Extracting from result of vector shuffle of differing
4454     // input and result sizes.
4455     InstructionFoldingCase<bool>(
4456         Header() +
4457             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4458             "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
4459             "%main = OpFunction %void None %void_func\n" +
4460             "%main_lab = OpLabel\n" +
4461             "%n = OpVariable %_ptr_v4int Function\n" +
4462             "%2 = OpLoad %v4int %n\n" +
4463             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
4464             "%4 = OpCompositeExtract %int %3 1\n" +
4465             "OpReturn\n" +
4466             "OpFunctionEnd",
4467         4, true)
4468 ));
4469 #endif
4470 }  // anonymous namespace