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