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