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 
31 namespace spvtools {
32 namespace opt {
33 namespace {
34 
35 using ::testing::Contains;
36 
Disassemble(const std::string& original, IRContext* context, uint32_t disassemble_options = 0)37 std::string Disassemble(const std::string& original, IRContext* context,
38                         uint32_t disassemble_options = 0) {
39   std::vector<uint32_t> optimized_bin;
40   context->module()->ToBinary(&optimized_bin, true);
41   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
42   SpirvTools tools(target_env);
43   std::string optimized_asm;
44   EXPECT_TRUE(
45       tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
46       << "Disassembling failed for shader:\n"
47       << original << std::endl;
48   return optimized_asm;
49 }
50 
Match(const std::string& original, IRContext* context, uint32_t disassemble_options = 0)51 void Match(const std::string& original, IRContext* context,
52            uint32_t disassemble_options = 0) {
53   std::string disassembly = Disassemble(original, context, disassemble_options);
54   auto match_result = effcee::Match(disassembly, original);
55   EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
56       << match_result.message() << "\nChecking result:\n"
57       << disassembly;
58 }
59 
60 template <class ResultType>
61 struct InstructionFoldingCase {
InstructionFoldingCasespvtools::opt::__anon26957::InstructionFoldingCase62   InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
63       : test_body(tb), id_to_fold(id), expected_result(result) {}
64 
65   std::string test_body;
66   uint32_t id_to_fold;
67   ResultType expected_result;
68 };
69 
70 using IntegerInstructionFoldingTest =
71     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
72 
TEST_P(IntegerInstructionFoldingTest, Case)73 TEST_P(IntegerInstructionFoldingTest, Case) {
74   const auto& tc = GetParam();
75 
76   // Build module.
77   std::unique_ptr<IRContext> context =
78       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
79                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
80   ASSERT_NE(nullptr, context);
81 
82   // Fold the instruction to test.
83   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
84   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
85   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
86 
87   // Make sure the instruction folded as expected.
88   EXPECT_TRUE(succeeded);
89   if (inst != nullptr) {
90     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
91     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
92     EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
93     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
94     const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
95     // We expect to see either integer types or 16-bit float types here.
96     EXPECT_TRUE((constant->AsIntConstant() != nullptr) ||
97                 ((constant->AsFloatConstant() != nullptr) &&
98                  (constant->type()->AsFloat()->width() == 16)));
99     const analysis::ScalarConstant* result =
100         const_mrg->GetConstantFromInst(inst)->AsScalarConstant();
101     EXPECT_NE(result, nullptr);
102     if (result != nullptr) {
103       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
104     }
105   }
106 }
107 
108 // Returns a common SPIR-V header for all of the test that follow.
109 #define INT_0_ID 100
110 #define TRUE_ID 101
111 #define VEC2_0_ID 102
112 #define INT_7_ID 103
113 #define FLOAT_0_ID 104
114 #define DOUBLE_0_ID 105
115 #define VEC4_0_ID 106
116 #define DVEC4_0_ID 106
117 #define HALF_0_ID 108
Header()118 const std::string& Header() {
119   static const std::string header = R"(OpCapability Shader
120 OpCapability Float16
121 OpCapability Float64
122 OpCapability Int8
123 OpCapability Int16
124 OpCapability Int64
125 %1 = OpExtInstImport "GLSL.std.450"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint Fragment %main "main"
128 OpExecutionMode %main OriginUpperLeft
129 OpSource GLSL 140
130 OpName %main "main"
131 %void = OpTypeVoid
132 %void_func = OpTypeFunction %void
133 %bool = OpTypeBool
134 %float = OpTypeFloat 32
135 %double = OpTypeFloat 64
136 %half = OpTypeFloat 16
137 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
138 %true = OpConstantTrue %bool
139 %false = OpConstantFalse %bool
140 %bool_null = OpConstantNull %bool
141 %short = OpTypeInt 16 1
142 %ushort = OpTypeInt 16 0
143 %byte = OpTypeInt 8 1
144 %ubyte = OpTypeInt 8 0
145 %int = OpTypeInt 32 1
146 %long = OpTypeInt 64 1
147 %uint = OpTypeInt 32 0
148 %ulong = OpTypeInt 64 0
149 %v2int = OpTypeVector %int 2
150 %v4int = OpTypeVector %int 4
151 %v4float = OpTypeVector %float 4
152 %v4double = OpTypeVector %double 4
153 %v2uint = OpTypeVector %uint 2
154 %v2float = OpTypeVector %float 2
155 %v2double = OpTypeVector %double 2
156 %v2half = OpTypeVector %half 2
157 %v2bool = OpTypeVector %bool 2
158 %m2x2int = OpTypeMatrix %v2int 2
159 %mat4v2float = OpTypeMatrix %v2float 4
160 %mat2v4float = OpTypeMatrix %v4float 2
161 %mat4v4float = OpTypeMatrix %v4float 4
162 %mat4v4double = OpTypeMatrix %v4double 4
163 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
164 %_ptr_int = OpTypePointer Function %int
165 %_ptr_uint = OpTypePointer Function %uint
166 %_ptr_bool = OpTypePointer Function %bool
167 %_ptr_float = OpTypePointer Function %float
168 %_ptr_double = OpTypePointer Function %double
169 %_ptr_half = OpTypePointer Function %half
170 %_ptr_long = OpTypePointer Function %long
171 %_ptr_ulong = OpTypePointer Function %ulong
172 %_ptr_v2int = OpTypePointer Function %v2int
173 %_ptr_v4int = OpTypePointer Function %v4int
174 %_ptr_v4float = OpTypePointer Function %v4float
175 %_ptr_v4double = OpTypePointer Function %v4double
176 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
177 %_ptr_v2float = OpTypePointer Function %v2float
178 %_ptr_v2double = OpTypePointer Function %v2double
179 %int_2 = OpConstant %int 2
180 %int_arr_2 = OpTypeArray %int %int_2
181 %short_0 = OpConstant %short 0
182 %short_2 = OpConstant %short 2
183 %short_3 = OpConstant %short 3
184 %ubyte_1 = OpConstant %ubyte 1
185 %byte_n1 = OpConstant %byte -1
186 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
187 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
188 %int_0 = OpConstant %int 0
189 %int_1 = OpConstant %int 1
190 %int_3 = OpConstant %int 3
191 %int_4 = OpConstant %int 4
192 %int_10 = OpConstant %int 10
193 %int_1073741824 = OpConstant %int 1073741824
194 %int_n1 = OpConstant %int -1
195 %int_n24 = OpConstant %int -24
196 %int_n858993459 = OpConstant %int -858993459
197 %int_min = OpConstant %int -2147483648
198 %int_max = OpConstant %int 2147483647
199 %long_0 = OpConstant %long 0
200 %long_1 = OpConstant %long 1
201 %long_2 = OpConstant %long 2
202 %long_3 = OpConstant %long 3
203 %long_10 = OpConstant %long 10
204 %long_4611686018427387904 = OpConstant %long 4611686018427387904
205 %long_n1 = OpConstant %long -1
206 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
207 %long_min = OpConstant %long -9223372036854775808
208 %long_max = OpConstant %long 9223372036854775807
209 %uint_0 = OpConstant %uint 0
210 %uint_1 = OpConstant %uint 1
211 %uint_2 = OpConstant %uint 2
212 %uint_3 = OpConstant %uint 3
213 %uint_4 = OpConstant %uint 4
214 %uint_32 = OpConstant %uint 32
215 %uint_42 = OpConstant %uint 42
216 %uint_2147483649 = OpConstant %uint 2147483649
217 %uint_max = OpConstant %uint 4294967295
218 %ulong_0 = OpConstant %ulong 0
219 %ulong_1 = OpConstant %ulong 1
220 %ulong_2 = OpConstant %ulong 2
221 %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809
222 %ulong_max = OpConstant %ulong 18446744073709551615
223 %v2int_undef = OpUndef %v2int
224 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
225 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
226 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
227 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
228 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
229 %v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24
230 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
231 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
232 %v2bool_null = OpConstantNull %v2bool
233 %v2bool_true_false = OpConstantComposite %v2bool %true %false
234 %v2bool_false_true = OpConstantComposite %v2bool %false %true
235 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
236 %v2int_null = OpConstantNull %v2int
237 %102 = OpConstantComposite %v2int %103 %103
238 %v4int_undef = OpUndef %v4int
239 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
240 %m2x2int_undef = OpUndef %m2x2int
241 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
242 %float_n1 = OpConstant %float -1
243 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
244 %float_null = OpConstantNull %float
245 %float_0 = OpConstant %float 0
246 %float_n0 = OpConstant %float -0.0
247 %float_1 = OpConstant %float 1
248 %float_2 = OpConstant %float 2
249 %float_3 = OpConstant %float 3
250 %float_4 = OpConstant %float 4
251 %float_2049 = OpConstant %float 2049
252 %float_n2049 = OpConstant %float -2049
253 %float_0p5 = OpConstant %float 0.5
254 %float_0p2 = OpConstant %float 0.2
255 %float_pi = OpConstant %float 1.5555
256 %float_1e16 = OpConstant %float 1e16
257 %float_n1e16 = OpConstant %float -1e16
258 %float_1en16 = OpConstant %float 1e-16
259 %float_n1en16 = OpConstant %float -1e-16
260 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
261 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
262 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
263 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
264 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
265 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
266 %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
267 %v2float_null = OpConstantNull %v2float
268 %double_n1 = OpConstant %double -1
269 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
270 %double_null = OpConstantNull %double
271 %double_0 = OpConstant %double 0
272 %double_n0 = OpConstant %double -0.0
273 %double_1 = OpConstant %double 1
274 %double_2 = OpConstant %double 2
275 %double_3 = OpConstant %double 3
276 %double_4 = OpConstant %double 4
277 %double_5 = OpConstant %double 5
278 %double_0p5 = OpConstant %double 0.5
279 %double_0p2 = OpConstant %double 0.2
280 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
281 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
282 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
283 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
284 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
285 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
286 %v2double_null = OpConstantNull %v2double
287 %108 = OpConstant %half 0
288 %half_1 = OpConstant %half 1
289 %half_2 = OpConstant %half 2
290 %half_0_1 = OpConstantComposite %v2half %108 %half_1
291 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
292 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
293 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
294 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
295 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
296 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
297 %v4float_null = OpConstantNull %v4float
298 %mat2v4float_null = OpConstantNull %mat2v4float
299 %mat4v4float_null = OpConstantNull %mat4v4float
300 %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4
301 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null
302 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
303 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
304 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
305 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
306 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
307 %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4
308 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
309 %v4double_null = OpConstantNull %v4double
310 %mat4v4double_null = OpConstantNull %mat4v4double
311 %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4
312 %mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null
313 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
314 %uint_0x3f800000 = OpConstant %uint 0x3f800000
315 %uint_0xbf800000 = OpConstant %uint 0xbf800000
316 %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000
317 %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000
318 %int_0x3FF00000 = OpConstant %int 0x3FF00000
319 %int_0x00000000 = OpConstant %int 0x00000000
320 %int_0xC05FD666 = OpConstant %int 0xC05FD666
321 %int_0x66666666 = OpConstant %int 0x66666666
322 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
323 %ushort_0x4400 = OpConstant %ushort 0x4400
324 %short_0x4400 = OpConstant %short 0x4400
325 %ushort_0xBC00 = OpConstant %ushort 0xBC00
326 %short_0xBC00 = OpConstant %short 0xBC00
327 %int_arr_2_undef = OpUndef %int_arr_2
328 )";
329 
330   return header;
331 }
332 
333 // Returns the header with definitions of float NaN and double NaN. Since FC
334 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
335 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
336 // %double_n0 = OpConstant %double -0,
337 // we separates those definitions from Header().
HeaderWithNaN()338 const std::string& HeaderWithNaN() {
339   static const std::string headerWithNaN =
340       Header() +
341       R"(%float_nan = OpConstant %float -0x1.8p+128
342 %double_nan = OpConstant %double -0x1.8p+1024
343 )";
344 
345   return headerWithNaN;
346 }
347 
348 // clang-format off
349 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
350                         ::testing::Values(
351   // Test case 0: fold 0*n
352   InstructionFoldingCase<uint32_t>(
353     Header() + "%main = OpFunction %void None %void_func\n" +
354     "%main_lab = OpLabel\n" +
355            "%n = OpVariable %_ptr_int Function\n" +
356         "%load = OpLoad %int %n\n" +
357            "%2 = OpIMul %int %int_0 %load\n" +
358                 "OpReturn\n" +
359                 "OpFunctionEnd",
360     2, 0),
361   // Test case 1: fold n*0
362   InstructionFoldingCase<uint32_t>(
363     Header() + "%main = OpFunction %void None %void_func\n" +
364         "%main_lab = OpLabel\n" +
365         "%n = OpVariable %_ptr_int Function\n" +
366         "%load = OpLoad %int %n\n" +
367         "%2 = OpIMul %int %load %int_0\n" +
368         "OpReturn\n" +
369         "OpFunctionEnd",
370     2, 0),
371   // Test case 2: fold 0/n (signed)
372   InstructionFoldingCase<uint32_t>(
373     Header() + "%main = OpFunction %void None %void_func\n" +
374         "%main_lab = OpLabel\n" +
375         "%n = OpVariable %_ptr_int Function\n" +
376         "%load = OpLoad %int %n\n" +
377         "%2 = OpSDiv %int %int_0 %load\n" +
378         "OpReturn\n" +
379         "OpFunctionEnd",
380         2, 0),
381   // Test case 3: fold n/0 (signed)
382   InstructionFoldingCase<uint32_t>(
383     Header() + "%main = OpFunction %void None %void_func\n" +
384         "%main_lab = OpLabel\n" +
385         "%n = OpVariable %_ptr_int Function\n" +
386         "%load = OpLoad %int %n\n" +
387         "%2 = OpSDiv %int %load %int_0\n" +
388         "OpReturn\n" +
389         "OpFunctionEnd",
390     2, 0),
391   // Test case 4: fold 0/n (unsigned)
392   InstructionFoldingCase<uint32_t>(
393     Header() + "%main = OpFunction %void None %void_func\n" +
394         "%main_lab = OpLabel\n" +
395         "%n = OpVariable %_ptr_uint Function\n" +
396         "%load = OpLoad %uint %n\n" +
397         "%2 = OpUDiv %uint %uint_0 %load\n" +
398         "OpReturn\n" +
399         "OpFunctionEnd",
400     2, 0),
401   // Test case 5: fold n/0 (unsigned)
402   InstructionFoldingCase<uint32_t>(
403     Header() + "%main = OpFunction %void None %void_func\n" +
404         "%main_lab = OpLabel\n" +
405         "%n = OpVariable %_ptr_int Function\n" +
406         "%load = OpLoad %int %n\n" +
407         "%2 = OpSDiv %int %load %int_0\n" +
408         "OpReturn\n" +
409         "OpFunctionEnd",
410     2, 0),
411   // Test case 6: fold 0 remainder n
412   InstructionFoldingCase<uint32_t>(
413     Header() + "%main = OpFunction %void None %void_func\n" +
414         "%main_lab = OpLabel\n" +
415         "%n = OpVariable %_ptr_int Function\n" +
416         "%load = OpLoad %int %n\n" +
417         "%2 = OpSRem %int %int_0 %load\n" +
418         "OpReturn\n" +
419         "OpFunctionEnd",
420     2, 0),
421   // Test case 7: fold n remainder 0
422   InstructionFoldingCase<uint32_t>(
423     Header() + "%main = OpFunction %void None %void_func\n" +
424         "%main_lab = OpLabel\n" +
425         "%n = OpVariable %_ptr_int Function\n" +
426         "%load = OpLoad %int %n\n" +
427         "%2 = OpSRem %int %load %int_0\n" +
428         "OpReturn\n" +
429         "OpFunctionEnd",
430     2, 0),
431   // Test case 8: fold 0%n (signed)
432   InstructionFoldingCase<uint32_t>(
433     Header() + "%main = OpFunction %void None %void_func\n" +
434         "%main_lab = OpLabel\n" +
435         "%n = OpVariable %_ptr_int Function\n" +
436         "%load = OpLoad %int %n\n" +
437         "%2 = OpSMod %int %int_0 %load\n" +
438         "OpReturn\n" +
439         "OpFunctionEnd",
440     2, 0),
441   // Test case 9: fold n%0 (signed)
442   InstructionFoldingCase<uint32_t>(
443     Header() + "%main = OpFunction %void None %void_func\n" +
444         "%main_lab = OpLabel\n" +
445         "%n = OpVariable %_ptr_int Function\n" +
446         "%load = OpLoad %int %n\n" +
447         "%2 = OpSMod %int %load %int_0\n" +
448         "OpReturn\n" +
449         "OpFunctionEnd",
450     2, 0),
451   // Test case 10: fold 0%n (unsigned)
452   InstructionFoldingCase<uint32_t>(
453     Header() + "%main = OpFunction %void None %void_func\n" +
454         "%main_lab = OpLabel\n" +
455         "%n = OpVariable %_ptr_uint Function\n" +
456         "%load = OpLoad %uint %n\n" +
457         "%2 = OpUMod %uint %uint_0 %load\n" +
458         "OpReturn\n" +
459         "OpFunctionEnd",
460     2, 0),
461   // Test case 11: fold n%0 (unsigned)
462   InstructionFoldingCase<uint32_t>(
463     Header() + "%main = OpFunction %void None %void_func\n" +
464         "%main_lab = OpLabel\n" +
465         "%n = OpVariable %_ptr_uint Function\n" +
466         "%load = OpLoad %uint %n\n" +
467         "%2 = OpUMod %uint %load %uint_0\n" +
468         "OpReturn\n" +
469         "OpFunctionEnd",
470     2, 0),
471   // Test case 12: fold n << 32
472   InstructionFoldingCase<uint32_t>(
473       Header() + "%main = OpFunction %void None %void_func\n" +
474           "%main_lab = OpLabel\n" +
475           "%n = OpVariable %_ptr_uint Function\n" +
476           "%load = OpLoad %uint %n\n" +
477           "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
478           "OpReturn\n" +
479           "OpFunctionEnd",
480       2, 0),
481   // Test case 13: fold n >> 32
482   InstructionFoldingCase<uint32_t>(
483       Header() + "%main = OpFunction %void None %void_func\n" +
484           "%main_lab = OpLabel\n" +
485           "%n = OpVariable %_ptr_uint Function\n" +
486           "%load = OpLoad %uint %n\n" +
487           "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
488           "OpReturn\n" +
489           "OpFunctionEnd",
490       2, 0),
491   // Test case 14: fold n | 0xFFFFFFFF
492   InstructionFoldingCase<uint32_t>(
493       Header() + "%main = OpFunction %void None %void_func\n" +
494   "%main_lab = OpLabel\n" +
495   "%n = OpVariable %_ptr_uint Function\n" +
496   "%load = OpLoad %uint %n\n" +
497   "%2 = OpBitwiseOr %uint %load %uint_max\n" +
498   "OpReturn\n" +
499   "OpFunctionEnd",
500   2, 0xFFFFFFFF),
501   // Test case 15: fold 0xFFFFFFFF | n
502   InstructionFoldingCase<uint32_t>(
503       Header() + "%main = OpFunction %void None %void_func\n" +
504           "%main_lab = OpLabel\n" +
505           "%n = OpVariable %_ptr_uint Function\n" +
506           "%load = OpLoad %uint %n\n" +
507           "%2 = OpBitwiseOr %uint %uint_max %load\n" +
508           "OpReturn\n" +
509           "OpFunctionEnd",
510       2, 0xFFFFFFFF),
511   // Test case 16: fold n & 0
512   InstructionFoldingCase<uint32_t>(
513       Header() + "%main = OpFunction %void None %void_func\n" +
514           "%main_lab = OpLabel\n" +
515           "%n = OpVariable %_ptr_uint Function\n" +
516           "%load = OpLoad %uint %n\n" +
517           "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
518           "OpReturn\n" +
519           "OpFunctionEnd",
520       2, 0),
521   // Test case 17: fold 1/0 (signed)
522   InstructionFoldingCase<uint32_t>(
523       Header() + "%main = OpFunction %void None %void_func\n" +
524           "%main_lab = OpLabel\n" +
525           "%2 = OpSDiv %int %int_1 %int_0\n" +
526           "OpReturn\n" +
527           "OpFunctionEnd",
528       2, 0),
529   // Test case 18: fold 1/0 (unsigned)
530   InstructionFoldingCase<uint32_t>(
531       Header() + "%main = OpFunction %void None %void_func\n" +
532           "%main_lab = OpLabel\n" +
533           "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
534           "OpReturn\n" +
535           "OpFunctionEnd",
536       2, 0),
537   // Test case 19: fold OpSRem 1 0 (signed)
538   InstructionFoldingCase<uint32_t>(
539       Header() + "%main = OpFunction %void None %void_func\n" +
540           "%main_lab = OpLabel\n" +
541           "%2 = OpSRem %int %int_1 %int_0\n" +
542           "OpReturn\n" +
543           "OpFunctionEnd",
544       2, 0),
545   // Test case 20: fold 1%0 (signed)
546   InstructionFoldingCase<uint32_t>(
547       Header() + "%main = OpFunction %void None %void_func\n" +
548           "%main_lab = OpLabel\n" +
549           "%2 = OpSMod %int %int_1 %int_0\n" +
550           "OpReturn\n" +
551           "OpFunctionEnd",
552       2, 0),
553   // Test case 21: fold 1%0 (unsigned)
554   InstructionFoldingCase<uint32_t>(
555       Header() + "%main = OpFunction %void None %void_func\n" +
556           "%main_lab = OpLabel\n" +
557           "%2 = OpUMod %uint %uint_1 %uint_0\n" +
558           "OpReturn\n" +
559           "OpFunctionEnd",
560       2, 0),
561   // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
562   InstructionFoldingCase<uint32_t>(
563       Header() + "%main = OpFunction %void None %void_func\n" +
564           "%main_lab = OpLabel\n" +
565           "%n = OpVariable %_ptr_uint Function\n" +
566           "%load = OpLoad %uint %n\n" +
567           "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
568           "OpReturn\n" +
569           "OpFunctionEnd",
570       2, 0),
571   // Test case 23: fold signed n >> 42 (undefined, so set to zero).
572   InstructionFoldingCase<uint32_t>(
573       Header() + "%main = OpFunction %void None %void_func\n" +
574           "%main_lab = OpLabel\n" +
575           "%n = OpVariable %_ptr_int Function\n" +
576           "%load = OpLoad %int %n\n" +
577           "%2 = OpShiftRightLogical %int %load %uint_42\n" +
578           "OpReturn\n" +
579           "OpFunctionEnd",
580       2, 0),
581   // Test case 24: fold n << 42 (undefined, so set to zero).
582   InstructionFoldingCase<uint32_t>(
583       Header() + "%main = OpFunction %void None %void_func\n" +
584           "%main_lab = OpLabel\n" +
585           "%n = OpVariable %_ptr_int Function\n" +
586           "%load = OpLoad %int %n\n" +
587           "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
588           "OpReturn\n" +
589           "OpFunctionEnd",
590       2, 0),
591   // Test case 25: fold -24 >> 32 (defined as -1)
592   InstructionFoldingCase<uint32_t>(
593       Header() + "%main = OpFunction %void None %void_func\n" +
594           "%main_lab = OpLabel\n" +
595           "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
596           "OpReturn\n" +
597           "OpFunctionEnd",
598       2, -1),
599   // Test case 26: fold 2 >> 32 (signed)
600   InstructionFoldingCase<uint32_t>(
601       Header() + "%main = OpFunction %void None %void_func\n" +
602           "%main_lab = OpLabel\n" +
603           "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
604           "OpReturn\n" +
605           "OpFunctionEnd",
606       2, 0),
607   // Test case 27: fold 2 >> 32 (unsigned)
608   InstructionFoldingCase<uint32_t>(
609       Header() + "%main = OpFunction %void None %void_func\n" +
610           "%main_lab = OpLabel\n" +
611           "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
612           "OpReturn\n" +
613           "OpFunctionEnd",
614       2, 0),
615   // Test case 28: fold 2 << 32
616   InstructionFoldingCase<uint32_t>(
617       Header() + "%main = OpFunction %void None %void_func\n" +
618           "%main_lab = OpLabel\n" +
619           "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
620           "OpReturn\n" +
621           "OpFunctionEnd",
622       2, 0),
623   // Test case 29: fold -INT_MIN
624   InstructionFoldingCase<uint32_t>(
625       Header() + "%main = OpFunction %void None %void_func\n" +
626           "%main_lab = OpLabel\n" +
627           "%2 = OpSNegate %int %int_min\n" +
628           "OpReturn\n" +
629           "OpFunctionEnd",
630       2, std::numeric_limits<int32_t>::min()),
631   // Test case 30: fold UMin 3 4
632   InstructionFoldingCase<uint32_t>(
633       Header() + "%main = OpFunction %void None %void_func\n" +
634           "%main_lab = OpLabel\n" +
635           "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
636           "OpReturn\n" +
637           "OpFunctionEnd",
638       2, 3),
639   // Test case 31: fold UMin 4 2
640   InstructionFoldingCase<uint32_t>(
641       Header() + "%main = OpFunction %void None %void_func\n" +
642           "%main_lab = OpLabel\n" +
643           "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
644           "OpReturn\n" +
645           "OpFunctionEnd",
646       2, 2),
647   // Test case 32: fold SMin 3 4
648   InstructionFoldingCase<uint32_t>(
649       Header() + "%main = OpFunction %void None %void_func\n" +
650           "%main_lab = OpLabel\n" +
651           "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
652           "OpReturn\n" +
653           "OpFunctionEnd",
654       2, 3),
655   // Test case 33: fold SMin 4 2
656   InstructionFoldingCase<uint32_t>(
657       Header() + "%main = OpFunction %void None %void_func\n" +
658           "%main_lab = OpLabel\n" +
659           "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
660           "OpReturn\n" +
661           "OpFunctionEnd",
662       2, 2),
663   // Test case 34: fold UMax 3 4
664   InstructionFoldingCase<uint32_t>(
665       Header() + "%main = OpFunction %void None %void_func\n" +
666           "%main_lab = OpLabel\n" +
667           "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
668           "OpReturn\n" +
669           "OpFunctionEnd",
670       2, 4),
671   // Test case 35: fold UMax 3 2
672   InstructionFoldingCase<uint32_t>(
673       Header() + "%main = OpFunction %void None %void_func\n" +
674           "%main_lab = OpLabel\n" +
675           "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
676           "OpReturn\n" +
677           "OpFunctionEnd",
678       2, 3),
679   // Test case 36: fold SMax 3 4
680   InstructionFoldingCase<uint32_t>(
681       Header() + "%main = OpFunction %void None %void_func\n" +
682           "%main_lab = OpLabel\n" +
683           "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
684           "OpReturn\n" +
685           "OpFunctionEnd",
686       2, 4),
687   // Test case 37: fold SMax 3 2
688   InstructionFoldingCase<uint32_t>(
689       Header() + "%main = OpFunction %void None %void_func\n" +
690           "%main_lab = OpLabel\n" +
691           "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
692           "OpReturn\n" +
693           "OpFunctionEnd",
694       2, 3),
695   // Test case 38: fold UClamp 2 3 4
696   InstructionFoldingCase<uint32_t>(
697       Header() + "%main = OpFunction %void None %void_func\n" +
698           "%main_lab = OpLabel\n" +
699           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
700           "OpReturn\n" +
701           "OpFunctionEnd",
702       2, 3),
703   // Test case 39: fold UClamp 2 0 4
704   InstructionFoldingCase<uint32_t>(
705       Header() + "%main = OpFunction %void None %void_func\n" +
706           "%main_lab = OpLabel\n" +
707           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
708           "OpReturn\n" +
709           "OpFunctionEnd",
710       2, 2),
711   // Test case 40: fold UClamp 2 0 1
712   InstructionFoldingCase<uint32_t>(
713       Header() + "%main = OpFunction %void None %void_func\n" +
714           "%main_lab = OpLabel\n" +
715           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
716           "OpReturn\n" +
717           "OpFunctionEnd",
718       2, 1),
719   // Test case 41: fold SClamp 2 3 4
720   InstructionFoldingCase<uint32_t>(
721       Header() + "%main = OpFunction %void None %void_func\n" +
722           "%main_lab = OpLabel\n" +
723           "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
724           "OpReturn\n" +
725           "OpFunctionEnd",
726       2, 3),
727   // Test case 42: fold SClamp 2 0 4
728   InstructionFoldingCase<uint32_t>(
729       Header() + "%main = OpFunction %void None %void_func\n" +
730           "%main_lab = OpLabel\n" +
731           "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
732           "OpReturn\n" +
733           "OpFunctionEnd",
734       2, 2),
735   // Test case 43: fold SClamp 2 0 1
736   InstructionFoldingCase<uint32_t>(
737       Header() + "%main = OpFunction %void None %void_func\n" +
738           "%main_lab = OpLabel\n" +
739           "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
740           "OpReturn\n" +
741           "OpFunctionEnd",
742       2, 1),
743   // Test case 44: SClamp 1 2 x
744   InstructionFoldingCase<uint32_t>(
745       Header() + "%main = OpFunction %void None %void_func\n" +
746           "%main_lab = OpLabel\n" +
747           "%undef = OpUndef %int\n" +
748           "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
749           "OpReturn\n" +
750           "OpFunctionEnd",
751       2, 2),
752   // Test case 45: SClamp 2 x 1
753   InstructionFoldingCase<uint32_t>(
754       Header() + "%main = OpFunction %void None %void_func\n" +
755           "%main_lab = OpLabel\n" +
756           "%undef = OpUndef %int\n" +
757           "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
758           "OpReturn\n" +
759           "OpFunctionEnd",
760       2, 1),
761   // Test case 46: UClamp 1 2 x
762   InstructionFoldingCase<uint32_t>(
763       Header() + "%main = OpFunction %void None %void_func\n" +
764           "%main_lab = OpLabel\n" +
765           "%undef = OpUndef %uint\n" +
766           "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
767           "OpReturn\n" +
768           "OpFunctionEnd",
769       2, 2),
770   // Test case 47: UClamp 2 x 1
771   InstructionFoldingCase<uint32_t>(
772       Header() + "%main = OpFunction %void None %void_func\n" +
773           "%main_lab = OpLabel\n" +
774           "%undef = OpUndef %uint\n" +
775           "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
776           "OpReturn\n" +
777           "OpFunctionEnd",
778       2, 1),
779     // Test case 48: Bit-cast int 0 to unsigned int
780     InstructionFoldingCase<uint32_t>(
781         Header() + "%main = OpFunction %void None %void_func\n" +
782             "%main_lab = OpLabel\n" +
783             "%2 = OpBitcast %uint %int_0\n" +
784             "OpReturn\n" +
785             "OpFunctionEnd",
786         2, 0),
787     // Test case 49: Bit-cast int -24 to unsigned int
788     InstructionFoldingCase<uint32_t>(
789         Header() + "%main = OpFunction %void None %void_func\n" +
790             "%main_lab = OpLabel\n" +
791             "%2 = OpBitcast %uint %int_n24\n" +
792             "OpReturn\n" +
793             "OpFunctionEnd",
794         2, static_cast<uint32_t>(-24)),
795     // Test case 50: Bit-cast float 1.0f to unsigned int
796     InstructionFoldingCase<uint32_t>(
797         Header() + "%main = OpFunction %void None %void_func\n" +
798             "%main_lab = OpLabel\n" +
799             "%2 = OpBitcast %uint %float_1\n" +
800             "OpReturn\n" +
801             "OpFunctionEnd",
802         2, static_cast<uint32_t>(0x3f800000)),
803     // Test case 51: Bit-cast ushort 0xBC00 to ushort
804     InstructionFoldingCase<uint32_t>(
805         Header() + "%main = OpFunction %void None %void_func\n" +
806             "%main_lab = OpLabel\n" +
807             "%2 = OpBitcast %ushort %ushort_0xBC00\n" +
808             "OpReturn\n" +
809             "OpFunctionEnd",
810         2, 0xBC00),
811     // Test case 52: Bit-cast short 0xBC00 to ushort
812     InstructionFoldingCase<uint32_t>(
813         Header() + "%main = OpFunction %void None %void_func\n" +
814             "%main_lab = OpLabel\n" +
815             "%2 = OpBitcast %ushort %short_0xBC00\n" +
816             "OpReturn\n" +
817             "OpFunctionEnd",
818         2, 0xFFFFBC00),
819     // Test case 53: Bit-cast half 1 to ushort
820     InstructionFoldingCase<uint32_t>(
821         Header() + "%main = OpFunction %void None %void_func\n" +
822             "%main_lab = OpLabel\n" +
823             "%2 = OpBitcast %ushort %half_1\n" +
824             "OpReturn\n" +
825             "OpFunctionEnd",
826         2, 0x3C00),
827     // Test case 54: Bit-cast ushort 0xBC00 to short
828     InstructionFoldingCase<uint32_t>(
829         Header() + "%main = OpFunction %void None %void_func\n" +
830             "%main_lab = OpLabel\n" +
831             "%2 = OpBitcast %short %ushort_0xBC00\n" +
832             "OpReturn\n" +
833             "OpFunctionEnd",
834         2, 0xBC00),
835     // Test case 55: Bit-cast short 0xBC00 to short
836     InstructionFoldingCase<uint32_t>(
837         Header() + "%main = OpFunction %void None %void_func\n" +
838             "%main_lab = OpLabel\n" +
839             "%2 = OpBitcast %short %short_0xBC00\n" +
840             "OpReturn\n" +
841             "OpFunctionEnd",
842         2, 0xFFFFBC00),
843     // Test case 56: Bit-cast half 1 to short
844     InstructionFoldingCase<uint32_t>(
845         Header() + "%main = OpFunction %void None %void_func\n" +
846             "%main_lab = OpLabel\n" +
847             "%2 = OpBitcast %short %half_1\n" +
848             "OpReturn\n" +
849             "OpFunctionEnd",
850         2, 0x3C00),
851     // Test case 57: Bit-cast ushort 0xBC00 to half
852     InstructionFoldingCase<uint32_t>(
853         Header() + "%main = OpFunction %void None %void_func\n" +
854             "%main_lab = OpLabel\n" +
855             "%2 = OpBitcast %half %ushort_0xBC00\n" +
856             "OpReturn\n" +
857             "OpFunctionEnd",
858         2, 0xBC00),
859     // Test case 58: Bit-cast short 0xBC00 to half
860     InstructionFoldingCase<uint32_t>(
861         Header() + "%main = OpFunction %void None %void_func\n" +
862             "%main_lab = OpLabel\n" +
863             "%2 = OpBitcast %half %short_0xBC00\n" +
864             "OpReturn\n" +
865             "OpFunctionEnd",
866         2, 0xFFFFBC00),
867     // Test case 59: Bit-cast half 1 to half
868     InstructionFoldingCase<uint32_t>(
869         Header() + "%main = OpFunction %void None %void_func\n" +
870             "%main_lab = OpLabel\n" +
871             "%2 = OpBitcast %half %half_1\n" +
872             "OpReturn\n" +
873             "OpFunctionEnd",
874         2, 0x3C00),
875     // Test case 60: Bit-cast ubyte 1 to byte
876     InstructionFoldingCase<uint32_t>(
877         Header() + "%main = OpFunction %void None %void_func\n" +
878             "%main_lab = OpLabel\n" +
879             "%2 = OpBitcast %byte %ubyte_1\n" +
880             "OpReturn\n" +
881             "OpFunctionEnd",
882         2, 1),
883     // Test case 61: Bit-cast byte -1 to ubyte
884     InstructionFoldingCase<uint32_t>(
885         Header() + "%main = OpFunction %void None %void_func\n" +
886             "%main_lab = OpLabel\n" +
887             "%2 = OpBitcast %ubyte %byte_n1\n" +
888             "OpReturn\n" +
889             "OpFunctionEnd",
890         2, 0xFFFFFFFF),
891     // Test case 62: Negate 2.
892     InstructionFoldingCase<uint32_t>(
893         Header() + "%main = OpFunction %void None %void_func\n" +
894             "%main_lab = OpLabel\n" +
895             "%2 = OpSNegate %int %int_2\n" +
896             "OpReturn\n" +
897             "OpFunctionEnd",
898         2, -2),
899     // Test case 63: Negate negative short.
900     InstructionFoldingCase<uint32_t>(
901         Header() + "%main = OpFunction %void None %void_func\n" +
902             "%main_lab = OpLabel\n" +
903             "%2 = OpSNegate %short %short_0xBC00\n" +
904             "OpReturn\n" +
905             "OpFunctionEnd",
906         2, 0x4400 /* expected to be sign extended. */),
907     // Test case 64: Negate positive short.
908     InstructionFoldingCase<uint32_t>(
909         Header() + "%main = OpFunction %void None %void_func\n" +
910             "%main_lab = OpLabel\n" +
911             "%2 = OpSNegate %short %short_0x4400\n" +
912             "OpReturn\n" +
913             "OpFunctionEnd",
914         2, 0xFFFFBC00 /* expected to be sign extended. */),
915     // Test case 65: Negate a negative short.
916     InstructionFoldingCase<uint32_t>(
917         Header() + "%main = OpFunction %void None %void_func\n" +
918             "%main_lab = OpLabel\n" +
919             "%2 = OpSNegate %ushort %ushort_0xBC00\n" +
920             "OpReturn\n" +
921             "OpFunctionEnd",
922         2, 0x4400 /* expected to be zero extended. */),
923     // Test case 66: Negate positive short.
924     InstructionFoldingCase<uint32_t>(
925         Header() + "%main = OpFunction %void None %void_func\n" +
926             "%main_lab = OpLabel\n" +
927             "%2 = OpSNegate %ushort %ushort_0x4400\n" +
928             "OpReturn\n" +
929             "OpFunctionEnd",
930         2, 0xBC00 /* expected to be zero extended. */)
931 ));
932 // clang-format on
933 
934 using UIntVectorInstructionFoldingTest =
935     ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
936 
TEST_P(UIntVectorInstructionFoldingTest, Case)937 TEST_P(UIntVectorInstructionFoldingTest, Case) {
938   const auto& tc = GetParam();
939 
940   // Build module.
941   std::unique_ptr<IRContext> context =
942       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
943                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
944   ASSERT_NE(nullptr, context);
945 
946   // Fold the instruction to test.
947   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
948   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
949   spv::Op original_opcode = inst->opcode();
950   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
951 
952   // Make sure the instruction folded as expected.
953   EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
954   if (succeeded && inst != nullptr) {
955     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
956     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
957     std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
958     EXPECT_THAT(opcodes, Contains(inst->opcode()));
959     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
960     const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
961     EXPECT_NE(result, nullptr);
962     if (result != nullptr) {
963       const std::vector<const analysis::Constant*>& componenets =
964           result->AsVectorConstant()->GetComponents();
965       EXPECT_EQ(componenets.size(), tc.expected_result.size());
966       for (size_t i = 0; i < componenets.size(); i++) {
967         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
968       }
969     }
970   }
971 }
972 
973 // clang-format off
974 INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest,
975 ::testing::Values(
976     // Test case 0: fold 0*n
977     InstructionFoldingCase<std::vector<uint32_t>>(
978         Header() + "%main = OpFunction %void None %void_func\n" +
979             "%main_lab = OpLabel\n" +
980             "%n = OpVariable %_ptr_int Function\n" +
981             "%load = OpLoad %int %n\n" +
982             "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
983             "OpReturn\n" +
984             "OpFunctionEnd",
985         2, {2,3}),
986     InstructionFoldingCase<std::vector<uint32_t>>(
987       Header() + "%main = OpFunction %void None %void_func\n" +
988           "%main_lab = OpLabel\n" +
989           "%n = OpVariable %_ptr_int Function\n" +
990           "%load = OpLoad %int %n\n" +
991           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
992           "OpReturn\n" +
993           "OpFunctionEnd",
994       2, {0,3}),
995     InstructionFoldingCase<std::vector<uint32_t>>(
996       Header() + "%main = OpFunction %void None %void_func\n" +
997           "%main_lab = OpLabel\n" +
998           "%n = OpVariable %_ptr_int Function\n" +
999           "%load = OpLoad %int %n\n" +
1000           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
1001           "OpReturn\n" +
1002           "OpFunctionEnd",
1003       2, {0,0}),
1004     InstructionFoldingCase<std::vector<uint32_t>>(
1005       Header() + "%main = OpFunction %void None %void_func\n" +
1006           "%main_lab = OpLabel\n" +
1007           "%n = OpVariable %_ptr_int Function\n" +
1008           "%load = OpLoad %int %n\n" +
1009           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
1010           "OpReturn\n" +
1011           "OpFunctionEnd",
1012       2, {0,0}),
1013     // Test case 4: fold bit-cast int -24 to unsigned int
1014     InstructionFoldingCase<std::vector<uint32_t>>(
1015       Header() + "%main = OpFunction %void None %void_func\n" +
1016           "%main_lab = OpLabel\n" +
1017           "%n = OpVariable %_ptr_int Function\n" +
1018           "%load = OpLoad %int %n\n" +
1019           "%2 = OpBitcast %v2uint %v2int_min_max\n" +
1020           "OpReturn\n" +
1021           "OpFunctionEnd",
1022       2, {2147483648, 2147483647}),
1023     // Test case 5: fold SNegate vector of uint
1024     InstructionFoldingCase<std::vector<uint32_t>>(
1025       Header() + "%main = OpFunction %void None %void_func\n" +
1026           "%main_lab = OpLabel\n" +
1027           "%n = OpVariable %_ptr_int Function\n" +
1028           "%load = OpLoad %int %n\n" +
1029           "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" +
1030           "OpReturn\n" +
1031           "OpFunctionEnd",
1032       2, {static_cast<uint32_t>(-0x3f800000), static_cast<uint32_t>(-0xbf800000)}),
1033     // Test case 6: fold vector components of uint (incuding integer overflow)
1034     InstructionFoldingCase<std::vector<uint32_t>>(
1035       Header() + "%main = OpFunction %void None %void_func\n" +
1036           "%main_lab = OpLabel\n" +
1037           "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" +
1038           "OpReturn\n" +
1039           "OpFunctionEnd",
1040       2, {0x7f000000u, 0x7f000000u})
1041 ));
1042 // clang-format on
1043 
1044 using IntVectorInstructionFoldingTest =
1045     ::testing::TestWithParam<InstructionFoldingCase<std::vector<int32_t>>>;
1046 
TEST_P(IntVectorInstructionFoldingTest, Case)1047 TEST_P(IntVectorInstructionFoldingTest, Case) {
1048   const auto& tc = GetParam();
1049 
1050   // Build module.
1051   std::unique_ptr<IRContext> context =
1052       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1053                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1054   ASSERT_NE(nullptr, context);
1055 
1056   // Fold the instruction to test.
1057   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1058   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1059   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1060 
1061   // Make sure the instruction folded as expected.
1062   EXPECT_TRUE(succeeded);
1063   if (succeeded && inst != nullptr) {
1064     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1065     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1066     std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1067     EXPECT_THAT(opcodes, Contains(inst->opcode()));
1068     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1069     const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1070     EXPECT_NE(result, nullptr);
1071     if (result != nullptr) {
1072       const std::vector<const analysis::Constant*>& componenets =
1073           result->AsVectorConstant()->GetComponents();
1074       EXPECT_EQ(componenets.size(), tc.expected_result.size());
1075       for (size_t i = 0; i < componenets.size(); i++) {
1076         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetS32());
1077       }
1078     }
1079   }
1080 }
1081 
1082 // clang-format off
1083 INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
1084 ::testing::Values(
1085     // Test case 0: fold negate of a vector
1086     InstructionFoldingCase<std::vector<int32_t>>(
1087       Header() + "%main = OpFunction %void None %void_func\n" +
1088           "%main_lab = OpLabel\n" +
1089           "%2 = OpSNegate %v2int %v2int_2_3\n" +
1090           "OpReturn\n" +
1091           "OpFunctionEnd",
1092       2, {-2, -3}),
1093     // Test case 1: fold negate of a vector containing negative values.
1094     InstructionFoldingCase<std::vector<int32_t>>(
1095       Header() + "%main = OpFunction %void None %void_func\n" +
1096           "%main_lab = OpLabel\n" +
1097           "%2 = OpSNegate %v2int %v2int_n1_n24\n" +
1098           "OpReturn\n" +
1099           "OpFunctionEnd",
1100       2, {1, 24}),
1101     // Test case 2: fold negate of a vector at the limits
1102     InstructionFoldingCase<std::vector<int32_t>>(
1103       Header() + "%main = OpFunction %void None %void_func\n" +
1104           "%main_lab = OpLabel\n" +
1105           "%2 = OpSNegate %v2int %v2int_min_max\n" +
1106           "OpReturn\n" +
1107           "OpFunctionEnd",
1108       2, {INT_MIN, -INT_MAX}),
1109     // Test case 3: fold vector components of int
1110     InstructionFoldingCase<std::vector<int32_t>>(
1111       Header() + "%main = OpFunction %void None %void_func\n" +
1112           "%main_lab = OpLabel\n" +
1113           "%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" +
1114           "OpReturn\n" +
1115           "OpFunctionEnd",
1116       2, {4,9})
1117 ));
1118 // clang-format on
1119 
1120 using DoubleVectorInstructionFoldingTest =
1121     ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
1122 
TEST_P(DoubleVectorInstructionFoldingTest, Case)1123 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
1124   const auto& tc = GetParam();
1125 
1126   // Build module.
1127   std::unique_ptr<IRContext> context =
1128       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1129                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1130   ASSERT_NE(nullptr, context);
1131 
1132   // Fold the instruction to test.
1133   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1134   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1135   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1136 
1137   // Make sure the instruction folded as expected.
1138   EXPECT_TRUE(succeeded);
1139   if (succeeded && inst != nullptr) {
1140     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1141     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1142     std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1143     EXPECT_THAT(opcodes, Contains(inst->opcode()));
1144     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1145     const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1146     EXPECT_NE(result, nullptr);
1147     if (result != nullptr) {
1148       const std::vector<const analysis::Constant*>& componenets =
1149           result->AsVectorConstant()->GetComponents();
1150       EXPECT_EQ(componenets.size(), tc.expected_result.size());
1151       for (size_t i = 0; i < componenets.size(); i++) {
1152         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble());
1153       }
1154     }
1155   }
1156 }
1157 
1158 // clang-format off
1159 INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
1160 ::testing::Values(
1161    // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
1162    //              to double vector
1163    InstructionFoldingCase<std::vector<double>>(
1164        Header() + "%main = OpFunction %void None %void_func\n" +
1165            "%main_lab = OpLabel\n" +
1166            "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
1167            "OpReturn\n" +
1168            "OpFunctionEnd",
1169        2, {1.0,-127.35}),
1170    // Test case 1: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1171    InstructionFoldingCase<std::vector<double>>(
1172        Header() +
1173        "%main = OpFunction %void None %void_func\n" +
1174        "%main_lab = OpLabel\n" +
1175        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" +
1176        "OpReturn\n" +
1177        "OpFunctionEnd",
1178        2, {0.0,0.0,0.0,0.0}),
1179    // Test case 2: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1180    InstructionFoldingCase<std::vector<double>>(
1181        Header() +
1182        "%main = OpFunction %void None %void_func\n" +
1183        "%main_lab = OpLabel\n" +
1184        "%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" +
1185        "OpReturn\n" +
1186        "OpFunctionEnd",
1187        2, {0.0,0.0,0.0,0.0}),
1188    // Test case 3: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1189    InstructionFoldingCase<std::vector<double>>(
1190        Header() +
1191        "%main = OpFunction %void None %void_func\n" +
1192        "%main_lab = OpLabel\n" +
1193        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" +
1194        "OpReturn\n" +
1195        "OpFunctionEnd",
1196        2, {30.0,30.0,30.0,30.0}),
1197    // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
1198    InstructionFoldingCase<std::vector<double>>(
1199        Header() +
1200        "%main = OpFunction %void None %void_func\n" +
1201        "%main_lab = OpLabel\n" +
1202        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null\n" +
1203        "OpReturn\n" +
1204        "OpFunctionEnd",
1205        2, {30.0,0.0,30.0,0.0}),
1206    // Test case 5: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1207    InstructionFoldingCase<std::vector<double>>(
1208        Header() +
1209        "%main = OpFunction %void None %void_func\n" +
1210        "%main_lab = OpLabel\n" +
1211        "%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" +
1212        "OpReturn\n" +
1213        "OpFunctionEnd",
1214        2, {0.0,0.0,0.0,0.0}),
1215    // Test case 6: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1216    InstructionFoldingCase<std::vector<double>>(
1217        Header() +
1218        "%main = OpFunction %void None %void_func\n" +
1219        "%main_lab = OpLabel\n" +
1220        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" +
1221        "OpReturn\n" +
1222        "OpFunctionEnd",
1223        2, {0.0,0.0,0.0,0.0}),
1224    // Test case 7: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1225    InstructionFoldingCase<std::vector<double>>(
1226        Header() +
1227        "%main = OpFunction %void None %void_func\n" +
1228        "%main_lab = OpLabel\n" +
1229        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" +
1230        "OpReturn\n" +
1231        "OpFunctionEnd",
1232        2, {10.0,20.0,30.0,40.0}),
1233    // Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
1234    InstructionFoldingCase<std::vector<double>>(
1235        Header() +
1236        "%main = OpFunction %void None %void_func\n" +
1237        "%main_lab = OpLabel\n" +
1238        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4_null %v4double_1_2_3_4\n" +
1239        "OpReturn\n" +
1240        "OpFunctionEnd",
1241        2, {4.0,8.0,12.0,16.0})
1242 ));
1243 
1244 using FloatVectorInstructionFoldingTest =
1245     ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
1246 
TEST_P(FloatVectorInstructionFoldingTest, Case)1247 TEST_P(FloatVectorInstructionFoldingTest, Case) {
1248   const auto& tc = GetParam();
1249 
1250   // Build module.
1251   std::unique_ptr<IRContext> context =
1252       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1253                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1254   ASSERT_NE(nullptr, context);
1255 
1256   // Fold the instruction to test.
1257   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1258   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1259   spv::Op original_opcode = inst->opcode();
1260   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1261 
1262   // Make sure the instruction folded as expected.
1263   EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
1264   if (succeeded && inst != nullptr) {
1265     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1266     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1267     std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1268     EXPECT_THAT(opcodes, Contains(inst->opcode()));
1269     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1270     const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1271     EXPECT_NE(result, nullptr);
1272     if (result != nullptr) {
1273       const std::vector<const analysis::Constant*>& componenets =
1274           result->AsVectorConstant()->GetComponents();
1275       EXPECT_EQ(componenets.size(), tc.expected_result.size());
1276       for (size_t i = 0; i < componenets.size(); i++) {
1277         EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
1278       }
1279     }
1280   }
1281 }
1282 
1283 // clang-format off
1284 INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
1285 ::testing::Values(
1286    // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
1287    InstructionFoldingCase<std::vector<float>>(
1288        Header() + "%main = OpFunction %void None %void_func\n" +
1289            "%main_lab = OpLabel\n" +
1290            "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
1291            "OpReturn\n" +
1292            "OpFunctionEnd",
1293        2, {1.6f,1.5f}),
1294    // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
1295    //              float vector
1296    InstructionFoldingCase<std::vector<float>>(
1297        Header() + "%main = OpFunction %void None %void_func\n" +
1298            "%main_lab = OpLabel\n" +
1299            "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
1300            "OpReturn\n" +
1301            "OpFunctionEnd",
1302        2, {1.0f,-1.0f}),
1303    // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
1304    InstructionFoldingCase<std::vector<float>>(
1305        Header() + "%main = OpFunction %void None %void_func\n" +
1306            "%main_lab = OpLabel\n" +
1307            "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
1308            "OpReturn\n" +
1309            "OpFunctionEnd",
1310        2, {1.0f,-1.0f}),
1311    // Test case 3: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1312    InstructionFoldingCase<std::vector<float>>(
1313        Header() +
1314        "%main = OpFunction %void None %void_func\n" +
1315        "%main_lab = OpLabel\n" +
1316        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" +
1317        "OpReturn\n" +
1318        "OpFunctionEnd",
1319        2, {0.0f,0.0f,0.0f,0.0f}),
1320    // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
1321    InstructionFoldingCase<std::vector<float>>(
1322        Header() +
1323        "%main = OpFunction %void None %void_func\n" +
1324        "%main_lab = OpLabel\n" +
1325        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null\n" +
1326        "OpReturn\n" +
1327        "OpFunctionEnd",
1328        2, {30.0,0.0,30.0,0.0}),
1329    // Test case 5: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1330    InstructionFoldingCase<std::vector<float>>(
1331        Header() +
1332        "%main = OpFunction %void None %void_func\n" +
1333        "%main_lab = OpLabel\n" +
1334        "%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" +
1335        "OpReturn\n" +
1336        "OpFunctionEnd",
1337        2, {0.0f,0.0f,0.0f,0.0f}),
1338    // Test case 6: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1339    InstructionFoldingCase<std::vector<float>>(
1340        Header() +
1341        "%main = OpFunction %void None %void_func\n" +
1342        "%main_lab = OpLabel\n" +
1343        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" +
1344        "OpReturn\n" +
1345        "OpFunctionEnd",
1346        2, {30.0f,30.0f,30.0f,30.0f}),
1347    // Test case 7: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1348    InstructionFoldingCase<std::vector<float>>(
1349        Header() +
1350        "%main = OpFunction %void None %void_func\n" +
1351        "%main_lab = OpLabel\n" +
1352        "%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" +
1353        "OpReturn\n" +
1354        "OpFunctionEnd",
1355        2, {0.0f,0.0f,0.0f,0.0f}),
1356    // Test case 8: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1357    InstructionFoldingCase<std::vector<float>>(
1358        Header() +
1359        "%main = OpFunction %void None %void_func\n" +
1360        "%main_lab = OpLabel\n" +
1361        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" +
1362        "OpReturn\n" +
1363        "OpFunctionEnd",
1364        2, {0.0f,0.0f,0.0f,0.0f}),
1365    // Test case 9: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1366    InstructionFoldingCase<std::vector<float>>(
1367        Header() +
1368        "%main = OpFunction %void None %void_func\n" +
1369        "%main_lab = OpLabel\n" +
1370        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" +
1371        "OpReturn\n" +
1372        "OpFunctionEnd",
1373        2, {10.0f,20.0f,30.0f,40.0f}),
1374    // Test case 10: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
1375    InstructionFoldingCase<std::vector<float>>(
1376        Header() +
1377        "%main = OpFunction %void None %void_func\n" +
1378        "%main_lab = OpLabel\n" +
1379        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4_null %v4float_1_2_3_4\n" +
1380        "OpReturn\n" +
1381        "OpFunctionEnd",
1382        2, {4.0,8.0,12.0,16.0})
1383 ));
1384 // clang-format on
1385 
1386 using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam<
1387     InstructionFoldingCase<std::vector<std::vector<float>>>>;
1388 
TEST_P(FloatMatrixInstructionFoldingTest, Case)1389 TEST_P(FloatMatrixInstructionFoldingTest, Case) {
1390   const auto& tc = GetParam();
1391 
1392   // Build module.
1393   std::unique_ptr<IRContext> context =
1394       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1395                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1396   ASSERT_NE(nullptr, context);
1397 
1398   // Fold the instruction to test.
1399   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1400   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1401   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1402 
1403   // Make sure the instruction folded as expected.
1404   EXPECT_TRUE(succeeded);
1405   EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1406 
1407   if (inst->opcode() == spv::Op::OpCopyObject) {
1408     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1409     analysis::ConstantManager* const_mgr = context->get_constant_mgr();
1410     const analysis::Constant* result = const_mgr->GetConstantFromInst(inst);
1411     EXPECT_NE(result, nullptr);
1412     if (result != nullptr) {
1413       std::vector<const analysis::Constant*> matrix =
1414           result->AsMatrixConstant()->GetComponents();
1415       EXPECT_EQ(matrix.size(), tc.expected_result.size());
1416       for (size_t c = 0; c < matrix.size(); c++) {
1417         if (matrix[c]->AsNullConstant() != nullptr) {
1418           matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type());
1419         }
1420         const analysis::VectorConstant* column_const =
1421             matrix[c]->AsVectorConstant();
1422         ASSERT_NE(column_const, nullptr);
1423         const std::vector<const analysis::Constant*>& column =
1424             column_const->GetComponents();
1425         EXPECT_EQ(column.size(), tc.expected_result[c].size());
1426         for (size_t r = 0; r < column.size(); r++) {
1427           EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat());
1428         }
1429       }
1430     }
1431   }
1432 }
1433 
1434 // clang-format off
1435 INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest,
1436 ::testing::Values(
1437    // Test case 0: OpTranspose square null matrix
1438    InstructionFoldingCase<std::vector<std::vector<float>>>(
1439        Header() + "%main = OpFunction %void None %void_func\n" +
1440            "%main_lab = OpLabel\n" +
1441            "%2 = OpTranspose %mat4v4float %mat4v4float_null\n" +
1442            "OpReturn\n" +
1443            "OpFunctionEnd",
1444        2, {{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f}}),
1445    // Test case 1: OpTranspose rectangular null matrix
1446    InstructionFoldingCase<std::vector<std::vector<float>>>(
1447        Header() + "%main = OpFunction %void None %void_func\n" +
1448            "%main_lab = OpLabel\n" +
1449            "%2 = OpTranspose %mat4v2float %mat2v4float_null\n" +
1450            "OpReturn\n" +
1451            "OpFunctionEnd",
1452        2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}),
1453    InstructionFoldingCase<std::vector<std::vector<float>>>(
1454        Header() + "%main = OpFunction %void None %void_func\n" +
1455            "%main_lab = OpLabel\n" +
1456            "%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" +
1457            "OpReturn\n" +
1458            "OpFunctionEnd",
1459        2, {{1.0f, 1.0f, 1.0f, 1.0f},{2.0f, 2.0f, 2.0f, 2.0f},{3.0f, 3.0f, 3.0f, 3.0f},{4.0f, 4.0f, 4.0f, 4.0f}})
1460 ));
1461 // clang-format on
1462 
1463 using BooleanInstructionFoldingTest =
1464     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
1465 
TEST_P(BooleanInstructionFoldingTest, Case)1466 TEST_P(BooleanInstructionFoldingTest, Case) {
1467   const auto& tc = GetParam();
1468 
1469   // Build module.
1470   std::unique_ptr<IRContext> context =
1471       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1472                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1473   ASSERT_NE(nullptr, context);
1474 
1475   // Fold the instruction to test.
1476   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1477   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1478   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1479 
1480   // Make sure the instruction folded as expected.
1481   EXPECT_TRUE(succeeded);
1482   if (inst != nullptr) {
1483     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1484     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1485     std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
1486                                          spv::Op::OpConstantFalse};
1487     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
1488     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1489     const analysis::BoolConstant* result =
1490         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
1491     EXPECT_NE(result, nullptr);
1492     if (result != nullptr) {
1493       EXPECT_EQ(result->value(), tc.expected_result);
1494     }
1495   }
1496 }
1497 
1498 // clang-format off
1499 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
1500                         ::testing::Values(
1501   // Test case 0: fold true || n
1502   InstructionFoldingCase<bool>(
1503       Header() + "%main = OpFunction %void None %void_func\n" +
1504           "%main_lab = OpLabel\n" +
1505           "%n = OpVariable %_ptr_bool Function\n" +
1506           "%load = OpLoad %bool %n\n" +
1507           "%2 = OpLogicalOr %bool %true %load\n" +
1508           "OpReturn\n" +
1509           "OpFunctionEnd",
1510       2, true),
1511   // Test case 1: fold n || true
1512   InstructionFoldingCase<bool>(
1513       Header() + "%main = OpFunction %void None %void_func\n" +
1514           "%main_lab = OpLabel\n" +
1515           "%n = OpVariable %_ptr_bool Function\n" +
1516           "%load = OpLoad %bool %n\n" +
1517           "%2 = OpLogicalOr %bool %load %true\n" +
1518           "OpReturn\n" +
1519           "OpFunctionEnd",
1520       2, true),
1521   // Test case 2: fold false && n
1522   InstructionFoldingCase<bool>(
1523       Header() + "%main = OpFunction %void None %void_func\n" +
1524           "%main_lab = OpLabel\n" +
1525           "%n = OpVariable %_ptr_bool Function\n" +
1526           "%load = OpLoad %bool %n\n" +
1527           "%2 = OpLogicalAnd %bool %false %load\n" +
1528           "OpReturn\n" +
1529           "OpFunctionEnd",
1530       2, false),
1531   // Test case 3: fold n && false
1532   InstructionFoldingCase<bool>(
1533       Header() + "%main = OpFunction %void None %void_func\n" +
1534           "%main_lab = OpLabel\n" +
1535           "%n = OpVariable %_ptr_bool Function\n" +
1536           "%load = OpLoad %bool %n\n" +
1537           "%2 = OpLogicalAnd %bool %load %false\n" +
1538           "OpReturn\n" +
1539           "OpFunctionEnd",
1540       2, false),
1541   // Test case 4: fold n < 0 (unsigned)
1542   InstructionFoldingCase<bool>(
1543       Header() + "%main = OpFunction %void None %void_func\n" +
1544           "%main_lab = OpLabel\n" +
1545           "%n = OpVariable %_ptr_uint Function\n" +
1546           "%load = OpLoad %uint %n\n" +
1547           "%2 = OpULessThan %bool %load %uint_0\n" +
1548           "OpReturn\n" +
1549           "OpFunctionEnd",
1550       2, false),
1551   // Test case 5: fold UINT_MAX < n (unsigned)
1552   InstructionFoldingCase<bool>(
1553       Header() + "%main = OpFunction %void None %void_func\n" +
1554           "%main_lab = OpLabel\n" +
1555           "%n = OpVariable %_ptr_uint Function\n" +
1556           "%load = OpLoad %uint %n\n" +
1557           "%2 = OpULessThan %bool %uint_max %load\n" +
1558           "OpReturn\n" +
1559           "OpFunctionEnd",
1560       2, false),
1561   // Test case 6: fold INT_MAX < n (signed)
1562   InstructionFoldingCase<bool>(
1563       Header() + "%main = OpFunction %void None %void_func\n" +
1564           "%main_lab = OpLabel\n" +
1565           "%n = OpVariable %_ptr_int Function\n" +
1566           "%load = OpLoad %int %n\n" +
1567           "%2 = OpSLessThan %bool %int_max %load\n" +
1568           "OpReturn\n" +
1569           "OpFunctionEnd",
1570       2, false),
1571   // Test case 7: fold n < INT_MIN (signed)
1572   InstructionFoldingCase<bool>(
1573       Header() + "%main = OpFunction %void None %void_func\n" +
1574           "%main_lab = OpLabel\n" +
1575           "%n = OpVariable %_ptr_int Function\n" +
1576           "%load = OpLoad %int %n\n" +
1577           "%2 = OpSLessThan %bool %load %int_min\n" +
1578           "OpReturn\n" +
1579           "OpFunctionEnd",
1580       2, false),
1581   // Test case 8: fold 0 > n (unsigned)
1582   InstructionFoldingCase<bool>(
1583       Header() + "%main = OpFunction %void None %void_func\n" +
1584           "%main_lab = OpLabel\n" +
1585           "%n = OpVariable %_ptr_uint Function\n" +
1586           "%load = OpLoad %uint %n\n" +
1587           "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
1588           "OpReturn\n" +
1589           "OpFunctionEnd",
1590       2, false),
1591   // Test case 9: fold n > UINT_MAX (unsigned)
1592   InstructionFoldingCase<bool>(
1593       Header() + "%main = OpFunction %void None %void_func\n" +
1594           "%main_lab = OpLabel\n" +
1595           "%n = OpVariable %_ptr_uint Function\n" +
1596           "%load = OpLoad %uint %n\n" +
1597           "%2 = OpUGreaterThan %bool %load %uint_max\n" +
1598           "OpReturn\n" +
1599           "OpFunctionEnd",
1600       2, false),
1601   // Test case 10: fold n > INT_MAX (signed)
1602   InstructionFoldingCase<bool>(
1603       Header() + "%main = OpFunction %void None %void_func\n" +
1604           "%main_lab = OpLabel\n" +
1605           "%n = OpVariable %_ptr_int Function\n" +
1606           "%load = OpLoad %int %n\n" +
1607           "%2 = OpSGreaterThan %bool %load %int_max\n" +
1608           "OpReturn\n" +
1609           "OpFunctionEnd",
1610       2, false),
1611   // Test case 11: fold INT_MIN > n (signed)
1612   InstructionFoldingCase<bool>(
1613       Header() + "%main = OpFunction %void None %void_func\n" +
1614           "%main_lab = OpLabel\n" +
1615           "%n = OpVariable %_ptr_uint Function\n" +
1616           "%load = OpLoad %uint %n\n" +
1617           "%2 = OpSGreaterThan %bool %int_min %load\n" +
1618           "OpReturn\n" +
1619           "OpFunctionEnd",
1620       2, false),
1621   // Test case 12: fold 0 <= n (unsigned)
1622   InstructionFoldingCase<bool>(
1623       Header() + "%main = OpFunction %void None %void_func\n" +
1624           "%main_lab = OpLabel\n" +
1625           "%n = OpVariable %_ptr_uint Function\n" +
1626           "%load = OpLoad %uint %n\n" +
1627           "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
1628           "OpReturn\n" +
1629           "OpFunctionEnd",
1630       2, true),
1631   // Test case 13: fold n <= UINT_MAX (unsigned)
1632   InstructionFoldingCase<bool>(
1633       Header() + "%main = OpFunction %void None %void_func\n" +
1634           "%main_lab = OpLabel\n" +
1635           "%n = OpVariable %_ptr_uint Function\n" +
1636           "%load = OpLoad %uint %n\n" +
1637           "%2 = OpULessThanEqual %bool %load %uint_max\n" +
1638           "OpReturn\n" +
1639           "OpFunctionEnd",
1640       2, true),
1641   // Test case 14: fold INT_MIN <= n (signed)
1642   InstructionFoldingCase<bool>(
1643       Header() + "%main = OpFunction %void None %void_func\n" +
1644           "%main_lab = OpLabel\n" +
1645           "%n = OpVariable %_ptr_int Function\n" +
1646           "%load = OpLoad %int %n\n" +
1647           "%2 = OpSLessThanEqual %bool %int_min %load\n" +
1648           "OpReturn\n" +
1649           "OpFunctionEnd",
1650       2, true),
1651   // Test case 15: fold n <= INT_MAX (signed)
1652   InstructionFoldingCase<bool>(
1653       Header() + "%main = OpFunction %void None %void_func\n" +
1654           "%main_lab = OpLabel\n" +
1655           "%n = OpVariable %_ptr_int Function\n" +
1656           "%load = OpLoad %int %n\n" +
1657           "%2 = OpSLessThanEqual %bool %load %int_max\n" +
1658           "OpReturn\n" +
1659           "OpFunctionEnd",
1660       2, true),
1661   // Test case 16: fold n >= 0 (unsigned)
1662   InstructionFoldingCase<bool>(
1663       Header() + "%main = OpFunction %void None %void_func\n" +
1664           "%main_lab = OpLabel\n" +
1665           "%n = OpVariable %_ptr_uint Function\n" +
1666           "%load = OpLoad %uint %n\n" +
1667           "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
1668           "OpReturn\n" +
1669           "OpFunctionEnd",
1670       2, true),
1671   // Test case 17: fold UINT_MAX >= n (unsigned)
1672   InstructionFoldingCase<bool>(
1673       Header() + "%main = OpFunction %void None %void_func\n" +
1674           "%main_lab = OpLabel\n" +
1675           "%n = OpVariable %_ptr_uint Function\n" +
1676           "%load = OpLoad %uint %n\n" +
1677           "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
1678           "OpReturn\n" +
1679           "OpFunctionEnd",
1680       2, true),
1681   // Test case 18: fold n >= INT_MIN (signed)
1682   InstructionFoldingCase<bool>(
1683       Header() + "%main = OpFunction %void None %void_func\n" +
1684           "%main_lab = OpLabel\n" +
1685           "%n = OpVariable %_ptr_int Function\n" +
1686           "%load = OpLoad %int %n\n" +
1687           "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
1688           "OpReturn\n" +
1689           "OpFunctionEnd",
1690       2, true),
1691   // Test case 19: fold INT_MAX >= n (signed)
1692   InstructionFoldingCase<bool>(
1693       Header() + "%main = OpFunction %void None %void_func\n" +
1694           "%main_lab = OpLabel\n" +
1695           "%n = OpVariable %_ptr_int Function\n" +
1696           "%load = OpLoad %int %n\n" +
1697           "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
1698           "OpReturn\n" +
1699           "OpFunctionEnd",
1700       2, true)
1701 ));
1702 
1703 INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
1704 ::testing::Values(
1705     // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
1706     InstructionFoldingCase<bool>(
1707         Header() + "%main = OpFunction %void None %void_func\n" +
1708             "%main_lab = OpLabel\n" +
1709             "%n = OpVariable %_ptr_float Function\n" +
1710             "%ld = OpLoad %float %n\n" +
1711             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1712             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1713             "OpReturn\n" +
1714             "OpFunctionEnd",
1715         2, false),
1716     // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
1717     InstructionFoldingCase<bool>(
1718         Header() + "%main = OpFunction %void None %void_func\n" +
1719             "%main_lab = OpLabel\n" +
1720             "%n = OpVariable %_ptr_float Function\n" +
1721             "%ld = OpLoad %float %n\n" +
1722             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1723             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1724             "OpReturn\n" +
1725             "OpFunctionEnd",
1726         2, true),
1727     // Test case 2: fold 0.0 >= clamp(n, 1, 2)
1728     InstructionFoldingCase<bool>(
1729         Header() + "%main = OpFunction %void None %void_func\n" +
1730             "%main_lab = OpLabel\n" +
1731             "%n = OpVariable %_ptr_float Function\n" +
1732             "%ld = OpLoad %float %n\n" +
1733             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1734             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1735             "OpReturn\n" +
1736             "OpFunctionEnd",
1737         2, false),
1738     // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
1739     InstructionFoldingCase<bool>(
1740         Header() + "%main = OpFunction %void None %void_func\n" +
1741             "%main_lab = OpLabel\n" +
1742             "%n = OpVariable %_ptr_float Function\n" +
1743             "%ld = OpLoad %float %n\n" +
1744             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1745             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1746             "OpReturn\n" +
1747             "OpFunctionEnd",
1748         2, true),
1749     // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
1750     InstructionFoldingCase<bool>(
1751         Header() + "%main = OpFunction %void None %void_func\n" +
1752             "%main_lab = OpLabel\n" +
1753             "%n = OpVariable %_ptr_float Function\n" +
1754             "%ld = OpLoad %float %n\n" +
1755             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1756             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1757             "OpReturn\n" +
1758             "OpFunctionEnd",
1759         2, true),
1760     // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
1761     InstructionFoldingCase<bool>(
1762         Header() + "%main = OpFunction %void None %void_func\n" +
1763             "%main_lab = OpLabel\n" +
1764             "%n = OpVariable %_ptr_float Function\n" +
1765             "%ld = OpLoad %float %n\n" +
1766             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1767             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1768             "OpReturn\n" +
1769             "OpFunctionEnd",
1770         2, false),
1771     // Test case 6: fold 0.0 < clamp(n, 1, 2)
1772     InstructionFoldingCase<bool>(
1773         Header() + "%main = OpFunction %void None %void_func\n" +
1774             "%main_lab = OpLabel\n" +
1775             "%n = OpVariable %_ptr_float Function\n" +
1776             "%ld = OpLoad %float %n\n" +
1777             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1778             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1779             "OpReturn\n" +
1780             "OpFunctionEnd",
1781         2, true),
1782     // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
1783     InstructionFoldingCase<bool>(
1784         Header() + "%main = OpFunction %void None %void_func\n" +
1785             "%main_lab = OpLabel\n" +
1786             "%n = OpVariable %_ptr_float Function\n" +
1787             "%ld = OpLoad %float %n\n" +
1788             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1789             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1790             "OpReturn\n" +
1791             "OpFunctionEnd",
1792         2, false),
1793     // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
1794     InstructionFoldingCase<bool>(
1795         Header() + "%main = OpFunction %void None %void_func\n" +
1796             "%main_lab = OpLabel\n" +
1797             "%n = OpVariable %_ptr_float Function\n" +
1798             "%ld = OpLoad %float %n\n" +
1799             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1800             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1801             "OpReturn\n" +
1802             "OpFunctionEnd",
1803         2, false),
1804     // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
1805     InstructionFoldingCase<bool>(
1806         Header() + "%main = OpFunction %void None %void_func\n" +
1807             "%main_lab = OpLabel\n" +
1808             "%n = OpVariable %_ptr_float Function\n" +
1809             "%ld = OpLoad %float %n\n" +
1810             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1811             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1812             "OpReturn\n" +
1813             "OpFunctionEnd",
1814         2, true),
1815     // Test case 10: fold 0.0 >= clamp(n, 1, 2)
1816     InstructionFoldingCase<bool>(
1817         Header() + "%main = OpFunction %void None %void_func\n" +
1818             "%main_lab = OpLabel\n" +
1819             "%n = OpVariable %_ptr_float Function\n" +
1820             "%ld = OpLoad %float %n\n" +
1821             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1822             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1823             "OpReturn\n" +
1824             "OpFunctionEnd",
1825         2, false),
1826     // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
1827     InstructionFoldingCase<bool>(
1828         Header() + "%main = OpFunction %void None %void_func\n" +
1829             "%main_lab = OpLabel\n" +
1830             "%n = OpVariable %_ptr_float Function\n" +
1831             "%ld = OpLoad %float %n\n" +
1832             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1833             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1834             "OpReturn\n" +
1835             "OpFunctionEnd",
1836         2, true),
1837     // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
1838     InstructionFoldingCase<bool>(
1839         Header() + "%main = OpFunction %void None %void_func\n" +
1840             "%main_lab = OpLabel\n" +
1841             "%n = OpVariable %_ptr_float Function\n" +
1842             "%ld = OpLoad %float %n\n" +
1843             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1844             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1845             "OpReturn\n" +
1846             "OpFunctionEnd",
1847         2, true),
1848     // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
1849     InstructionFoldingCase<bool>(
1850         Header() + "%main = OpFunction %void None %void_func\n" +
1851             "%main_lab = OpLabel\n" +
1852             "%n = OpVariable %_ptr_float Function\n" +
1853             "%ld = OpLoad %float %n\n" +
1854             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1855             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1856             "OpReturn\n" +
1857             "OpFunctionEnd",
1858         2, false),
1859     // Test case 14: fold 0.0 < clamp(n, 1, 2)
1860     InstructionFoldingCase<bool>(
1861         Header() + "%main = OpFunction %void None %void_func\n" +
1862             "%main_lab = OpLabel\n" +
1863             "%n = OpVariable %_ptr_float Function\n" +
1864             "%ld = OpLoad %float %n\n" +
1865             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1866             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1867             "OpReturn\n" +
1868             "OpFunctionEnd",
1869         2, true),
1870     // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
1871     InstructionFoldingCase<bool>(
1872         Header() + "%main = OpFunction %void None %void_func\n" +
1873             "%main_lab = OpLabel\n" +
1874             "%n = OpVariable %_ptr_float Function\n" +
1875             "%ld = OpLoad %float %n\n" +
1876             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1877             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1878             "OpReturn\n" +
1879             "OpFunctionEnd",
1880         2, false)
1881 ));
1882 
1883 INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
1884 ::testing::Values(
1885     // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
1886     InstructionFoldingCase<bool>(
1887       Header() + "%main = OpFunction %void None %void_func\n" +
1888       "%main_lab = OpLabel\n" +
1889       "%n = OpVariable %_ptr_float Function\n" +
1890       "%ld = OpLoad %float %n\n" +
1891       "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1892       "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
1893       "OpReturn\n" +
1894       "OpFunctionEnd",
1895       2, false),
1896     // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
1897     InstructionFoldingCase<bool>(
1898       Header() + "%main = OpFunction %void None %void_func\n" +
1899       "%main_lab = OpLabel\n" +
1900       "%n = OpVariable %_ptr_float Function\n" +
1901       "%ld = OpLoad %float %n\n" +
1902       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1903       "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
1904       "OpReturn\n" +
1905       "OpFunctionEnd",
1906       2, true),
1907     // Test case 2: fold clamp(n, 1, 2) >= 0.0
1908     InstructionFoldingCase<bool>(
1909       Header() + "%main = OpFunction %void None %void_func\n" +
1910       "%main_lab = OpLabel\n" +
1911       "%n = OpVariable %_ptr_float Function\n" +
1912       "%ld = OpLoad %float %n\n" +
1913       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1914       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
1915       "OpReturn\n" +
1916       "OpFunctionEnd",
1917       2, true),
1918     // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
1919     InstructionFoldingCase<bool>(
1920       Header() + "%main = OpFunction %void None %void_func\n" +
1921       "%main_lab = OpLabel\n" +
1922       "%n = OpVariable %_ptr_float Function\n" +
1923       "%ld = OpLoad %float %n\n" +
1924       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1925       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
1926       "OpReturn\n" +
1927       "OpFunctionEnd",
1928       2, false),
1929     // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
1930     InstructionFoldingCase<bool>(
1931         Header() + "%main = OpFunction %void None %void_func\n" +
1932             "%main_lab = OpLabel\n" +
1933             "%n = OpVariable %_ptr_float Function\n" +
1934             "%ld = OpLoad %float %n\n" +
1935             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1936             "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
1937             "OpReturn\n" +
1938             "OpFunctionEnd",
1939         2, true),
1940     // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
1941     InstructionFoldingCase<bool>(
1942         Header() + "%main = OpFunction %void None %void_func\n" +
1943             "%main_lab = OpLabel\n" +
1944             "%n = OpVariable %_ptr_float Function\n" +
1945             "%ld = OpLoad %float %n\n" +
1946             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1947             "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
1948             "OpReturn\n" +
1949             "OpFunctionEnd",
1950         2, false),
1951     // Test case 6: fold clamp(n, 1, 2) < 3
1952     InstructionFoldingCase<bool>(
1953         Header() + "%main = OpFunction %void None %void_func\n" +
1954             "%main_lab = OpLabel\n" +
1955             "%n = OpVariable %_ptr_float Function\n" +
1956             "%ld = OpLoad %float %n\n" +
1957             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1958             "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
1959             "OpReturn\n" +
1960             "OpFunctionEnd",
1961         2, true),
1962     // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
1963     InstructionFoldingCase<bool>(
1964         Header() + "%main = OpFunction %void None %void_func\n" +
1965             "%main_lab = OpLabel\n" +
1966             "%n = OpVariable %_ptr_float Function\n" +
1967             "%ld = OpLoad %float %n\n" +
1968             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1969             "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
1970             "OpReturn\n" +
1971             "OpFunctionEnd",
1972         2, false),
1973     // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
1974     InstructionFoldingCase<bool>(
1975         Header() + "%main = OpFunction %void None %void_func\n" +
1976             "%main_lab = OpLabel\n" +
1977             "%n = OpVariable %_ptr_float Function\n" +
1978             "%ld = OpLoad %float %n\n" +
1979             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1980             "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
1981             "OpReturn\n" +
1982             "OpFunctionEnd",
1983         2, false),
1984     // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
1985     InstructionFoldingCase<bool>(
1986         Header() + "%main = OpFunction %void None %void_func\n" +
1987             "%main_lab = OpLabel\n" +
1988             "%n = OpVariable %_ptr_float Function\n" +
1989             "%ld = OpLoad %float %n\n" +
1990             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1991             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
1992             "OpReturn\n" +
1993             "OpFunctionEnd",
1994         2, true),
1995     // Test case 10: fold clamp(n, 1, 2) >= 3.0
1996     InstructionFoldingCase<bool>(
1997         Header() + "%main = OpFunction %void None %void_func\n" +
1998             "%main_lab = OpLabel\n" +
1999             "%n = OpVariable %_ptr_float Function\n" +
2000             "%ld = OpLoad %float %n\n" +
2001             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2002             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
2003             "OpReturn\n" +
2004             "OpFunctionEnd",
2005         2, false),
2006     // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
2007     InstructionFoldingCase<bool>(
2008         Header() + "%main = OpFunction %void None %void_func\n" +
2009             "%main_lab = OpLabel\n" +
2010             "%n = OpVariable %_ptr_float Function\n" +
2011             "%ld = OpLoad %float %n\n" +
2012             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2013             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
2014             "OpReturn\n" +
2015             "OpFunctionEnd",
2016         2, true),
2017     // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
2018     InstructionFoldingCase<bool>(
2019         Header() + "%main = OpFunction %void None %void_func\n" +
2020             "%main_lab = OpLabel\n" +
2021             "%n = OpVariable %_ptr_float Function\n" +
2022             "%ld = OpLoad %float %n\n" +
2023             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2024             "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
2025             "OpReturn\n" +
2026             "OpFunctionEnd",
2027         2, true),
2028     // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
2029     InstructionFoldingCase<bool>(
2030         Header() + "%main = OpFunction %void None %void_func\n" +
2031             "%main_lab = OpLabel\n" +
2032             "%n = OpVariable %_ptr_float Function\n" +
2033             "%ld = OpLoad %float %n\n" +
2034             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
2035             "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
2036             "OpReturn\n" +
2037             "OpFunctionEnd",
2038         2, false),
2039     // Test case 14: fold clamp(n, 1, 2) < 3
2040     InstructionFoldingCase<bool>(
2041         Header() + "%main = OpFunction %void None %void_func\n" +
2042             "%main_lab = OpLabel\n" +
2043             "%n = OpVariable %_ptr_float Function\n" +
2044             "%ld = OpLoad %float %n\n" +
2045             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2046             "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
2047             "OpReturn\n" +
2048             "OpFunctionEnd",
2049         2, true),
2050     // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
2051     InstructionFoldingCase<bool>(
2052         Header() + "%main = OpFunction %void None %void_func\n" +
2053             "%main_lab = OpLabel\n" +
2054             "%n = OpVariable %_ptr_float Function\n" +
2055             "%ld = OpLoad %float %n\n" +
2056             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2057             "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
2058             "OpReturn\n" +
2059             "OpFunctionEnd",
2060         2, false),
2061     // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
2062     InstructionFoldingCase<bool>(
2063         Header() + "%main = OpFunction %void None %void_func\n" +
2064             "%main_lab = OpLabel\n" +
2065             "%n = OpVariable %_ptr_double Function\n" +
2066             "%ld = OpLoad %double %n\n" +
2067             "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
2068             "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
2069             "OpReturn\n" +
2070             "OpFunctionEnd",
2071         2, false)
2072 ));
2073 // clang-format on
2074 
2075 using FloatInstructionFoldingTest =
2076     ::testing::TestWithParam<InstructionFoldingCase<float>>;
2077 
TEST_P(FloatInstructionFoldingTest, Case)2078 TEST_P(FloatInstructionFoldingTest, Case) {
2079   const auto& tc = GetParam();
2080 
2081   // Build module.
2082   std::unique_ptr<IRContext> context =
2083       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2084                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2085   ASSERT_NE(nullptr, context);
2086 
2087   // Fold the instruction to test.
2088   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2089   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2090   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2091 
2092   // Make sure the instruction folded as expected.
2093   EXPECT_TRUE(succeeded);
2094   if (inst != nullptr) {
2095     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
2096     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2097     EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
2098     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2099     const analysis::FloatConstant* result =
2100         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2101     EXPECT_NE(result, nullptr);
2102     if (result != nullptr) {
2103       if (!std::isnan(tc.expected_result)) {
2104         EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
2105       } else {
2106         EXPECT_TRUE(std::isnan(result->GetFloatValue()));
2107       }
2108     }
2109   }
2110 }
2111 
2112 // Not testing NaNs because there are no expectations concerning NaNs according
2113 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
2114 // specification.
2115 
2116 // clang-format off
2117 INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
2118 ::testing::Values(
2119     // Test case 0: Fold 2.0 - 1.0
2120     InstructionFoldingCase<float>(
2121         Header() + "%main = OpFunction %void None %void_func\n" +
2122             "%main_lab = OpLabel\n" +
2123             "%2 = OpFSub %float %float_2 %float_1\n" +
2124             "OpReturn\n" +
2125             "OpFunctionEnd",
2126         2, 1.0),
2127     // Test case 1: Fold 2.0 + 1.0
2128     InstructionFoldingCase<float>(
2129         Header() + "%main = OpFunction %void None %void_func\n" +
2130             "%main_lab = OpLabel\n" +
2131             "%2 = OpFAdd %float %float_2 %float_1\n" +
2132             "OpReturn\n" +
2133             "OpFunctionEnd",
2134         2, 3.0),
2135     // Test case 2: Fold 3.0 * 2.0
2136     InstructionFoldingCase<float>(
2137         Header() + "%main = OpFunction %void None %void_func\n" +
2138             "%main_lab = OpLabel\n" +
2139             "%2 = OpFMul %float %float_3 %float_2\n" +
2140             "OpReturn\n" +
2141             "OpFunctionEnd",
2142         2, 6.0),
2143     // Test case 3: Fold 1.0 / 2.0
2144     InstructionFoldingCase<float>(
2145         Header() + "%main = OpFunction %void None %void_func\n" +
2146             "%main_lab = OpLabel\n" +
2147             "%2 = OpFDiv %float %float_1 %float_2\n" +
2148             "OpReturn\n" +
2149             "OpFunctionEnd",
2150         2, 0.5),
2151     // Test case 4: Fold 1.0 / 0.0
2152     InstructionFoldingCase<float>(
2153         Header() + "%main = OpFunction %void None %void_func\n" +
2154             "%main_lab = OpLabel\n" +
2155             "%2 = OpFDiv %float %float_1 %float_0\n" +
2156             "OpReturn\n" +
2157             "OpFunctionEnd",
2158         2, std::numeric_limits<float>::infinity()),
2159     // Test case 5: Fold -1.0 / 0.0
2160     InstructionFoldingCase<float>(
2161         Header() + "%main = OpFunction %void None %void_func\n" +
2162             "%main_lab = OpLabel\n" +
2163             "%2 = OpFDiv %float %float_n1 %float_0\n" +
2164             "OpReturn\n" +
2165             "OpFunctionEnd",
2166         2, -std::numeric_limits<float>::infinity()),
2167     // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2168     InstructionFoldingCase<float>(
2169         Header() + "%main = OpFunction %void None %void_func\n" +
2170             "%main_lab = OpLabel\n" +
2171             "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
2172             "OpReturn\n" +
2173             "OpFunctionEnd",
2174         2, 5.5f),
2175     // Test case 7: Fold (0.0, 0.0) dot v
2176     InstructionFoldingCase<float>(
2177         Header() + "%main = OpFunction %void None %void_func\n" +
2178             "%main_lab = OpLabel\n" +
2179             "%v = OpVariable %_ptr_v2float Function\n" +
2180             "%2 = OpLoad %v2float %v\n" +
2181             "%3 = OpDot %float %v2float_0_0 %2\n" +
2182             "OpReturn\n" +
2183             "OpFunctionEnd",
2184         3, 0.0f),
2185     // Test case 8: Fold v dot (0.0, 0.0)
2186     InstructionFoldingCase<float>(
2187         Header() + "%main = OpFunction %void None %void_func\n" +
2188             "%main_lab = OpLabel\n" +
2189             "%v = OpVariable %_ptr_v2float Function\n" +
2190             "%2 = OpLoad %v2float %v\n" +
2191             "%3 = OpDot %float %2 %v2float_0_0\n" +
2192             "OpReturn\n" +
2193             "OpFunctionEnd",
2194         3, 0.0f),
2195     // Test case 9: Fold Null dot v
2196     InstructionFoldingCase<float>(
2197         Header() + "%main = OpFunction %void None %void_func\n" +
2198             "%main_lab = OpLabel\n" +
2199             "%v = OpVariable %_ptr_v2float Function\n" +
2200             "%2 = OpLoad %v2float %v\n" +
2201             "%3 = OpDot %float %v2float_null %2\n" +
2202             "OpReturn\n" +
2203             "OpFunctionEnd",
2204         3, 0.0f),
2205     // Test case 10: Fold v dot Null
2206     InstructionFoldingCase<float>(
2207         Header() + "%main = OpFunction %void None %void_func\n" +
2208             "%main_lab = OpLabel\n" +
2209             "%v = OpVariable %_ptr_v2float Function\n" +
2210             "%2 = OpLoad %v2float %v\n" +
2211             "%3 = OpDot %float %2 %v2float_null\n" +
2212             "OpReturn\n" +
2213             "OpFunctionEnd",
2214         3, 0.0f),
2215     // Test case 11: Fold -2.0
2216     InstructionFoldingCase<float>(
2217         Header() + "%main = OpFunction %void None %void_func\n" +
2218             "%main_lab = OpLabel\n" +
2219             "%2 = OpFNegate %float %float_2\n" +
2220             "OpReturn\n" +
2221             "OpFunctionEnd",
2222         2, -2),
2223     // Test case 12: QuantizeToF16 1.0
2224     InstructionFoldingCase<float>(
2225         Header() + "%main = OpFunction %void None %void_func\n" +
2226             "%main_lab = OpLabel\n" +
2227             "%2 = OpQuantizeToF16 %float %float_1\n" +
2228             "OpReturn\n" +
2229             "OpFunctionEnd",
2230         2, 1.0),
2231     // Test case 13: QuantizeToF16 positive non exact
2232     InstructionFoldingCase<float>(
2233         Header() + "%main = OpFunction %void None %void_func\n" +
2234             "%main_lab = OpLabel\n" +
2235             "%2 = OpQuantizeToF16 %float %float_2049\n" +
2236             "OpReturn\n" +
2237             "OpFunctionEnd",
2238         2, 2048),
2239     // Test case 14: QuantizeToF16 negative non exact
2240     InstructionFoldingCase<float>(
2241         Header() + "%main = OpFunction %void None %void_func\n" +
2242             "%main_lab = OpLabel\n" +
2243             "%2 = OpQuantizeToF16 %float %float_n2049\n" +
2244             "OpReturn\n" +
2245             "OpFunctionEnd",
2246         2, -2048),
2247     // Test case 15: QuantizeToF16 large positive
2248     InstructionFoldingCase<float>(
2249         Header() + "%main = OpFunction %void None %void_func\n" +
2250             "%main_lab = OpLabel\n" +
2251             "%2 = OpQuantizeToF16 %float %float_1e16\n" +
2252             "OpReturn\n" +
2253             "OpFunctionEnd",
2254         2, std::numeric_limits<float>::infinity()),
2255     // Test case 16: QuantizeToF16 large negative
2256     InstructionFoldingCase<float>(
2257         Header() + "%main = OpFunction %void None %void_func\n" +
2258             "%main_lab = OpLabel\n" +
2259             "%2 = OpQuantizeToF16 %float %float_n1e16\n" +
2260             "OpReturn\n" +
2261             "OpFunctionEnd",
2262         2, -std::numeric_limits<float>::infinity()),
2263     // Test case 17: QuantizeToF16 small positive
2264     InstructionFoldingCase<float>(
2265         Header() + "%main = OpFunction %void None %void_func\n" +
2266             "%main_lab = OpLabel\n" +
2267             "%2 = OpQuantizeToF16 %float %float_1en16\n" +
2268             "OpReturn\n" +
2269             "OpFunctionEnd",
2270         2, 0.0),
2271     // Test case 18: QuantizeToF16 small negative
2272     InstructionFoldingCase<float>(
2273         Header() + "%main = OpFunction %void None %void_func\n" +
2274             "%main_lab = OpLabel\n" +
2275             "%2 = OpQuantizeToF16 %float %float_n1en16\n" +
2276             "OpReturn\n" +
2277             "OpFunctionEnd",
2278         2, 0.0),
2279     // Test case 19: QuantizeToF16 nan
2280     InstructionFoldingCase<float>(
2281         HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2282             "%main_lab = OpLabel\n" +
2283             "%2 = OpQuantizeToF16 %float %float_nan\n" +
2284             "OpReturn\n" +
2285             "OpFunctionEnd",
2286         2, std::numeric_limits<float>::quiet_NaN()),
2287     // Test case 20: FMix 1.0 4.0 0.2
2288     InstructionFoldingCase<float>(
2289         Header() + "%main = OpFunction %void None %void_func\n" +
2290             "%main_lab = OpLabel\n" +
2291             "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
2292             "OpReturn\n" +
2293             "OpFunctionEnd",
2294         2, 1.6f),
2295     // Test case 21: FMin 1.0 4.0
2296     InstructionFoldingCase<float>(
2297         Header() + "%main = OpFunction %void None %void_func\n" +
2298             "%main_lab = OpLabel\n" +
2299             "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
2300             "OpReturn\n" +
2301             "OpFunctionEnd",
2302         2, 1.0f),
2303     // Test case 22: FMin 4.0 0.2
2304     InstructionFoldingCase<float>(
2305         Header() + "%main = OpFunction %void None %void_func\n" +
2306             "%main_lab = OpLabel\n" +
2307             "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
2308             "OpReturn\n" +
2309             "OpFunctionEnd",
2310         2, 0.2f),
2311     // Test case 23: FMax 1.0 4.0
2312     InstructionFoldingCase<float>(
2313         Header() + "%main = OpFunction %void None %void_func\n" +
2314             "%main_lab = OpLabel\n" +
2315             "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
2316             "OpReturn\n" +
2317             "OpFunctionEnd",
2318         2, 4.0f),
2319     // Test case 24: FMax 1.0 0.2
2320     InstructionFoldingCase<float>(
2321         Header() + "%main = OpFunction %void None %void_func\n" +
2322             "%main_lab = OpLabel\n" +
2323             "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
2324             "OpReturn\n" +
2325             "OpFunctionEnd",
2326         2, 1.0f),
2327     // Test case 25: FClamp 1.0 0.2 4.0
2328     InstructionFoldingCase<float>(
2329         Header() + "%main = OpFunction %void None %void_func\n" +
2330             "%main_lab = OpLabel\n" +
2331             "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
2332             "OpReturn\n" +
2333             "OpFunctionEnd",
2334         2, 1.0f),
2335     // Test case 26: FClamp 0.2 2.0 4.0
2336     InstructionFoldingCase<float>(
2337         Header() + "%main = OpFunction %void None %void_func\n" +
2338             "%main_lab = OpLabel\n" +
2339             "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
2340             "OpReturn\n" +
2341             "OpFunctionEnd",
2342         2, 2.0f),
2343     // Test case 27: FClamp 2049.0 2.0 4.0
2344     InstructionFoldingCase<float>(
2345         Header() + "%main = OpFunction %void None %void_func\n" +
2346             "%main_lab = OpLabel\n" +
2347             "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
2348             "OpReturn\n" +
2349             "OpFunctionEnd",
2350         2, 4.0f),
2351     // Test case 28: FClamp 1.0 2.0 x
2352     InstructionFoldingCase<float>(
2353         Header() + "%main = OpFunction %void None %void_func\n" +
2354             "%main_lab = OpLabel\n" +
2355             "%undef = OpUndef %float\n" +
2356             "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
2357             "OpReturn\n" +
2358             "OpFunctionEnd",
2359         2, 2.0),
2360     // Test case 29: FClamp 1.0 x 0.5
2361     InstructionFoldingCase<float>(
2362         Header() + "%main = OpFunction %void None %void_func\n" +
2363             "%main_lab = OpLabel\n" +
2364             "%undef = OpUndef %float\n" +
2365             "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
2366             "OpReturn\n" +
2367             "OpFunctionEnd",
2368         2, 0.5),
2369     // Test case 30: Sin 0.0
2370     InstructionFoldingCase<float>(
2371         Header() + "%main = OpFunction %void None %void_func\n" +
2372             "%main_lab = OpLabel\n" +
2373             "%2 = OpExtInst %float %1 Sin %float_0\n" +
2374             "OpReturn\n" +
2375             "OpFunctionEnd",
2376         2, 0.0),
2377     // Test case 31: Cos 0.0
2378     InstructionFoldingCase<float>(
2379         Header() + "%main = OpFunction %void None %void_func\n" +
2380             "%main_lab = OpLabel\n" +
2381             "%2 = OpExtInst %float %1 Cos %float_0\n" +
2382             "OpReturn\n" +
2383             "OpFunctionEnd",
2384         2, 1.0),
2385     // Test case 32: Tan 0.0
2386     InstructionFoldingCase<float>(
2387         Header() + "%main = OpFunction %void None %void_func\n" +
2388             "%main_lab = OpLabel\n" +
2389             "%2 = OpExtInst %float %1 Tan %float_0\n" +
2390             "OpReturn\n" +
2391             "OpFunctionEnd",
2392         2, 0.0),
2393     // Test case 33: Asin 0.0
2394     InstructionFoldingCase<float>(
2395         Header() + "%main = OpFunction %void None %void_func\n" +
2396             "%main_lab = OpLabel\n" +
2397             "%2 = OpExtInst %float %1 Asin %float_0\n" +
2398             "OpReturn\n" +
2399             "OpFunctionEnd",
2400         2, 0.0),
2401     // Test case 34: Acos 1.0
2402     InstructionFoldingCase<float>(
2403         Header() + "%main = OpFunction %void None %void_func\n" +
2404             "%main_lab = OpLabel\n" +
2405             "%2 = OpExtInst %float %1 Acos %float_1\n" +
2406             "OpReturn\n" +
2407             "OpFunctionEnd",
2408         2, 0.0),
2409     // Test case 35: Atan 0.0
2410     InstructionFoldingCase<float>(
2411         Header() + "%main = OpFunction %void None %void_func\n" +
2412             "%main_lab = OpLabel\n" +
2413             "%2 = OpExtInst %float %1 Atan %float_0\n" +
2414             "OpReturn\n" +
2415             "OpFunctionEnd",
2416         2, 0.0),
2417     // Test case 36: Exp 0.0
2418     InstructionFoldingCase<float>(
2419         Header() + "%main = OpFunction %void None %void_func\n" +
2420             "%main_lab = OpLabel\n" +
2421             "%2 = OpExtInst %float %1 Exp %float_0\n" +
2422             "OpReturn\n" +
2423             "OpFunctionEnd",
2424         2, 1.0),
2425     // Test case 37: Log 1.0
2426     InstructionFoldingCase<float>(
2427         Header() + "%main = OpFunction %void None %void_func\n" +
2428             "%main_lab = OpLabel\n" +
2429             "%2 = OpExtInst %float %1 Log %float_1\n" +
2430             "OpReturn\n" +
2431             "OpFunctionEnd",
2432         2, 0.0),
2433     // Test case 38: Exp2 2.0
2434     InstructionFoldingCase<float>(
2435         Header() + "%main = OpFunction %void None %void_func\n" +
2436             "%main_lab = OpLabel\n" +
2437             "%2 = OpExtInst %float %1 Exp2 %float_2\n" +
2438             "OpReturn\n" +
2439             "OpFunctionEnd",
2440         2, 4.0),
2441     // Test case 39: Log2 4.0
2442     InstructionFoldingCase<float>(
2443         Header() + "%main = OpFunction %void None %void_func\n" +
2444             "%main_lab = OpLabel\n" +
2445             "%2 = OpExtInst %float %1 Log2 %float_4\n" +
2446             "OpReturn\n" +
2447             "OpFunctionEnd",
2448         2, 2.0),
2449     // Test case 40: Sqrt 4.0
2450     InstructionFoldingCase<float>(
2451         Header() + "%main = OpFunction %void None %void_func\n" +
2452             "%main_lab = OpLabel\n" +
2453             "%2 = OpExtInst %float %1 Sqrt %float_4\n" +
2454             "OpReturn\n" +
2455             "OpFunctionEnd",
2456         2, 2.0),
2457     // Test case 41: Atan2 0.0 1.0
2458     InstructionFoldingCase<float>(
2459         Header() + "%main = OpFunction %void None %void_func\n" +
2460             "%main_lab = OpLabel\n" +
2461             "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
2462             "OpReturn\n" +
2463             "OpFunctionEnd",
2464         2, 0.0),
2465     // Test case 42: Pow 2.0 3.0
2466     InstructionFoldingCase<float>(
2467         Header() + "%main = OpFunction %void None %void_func\n" +
2468             "%main_lab = OpLabel\n" +
2469             "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
2470             "OpReturn\n" +
2471             "OpFunctionEnd",
2472         2, 8.0),
2473     // Test case 43: Fold 1.0 / -0.0.
2474     InstructionFoldingCase<float>(
2475         Header() + "%main = OpFunction %void None %void_func\n" +
2476             "%main_lab = OpLabel\n" +
2477             "%2 = OpFDiv %float %float_1 %float_n0\n" +
2478             "OpReturn\n" +
2479             "OpFunctionEnd",
2480         2, -std::numeric_limits<float>::infinity()),
2481     // Test case 44: Fold -1.0 / -0.0
2482     InstructionFoldingCase<float>(
2483         Header() + "%main = OpFunction %void None %void_func\n" +
2484             "%main_lab = OpLabel\n" +
2485             "%2 = OpFDiv %float %float_n1 %float_n0\n" +
2486             "OpReturn\n" +
2487             "OpFunctionEnd",
2488         2, std::numeric_limits<float>::infinity()),
2489     // Test case 45: Fold 0.0 / 0.0
2490     InstructionFoldingCase<float>(
2491         Header() + "%main = OpFunction %void None %void_func\n" +
2492             "%main_lab = OpLabel\n" +
2493             "%2 = OpFDiv %float %float_0 %float_0\n" +
2494             "OpReturn\n" +
2495             "OpFunctionEnd",
2496         2, std::numeric_limits<float>::quiet_NaN()),
2497     // Test case 46: Fold 0.0 / -0.0
2498     InstructionFoldingCase<float>(
2499         Header() + "%main = OpFunction %void None %void_func\n" +
2500             "%main_lab = OpLabel\n" +
2501             "%2 = OpFDiv %float %float_0 %float_n0\n" +
2502             "OpReturn\n" +
2503             "OpFunctionEnd",
2504         2, std::numeric_limits<float>::quiet_NaN())
2505 ));
2506 // clang-format on
2507 
2508 using DoubleInstructionFoldingTest =
2509     ::testing::TestWithParam<InstructionFoldingCase<double>>;
2510 
TEST_P(DoubleInstructionFoldingTest, Case)2511 TEST_P(DoubleInstructionFoldingTest, Case) {
2512   const auto& tc = GetParam();
2513 
2514   // Build module.
2515   std::unique_ptr<IRContext> context =
2516       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2517                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2518   ASSERT_NE(nullptr, context);
2519 
2520   // Fold the instruction to test.
2521   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2522   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2523   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2524 
2525   // Make sure the instruction folded as expected.
2526   EXPECT_TRUE(succeeded);
2527   if (inst != nullptr) {
2528     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
2529     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2530     EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
2531     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2532     const analysis::FloatConstant* result =
2533         const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2534     EXPECT_NE(result, nullptr);
2535     if (result != nullptr) {
2536       if (!std::isnan(tc.expected_result)) {
2537         EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
2538       } else {
2539         EXPECT_TRUE(std::isnan(result->GetDoubleValue()));
2540       }
2541     }
2542   }
2543 }
2544 
2545 // clang-format off
2546 INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
2547 ::testing::Values(
2548     // Test case 0: Fold 2.0 - 1.0
2549     InstructionFoldingCase<double>(
2550         Header() + "%main = OpFunction %void None %void_func\n" +
2551             "%main_lab = OpLabel\n" +
2552             "%2 = OpFSub %double %double_2 %double_1\n" +
2553             "OpReturn\n" +
2554             "OpFunctionEnd",
2555         2, 1.0),
2556         // Test case 1: Fold 2.0 + 1.0
2557         InstructionFoldingCase<double>(
2558             Header() + "%main = OpFunction %void None %void_func\n" +
2559                 "%main_lab = OpLabel\n" +
2560                 "%2 = OpFAdd %double %double_2 %double_1\n" +
2561                 "OpReturn\n" +
2562                 "OpFunctionEnd",
2563             2, 3.0),
2564         // Test case 2: Fold 3.0 * 2.0
2565         InstructionFoldingCase<double>(
2566             Header() + "%main = OpFunction %void None %void_func\n" +
2567                 "%main_lab = OpLabel\n" +
2568                 "%2 = OpFMul %double %double_3 %double_2\n" +
2569                 "OpReturn\n" +
2570                 "OpFunctionEnd",
2571             2, 6.0),
2572         // Test case 3: Fold 1.0 / 2.0
2573         InstructionFoldingCase<double>(
2574             Header() + "%main = OpFunction %void None %void_func\n" +
2575                 "%main_lab = OpLabel\n" +
2576                 "%2 = OpFDiv %double %double_1 %double_2\n" +
2577                 "OpReturn\n" +
2578                 "OpFunctionEnd",
2579             2, 0.5),
2580         // Test case 4: Fold 1.0 / 0.0
2581         InstructionFoldingCase<double>(
2582             Header() + "%main = OpFunction %void None %void_func\n" +
2583                 "%main_lab = OpLabel\n" +
2584                 "%2 = OpFDiv %double %double_1 %double_0\n" +
2585                 "OpReturn\n" +
2586                 "OpFunctionEnd",
2587             2, std::numeric_limits<double>::infinity()),
2588         // Test case 5: Fold -1.0 / 0.0
2589         InstructionFoldingCase<double>(
2590             Header() + "%main = OpFunction %void None %void_func\n" +
2591                 "%main_lab = OpLabel\n" +
2592                 "%2 = OpFDiv %double %double_n1 %double_0\n" +
2593                 "OpReturn\n" +
2594                 "OpFunctionEnd",
2595             2, -std::numeric_limits<double>::infinity()),
2596         // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2597         InstructionFoldingCase<double>(
2598             Header() + "%main = OpFunction %void None %void_func\n" +
2599                 "%main_lab = OpLabel\n" +
2600                 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
2601                 "OpReturn\n" +
2602                 "OpFunctionEnd",
2603             2, 5.5f),
2604         // Test case 7: Fold (0.0, 0.0) dot v
2605         InstructionFoldingCase<double>(
2606             Header() + "%main = OpFunction %void None %void_func\n" +
2607                 "%main_lab = OpLabel\n" +
2608                 "%v = OpVariable %_ptr_v2double Function\n" +
2609                 "%2 = OpLoad %v2double %v\n" +
2610                 "%3 = OpDot %double %v2double_0_0 %2\n" +
2611                 "OpReturn\n" +
2612                 "OpFunctionEnd",
2613             3, 0.0f),
2614         // Test case 8: Fold v dot (0.0, 0.0)
2615         InstructionFoldingCase<double>(
2616             Header() + "%main = OpFunction %void None %void_func\n" +
2617                 "%main_lab = OpLabel\n" +
2618                 "%v = OpVariable %_ptr_v2double Function\n" +
2619                 "%2 = OpLoad %v2double %v\n" +
2620                 "%3 = OpDot %double %2 %v2double_0_0\n" +
2621                 "OpReturn\n" +
2622                 "OpFunctionEnd",
2623             3, 0.0f),
2624         // Test case 9: Fold Null dot v
2625         InstructionFoldingCase<double>(
2626             Header() + "%main = OpFunction %void None %void_func\n" +
2627                 "%main_lab = OpLabel\n" +
2628                 "%v = OpVariable %_ptr_v2double Function\n" +
2629                 "%2 = OpLoad %v2double %v\n" +
2630                 "%3 = OpDot %double %v2double_null %2\n" +
2631                 "OpReturn\n" +
2632                 "OpFunctionEnd",
2633             3, 0.0f),
2634         // Test case 10: Fold v dot Null
2635         InstructionFoldingCase<double>(
2636             Header() + "%main = OpFunction %void None %void_func\n" +
2637                 "%main_lab = OpLabel\n" +
2638                 "%v = OpVariable %_ptr_v2double Function\n" +
2639                 "%2 = OpLoad %v2double %v\n" +
2640                 "%3 = OpDot %double %2 %v2double_null\n" +
2641                 "OpReturn\n" +
2642                 "OpFunctionEnd",
2643             3, 0.0f),
2644         // Test case 11: Fold -2.0
2645         InstructionFoldingCase<double>(
2646             Header() + "%main = OpFunction %void None %void_func\n" +
2647                 "%main_lab = OpLabel\n" +
2648                 "%2 = OpFNegate %double %double_2\n" +
2649                 "OpReturn\n" +
2650                 "OpFunctionEnd",
2651             2, -2),
2652         // Test case 12: FMin 1.0 4.0
2653         InstructionFoldingCase<double>(
2654             Header() + "%main = OpFunction %void None %void_func\n" +
2655                 "%main_lab = OpLabel\n" +
2656                 "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
2657                 "OpReturn\n" +
2658                 "OpFunctionEnd",
2659             2, 1.0),
2660         // Test case 13: FMin 4.0 0.2
2661         InstructionFoldingCase<double>(
2662             Header() + "%main = OpFunction %void None %void_func\n" +
2663                 "%main_lab = OpLabel\n" +
2664                 "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
2665                 "OpReturn\n" +
2666                 "OpFunctionEnd",
2667             2, 0.2),
2668         // Test case 14: FMax 1.0 4.0
2669         InstructionFoldingCase<double>(
2670             Header() + "%main = OpFunction %void None %void_func\n" +
2671                 "%main_lab = OpLabel\n" +
2672                 "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
2673                 "OpReturn\n" +
2674                 "OpFunctionEnd",
2675             2, 4.0),
2676         // Test case 15: FMax 1.0 0.2
2677         InstructionFoldingCase<double>(
2678             Header() + "%main = OpFunction %void None %void_func\n" +
2679                 "%main_lab = OpLabel\n" +
2680                 "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
2681                 "OpReturn\n" +
2682                 "OpFunctionEnd",
2683             2, 1.0),
2684         // Test case 16: FClamp 1.0 0.2 4.0
2685         InstructionFoldingCase<double>(
2686             Header() + "%main = OpFunction %void None %void_func\n" +
2687                 "%main_lab = OpLabel\n" +
2688                 "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
2689                 "OpReturn\n" +
2690                 "OpFunctionEnd",
2691             2, 1.0),
2692         // Test case 17: FClamp 0.2 2.0 4.0
2693         InstructionFoldingCase<double>(
2694             Header() + "%main = OpFunction %void None %void_func\n" +
2695                 "%main_lab = OpLabel\n" +
2696                 "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
2697                 "OpReturn\n" +
2698                 "OpFunctionEnd",
2699             2, 2.0),
2700         // Test case 18: FClamp 5.0 2.0 4.0
2701         InstructionFoldingCase<double>(
2702             Header() + "%main = OpFunction %void None %void_func\n" +
2703                 "%main_lab = OpLabel\n" +
2704                 "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
2705                 "OpReturn\n" +
2706                 "OpFunctionEnd",
2707             2, 4.0),
2708         // Test case 19: FClamp 1.0 2.0 x
2709         InstructionFoldingCase<double>(
2710             Header() + "%main = OpFunction %void None %void_func\n" +
2711                 "%main_lab = OpLabel\n" +
2712                 "%undef = OpUndef %double\n" +
2713                 "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
2714                 "OpReturn\n" +
2715                 "OpFunctionEnd",
2716             2, 2.0),
2717         // Test case 20: FClamp 1.0 x 0.5
2718         InstructionFoldingCase<double>(
2719             Header() + "%main = OpFunction %void None %void_func\n" +
2720                 "%main_lab = OpLabel\n" +
2721                 "%undef = OpUndef %double\n" +
2722                 "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
2723                 "OpReturn\n" +
2724                 "OpFunctionEnd",
2725             2, 0.5),
2726         // Test case 21: Sqrt 4.0
2727         InstructionFoldingCase<double>(
2728             Header() + "%main = OpFunction %void None %void_func\n" +
2729                 "%main_lab = OpLabel\n" +
2730                 "%undef = OpUndef %double\n" +
2731                 "%2 = OpExtInst %double %1 Sqrt %double_4\n" +
2732                 "OpReturn\n" +
2733                 "OpFunctionEnd",
2734             2, 2.0),
2735         // Test case 22: Pow 2.0 3.0
2736         InstructionFoldingCase<double>(
2737             Header() + "%main = OpFunction %void None %void_func\n" +
2738                 "%main_lab = OpLabel\n" +
2739                 "%undef = OpUndef %double\n" +
2740                 "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" +
2741                 "OpReturn\n" +
2742                 "OpFunctionEnd",
2743             2, 8.0),
2744         // Test case 23: Fold 1.0 / -0.0.
2745         InstructionFoldingCase<double>(
2746             Header() + "%main = OpFunction %void None %void_func\n" +
2747                 "%main_lab = OpLabel\n" +
2748                 "%2 = OpFDiv %double %double_1 %double_n0\n" +
2749                 "OpReturn\n" +
2750                 "OpFunctionEnd",
2751             2, -std::numeric_limits<double>::infinity()),
2752         // Test case 24: Fold -1.0 / -0.0
2753         InstructionFoldingCase<double>(
2754             Header() + "%main = OpFunction %void None %void_func\n" +
2755                 "%main_lab = OpLabel\n" +
2756                 "%2 = OpFDiv %double %double_n1 %double_n0\n" +
2757                 "OpReturn\n" +
2758                 "OpFunctionEnd",
2759             2, std::numeric_limits<double>::infinity()),
2760         // Test case 25: Fold 0.0 / 0.0
2761         InstructionFoldingCase<double>(
2762             Header() + "%main = OpFunction %void None %void_func\n" +
2763                 "%main_lab = OpLabel\n" +
2764                 "%2 = OpFDiv %double %double_0 %double_0\n" +
2765                 "OpReturn\n" +
2766                 "OpFunctionEnd",
2767             2, std::numeric_limits<double>::quiet_NaN()),
2768         // Test case 26: Fold 0.0 / -0.0
2769         InstructionFoldingCase<double>(
2770             Header() + "%main = OpFunction %void None %void_func\n" +
2771                 "%main_lab = OpLabel\n" +
2772                 "%2 = OpFDiv %double %double_0 %double_n0\n" +
2773                 "OpReturn\n" +
2774                 "OpFunctionEnd",
2775             2, std::numeric_limits<double>::quiet_NaN())
2776 ));
2777 // clang-format on
2778 
2779 // clang-format off
2780 INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2781                         ::testing::Values(
2782   // Test case 0: fold 1.0 == 2.0
2783   InstructionFoldingCase<bool>(
2784       Header() + "%main = OpFunction %void None %void_func\n" +
2785           "%main_lab = OpLabel\n" +
2786           "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
2787           "OpReturn\n" +
2788           "OpFunctionEnd",
2789       2, false),
2790   // Test case 1: fold 1.0 != 2.0
2791   InstructionFoldingCase<bool>(
2792       Header() + "%main = OpFunction %void None %void_func\n" +
2793           "%main_lab = OpLabel\n" +
2794           "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
2795           "OpReturn\n" +
2796           "OpFunctionEnd",
2797       2, true),
2798   // Test case 2: fold 1.0 < 2.0
2799   InstructionFoldingCase<bool>(
2800       Header() + "%main = OpFunction %void None %void_func\n" +
2801           "%main_lab = OpLabel\n" +
2802           "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
2803           "OpReturn\n" +
2804           "OpFunctionEnd",
2805       2, true),
2806   // Test case 3: fold 1.0 > 2.0
2807   InstructionFoldingCase<bool>(
2808       Header() + "%main = OpFunction %void None %void_func\n" +
2809           "%main_lab = OpLabel\n" +
2810           "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
2811           "OpReturn\n" +
2812           "OpFunctionEnd",
2813       2, false),
2814   // Test case 4: fold 1.0 <= 2.0
2815   InstructionFoldingCase<bool>(
2816       Header() + "%main = OpFunction %void None %void_func\n" +
2817           "%main_lab = OpLabel\n" +
2818           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
2819           "OpReturn\n" +
2820           "OpFunctionEnd",
2821       2, true),
2822   // Test case 5: fold 1.0 >= 2.0
2823   InstructionFoldingCase<bool>(
2824       Header() + "%main = OpFunction %void None %void_func\n" +
2825           "%main_lab = OpLabel\n" +
2826           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
2827           "OpReturn\n" +
2828           "OpFunctionEnd",
2829       2, false),
2830   // Test case 6: fold 1.0 == 1.0
2831   InstructionFoldingCase<bool>(
2832       Header() + "%main = OpFunction %void None %void_func\n" +
2833           "%main_lab = OpLabel\n" +
2834           "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
2835           "OpReturn\n" +
2836           "OpFunctionEnd",
2837       2, true),
2838   // Test case 7: fold 1.0 != 1.0
2839   InstructionFoldingCase<bool>(
2840       Header() + "%main = OpFunction %void None %void_func\n" +
2841           "%main_lab = OpLabel\n" +
2842           "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
2843           "OpReturn\n" +
2844           "OpFunctionEnd",
2845       2, false),
2846   // Test case 8: fold 1.0 < 1.0
2847   InstructionFoldingCase<bool>(
2848       Header() + "%main = OpFunction %void None %void_func\n" +
2849           "%main_lab = OpLabel\n" +
2850           "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
2851           "OpReturn\n" +
2852           "OpFunctionEnd",
2853       2, false),
2854   // Test case 9: fold 1.0 > 1.0
2855   InstructionFoldingCase<bool>(
2856       Header() + "%main = OpFunction %void None %void_func\n" +
2857           "%main_lab = OpLabel\n" +
2858           "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
2859           "OpReturn\n" +
2860           "OpFunctionEnd",
2861       2, false),
2862   // Test case 10: fold 1.0 <= 1.0
2863   InstructionFoldingCase<bool>(
2864       Header() + "%main = OpFunction %void None %void_func\n" +
2865           "%main_lab = OpLabel\n" +
2866           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
2867           "OpReturn\n" +
2868           "OpFunctionEnd",
2869       2, true),
2870   // Test case 11: fold 1.0 >= 1.0
2871   InstructionFoldingCase<bool>(
2872       Header() + "%main = OpFunction %void None %void_func\n" +
2873           "%main_lab = OpLabel\n" +
2874           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
2875           "OpReturn\n" +
2876           "OpFunctionEnd",
2877       2, true),
2878   // Test case 12: fold 2.0 < 1.0
2879   InstructionFoldingCase<bool>(
2880       Header() + "%main = OpFunction %void None %void_func\n" +
2881           "%main_lab = OpLabel\n" +
2882           "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
2883           "OpReturn\n" +
2884           "OpFunctionEnd",
2885       2, false),
2886   // Test case 13: fold 2.0 > 1.0
2887   InstructionFoldingCase<bool>(
2888       Header() + "%main = OpFunction %void None %void_func\n" +
2889           "%main_lab = OpLabel\n" +
2890           "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
2891           "OpReturn\n" +
2892           "OpFunctionEnd",
2893       2, true),
2894   // Test case 14: fold 2.0 <= 1.0
2895   InstructionFoldingCase<bool>(
2896       Header() + "%main = OpFunction %void None %void_func\n" +
2897           "%main_lab = OpLabel\n" +
2898           "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
2899           "OpReturn\n" +
2900           "OpFunctionEnd",
2901       2, false),
2902   // Test case 15: fold 2.0 >= 1.0
2903   InstructionFoldingCase<bool>(
2904       Header() + "%main = OpFunction %void None %void_func\n" +
2905           "%main_lab = OpLabel\n" +
2906           "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
2907           "OpReturn\n" +
2908           "OpFunctionEnd",
2909       2, true)
2910 ));
2911 
2912 INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2913                         ::testing::Values(
2914   // Test case 0: fold 1.0 == 2.0
2915   InstructionFoldingCase<bool>(
2916       Header() + "%main = OpFunction %void None %void_func\n" +
2917           "%main_lab = OpLabel\n" +
2918           "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
2919           "OpReturn\n" +
2920           "OpFunctionEnd",
2921       2, false),
2922   // Test case 1: fold 1.0 != 2.0
2923   InstructionFoldingCase<bool>(
2924       Header() + "%main = OpFunction %void None %void_func\n" +
2925           "%main_lab = OpLabel\n" +
2926           "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
2927           "OpReturn\n" +
2928           "OpFunctionEnd",
2929       2, true),
2930   // Test case 2: fold 1.0 < 2.0
2931   InstructionFoldingCase<bool>(
2932       Header() + "%main = OpFunction %void None %void_func\n" +
2933           "%main_lab = OpLabel\n" +
2934           "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
2935           "OpReturn\n" +
2936           "OpFunctionEnd",
2937       2, true),
2938   // Test case 3: fold 1.0 > 2.0
2939   InstructionFoldingCase<bool>(
2940       Header() + "%main = OpFunction %void None %void_func\n" +
2941           "%main_lab = OpLabel\n" +
2942           "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
2943           "OpReturn\n" +
2944           "OpFunctionEnd",
2945       2, false),
2946   // Test case 4: fold 1.0 <= 2.0
2947   InstructionFoldingCase<bool>(
2948       Header() + "%main = OpFunction %void None %void_func\n" +
2949           "%main_lab = OpLabel\n" +
2950           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
2951           "OpReturn\n" +
2952           "OpFunctionEnd",
2953       2, true),
2954   // Test case 5: fold 1.0 >= 2.0
2955   InstructionFoldingCase<bool>(
2956       Header() + "%main = OpFunction %void None %void_func\n" +
2957           "%main_lab = OpLabel\n" +
2958           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
2959           "OpReturn\n" +
2960           "OpFunctionEnd",
2961       2, false),
2962   // Test case 6: fold 1.0 == 1.0
2963   InstructionFoldingCase<bool>(
2964       Header() + "%main = OpFunction %void None %void_func\n" +
2965           "%main_lab = OpLabel\n" +
2966           "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
2967           "OpReturn\n" +
2968           "OpFunctionEnd",
2969       2, true),
2970   // Test case 7: fold 1.0 != 1.0
2971   InstructionFoldingCase<bool>(
2972       Header() + "%main = OpFunction %void None %void_func\n" +
2973           "%main_lab = OpLabel\n" +
2974           "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
2975           "OpReturn\n" +
2976           "OpFunctionEnd",
2977       2, false),
2978   // Test case 8: fold 1.0 < 1.0
2979   InstructionFoldingCase<bool>(
2980       Header() + "%main = OpFunction %void None %void_func\n" +
2981           "%main_lab = OpLabel\n" +
2982           "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
2983           "OpReturn\n" +
2984           "OpFunctionEnd",
2985       2, false),
2986   // Test case 9: fold 1.0 > 1.0
2987   InstructionFoldingCase<bool>(
2988       Header() + "%main = OpFunction %void None %void_func\n" +
2989           "%main_lab = OpLabel\n" +
2990           "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
2991           "OpReturn\n" +
2992           "OpFunctionEnd",
2993       2, false),
2994   // Test case 10: fold 1.0 <= 1.0
2995   InstructionFoldingCase<bool>(
2996       Header() + "%main = OpFunction %void None %void_func\n" +
2997           "%main_lab = OpLabel\n" +
2998           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
2999           "OpReturn\n" +
3000           "OpFunctionEnd",
3001       2, true),
3002   // Test case 11: fold 1.0 >= 1.0
3003   InstructionFoldingCase<bool>(
3004       Header() + "%main = OpFunction %void None %void_func\n" +
3005           "%main_lab = OpLabel\n" +
3006           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
3007           "OpReturn\n" +
3008           "OpFunctionEnd",
3009       2, true),
3010   // Test case 12: fold 2.0 < 1.0
3011   InstructionFoldingCase<bool>(
3012       Header() + "%main = OpFunction %void None %void_func\n" +
3013           "%main_lab = OpLabel\n" +
3014           "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
3015           "OpReturn\n" +
3016           "OpFunctionEnd",
3017       2, false),
3018   // Test case 13: fold 2.0 > 1.0
3019   InstructionFoldingCase<bool>(
3020       Header() + "%main = OpFunction %void None %void_func\n" +
3021           "%main_lab = OpLabel\n" +
3022           "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
3023           "OpReturn\n" +
3024           "OpFunctionEnd",
3025       2, true),
3026   // Test case 14: fold 2.0 <= 1.0
3027   InstructionFoldingCase<bool>(
3028       Header() + "%main = OpFunction %void None %void_func\n" +
3029           "%main_lab = OpLabel\n" +
3030           "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
3031           "OpReturn\n" +
3032           "OpFunctionEnd",
3033       2, false),
3034   // Test case 15: fold 2.0 >= 1.0
3035   InstructionFoldingCase<bool>(
3036       Header() + "%main = OpFunction %void None %void_func\n" +
3037           "%main_lab = OpLabel\n" +
3038           "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
3039           "OpReturn\n" +
3040           "OpFunctionEnd",
3041       2, true)
3042 ));
3043 
3044 INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3045                         ::testing::Values(
3046   // Test case 0: fold 1.0 == 2.0
3047   InstructionFoldingCase<bool>(
3048       Header() + "%main = OpFunction %void None %void_func\n" +
3049           "%main_lab = OpLabel\n" +
3050           "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
3051           "OpReturn\n" +
3052           "OpFunctionEnd",
3053       2, false),
3054   // Test case 1: fold 1.0 != 2.0
3055   InstructionFoldingCase<bool>(
3056       Header() + "%main = OpFunction %void None %void_func\n" +
3057           "%main_lab = OpLabel\n" +
3058           "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
3059           "OpReturn\n" +
3060           "OpFunctionEnd",
3061       2, true),
3062   // Test case 2: fold 1.0 < 2.0
3063   InstructionFoldingCase<bool>(
3064       Header() + "%main = OpFunction %void None %void_func\n" +
3065           "%main_lab = OpLabel\n" +
3066           "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
3067           "OpReturn\n" +
3068           "OpFunctionEnd",
3069       2, true),
3070   // Test case 3: fold 1.0 > 2.0
3071   InstructionFoldingCase<bool>(
3072       Header() + "%main = OpFunction %void None %void_func\n" +
3073           "%main_lab = OpLabel\n" +
3074           "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
3075           "OpReturn\n" +
3076           "OpFunctionEnd",
3077       2, false),
3078   // Test case 4: fold 1.0 <= 2.0
3079   InstructionFoldingCase<bool>(
3080       Header() + "%main = OpFunction %void None %void_func\n" +
3081           "%main_lab = OpLabel\n" +
3082           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
3083           "OpReturn\n" +
3084           "OpFunctionEnd",
3085       2, true),
3086   // Test case 5: fold 1.0 >= 2.0
3087   InstructionFoldingCase<bool>(
3088       Header() + "%main = OpFunction %void None %void_func\n" +
3089           "%main_lab = OpLabel\n" +
3090           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
3091           "OpReturn\n" +
3092           "OpFunctionEnd",
3093       2, false),
3094   // Test case 6: fold 1.0 == 1.0
3095   InstructionFoldingCase<bool>(
3096       Header() + "%main = OpFunction %void None %void_func\n" +
3097           "%main_lab = OpLabel\n" +
3098           "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
3099           "OpReturn\n" +
3100           "OpFunctionEnd",
3101       2, true),
3102   // Test case 7: fold 1.0 != 1.0
3103   InstructionFoldingCase<bool>(
3104       Header() + "%main = OpFunction %void None %void_func\n" +
3105           "%main_lab = OpLabel\n" +
3106           "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
3107           "OpReturn\n" +
3108           "OpFunctionEnd",
3109       2, false),
3110   // Test case 8: fold 1.0 < 1.0
3111   InstructionFoldingCase<bool>(
3112       Header() + "%main = OpFunction %void None %void_func\n" +
3113           "%main_lab = OpLabel\n" +
3114           "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
3115           "OpReturn\n" +
3116           "OpFunctionEnd",
3117       2, false),
3118   // Test case 9: fold 1.0 > 1.0
3119   InstructionFoldingCase<bool>(
3120       Header() + "%main = OpFunction %void None %void_func\n" +
3121           "%main_lab = OpLabel\n" +
3122           "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
3123           "OpReturn\n" +
3124           "OpFunctionEnd",
3125       2, false),
3126   // Test case 10: fold 1.0 <= 1.0
3127   InstructionFoldingCase<bool>(
3128       Header() + "%main = OpFunction %void None %void_func\n" +
3129           "%main_lab = OpLabel\n" +
3130           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
3131           "OpReturn\n" +
3132           "OpFunctionEnd",
3133       2, true),
3134   // Test case 11: fold 1.0 >= 1.0
3135   InstructionFoldingCase<bool>(
3136       Header() + "%main = OpFunction %void None %void_func\n" +
3137           "%main_lab = OpLabel\n" +
3138           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
3139           "OpReturn\n" +
3140           "OpFunctionEnd",
3141       2, true),
3142   // Test case 12: fold 2.0 < 1.0
3143   InstructionFoldingCase<bool>(
3144       Header() + "%main = OpFunction %void None %void_func\n" +
3145           "%main_lab = OpLabel\n" +
3146           "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
3147           "OpReturn\n" +
3148           "OpFunctionEnd",
3149       2, false),
3150   // Test case 13: fold 2.0 > 1.0
3151   InstructionFoldingCase<bool>(
3152       Header() + "%main = OpFunction %void None %void_func\n" +
3153           "%main_lab = OpLabel\n" +
3154           "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
3155           "OpReturn\n" +
3156           "OpFunctionEnd",
3157       2, true),
3158   // Test case 14: fold 2.0 <= 1.0
3159   InstructionFoldingCase<bool>(
3160       Header() + "%main = OpFunction %void None %void_func\n" +
3161           "%main_lab = OpLabel\n" +
3162           "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
3163           "OpReturn\n" +
3164           "OpFunctionEnd",
3165       2, false),
3166   // Test case 15: fold 2.0 >= 1.0
3167   InstructionFoldingCase<bool>(
3168       Header() + "%main = OpFunction %void None %void_func\n" +
3169           "%main_lab = OpLabel\n" +
3170           "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
3171           "OpReturn\n" +
3172           "OpFunctionEnd",
3173       2, true)
3174 ));
3175 
3176 INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3177                         ::testing::Values(
3178   // Test case 0: fold 1.0 == 2.0
3179   InstructionFoldingCase<bool>(
3180       Header() + "%main = OpFunction %void None %void_func\n" +
3181           "%main_lab = OpLabel\n" +
3182           "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
3183           "OpReturn\n" +
3184           "OpFunctionEnd",
3185       2, false),
3186   // Test case 1: fold 1.0 != 2.0
3187   InstructionFoldingCase<bool>(
3188       Header() + "%main = OpFunction %void None %void_func\n" +
3189           "%main_lab = OpLabel\n" +
3190           "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
3191           "OpReturn\n" +
3192           "OpFunctionEnd",
3193       2, true),
3194   // Test case 2: fold 1.0 < 2.0
3195   InstructionFoldingCase<bool>(
3196       Header() + "%main = OpFunction %void None %void_func\n" +
3197           "%main_lab = OpLabel\n" +
3198           "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
3199           "OpReturn\n" +
3200           "OpFunctionEnd",
3201       2, true),
3202   // Test case 3: fold 1.0 > 2.0
3203   InstructionFoldingCase<bool>(
3204       Header() + "%main = OpFunction %void None %void_func\n" +
3205           "%main_lab = OpLabel\n" +
3206           "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
3207           "OpReturn\n" +
3208           "OpFunctionEnd",
3209       2, false),
3210   // Test case 4: fold 1.0 <= 2.0
3211   InstructionFoldingCase<bool>(
3212       Header() + "%main = OpFunction %void None %void_func\n" +
3213           "%main_lab = OpLabel\n" +
3214           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
3215           "OpReturn\n" +
3216           "OpFunctionEnd",
3217       2, true),
3218   // Test case 5: fold 1.0 >= 2.0
3219   InstructionFoldingCase<bool>(
3220       Header() + "%main = OpFunction %void None %void_func\n" +
3221           "%main_lab = OpLabel\n" +
3222           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
3223           "OpReturn\n" +
3224           "OpFunctionEnd",
3225       2, false),
3226   // Test case 6: fold 1.0 == 1.0
3227   InstructionFoldingCase<bool>(
3228       Header() + "%main = OpFunction %void None %void_func\n" +
3229           "%main_lab = OpLabel\n" +
3230           "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
3231           "OpReturn\n" +
3232           "OpFunctionEnd",
3233       2, true),
3234   // Test case 7: fold 1.0 != 1.0
3235   InstructionFoldingCase<bool>(
3236       Header() + "%main = OpFunction %void None %void_func\n" +
3237           "%main_lab = OpLabel\n" +
3238           "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
3239           "OpReturn\n" +
3240           "OpFunctionEnd",
3241       2, false),
3242   // Test case 8: fold 1.0 < 1.0
3243   InstructionFoldingCase<bool>(
3244       Header() + "%main = OpFunction %void None %void_func\n" +
3245           "%main_lab = OpLabel\n" +
3246           "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
3247           "OpReturn\n" +
3248           "OpFunctionEnd",
3249       2, false),
3250   // Test case 9: fold 1.0 > 1.0
3251   InstructionFoldingCase<bool>(
3252       Header() + "%main = OpFunction %void None %void_func\n" +
3253           "%main_lab = OpLabel\n" +
3254           "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
3255           "OpReturn\n" +
3256           "OpFunctionEnd",
3257       2, false),
3258   // Test case 10: fold 1.0 <= 1.0
3259   InstructionFoldingCase<bool>(
3260       Header() + "%main = OpFunction %void None %void_func\n" +
3261           "%main_lab = OpLabel\n" +
3262           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
3263           "OpReturn\n" +
3264           "OpFunctionEnd",
3265       2, true),
3266   // Test case 11: fold 1.0 >= 1.0
3267   InstructionFoldingCase<bool>(
3268       Header() + "%main = OpFunction %void None %void_func\n" +
3269           "%main_lab = OpLabel\n" +
3270           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
3271           "OpReturn\n" +
3272           "OpFunctionEnd",
3273       2, true),
3274   // Test case 12: fold 2.0 < 1.0
3275   InstructionFoldingCase<bool>(
3276       Header() + "%main = OpFunction %void None %void_func\n" +
3277           "%main_lab = OpLabel\n" +
3278           "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
3279           "OpReturn\n" +
3280           "OpFunctionEnd",
3281       2, false),
3282   // Test case 13: fold 2.0 > 1.0
3283   InstructionFoldingCase<bool>(
3284       Header() + "%main = OpFunction %void None %void_func\n" +
3285           "%main_lab = OpLabel\n" +
3286           "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
3287           "OpReturn\n" +
3288           "OpFunctionEnd",
3289       2, true),
3290   // Test case 14: fold 2.0 <= 1.0
3291   InstructionFoldingCase<bool>(
3292       Header() + "%main = OpFunction %void None %void_func\n" +
3293           "%main_lab = OpLabel\n" +
3294           "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
3295           "OpReturn\n" +
3296           "OpFunctionEnd",
3297       2, false),
3298   // Test case 15: fold 2.0 >= 1.0
3299   InstructionFoldingCase<bool>(
3300       Header() + "%main = OpFunction %void None %void_func\n" +
3301           "%main_lab = OpLabel\n" +
3302           "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
3303           "OpReturn\n" +
3304           "OpFunctionEnd",
3305       2, true)
3306 ));
3307 
3308 INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3309                         ::testing::Values(
3310   // Test case 0: fold NaN == 0 (ord)
3311   InstructionFoldingCase<bool>(
3312       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3313           "%main_lab = OpLabel\n" +
3314           "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
3315           "OpReturn\n" +
3316           "OpFunctionEnd",
3317       2, false),
3318   // Test case 1: fold NaN == NaN (unord)
3319   InstructionFoldingCase<bool>(
3320       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3321           "%main_lab = OpLabel\n" +
3322           "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
3323           "OpReturn\n" +
3324           "OpFunctionEnd",
3325       2, true),
3326   // Test case 2: fold NaN != NaN (ord)
3327   InstructionFoldingCase<bool>(
3328       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3329           "%main_lab = OpLabel\n" +
3330           "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
3331           "OpReturn\n" +
3332           "OpFunctionEnd",
3333       2, false),
3334   // Test case 3: fold NaN != NaN (unord)
3335   InstructionFoldingCase<bool>(
3336       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3337           "%main_lab = OpLabel\n" +
3338           "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
3339           "OpReturn\n" +
3340           "OpFunctionEnd",
3341       2, true)
3342 ));
3343 
3344 INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3345                         ::testing::Values(
3346   // Test case 0: fold NaN == 0 (ord)
3347   InstructionFoldingCase<bool>(
3348       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3349           "%main_lab = OpLabel\n" +
3350           "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
3351           "OpReturn\n" +
3352           "OpFunctionEnd",
3353       2, false),
3354   // Test case 1: fold NaN == NaN (unord)
3355   InstructionFoldingCase<bool>(
3356       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3357           "%main_lab = OpLabel\n" +
3358           "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
3359           "OpReturn\n" +
3360           "OpFunctionEnd",
3361       2, true),
3362   // Test case 2: fold NaN != NaN (ord)
3363   InstructionFoldingCase<bool>(
3364       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3365           "%main_lab = OpLabel\n" +
3366           "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
3367           "OpReturn\n" +
3368           "OpFunctionEnd",
3369       2, false),
3370   // Test case 3: fold NaN != NaN (unord)
3371   InstructionFoldingCase<bool>(
3372       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3373           "%main_lab = OpLabel\n" +
3374           "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
3375           "OpReturn\n" +
3376           "OpFunctionEnd",
3377       2, true)
3378 ));
3379 // clang-format on
3380 
3381 template <class ResultType>
3382 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anon26957::InstructionFoldingCaseWithMap3383   InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
3384                                 ResultType result,
3385                                 std::function<uint32_t(uint32_t)> map)
3386       : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
3387 
3388   std::string test_body;
3389   uint32_t id_to_fold;
3390   ResultType expected_result;
3391   std::function<uint32_t(uint32_t)> id_map;
3392 };
3393 
3394 using IntegerInstructionFoldingTestWithMap =
3395     ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
3396 
TEST_P(IntegerInstructionFoldingTestWithMap, Case)3397 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
3398   const auto& tc = GetParam();
3399 
3400   // Build module.
3401   std::unique_ptr<IRContext> context =
3402       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3403                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3404   ASSERT_NE(nullptr, context);
3405 
3406   // Fold the instruction to test.
3407   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3408   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3409   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3410                                                                      tc.id_map);
3411 
3412   // Make sure the instruction folded as expected.
3413   EXPECT_NE(inst, nullptr);
3414   if (inst != nullptr) {
3415     EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
3416     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3417     const analysis::IntConstant* result =
3418         const_mrg->GetConstantFromInst(inst)->AsIntConstant();
3419     EXPECT_NE(result, nullptr);
3420     if (result != nullptr) {
3421       EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
3422     }
3423   }
3424 }
3425 // clang-format off
3426 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
3427   ::testing::Values(
3428       // Test case 0: fold %3 = 0; %3 * n
3429       InstructionFoldingCaseWithMap<uint32_t>(
3430           Header() + "%main = OpFunction %void None %void_func\n" +
3431               "%main_lab = OpLabel\n" +
3432               "%n = OpVariable %_ptr_int Function\n" +
3433               "%load = OpLoad %int %n\n" +
3434               "%3 = OpCopyObject %int %int_0\n"
3435               "%2 = OpIMul %int %3 %load\n" +
3436               "OpReturn\n" +
3437               "OpFunctionEnd",
3438           2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
3439   ));
3440 // clang-format on
3441 
3442 using BooleanInstructionFoldingTestWithMap =
3443     ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
3444 
TEST_P(BooleanInstructionFoldingTestWithMap, Case)3445 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
3446   const auto& tc = GetParam();
3447 
3448   // Build module.
3449   std::unique_ptr<IRContext> context =
3450       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3451                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3452   ASSERT_NE(nullptr, context);
3453 
3454   // Fold the instruction to test.
3455   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3456   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3457   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3458                                                                      tc.id_map);
3459 
3460   // Make sure the instruction folded as expected.
3461   EXPECT_NE(inst, nullptr);
3462   if (inst != nullptr) {
3463     std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
3464                                          spv::Op::OpConstantFalse};
3465     EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
3466     analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3467     const analysis::BoolConstant* result =
3468         const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
3469     EXPECT_NE(result, nullptr);
3470     if (result != nullptr) {
3471       EXPECT_EQ(result->value(), tc.expected_result);
3472     }
3473   }
3474 }
3475 
3476 // clang-format off
3477 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap,
3478   ::testing::Values(
3479       // Test case 0: fold %3 = true; %3 || n
3480       InstructionFoldingCaseWithMap<bool>(
3481           Header() + "%main = OpFunction %void None %void_func\n" +
3482               "%main_lab = OpLabel\n" +
3483               "%n = OpVariable %_ptr_bool Function\n" +
3484               "%load = OpLoad %bool %n\n" +
3485               "%3 = OpCopyObject %bool %true\n" +
3486               "%2 = OpLogicalOr %bool %3 %load\n" +
3487               "OpReturn\n" +
3488               "OpFunctionEnd",
3489           2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
3490   ));
3491 // clang-format on
3492 
3493 using GeneralInstructionFoldingTest =
3494     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
3495 
TEST_P(GeneralInstructionFoldingTest, Case)3496 TEST_P(GeneralInstructionFoldingTest, Case) {
3497   const auto& tc = GetParam();
3498 
3499   // Build module.
3500   std::unique_ptr<IRContext> context =
3501       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3502                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3503   ASSERT_NE(nullptr, context);
3504 
3505   // Fold the instruction to test.
3506   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3507   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3508   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
3509   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
3510 
3511   // Make sure the instruction folded as expected.
3512   EXPECT_EQ(inst->result_id(), original_inst->result_id());
3513   EXPECT_EQ(inst->type_id(), original_inst->type_id());
3514   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
3515   if (succeeded) {
3516     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
3517     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
3518   } else {
3519     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
3520     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
3521       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
3522     }
3523   }
3524 }
3525 
3526 // clang-format off
3527 INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
3528                         ::testing::Values(
3529     // Test case 0: Don't fold n * m
3530     InstructionFoldingCase<uint32_t>(
3531         Header() + "%main = OpFunction %void None %void_func\n" +
3532             "%main_lab = OpLabel\n" +
3533             "%n = OpVariable %_ptr_int Function\n" +
3534             "%m = OpVariable %_ptr_int Function\n" +
3535             "%load_n = OpLoad %int %n\n" +
3536             "%load_m = OpLoad %int %m\n" +
3537             "%2 = OpIMul %int %load_n %load_m\n" +
3538             "OpReturn\n" +
3539             "OpFunctionEnd",
3540         2, 0),
3541     // Test case 1: Don't fold n / m (unsigned)
3542     InstructionFoldingCase<uint32_t>(
3543         Header() + "%main = OpFunction %void None %void_func\n" +
3544             "%main_lab = OpLabel\n" +
3545             "%n = OpVariable %_ptr_uint Function\n" +
3546             "%m = OpVariable %_ptr_uint Function\n" +
3547             "%load_n = OpLoad %uint %n\n" +
3548             "%load_m = OpLoad %uint %m\n" +
3549             "%2 = OpUDiv %uint %load_n %load_m\n" +
3550             "OpReturn\n" +
3551             "OpFunctionEnd",
3552         2, 0),
3553     // Test case 2: Don't fold n / m (signed)
3554     InstructionFoldingCase<uint32_t>(
3555         Header() + "%main = OpFunction %void None %void_func\n" +
3556             "%main_lab = OpLabel\n" +
3557             "%n = OpVariable %_ptr_int Function\n" +
3558             "%m = OpVariable %_ptr_int Function\n" +
3559             "%load_n = OpLoad %int %n\n" +
3560             "%load_m = OpLoad %int %m\n" +
3561             "%2 = OpSDiv %int %load_n %load_m\n" +
3562             "OpReturn\n" +
3563             "OpFunctionEnd",
3564         2, 0),
3565     // Test case 3: Don't fold n remainder m
3566     InstructionFoldingCase<uint32_t>(
3567         Header() + "%main = OpFunction %void None %void_func\n" +
3568             "%main_lab = OpLabel\n" +
3569             "%n = OpVariable %_ptr_int Function\n" +
3570             "%m = OpVariable %_ptr_int Function\n" +
3571             "%load_n = OpLoad %int %n\n" +
3572             "%load_m = OpLoad %int %m\n" +
3573             "%2 = OpSRem %int %load_n %load_m\n" +
3574             "OpReturn\n" +
3575             "OpFunctionEnd",
3576         2, 0),
3577     // Test case 4: Don't fold n % m (signed)
3578     InstructionFoldingCase<uint32_t>(
3579         Header() + "%main = OpFunction %void None %void_func\n" +
3580             "%main_lab = OpLabel\n" +
3581             "%n = OpVariable %_ptr_int Function\n" +
3582             "%m = OpVariable %_ptr_int Function\n" +
3583             "%load_n = OpLoad %int %n\n" +
3584             "%load_m = OpLoad %int %m\n" +
3585             "%2 = OpSMod %int %load_n %load_m\n" +
3586             "OpReturn\n" +
3587             "OpFunctionEnd",
3588         2, 0),
3589     // Test case 5: Don't fold n % m (unsigned)
3590     InstructionFoldingCase<uint32_t>(
3591         Header() + "%main = OpFunction %void None %void_func\n" +
3592             "%main_lab = OpLabel\n" +
3593             "%n = OpVariable %_ptr_uint Function\n" +
3594             "%m = OpVariable %_ptr_uint Function\n" +
3595             "%load_n = OpLoad %uint %n\n" +
3596             "%load_m = OpLoad %uint %m\n" +
3597             "%2 = OpUMod %int %load_n %load_m\n" +
3598             "OpReturn\n" +
3599             "OpFunctionEnd",
3600         2, 0),
3601     // Test case 6: Don't fold n << m
3602     InstructionFoldingCase<uint32_t>(
3603         Header() + "%main = OpFunction %void None %void_func\n" +
3604             "%main_lab = OpLabel\n" +
3605             "%n = OpVariable %_ptr_uint Function\n" +
3606             "%m = OpVariable %_ptr_uint Function\n" +
3607             "%load_n = OpLoad %uint %n\n" +
3608             "%load_m = OpLoad %uint %m\n" +
3609             "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
3610             "OpReturn\n" +
3611             "OpFunctionEnd",
3612         2, 0),
3613     // Test case 7: Don't fold n >> m
3614     InstructionFoldingCase<uint32_t>(
3615         Header() + "%main = OpFunction %void None %void_func\n" +
3616             "%main_lab = OpLabel\n" +
3617             "%n = OpVariable %_ptr_uint Function\n" +
3618             "%m = OpVariable %_ptr_uint Function\n" +
3619             "%load_n = OpLoad %uint %n\n" +
3620             "%load_m = OpLoad %uint %m\n" +
3621             "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
3622             "OpReturn\n" +
3623             "OpFunctionEnd",
3624         2, 0),
3625     // Test case 8: Don't fold n | m
3626     InstructionFoldingCase<uint32_t>(
3627         Header() + "%main = OpFunction %void None %void_func\n" +
3628             "%main_lab = OpLabel\n" +
3629             "%n = OpVariable %_ptr_uint Function\n" +
3630             "%m = OpVariable %_ptr_uint Function\n" +
3631             "%load_n = OpLoad %uint %n\n" +
3632             "%load_m = OpLoad %uint %m\n" +
3633             "%2 = OpBitwiseOr %int %load_n %load_m\n" +
3634             "OpReturn\n" +
3635             "OpFunctionEnd",
3636         2, 0),
3637     // Test case 9: Don't fold n & m
3638     InstructionFoldingCase<uint32_t>(
3639         Header() + "%main = OpFunction %void None %void_func\n" +
3640             "%main_lab = OpLabel\n" +
3641             "%n = OpVariable %_ptr_uint Function\n" +
3642             "%m = OpVariable %_ptr_uint Function\n" +
3643             "%load_n = OpLoad %uint %n\n" +
3644             "%load_m = OpLoad %uint %m\n" +
3645             "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
3646             "OpReturn\n" +
3647             "OpFunctionEnd",
3648         2, 0),
3649     // Test case 10: Don't fold n < m (unsigned)
3650     InstructionFoldingCase<uint32_t>(
3651         Header() + "%main = OpFunction %void None %void_func\n" +
3652             "%main_lab = OpLabel\n" +
3653             "%n = OpVariable %_ptr_uint Function\n" +
3654             "%m = OpVariable %_ptr_uint Function\n" +
3655             "%load_n = OpLoad %uint %n\n" +
3656             "%load_m = OpLoad %uint %m\n" +
3657             "%2 = OpULessThan %bool %load_n %load_m\n" +
3658             "OpReturn\n" +
3659             "OpFunctionEnd",
3660         2, 0),
3661     // Test case 11: Don't fold n > m (unsigned)
3662     InstructionFoldingCase<uint32_t>(
3663         Header() + "%main = OpFunction %void None %void_func\n" +
3664             "%main_lab = OpLabel\n" +
3665             "%n = OpVariable %_ptr_uint Function\n" +
3666             "%m = OpVariable %_ptr_uint Function\n" +
3667             "%load_n = OpLoad %uint %n\n" +
3668             "%load_m = OpLoad %uint %m\n" +
3669             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3670             "OpReturn\n" +
3671             "OpFunctionEnd",
3672         2, 0),
3673     // Test case 12: Don't fold n <= m (unsigned)
3674     InstructionFoldingCase<uint32_t>(
3675         Header() + "%main = OpFunction %void None %void_func\n" +
3676             "%main_lab = OpLabel\n" +
3677             "%n = OpVariable %_ptr_uint Function\n" +
3678             "%m = OpVariable %_ptr_uint Function\n" +
3679             "%load_n = OpLoad %uint %n\n" +
3680             "%load_m = OpLoad %uint %m\n" +
3681             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3682             "OpReturn\n" +
3683             "OpFunctionEnd",
3684         2, 0),
3685     // Test case 13: Don't fold n >= m (unsigned)
3686     InstructionFoldingCase<uint32_t>(
3687         Header() + "%main = OpFunction %void None %void_func\n" +
3688             "%main_lab = OpLabel\n" +
3689             "%n = OpVariable %_ptr_uint Function\n" +
3690             "%m = OpVariable %_ptr_uint Function\n" +
3691             "%load_n = OpLoad %uint %n\n" +
3692             "%load_m = OpLoad %uint %m\n" +
3693             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3694             "OpReturn\n" +
3695             "OpFunctionEnd",
3696         2, 0),
3697     // Test case 14: Don't fold n < m (signed)
3698     InstructionFoldingCase<uint32_t>(
3699         Header() + "%main = OpFunction %void None %void_func\n" +
3700             "%main_lab = OpLabel\n" +
3701             "%n = OpVariable %_ptr_int Function\n" +
3702             "%m = OpVariable %_ptr_int Function\n" +
3703             "%load_n = OpLoad %int %n\n" +
3704             "%load_m = OpLoad %int %m\n" +
3705             "%2 = OpULessThan %bool %load_n %load_m\n" +
3706             "OpReturn\n" +
3707             "OpFunctionEnd",
3708         2, 0),
3709     // Test case 15: Don't fold n > m (signed)
3710     InstructionFoldingCase<uint32_t>(
3711         Header() + "%main = OpFunction %void None %void_func\n" +
3712             "%main_lab = OpLabel\n" +
3713             "%n = OpVariable %_ptr_int Function\n" +
3714             "%m = OpVariable %_ptr_int Function\n" +
3715             "%load_n = OpLoad %int %n\n" +
3716             "%load_m = OpLoad %int %m\n" +
3717             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3718             "OpReturn\n" +
3719             "OpFunctionEnd",
3720         2, 0),
3721     // Test case 16: Don't fold n <= m (signed)
3722     InstructionFoldingCase<uint32_t>(
3723         Header() + "%main = OpFunction %void None %void_func\n" +
3724             "%main_lab = OpLabel\n" +
3725             "%n = OpVariable %_ptr_int Function\n" +
3726             "%m = OpVariable %_ptr_int Function\n" +
3727             "%load_n = OpLoad %int %n\n" +
3728             "%load_m = OpLoad %int %m\n" +
3729             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3730             "OpReturn\n" +
3731             "OpFunctionEnd",
3732         2, 0),
3733     // Test case 17: Don't fold n >= m (signed)
3734     InstructionFoldingCase<uint32_t>(
3735         Header() + "%main = OpFunction %void None %void_func\n" +
3736             "%main_lab = OpLabel\n" +
3737             "%n = OpVariable %_ptr_int Function\n" +
3738             "%m = OpVariable %_ptr_int Function\n" +
3739             "%load_n = OpLoad %int %n\n" +
3740             "%load_m = OpLoad %int %m\n" +
3741             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3742             "OpReturn\n" +
3743             "OpFunctionEnd",
3744         2, 0),
3745     // Test case 18: Don't fold n || m
3746     InstructionFoldingCase<uint32_t>(
3747         Header() + "%main = OpFunction %void None %void_func\n" +
3748             "%main_lab = OpLabel\n" +
3749             "%n = OpVariable %_ptr_bool Function\n" +
3750             "%m = OpVariable %_ptr_bool Function\n" +
3751             "%load_n = OpLoad %bool %n\n" +
3752             "%load_m = OpLoad %bool %m\n" +
3753             "%2 = OpLogicalOr %bool %load_n %load_m\n" +
3754             "OpReturn\n" +
3755             "OpFunctionEnd",
3756         2, 0),
3757     // Test case 19: Don't fold n && m
3758     InstructionFoldingCase<uint32_t>(
3759         Header() + "%main = OpFunction %void None %void_func\n" +
3760             "%main_lab = OpLabel\n" +
3761             "%n = OpVariable %_ptr_bool Function\n" +
3762             "%m = OpVariable %_ptr_bool Function\n" +
3763             "%load_n = OpLoad %bool %n\n" +
3764             "%load_m = OpLoad %bool %m\n" +
3765             "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
3766             "OpReturn\n" +
3767             "OpFunctionEnd",
3768         2, 0),
3769     // Test case 20: Don't fold n * 3
3770     InstructionFoldingCase<uint32_t>(
3771         Header() + "%main = OpFunction %void None %void_func\n" +
3772             "%main_lab = OpLabel\n" +
3773             "%n = OpVariable %_ptr_int Function\n" +
3774             "%load_n = OpLoad %int %n\n" +
3775             "%2 = OpIMul %int %load_n %int_3\n" +
3776             "OpReturn\n" +
3777             "OpFunctionEnd",
3778         2, 0),
3779     // Test case 21: Don't fold n / 3 (unsigned)
3780     InstructionFoldingCase<uint32_t>(
3781         Header() + "%main = OpFunction %void None %void_func\n" +
3782             "%main_lab = OpLabel\n" +
3783             "%n = OpVariable %_ptr_uint Function\n" +
3784             "%load_n = OpLoad %uint %n\n" +
3785             "%2 = OpUDiv %uint %load_n %uint_3\n" +
3786             "OpReturn\n" +
3787             "OpFunctionEnd",
3788         2, 0),
3789     // Test case 22: Don't fold n / 3 (signed)
3790     InstructionFoldingCase<uint32_t>(
3791         Header() + "%main = OpFunction %void None %void_func\n" +
3792             "%main_lab = OpLabel\n" +
3793             "%n = OpVariable %_ptr_int Function\n" +
3794             "%load_n = OpLoad %int %n\n" +
3795             "%2 = OpSDiv %int %load_n %int_3\n" +
3796             "OpReturn\n" +
3797             "OpFunctionEnd",
3798         2, 0),
3799     // Test case 23: Don't fold n remainder 3
3800     InstructionFoldingCase<uint32_t>(
3801         Header() + "%main = OpFunction %void None %void_func\n" +
3802             "%main_lab = OpLabel\n" +
3803             "%n = OpVariable %_ptr_int Function\n" +
3804             "%load_n = OpLoad %int %n\n" +
3805             "%2 = OpSRem %int %load_n %int_3\n" +
3806             "OpReturn\n" +
3807             "OpFunctionEnd",
3808         2, 0),
3809     // Test case 24: Don't fold n % 3 (signed)
3810     InstructionFoldingCase<uint32_t>(
3811         Header() + "%main = OpFunction %void None %void_func\n" +
3812             "%main_lab = OpLabel\n" +
3813             "%n = OpVariable %_ptr_int Function\n" +
3814             "%load_n = OpLoad %int %n\n" +
3815             "%2 = OpSMod %int %load_n %int_3\n" +
3816             "OpReturn\n" +
3817             "OpFunctionEnd",
3818         2, 0),
3819     // Test case 25: Don't fold n % 3 (unsigned)
3820     InstructionFoldingCase<uint32_t>(
3821         Header() + "%main = OpFunction %void None %void_func\n" +
3822             "%main_lab = OpLabel\n" +
3823             "%n = OpVariable %_ptr_uint Function\n" +
3824             "%load_n = OpLoad %uint %n\n" +
3825             "%2 = OpUMod %int %load_n %int_3\n" +
3826             "OpReturn\n" +
3827             "OpFunctionEnd",
3828         2, 0),
3829     // Test case 26: Don't fold n << 3
3830     InstructionFoldingCase<uint32_t>(
3831         Header() + "%main = OpFunction %void None %void_func\n" +
3832             "%main_lab = OpLabel\n" +
3833             "%n = OpVariable %_ptr_uint Function\n" +
3834             "%load_n = OpLoad %uint %n\n" +
3835             "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
3836             "OpReturn\n" +
3837             "OpFunctionEnd",
3838         2, 0),
3839     // Test case 27: Don't fold n >> 3
3840     InstructionFoldingCase<uint32_t>(
3841         Header() + "%main = OpFunction %void None %void_func\n" +
3842             "%main_lab = OpLabel\n" +
3843             "%n = OpVariable %_ptr_uint Function\n" +
3844             "%load_n = OpLoad %uint %n\n" +
3845             "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
3846             "OpReturn\n" +
3847             "OpFunctionEnd",
3848         2, 0),
3849     // Test case 28: Don't fold n | 3
3850     InstructionFoldingCase<uint32_t>(
3851         Header() + "%main = OpFunction %void None %void_func\n" +
3852             "%main_lab = OpLabel\n" +
3853             "%n = OpVariable %_ptr_uint Function\n" +
3854             "%load_n = OpLoad %uint %n\n" +
3855             "%2 = OpBitwiseOr %int %load_n %int_3\n" +
3856             "OpReturn\n" +
3857             "OpFunctionEnd",
3858         2, 0),
3859     // Test case 29: Don't fold n & 3
3860     InstructionFoldingCase<uint32_t>(
3861         Header() + "%main = OpFunction %void None %void_func\n" +
3862             "%main_lab = OpLabel\n" +
3863             "%n = OpVariable %_ptr_uint Function\n" +
3864             "%load_n = OpLoad %uint %n\n" +
3865             "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
3866             "OpReturn\n" +
3867             "OpFunctionEnd",
3868         2, 0),
3869     // Test case 30: Don't fold n < 3 (unsigned)
3870     InstructionFoldingCase<uint32_t>(
3871         Header() + "%main = OpFunction %void None %void_func\n" +
3872             "%main_lab = OpLabel\n" +
3873             "%n = OpVariable %_ptr_uint Function\n" +
3874             "%load_n = OpLoad %uint %n\n" +
3875             "%2 = OpULessThan %bool %load_n %uint_3\n" +
3876             "OpReturn\n" +
3877             "OpFunctionEnd",
3878         2, 0),
3879     // Test case 31: Don't fold n > 3 (unsigned)
3880     InstructionFoldingCase<uint32_t>(
3881         Header() + "%main = OpFunction %void None %void_func\n" +
3882             "%main_lab = OpLabel\n" +
3883             "%n = OpVariable %_ptr_uint Function\n" +
3884             "%load_n = OpLoad %uint %n\n" +
3885             "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
3886             "OpReturn\n" +
3887             "OpFunctionEnd",
3888         2, 0),
3889     // Test case 32: Don't fold n <= 3 (unsigned)
3890     InstructionFoldingCase<uint32_t>(
3891         Header() + "%main = OpFunction %void None %void_func\n" +
3892             "%main_lab = OpLabel\n" +
3893             "%n = OpVariable %_ptr_uint Function\n" +
3894             "%load_n = OpLoad %uint %n\n" +
3895             "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
3896             "OpReturn\n" +
3897             "OpFunctionEnd",
3898         2, 0),
3899     // Test case 33: Don't fold n >= 3 (unsigned)
3900     InstructionFoldingCase<uint32_t>(
3901         Header() + "%main = OpFunction %void None %void_func\n" +
3902             "%main_lab = OpLabel\n" +
3903             "%n = OpVariable %_ptr_uint Function\n" +
3904             "%load_n = OpLoad %uint %n\n" +
3905             "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
3906             "OpReturn\n" +
3907             "OpFunctionEnd",
3908         2, 0),
3909     // Test case 34: Don't fold n < 3 (signed)
3910     InstructionFoldingCase<uint32_t>(
3911         Header() + "%main = OpFunction %void None %void_func\n" +
3912             "%main_lab = OpLabel\n" +
3913             "%n = OpVariable %_ptr_int Function\n" +
3914             "%load_n = OpLoad %int %n\n" +
3915             "%2 = OpULessThan %bool %load_n %int_3\n" +
3916             "OpReturn\n" +
3917             "OpFunctionEnd",
3918         2, 0),
3919     // Test case 35: Don't fold n > 3 (signed)
3920     InstructionFoldingCase<uint32_t>(
3921         Header() + "%main = OpFunction %void None %void_func\n" +
3922             "%main_lab = OpLabel\n" +
3923             "%n = OpVariable %_ptr_int Function\n" +
3924             "%load_n = OpLoad %int %n\n" +
3925             "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
3926             "OpReturn\n" +
3927             "OpFunctionEnd",
3928         2, 0),
3929     // Test case 36: Don't fold n <= 3 (signed)
3930     InstructionFoldingCase<uint32_t>(
3931         Header() + "%main = OpFunction %void None %void_func\n" +
3932             "%main_lab = OpLabel\n" +
3933             "%n = OpVariable %_ptr_int Function\n" +
3934             "%load_n = OpLoad %int %n\n" +
3935             "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
3936             "OpReturn\n" +
3937             "OpFunctionEnd",
3938         2, 0),
3939     // Test case 37: Don't fold n >= 3 (signed)
3940     InstructionFoldingCase<uint32_t>(
3941         Header() + "%main = OpFunction %void None %void_func\n" +
3942             "%main_lab = OpLabel\n" +
3943             "%n = OpVariable %_ptr_int Function\n" +
3944             "%load_n = OpLoad %int %n\n" +
3945             "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
3946             "OpReturn\n" +
3947             "OpFunctionEnd",
3948         2, 0),
3949     // Test case 38: Don't fold 2 + 3 (long), bad length
3950     InstructionFoldingCase<uint32_t>(
3951         Header() + "%main = OpFunction %void None %void_func\n" +
3952             "%main_lab = OpLabel\n" +
3953             "%2 = OpIAdd %long %long_2 %long_3\n" +
3954             "OpReturn\n" +
3955             "OpFunctionEnd",
3956         2, 0),
3957     // Test case 39: Don't fold 2 + 3 (short), bad length
3958     InstructionFoldingCase<uint32_t>(
3959         Header() + "%main = OpFunction %void None %void_func\n" +
3960             "%main_lab = OpLabel\n" +
3961             "%2 = OpIAdd %short %short_2 %short_3\n" +
3962             "OpReturn\n" +
3963             "OpFunctionEnd",
3964         2, 0),
3965     // Test case 40: fold 1*n
3966     InstructionFoldingCase<uint32_t>(
3967         Header() + "%main = OpFunction %void None %void_func\n" +
3968             "%main_lab = OpLabel\n" +
3969             "%n = OpVariable %_ptr_int Function\n" +
3970             "%3 = OpLoad %int %n\n" +
3971             "%2 = OpIMul %int %int_1 %3\n" +
3972             "OpReturn\n" +
3973             "OpFunctionEnd",
3974         2, 3),
3975     // Test case 41: fold n*1
3976     InstructionFoldingCase<uint32_t>(
3977         Header() + "%main = OpFunction %void None %void_func\n" +
3978             "%main_lab = OpLabel\n" +
3979             "%n = OpVariable %_ptr_int Function\n" +
3980             "%3 = OpLoad %int %n\n" +
3981             "%2 = OpIMul %int %3 %int_1\n" +
3982             "OpReturn\n" +
3983             "OpFunctionEnd",
3984         2, 3),
3985     // Test case 42: Don't fold comparisons of 64-bit types
3986     // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
3987     InstructionFoldingCase<uint32_t>(
3988         Header() + "%main = OpFunction %void None %void_func\n" +
3989           "%main_lab = OpLabel\n" +
3990           "%2 = OpSLessThan %bool %long_0 %long_2\n" +
3991           "OpReturn\n" +
3992           "OpFunctionEnd",
3993         2, 0)
3994 ));
3995 
3996 INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
3997 ::testing::Values(
3998     // Test case 0: fold Insert feeding extract
3999     InstructionFoldingCase<uint32_t>(
4000         Header() + "%main = OpFunction %void None %void_func\n" +
4001             "%main_lab = OpLabel\n" +
4002             "%n = OpVariable %_ptr_int Function\n" +
4003             "%2 = OpLoad %int %n\n" +
4004             "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
4005             "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
4006             "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
4007             "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
4008             "%7 = OpCompositeExtract %int %6 0\n" +
4009             "OpReturn\n" +
4010             "OpFunctionEnd",
4011         7, 2),
4012     // Test case 1: fold Composite construct feeding extract (position 0)
4013     InstructionFoldingCase<uint32_t>(
4014         Header() + "%main = OpFunction %void None %void_func\n" +
4015             "%main_lab = OpLabel\n" +
4016             "%n = OpVariable %_ptr_int Function\n" +
4017             "%2 = OpLoad %int %n\n" +
4018             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
4019             "%4 = OpCompositeExtract %int %3 0\n" +
4020             "OpReturn\n" +
4021             "OpFunctionEnd",
4022         4, 2),
4023     // Test case 2: fold Composite construct feeding extract (position 3)
4024     InstructionFoldingCase<uint32_t>(
4025         Header() + "%main = OpFunction %void None %void_func\n" +
4026             "%main_lab = OpLabel\n" +
4027             "%n = OpVariable %_ptr_int Function\n" +
4028             "%2 = OpLoad %int %n\n" +
4029             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
4030             "%4 = OpCompositeExtract %int %3 3\n" +
4031             "OpReturn\n" +
4032             "OpFunctionEnd",
4033         4, INT_0_ID),
4034     // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
4035     InstructionFoldingCase<uint32_t>(
4036         Header() + "%main = OpFunction %void None %void_func\n" +
4037             "%main_lab = OpLabel\n" +
4038             "%n = OpVariable %_ptr_int Function\n" +
4039             "%2 = OpLoad %int %n\n" +
4040             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4041             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4042             "%5 = OpCompositeExtract %int %4 3\n" +
4043             "OpReturn\n" +
4044             "OpFunctionEnd",
4045         5, INT_0_ID),
4046     // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
4047     InstructionFoldingCase<uint32_t>(
4048         Header() + "%main = OpFunction %void None %void_func\n" +
4049             "%main_lab = OpLabel\n" +
4050             "%n = OpVariable %_ptr_int Function\n" +
4051             "%2 = OpLoad %int %n\n" +
4052             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4053             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4054             "%5 = OpCompositeExtract %int %4 0\n" +
4055             "OpReturn\n" +
4056             "OpFunctionEnd",
4057         5, 2),
4058     // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
4059     InstructionFoldingCase<uint32_t>(
4060         Header() + "%main = OpFunction %void None %void_func\n" +
4061             "%main_lab = OpLabel\n" +
4062             "%n = OpVariable %_ptr_int Function\n" +
4063             "%2 = OpLoad %int %n\n" +
4064             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4065             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4066             "%5 = OpCompositeExtract %int %4 1\n" +
4067             "OpReturn\n" +
4068             "OpFunctionEnd",
4069         5, 2),
4070     // Test case 6: fold Composite construct with multiple indices.
4071     InstructionFoldingCase<uint32_t>(
4072         Header() + "%main = OpFunction %void None %void_func\n" +
4073             "%main_lab = OpLabel\n" +
4074             "%n = OpVariable %_ptr_int Function\n" +
4075             "%2 = OpLoad %int %n\n" +
4076             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4077             "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
4078             "%5 = OpCompositeExtract %int %4 0 1\n" +
4079             "OpReturn\n" +
4080             "OpFunctionEnd",
4081         5, 2),
4082     // Test case 7: fold constant extract.
4083     InstructionFoldingCase<uint32_t>(
4084         Header() + "%main = OpFunction %void None %void_func\n" +
4085             "%main_lab = OpLabel\n" +
4086             "%2 = OpCompositeExtract %int %102 1\n" +
4087             "OpReturn\n" +
4088             "OpFunctionEnd",
4089         2, INT_7_ID),
4090     // Test case 8: constant struct has OpUndef
4091     InstructionFoldingCase<uint32_t>(
4092         Header() + "%main = OpFunction %void None %void_func\n" +
4093             "%main_lab = OpLabel\n" +
4094             "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
4095             "OpReturn\n" +
4096             "OpFunctionEnd",
4097         2, 0),
4098     // Test case 9: Extracting a member of element inserted via Insert
4099     InstructionFoldingCase<uint32_t>(
4100         Header() + "%main = OpFunction %void None %void_func\n" +
4101             "%main_lab = OpLabel\n" +
4102             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4103             "%2 = OpLoad %struct_v2int_int_int %n\n" +
4104             "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
4105             "%4 = OpCompositeExtract %int %3 0 1\n" +
4106             "OpReturn\n" +
4107             "OpFunctionEnd",
4108         4, 103),
4109     // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
4110     InstructionFoldingCase<uint32_t>(
4111         Header() + "%main = OpFunction %void None %void_func\n" +
4112             "%main_lab = OpLabel\n" +
4113             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4114             "%2 = OpLoad %struct_v2int_int_int %n\n" +
4115             "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
4116             "%4 = OpCompositeExtract %v2int %3 0\n" +
4117             "OpReturn\n" +
4118             "OpFunctionEnd",
4119         4, 0),
4120     // Test case 11: Extracting from result of vector shuffle (first input)
4121     InstructionFoldingCase<uint32_t>(
4122         Header() + "%main = OpFunction %void None %void_func\n" +
4123             "%main_lab = OpLabel\n" +
4124             "%n = OpVariable %_ptr_v2int Function\n" +
4125             "%2 = OpLoad %v2int %n\n" +
4126             "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
4127             "%4 = OpCompositeExtract %int %3 1\n" +
4128             "OpReturn\n" +
4129             "OpFunctionEnd",
4130         4, INT_7_ID),
4131     // Test case 12: Extracting from result of vector shuffle (second input)
4132     InstructionFoldingCase<uint32_t>(
4133         Header() + "%main = OpFunction %void None %void_func\n" +
4134             "%main_lab = OpLabel\n" +
4135             "%n = OpVariable %_ptr_v2int Function\n" +
4136             "%2 = OpLoad %v2int %n\n" +
4137             "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
4138             "%4 = OpCompositeExtract %int %3 0\n" +
4139             "OpReturn\n" +
4140             "OpFunctionEnd",
4141         4, INT_7_ID),
4142     // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608
4143     // Out of bounds access.  Do not fold.
4144     InstructionFoldingCase<uint32_t>(
4145         Header() + "%main = OpFunction %void None %void_func\n" +
4146             "%main_lab = OpLabel\n" +
4147             "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" +
4148             "%3 = OpCompositeExtract %float %2 4\n" +
4149             "OpReturn\n" +
4150             "OpFunctionEnd",
4151         3, 0),
4152     // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631
4153     // Extract the component right after the vector constituent.
4154     InstructionFoldingCase<uint32_t>(
4155         Header() + "%main = OpFunction %void None %void_func\n" +
4156             "%main_lab = OpLabel\n" +
4157             "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4158             "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4159             "%4 = OpCompositeExtract %int %3 2\n" +
4160             "OpReturn\n" +
4161             "OpFunctionEnd",
4162         4, INT_0_ID),
4163     // Test case 15:
4164     // Don't fold extract fed by construct with vector result if the index is
4165     // past the last element.
4166     InstructionFoldingCase<uint32_t>(
4167         Header() + "%main = OpFunction %void None %void_func\n" +
4168             "%main_lab = OpLabel\n" +
4169             "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4170             "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4171             "%4 = OpCompositeExtract %int %3 4\n" +
4172             "OpReturn\n" +
4173             "OpFunctionEnd",
4174         4, 0)
4175 ));
4176 
4177 INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
4178 ::testing::Values(
4179     // Test case 0: fold Extracts feeding construct
4180     InstructionFoldingCase<uint32_t>(
4181         Header() + "%main = OpFunction %void None %void_func\n" +
4182             "%main_lab = OpLabel\n" +
4183             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4184             "%3 = OpCompositeExtract %int %2 0\n" +
4185             "%4 = OpCompositeExtract %int %2 1\n" +
4186             "%5 = OpCompositeExtract %int %2 2\n" +
4187             "%6 = OpCompositeExtract %int %2 3\n" +
4188             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4189             "OpReturn\n" +
4190             "OpFunctionEnd",
4191         7, 2),
4192     // Test case 1: Don't fold Extracts feeding construct (Different source)
4193     InstructionFoldingCase<uint32_t>(
4194         Header() + "%main = OpFunction %void None %void_func\n" +
4195             "%main_lab = OpLabel\n" +
4196             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4197             "%3 = OpCompositeExtract %int %2 0\n" +
4198             "%4 = OpCompositeExtract %int %2 1\n" +
4199             "%5 = OpCompositeExtract %int %2 2\n" +
4200             "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
4201             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4202             "OpReturn\n" +
4203             "OpFunctionEnd",
4204         7, 0),
4205     // Test case 2: Don't fold Extracts feeding construct (bad indices)
4206     InstructionFoldingCase<uint32_t>(
4207         Header() + "%main = OpFunction %void None %void_func\n" +
4208             "%main_lab = OpLabel\n" +
4209             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4210             "%3 = OpCompositeExtract %int %2 0\n" +
4211             "%4 = OpCompositeExtract %int %2 0\n" +
4212             "%5 = OpCompositeExtract %int %2 2\n" +
4213             "%6 = OpCompositeExtract %int %2 3\n" +
4214             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4215             "OpReturn\n" +
4216             "OpFunctionEnd",
4217         7, 0),
4218     // Test case 3: Don't fold Extracts feeding construct (different type)
4219     InstructionFoldingCase<uint32_t>(
4220         Header() + "%main = OpFunction %void None %void_func\n" +
4221             "%main_lab = OpLabel\n" +
4222             "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
4223             "%3 = OpCompositeExtract %v2int %2 0\n" +
4224             "%4 = OpCompositeExtract %int %2 1\n" +
4225             "%5 = OpCompositeExtract %int %2 2\n" +
4226             "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
4227             "OpReturn\n" +
4228             "OpFunctionEnd",
4229         7, 0),
4230     // Test case 4: Fold construct with constants to constant.
4231     InstructionFoldingCase<uint32_t>(
4232         Header() + "%main = OpFunction %void None %void_func\n" +
4233             "%main_lab = OpLabel\n" +
4234             "%2 = OpCompositeConstruct %v2int %103 %103\n" +
4235             "OpReturn\n" +
4236             "OpFunctionEnd",
4237         2, VEC2_0_ID),
4238     // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct
4239     // for an empty struct, and we reached the id limit.
4240     InstructionFoldingCase<uint32_t>(
4241         Header() + "%empty_struct = OpTypeStruct\n" +
4242             "%main = OpFunction %void None %void_func\n" +
4243             "%main_lab = OpLabel\n" +
4244             "%4194303 = OpCompositeConstruct %empty_struct\n" +
4245             "OpReturn\n" +
4246             "OpFunctionEnd",
4247         4194303, 0)
4248 ));
4249 
4250 INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
4251 ::testing::Values(
4252   // Test case 0: Fold phi with the same values for all edges.
4253   InstructionFoldingCase<uint32_t>(
4254       Header() + "%main = OpFunction %void None %void_func\n" +
4255           "%main_lab = OpLabel\n" +
4256           "            OpBranchConditional %true %l1 %l2\n" +
4257           "%l1 = OpLabel\n" +
4258           "      OpBranch %merge_lab\n" +
4259           "%l2 = OpLabel\n" +
4260           "      OpBranch %merge_lab\n" +
4261           "%merge_lab = OpLabel\n" +
4262           "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
4263           "OpReturn\n" +
4264           "OpFunctionEnd",
4265       2, INT_0_ID),
4266   // Test case 1: Fold phi in pass through loop.
4267   InstructionFoldingCase<uint32_t>(
4268       Header() + "%main = OpFunction %void None %void_func\n" +
4269           "%main_lab = OpLabel\n" +
4270           "            OpBranch %l1\n" +
4271           "%l1 = OpLabel\n" +
4272           "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
4273           "      OpBranchConditional %true %l1 %merge_lab\n" +
4274           "%merge_lab = OpLabel\n" +
4275           "OpReturn\n" +
4276           "OpFunctionEnd",
4277       2, INT_0_ID),
4278   // Test case 2: Don't Fold phi because of different values.
4279   InstructionFoldingCase<uint32_t>(
4280       Header() + "%main = OpFunction %void None %void_func\n" +
4281           "%main_lab = OpLabel\n" +
4282           "            OpBranch %l1\n" +
4283           "%l1 = OpLabel\n" +
4284           "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
4285           "      OpBranchConditional %true %l1 %merge_lab\n" +
4286           "%merge_lab = OpLabel\n" +
4287           "OpReturn\n" +
4288           "OpFunctionEnd",
4289       2, 0)
4290 ));
4291 
4292 INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
4293                         ::testing::Values(
4294     // Test case 0: Don't fold n + 1.0
4295     InstructionFoldingCase<uint32_t>(
4296         Header() + "%main = OpFunction %void None %void_func\n" +
4297             "%main_lab = OpLabel\n" +
4298             "%n = OpVariable %_ptr_float Function\n" +
4299             "%3 = OpLoad %float %n\n" +
4300             "%2 = OpFAdd %float %3 %float_2\n" +
4301             "OpReturn\n" +
4302             "OpFunctionEnd",
4303         2, 0),
4304     // Test case 1: Don't fold n - 1.0
4305     InstructionFoldingCase<uint32_t>(
4306         Header() + "%main = OpFunction %void None %void_func\n" +
4307             "%main_lab = OpLabel\n" +
4308             "%n = OpVariable %_ptr_float Function\n" +
4309             "%3 = OpLoad %float %n\n" +
4310             "%2 = OpFSub %float %3 %float_2\n" +
4311             "OpReturn\n" +
4312             "OpFunctionEnd",
4313         2, 0),
4314     // Test case 2: Don't fold n * 2.0
4315     InstructionFoldingCase<uint32_t>(
4316         Header() + "%main = OpFunction %void None %void_func\n" +
4317             "%main_lab = OpLabel\n" +
4318             "%n = OpVariable %_ptr_float Function\n" +
4319             "%3 = OpLoad %float %n\n" +
4320             "%2 = OpFMul %float %3 %float_2\n" +
4321             "OpReturn\n" +
4322             "OpFunctionEnd",
4323         2, 0),
4324     // Test case 3: Fold n + 0.0
4325     InstructionFoldingCase<uint32_t>(
4326         Header() + "%main = OpFunction %void None %void_func\n" +
4327             "%main_lab = OpLabel\n" +
4328             "%n = OpVariable %_ptr_float Function\n" +
4329             "%3 = OpLoad %float %n\n" +
4330             "%2 = OpFAdd %float %3 %float_0\n" +
4331             "OpReturn\n" +
4332             "OpFunctionEnd",
4333         2, 3),
4334     // Test case 4: Fold 0.0 + n
4335     InstructionFoldingCase<uint32_t>(
4336         Header() + "%main = OpFunction %void None %void_func\n" +
4337             "%main_lab = OpLabel\n" +
4338             "%n = OpVariable %_ptr_float Function\n" +
4339             "%3 = OpLoad %float %n\n" +
4340             "%2 = OpFAdd %float %float_0 %3\n" +
4341             "OpReturn\n" +
4342             "OpFunctionEnd",
4343         2, 3),
4344     // Test case 5: Fold n - 0.0
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             "%3 = OpLoad %float %n\n" +
4350             "%2 = OpFSub %float %3 %float_0\n" +
4351             "OpReturn\n" +
4352             "OpFunctionEnd",
4353         2, 3),
4354     // Test case 6: Fold n * 1.0
4355     InstructionFoldingCase<uint32_t>(
4356         Header() + "%main = OpFunction %void None %void_func\n" +
4357             "%main_lab = OpLabel\n" +
4358             "%n = OpVariable %_ptr_float Function\n" +
4359             "%3 = OpLoad %float %n\n" +
4360             "%2 = OpFMul %float %3 %float_1\n" +
4361             "OpReturn\n" +
4362             "OpFunctionEnd",
4363         2, 3),
4364     // Test case 7: Fold 1.0 * n
4365     InstructionFoldingCase<uint32_t>(
4366         Header() + "%main = OpFunction %void None %void_func\n" +
4367             "%main_lab = OpLabel\n" +
4368             "%n = OpVariable %_ptr_float Function\n" +
4369             "%3 = OpLoad %float %n\n" +
4370             "%2 = OpFMul %float %float_1 %3\n" +
4371             "OpReturn\n" +
4372             "OpFunctionEnd",
4373         2, 3),
4374     // Test case 8: Fold n / 1.0
4375     InstructionFoldingCase<uint32_t>(
4376         Header() + "%main = OpFunction %void None %void_func\n" +
4377             "%main_lab = OpLabel\n" +
4378             "%n = OpVariable %_ptr_float Function\n" +
4379             "%3 = OpLoad %float %n\n" +
4380             "%2 = OpFDiv %float %3 %float_1\n" +
4381             "OpReturn\n" +
4382             "OpFunctionEnd",
4383         2, 3),
4384     // Test case 9: Fold n * 0.0
4385     InstructionFoldingCase<uint32_t>(
4386         Header() + "%main = OpFunction %void None %void_func\n" +
4387             "%main_lab = OpLabel\n" +
4388             "%n = OpVariable %_ptr_float Function\n" +
4389             "%3 = OpLoad %float %n\n" +
4390             "%2 = OpFMul %float %3 %104\n" +
4391             "OpReturn\n" +
4392             "OpFunctionEnd",
4393         2, FLOAT_0_ID),
4394     // Test case 10: Fold 0.0 * n
4395     InstructionFoldingCase<uint32_t>(
4396         Header() + "%main = OpFunction %void None %void_func\n" +
4397             "%main_lab = OpLabel\n" +
4398             "%n = OpVariable %_ptr_float Function\n" +
4399             "%3 = OpLoad %float %n\n" +
4400             "%2 = OpFMul %float %104 %3\n" +
4401             "OpReturn\n" +
4402             "OpFunctionEnd",
4403         2, FLOAT_0_ID),
4404     // Test case 11: Fold 0.0 / n
4405     InstructionFoldingCase<uint32_t>(
4406         Header() + "%main = OpFunction %void None %void_func\n" +
4407             "%main_lab = OpLabel\n" +
4408             "%n = OpVariable %_ptr_float Function\n" +
4409             "%3 = OpLoad %float %n\n" +
4410             "%2 = OpFDiv %float %104 %3\n" +
4411             "OpReturn\n" +
4412             "OpFunctionEnd",
4413         2, FLOAT_0_ID),
4414     // Test case 12: Don't fold mix(a, b, 2.0)
4415     InstructionFoldingCase<uint32_t>(
4416         Header() + "%main = OpFunction %void None %void_func\n" +
4417             "%main_lab = OpLabel\n" +
4418             "%a = OpVariable %_ptr_float Function\n" +
4419             "%b = OpVariable %_ptr_float Function\n" +
4420             "%3 = OpLoad %float %a\n" +
4421             "%4 = OpLoad %float %b\n" +
4422             "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
4423             "OpReturn\n" +
4424             "OpFunctionEnd",
4425         2, 0),
4426     // Test case 13: Fold mix(a, b, 0.0)
4427     InstructionFoldingCase<uint32_t>(
4428         Header() + "%main = OpFunction %void None %void_func\n" +
4429             "%main_lab = OpLabel\n" +
4430             "%a = OpVariable %_ptr_float Function\n" +
4431             "%b = OpVariable %_ptr_float Function\n" +
4432             "%3 = OpLoad %float %a\n" +
4433             "%4 = OpLoad %float %b\n" +
4434             "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
4435             "OpReturn\n" +
4436             "OpFunctionEnd",
4437         2, 3),
4438     // Test case 14: Fold mix(a, b, 1.0)
4439     InstructionFoldingCase<uint32_t>(
4440         Header() + "%main = OpFunction %void None %void_func\n" +
4441             "%main_lab = OpLabel\n" +
4442             "%a = OpVariable %_ptr_float Function\n" +
4443             "%b = OpVariable %_ptr_float Function\n" +
4444             "%3 = OpLoad %float %a\n" +
4445             "%4 = OpLoad %float %b\n" +
4446             "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
4447             "OpReturn\n" +
4448             "OpFunctionEnd",
4449         2, 4),
4450     // Test case 15: Fold vector fadd with null
4451     InstructionFoldingCase<uint32_t>(
4452         Header() + "%main = OpFunction %void None %void_func\n" +
4453             "%main_lab = OpLabel\n" +
4454             "%a = OpVariable %_ptr_v2float Function\n" +
4455             "%2 = OpLoad %v2float %a\n" +
4456             "%3 = OpFAdd %v2float %2 %v2float_null\n" +
4457             "OpReturn\n" +
4458             "OpFunctionEnd",
4459         3, 2),
4460     // Test case 16: Fold vector fadd with null
4461     InstructionFoldingCase<uint32_t>(
4462         Header() + "%main = OpFunction %void None %void_func\n" +
4463             "%main_lab = OpLabel\n" +
4464             "%a = OpVariable %_ptr_v2float Function\n" +
4465             "%2 = OpLoad %v2float %a\n" +
4466             "%3 = OpFAdd %v2float %v2float_null %2\n" +
4467             "OpReturn\n" +
4468             "OpFunctionEnd",
4469         3, 2),
4470     // Test case 17: Fold vector fsub with null
4471     InstructionFoldingCase<uint32_t>(
4472         Header() + "%main = OpFunction %void None %void_func\n" +
4473             "%main_lab = OpLabel\n" +
4474             "%a = OpVariable %_ptr_v2float Function\n" +
4475             "%2 = OpLoad %v2float %a\n" +
4476             "%3 = OpFSub %v2float %2 %v2float_null\n" +
4477             "OpReturn\n" +
4478             "OpFunctionEnd",
4479         3, 2),
4480     // Test case 18: Fold 0.0(half) * n
4481     InstructionFoldingCase<uint32_t>(
4482         Header() + "%main = OpFunction %void None %void_func\n" +
4483             "%main_lab = OpLabel\n" +
4484             "%n = OpVariable %_ptr_half Function\n" +
4485             "%3 = OpLoad %half %n\n" +
4486             "%2 = OpFMul %half %108 %3\n" +
4487             "OpReturn\n" +
4488             "OpFunctionEnd",
4489         2, HALF_0_ID),
4490     // Test case 19: Don't fold 1.0(half) * n
4491     InstructionFoldingCase<uint32_t>(
4492         Header() + "%main = OpFunction %void None %void_func\n" +
4493             "%main_lab = OpLabel\n" +
4494             "%n = OpVariable %_ptr_half Function\n" +
4495             "%3 = OpLoad %half %n\n" +
4496             "%2 = OpFMul %half %half_1 %3\n" +
4497             "OpReturn\n" +
4498             "OpFunctionEnd",
4499         2, 0),
4500     // Test case 20: Don't fold 1.0 * 1.0 (half)
4501     InstructionFoldingCase<uint32_t>(
4502         Header() + "%main = OpFunction %void None %void_func\n" +
4503             "%main_lab = OpLabel\n" +
4504             "%2 = OpFMul %half %half_1 %half_1\n" +
4505             "OpReturn\n" +
4506             "OpFunctionEnd",
4507         2, 0),
4508     // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half)
4509     InstructionFoldingCase<uint32_t>(
4510         Header() + "%main = OpFunction %void None %void_func\n" +
4511             "%main_lab = OpLabel\n" +
4512             "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" +
4513             "OpReturn\n" +
4514             "OpFunctionEnd",
4515         2, 0),
4516     // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half)
4517     InstructionFoldingCase<uint32_t>(
4518         Header() + "%main = OpFunction %void None %void_func\n" +
4519             "%main_lab = OpLabel\n" +
4520             "%2 = OpDot %half %half_0_1 %half_0_1\n" +
4521             "OpReturn\n" +
4522             "OpFunctionEnd",
4523         2, 0),
4524     // Test case 23: Don't fold 1.0(half) / 2.0(half)
4525     // We do not have to code to emulate 16-bit float operations. Just make sure we do not crash.
4526     InstructionFoldingCase<uint32_t>(
4527         Header() + "%main = OpFunction %void None %void_func\n" +
4528             "%main_lab = OpLabel\n" +
4529             "%n = OpVariable %_ptr_half Function\n" +
4530             "%3 = OpLoad %half %n\n" +
4531             "%2 = OpFDiv %half %half_1 %half_2\n" +
4532             "OpReturn\n" +
4533             "OpFunctionEnd",
4534         2, 0)
4535 ));
4536 
4537 INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
4538                         ::testing::Values(
4539     // Test case 0: Don't fold n + 1.0
4540     InstructionFoldingCase<uint32_t>(
4541         Header() + "%main = OpFunction %void None %void_func\n" +
4542             "%main_lab = OpLabel\n" +
4543             "%n = OpVariable %_ptr_double Function\n" +
4544             "%3 = OpLoad %double %n\n" +
4545             "%2 = OpFAdd %double %3 %double_2\n" +
4546             "OpReturn\n" +
4547             "OpFunctionEnd",
4548         2, 0),
4549     // Test case 1: Don't fold n - 1.0
4550     InstructionFoldingCase<uint32_t>(
4551         Header() + "%main = OpFunction %void None %void_func\n" +
4552             "%main_lab = OpLabel\n" +
4553             "%n = OpVariable %_ptr_double Function\n" +
4554             "%3 = OpLoad %double %n\n" +
4555             "%2 = OpFSub %double %3 %double_2\n" +
4556             "OpReturn\n" +
4557             "OpFunctionEnd",
4558         2, 0),
4559     // Test case 2: Don't fold n * 2.0
4560     InstructionFoldingCase<uint32_t>(
4561         Header() + "%main = OpFunction %void None %void_func\n" +
4562             "%main_lab = OpLabel\n" +
4563             "%n = OpVariable %_ptr_double Function\n" +
4564             "%3 = OpLoad %double %n\n" +
4565             "%2 = OpFMul %double %3 %double_2\n" +
4566             "OpReturn\n" +
4567             "OpFunctionEnd",
4568         2, 0),
4569     // Test case 3: Fold n + 0.0
4570     InstructionFoldingCase<uint32_t>(
4571         Header() + "%main = OpFunction %void None %void_func\n" +
4572             "%main_lab = OpLabel\n" +
4573             "%n = OpVariable %_ptr_double Function\n" +
4574             "%3 = OpLoad %double %n\n" +
4575             "%2 = OpFAdd %double %3 %double_0\n" +
4576             "OpReturn\n" +
4577             "OpFunctionEnd",
4578         2, 3),
4579     // Test case 4: Fold 0.0 + n
4580     InstructionFoldingCase<uint32_t>(
4581         Header() + "%main = OpFunction %void None %void_func\n" +
4582             "%main_lab = OpLabel\n" +
4583             "%n = OpVariable %_ptr_double Function\n" +
4584             "%3 = OpLoad %double %n\n" +
4585             "%2 = OpFAdd %double %double_0 %3\n" +
4586             "OpReturn\n" +
4587             "OpFunctionEnd",
4588         2, 3),
4589     // Test case 5: Fold n - 0.0
4590     InstructionFoldingCase<uint32_t>(
4591         Header() + "%main = OpFunction %void None %void_func\n" +
4592             "%main_lab = OpLabel\n" +
4593             "%n = OpVariable %_ptr_double Function\n" +
4594             "%3 = OpLoad %double %n\n" +
4595             "%2 = OpFSub %double %3 %double_0\n" +
4596             "OpReturn\n" +
4597             "OpFunctionEnd",
4598         2, 3),
4599     // Test case 6: Fold n * 1.0
4600     InstructionFoldingCase<uint32_t>(
4601         Header() + "%main = OpFunction %void None %void_func\n" +
4602             "%main_lab = OpLabel\n" +
4603             "%n = OpVariable %_ptr_double Function\n" +
4604             "%3 = OpLoad %double %n\n" +
4605             "%2 = OpFMul %double %3 %double_1\n" +
4606             "OpReturn\n" +
4607             "OpFunctionEnd",
4608         2, 3),
4609     // Test case 7: Fold 1.0 * n
4610     InstructionFoldingCase<uint32_t>(
4611         Header() + "%main = OpFunction %void None %void_func\n" +
4612             "%main_lab = OpLabel\n" +
4613             "%n = OpVariable %_ptr_double Function\n" +
4614             "%3 = OpLoad %double %n\n" +
4615             "%2 = OpFMul %double %double_1 %3\n" +
4616             "OpReturn\n" +
4617             "OpFunctionEnd",
4618         2, 3),
4619     // Test case 8: Fold n / 1.0
4620     InstructionFoldingCase<uint32_t>(
4621         Header() + "%main = OpFunction %void None %void_func\n" +
4622             "%main_lab = OpLabel\n" +
4623             "%n = OpVariable %_ptr_double Function\n" +
4624             "%3 = OpLoad %double %n\n" +
4625             "%2 = OpFDiv %double %3 %double_1\n" +
4626             "OpReturn\n" +
4627             "OpFunctionEnd",
4628         2, 3),
4629     // Test case 9: Fold n * 0.0
4630     InstructionFoldingCase<uint32_t>(
4631         Header() + "%main = OpFunction %void None %void_func\n" +
4632             "%main_lab = OpLabel\n" +
4633             "%n = OpVariable %_ptr_double Function\n" +
4634             "%3 = OpLoad %double %n\n" +
4635             "%2 = OpFMul %double %3 %105\n" +
4636             "OpReturn\n" +
4637             "OpFunctionEnd",
4638         2, DOUBLE_0_ID),
4639     // Test case 10: Fold 0.0 * n
4640     InstructionFoldingCase<uint32_t>(
4641         Header() + "%main = OpFunction %void None %void_func\n" +
4642             "%main_lab = OpLabel\n" +
4643             "%n = OpVariable %_ptr_double Function\n" +
4644             "%3 = OpLoad %double %n\n" +
4645             "%2 = OpFMul %double %105 %3\n" +
4646             "OpReturn\n" +
4647             "OpFunctionEnd",
4648         2, DOUBLE_0_ID),
4649     // Test case 11: Fold 0.0 / n
4650     InstructionFoldingCase<uint32_t>(
4651         Header() + "%main = OpFunction %void None %void_func\n" +
4652             "%main_lab = OpLabel\n" +
4653             "%n = OpVariable %_ptr_double Function\n" +
4654             "%3 = OpLoad %double %n\n" +
4655             "%2 = OpFDiv %double %105 %3\n" +
4656             "OpReturn\n" +
4657             "OpFunctionEnd",
4658         2, DOUBLE_0_ID),
4659     // Test case 12: Don't fold mix(a, b, 2.0)
4660     InstructionFoldingCase<uint32_t>(
4661         Header() + "%main = OpFunction %void None %void_func\n" +
4662             "%main_lab = OpLabel\n" +
4663             "%a = OpVariable %_ptr_double Function\n" +
4664             "%b = OpVariable %_ptr_double Function\n" +
4665             "%3 = OpLoad %double %a\n" +
4666             "%4 = OpLoad %double %b\n" +
4667             "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
4668             "OpReturn\n" +
4669             "OpFunctionEnd",
4670         2, 0),
4671     // Test case 13: Fold mix(a, b, 0.0)
4672     InstructionFoldingCase<uint32_t>(
4673         Header() + "%main = OpFunction %void None %void_func\n" +
4674             "%main_lab = OpLabel\n" +
4675             "%a = OpVariable %_ptr_double Function\n" +
4676             "%b = OpVariable %_ptr_double Function\n" +
4677             "%3 = OpLoad %double %a\n" +
4678             "%4 = OpLoad %double %b\n" +
4679             "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
4680             "OpReturn\n" +
4681             "OpFunctionEnd",
4682         2, 3),
4683     // Test case 14: Fold mix(a, b, 1.0)
4684     InstructionFoldingCase<uint32_t>(
4685         Header() + "%main = OpFunction %void None %void_func\n" +
4686             "%main_lab = OpLabel\n" +
4687             "%a = OpVariable %_ptr_double Function\n" +
4688             "%b = OpVariable %_ptr_double Function\n" +
4689             "%3 = OpLoad %double %a\n" +
4690             "%4 = OpLoad %double %b\n" +
4691             "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
4692             "OpReturn\n" +
4693             "OpFunctionEnd",
4694         2, 4)
4695 ));
4696 
4697 INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4698                         ::testing::Values(
4699     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4700     InstructionFoldingCase<uint32_t>(
4701         Header() + "%main = OpFunction %void None %void_func\n" +
4702             "%main_lab = OpLabel\n" +
4703             "%n = OpVariable %_ptr_v4float Function\n" +
4704             "%3 = OpLoad %v4float %n\n" +
4705             "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
4706             "OpReturn\n" +
4707             "OpFunctionEnd",
4708         2, 0),
4709     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4710     InstructionFoldingCase<uint32_t>(
4711         Header() + "%main = OpFunction %void None %void_func\n" +
4712             "%main_lab = OpLabel\n" +
4713             "%n = OpVariable %_ptr_v4float Function\n" +
4714             "%3 = OpLoad %v4float %n\n" +
4715             "%2 = OpFMul %v4float %3 %106\n" +
4716             "OpReturn\n" +
4717             "OpFunctionEnd",
4718         2, VEC4_0_ID),
4719     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4720     InstructionFoldingCase<uint32_t>(
4721         Header() + "%main = OpFunction %void None %void_func\n" +
4722             "%main_lab = OpLabel\n" +
4723             "%n = OpVariable %_ptr_v4float Function\n" +
4724             "%3 = OpLoad %v4float %n\n" +
4725             "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
4726             "OpReturn\n" +
4727             "OpFunctionEnd",
4728         2, 3)
4729 ));
4730 
4731 INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4732                         ::testing::Values(
4733     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4734     InstructionFoldingCase<uint32_t>(
4735         Header() + "%main = OpFunction %void None %void_func\n" +
4736             "%main_lab = OpLabel\n" +
4737             "%n = OpVariable %_ptr_v4double Function\n" +
4738             "%3 = OpLoad %v4double %n\n" +
4739             "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
4740             "OpReturn\n" +
4741             "OpFunctionEnd",
4742         2, 0),
4743     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4744     InstructionFoldingCase<uint32_t>(
4745         Header() + "%main = OpFunction %void None %void_func\n" +
4746             "%main_lab = OpLabel\n" +
4747             "%n = OpVariable %_ptr_v4double Function\n" +
4748             "%3 = OpLoad %v4double %n\n" +
4749             "%2 = OpFMul %v4double %3 %106\n" +
4750             "OpReturn\n" +
4751             "OpFunctionEnd",
4752         2, DVEC4_0_ID),
4753     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4754     InstructionFoldingCase<uint32_t>(
4755         Header() + "%main = OpFunction %void None %void_func\n" +
4756             "%main_lab = OpLabel\n" +
4757             "%n = OpVariable %_ptr_v4double Function\n" +
4758             "%3 = OpLoad %v4double %n\n" +
4759             "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
4760             "OpReturn\n" +
4761             "OpFunctionEnd",
4762         2, 3)
4763 ));
4764 
4765 INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
4766                         ::testing::Values(
4767     // Test case 0: Don't fold n + 1
4768     InstructionFoldingCase<uint32_t>(
4769         Header() + "%main = OpFunction %void None %void_func\n" +
4770             "%main_lab = OpLabel\n" +
4771             "%n = OpVariable %_ptr_uint Function\n" +
4772             "%3 = OpLoad %uint %n\n" +
4773             "%2 = OpIAdd %uint %3 %uint_1\n" +
4774             "OpReturn\n" +
4775             "OpFunctionEnd",
4776         2, 0),
4777     // Test case 1: Don't fold 1 + n
4778     InstructionFoldingCase<uint32_t>(
4779         Header() + "%main = OpFunction %void None %void_func\n" +
4780             "%main_lab = OpLabel\n" +
4781             "%n = OpVariable %_ptr_uint Function\n" +
4782             "%3 = OpLoad %uint %n\n" +
4783             "%2 = OpIAdd %uint %uint_1 %3\n" +
4784             "OpReturn\n" +
4785             "OpFunctionEnd",
4786         2, 0),
4787     // Test case 2: Fold n + 0
4788     InstructionFoldingCase<uint32_t>(
4789         Header() + "%main = OpFunction %void None %void_func\n" +
4790             "%main_lab = OpLabel\n" +
4791             "%n = OpVariable %_ptr_uint Function\n" +
4792             "%3 = OpLoad %uint %n\n" +
4793             "%2 = OpIAdd %uint %3 %uint_0\n" +
4794             "OpReturn\n" +
4795             "OpFunctionEnd",
4796         2, 3),
4797     // Test case 3: Fold 0 + n
4798     InstructionFoldingCase<uint32_t>(
4799         Header() + "%main = OpFunction %void None %void_func\n" +
4800             "%main_lab = OpLabel\n" +
4801             "%n = OpVariable %_ptr_uint Function\n" +
4802             "%3 = OpLoad %uint %n\n" +
4803             "%2 = OpIAdd %uint %uint_0 %3\n" +
4804             "OpReturn\n" +
4805             "OpFunctionEnd",
4806         2, 3),
4807     // Test case 4: Don't fold n + (1,0)
4808     InstructionFoldingCase<uint32_t>(
4809         Header() + "%main = OpFunction %void None %void_func\n" +
4810             "%main_lab = OpLabel\n" +
4811             "%n = OpVariable %_ptr_v2int Function\n" +
4812             "%3 = OpLoad %v2int %n\n" +
4813             "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
4814             "OpReturn\n" +
4815             "OpFunctionEnd",
4816         2, 0),
4817     // Test case 5: Don't fold (1,0) + n
4818     InstructionFoldingCase<uint32_t>(
4819         Header() + "%main = OpFunction %void None %void_func\n" +
4820             "%main_lab = OpLabel\n" +
4821             "%n = OpVariable %_ptr_v2int Function\n" +
4822             "%3 = OpLoad %v2int %n\n" +
4823             "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
4824             "OpReturn\n" +
4825             "OpFunctionEnd",
4826         2, 0),
4827     // Test case 6: Fold n + (0,0)
4828     InstructionFoldingCase<uint32_t>(
4829         Header() + "%main = OpFunction %void None %void_func\n" +
4830             "%main_lab = OpLabel\n" +
4831             "%n = OpVariable %_ptr_v2int Function\n" +
4832             "%3 = OpLoad %v2int %n\n" +
4833             "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
4834             "OpReturn\n" +
4835             "OpFunctionEnd",
4836         2, 3),
4837     // Test case 7: Fold (0,0) + n
4838     InstructionFoldingCase<uint32_t>(
4839         Header() + "%main = OpFunction %void None %void_func\n" +
4840             "%main_lab = OpLabel\n" +
4841             "%n = OpVariable %_ptr_v2int Function\n" +
4842             "%3 = OpLoad %v2int %n\n" +
4843             "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
4844             "OpReturn\n" +
4845             "OpFunctionEnd",
4846         2, 3)
4847 ));
4848 
4849 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
4850 ::testing::Values(
4851     // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
4852     InstructionFoldingCase<uint32_t>(
4853         Header() + "%main = OpFunction %void None %void_func\n" +
4854             "%main_lab = OpLabel\n" +
4855             "%n = OpVariable %_ptr_float Function\n" +
4856             "%ld = OpLoad %float %n\n" +
4857             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4858             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4859             "OpReturn\n" +
4860             "OpFunctionEnd",
4861         2, 0),
4862     // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
4863     InstructionFoldingCase<uint32_t>(
4864         Header() + "%main = OpFunction %void None %void_func\n" +
4865             "%main_lab = OpLabel\n" +
4866             "%n = OpVariable %_ptr_float Function\n" +
4867             "%ld = OpLoad %float %n\n" +
4868             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4869             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4870             "OpReturn\n" +
4871             "OpFunctionEnd",
4872         2, 0),
4873     // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
4874     InstructionFoldingCase<uint32_t>(
4875         Header() + "%main = OpFunction %void None %void_func\n" +
4876             "%main_lab = OpLabel\n" +
4877             "%n = OpVariable %_ptr_float Function\n" +
4878             "%ld = OpLoad %float %n\n" +
4879             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4880             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
4881             "OpReturn\n" +
4882             "OpFunctionEnd",
4883         2, 0),
4884     // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
4885     InstructionFoldingCase<uint32_t>(
4886         Header() + "%main = OpFunction %void None %void_func\n" +
4887             "%main_lab = OpLabel\n" +
4888             "%n = OpVariable %_ptr_float Function\n" +
4889             "%ld = OpLoad %float %n\n" +
4890             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4891             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
4892             "OpReturn\n" +
4893             "OpFunctionEnd",
4894         2, 0),
4895     // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
4896     InstructionFoldingCase<uint32_t>(
4897         Header() + "%main = OpFunction %void None %void_func\n" +
4898             "%main_lab = OpLabel\n" +
4899             "%n = OpVariable %_ptr_float Function\n" +
4900             "%ld = OpLoad %float %n\n" +
4901             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4902             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4903             "OpReturn\n" +
4904             "OpFunctionEnd",
4905         2, 0),
4906     // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
4907     InstructionFoldingCase<uint32_t>(
4908         Header() + "%main = OpFunction %void None %void_func\n" +
4909             "%main_lab = OpLabel\n" +
4910             "%n = OpVariable %_ptr_float Function\n" +
4911             "%ld = OpLoad %float %n\n" +
4912             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4913             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4914             "OpReturn\n" +
4915             "OpFunctionEnd",
4916         2, 0),
4917     // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
4918     InstructionFoldingCase<uint32_t>(
4919         Header() + "%main = OpFunction %void None %void_func\n" +
4920             "%main_lab = OpLabel\n" +
4921             "%n = OpVariable %_ptr_float Function\n" +
4922             "%ld = OpLoad %float %n\n" +
4923             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4924             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
4925             "OpReturn\n" +
4926             "OpFunctionEnd",
4927         2, 0),
4928     // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
4929     InstructionFoldingCase<uint32_t>(
4930         Header() + "%main = OpFunction %void None %void_func\n" +
4931             "%main_lab = OpLabel\n" +
4932             "%n = OpVariable %_ptr_float Function\n" +
4933             "%ld = OpLoad %float %n\n" +
4934             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4935             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
4936             "OpReturn\n" +
4937             "OpFunctionEnd",
4938         2, 0),
4939     // Test case 8: Don't Fold 0.0 < clamp(0, 1)
4940     InstructionFoldingCase<uint32_t>(
4941         Header() + "%main = OpFunction %void None %void_func\n" +
4942             "%main_lab = OpLabel\n" +
4943             "%n = OpVariable %_ptr_float Function\n" +
4944             "%ld = OpLoad %float %n\n" +
4945             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4946             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4947             "OpReturn\n" +
4948             "OpFunctionEnd",
4949         2, 0),
4950     // Test case 9: Don't Fold 0.0 < clamp(0, 1)
4951     InstructionFoldingCase<uint32_t>(
4952         Header() + "%main = OpFunction %void None %void_func\n" +
4953             "%main_lab = OpLabel\n" +
4954             "%n = OpVariable %_ptr_float Function\n" +
4955             "%ld = OpLoad %float %n\n" +
4956             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4957             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4958             "OpReturn\n" +
4959             "OpFunctionEnd",
4960         2, 0),
4961     // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
4962     InstructionFoldingCase<uint32_t>(
4963         Header() + "%main = OpFunction %void None %void_func\n" +
4964             "%main_lab = OpLabel\n" +
4965             "%n = OpVariable %_ptr_float Function\n" +
4966             "%ld = OpLoad %float %n\n" +
4967             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4968             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4969             "OpReturn\n" +
4970             "OpFunctionEnd",
4971         2, 0),
4972     // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
4973     InstructionFoldingCase<uint32_t>(
4974         Header() + "%main = OpFunction %void None %void_func\n" +
4975             "%main_lab = OpLabel\n" +
4976             "%n = OpVariable %_ptr_float Function\n" +
4977             "%ld = OpLoad %float %n\n" +
4978             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4979             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4980             "OpReturn\n" +
4981             "OpFunctionEnd",
4982         2, 0)
4983 ));
4984 
4985 INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
4986 ::testing::Values(
4987     // Test case 0: Don't Fold clamp(-1, 1) < 0.0
4988     InstructionFoldingCase<uint32_t>(
4989       Header() + "%main = OpFunction %void None %void_func\n" +
4990           "%main_lab = OpLabel\n" +
4991           "%n = OpVariable %_ptr_float Function\n" +
4992           "%ld = OpLoad %float %n\n" +
4993           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4994           "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4995           "OpReturn\n" +
4996           "OpFunctionEnd",
4997       2, 0),
4998     // Test case 1: Don't Fold clamp(-1, 1) < 0.0
4999     InstructionFoldingCase<uint32_t>(
5000       Header() + "%main = OpFunction %void None %void_func\n" +
5001           "%main_lab = OpLabel\n" +
5002           "%n = OpVariable %_ptr_float Function\n" +
5003           "%ld = OpLoad %float %n\n" +
5004           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5005           "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
5006           "OpReturn\n" +
5007           "OpFunctionEnd",
5008       2, 0),
5009     // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
5010     InstructionFoldingCase<uint32_t>(
5011       Header() + "%main = OpFunction %void None %void_func\n" +
5012           "%main_lab = OpLabel\n" +
5013           "%n = OpVariable %_ptr_float Function\n" +
5014           "%ld = OpLoad %float %n\n" +
5015           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5016           "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
5017           "OpReturn\n" +
5018           "OpFunctionEnd",
5019       2, 0),
5020     // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
5021     InstructionFoldingCase<uint32_t>(
5022       Header() + "%main = OpFunction %void None %void_func\n" +
5023           "%main_lab = OpLabel\n" +
5024           "%n = OpVariable %_ptr_float Function\n" +
5025           "%ld = OpLoad %float %n\n" +
5026           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5027           "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
5028           "OpReturn\n" +
5029           "OpFunctionEnd",
5030       2, 0),
5031     // Test case 4: Don't Fold clamp(-1, 1) > 0.0
5032     InstructionFoldingCase<uint32_t>(
5033         Header() + "%main = OpFunction %void None %void_func\n" +
5034             "%main_lab = OpLabel\n" +
5035             "%n = OpVariable %_ptr_float Function\n" +
5036             "%ld = OpLoad %float %n\n" +
5037             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5038             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
5039             "OpReturn\n" +
5040             "OpFunctionEnd",
5041         2, 0),
5042     // Test case 5: Don't Fold clamp(-1, 1) > 0.0
5043     InstructionFoldingCase<uint32_t>(
5044         Header() + "%main = OpFunction %void None %void_func\n" +
5045             "%main_lab = OpLabel\n" +
5046             "%n = OpVariable %_ptr_float Function\n" +
5047             "%ld = OpLoad %float %n\n" +
5048             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5049             "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
5050             "OpReturn\n" +
5051             "OpFunctionEnd",
5052         2, 0),
5053     // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
5054     InstructionFoldingCase<uint32_t>(
5055         Header() + "%main = OpFunction %void None %void_func\n" +
5056             "%main_lab = OpLabel\n" +
5057             "%n = OpVariable %_ptr_float Function\n" +
5058             "%ld = OpLoad %float %n\n" +
5059             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5060             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
5061             "OpReturn\n" +
5062             "OpFunctionEnd",
5063         2, 0),
5064     // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
5065     InstructionFoldingCase<uint32_t>(
5066         Header() + "%main = OpFunction %void None %void_func\n" +
5067             "%main_lab = OpLabel\n" +
5068             "%n = OpVariable %_ptr_float Function\n" +
5069             "%ld = OpLoad %float %n\n" +
5070             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5071             "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
5072             "OpReturn\n" +
5073             "OpFunctionEnd",
5074         2, 0),
5075     // Test case 8: Don't Fold clamp(-1, 0) < 0.0
5076     InstructionFoldingCase<uint32_t>(
5077         Header() + "%main = OpFunction %void None %void_func\n" +
5078             "%main_lab = OpLabel\n" +
5079             "%n = OpVariable %_ptr_float Function\n" +
5080             "%ld = OpLoad %float %n\n" +
5081             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5082             "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
5083             "OpReturn\n" +
5084             "OpFunctionEnd",
5085         2, 0),
5086     // Test case 9: Don't Fold clamp(0, 1) < 1
5087     InstructionFoldingCase<uint32_t>(
5088         Header() + "%main = OpFunction %void None %void_func\n" +
5089             "%main_lab = OpLabel\n" +
5090             "%n = OpVariable %_ptr_float Function\n" +
5091             "%ld = OpLoad %float %n\n" +
5092             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
5093             "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
5094             "OpReturn\n" +
5095             "OpFunctionEnd",
5096         2, 0),
5097     // Test case 10: Don't Fold clamp(-1, 0) > -1
5098     InstructionFoldingCase<uint32_t>(
5099         Header() + "%main = OpFunction %void None %void_func\n" +
5100             "%main_lab = OpLabel\n" +
5101             "%n = OpVariable %_ptr_float Function\n" +
5102             "%ld = OpLoad %float %n\n" +
5103             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5104             "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
5105             "OpReturn\n" +
5106             "OpFunctionEnd",
5107         2, 0),
5108     // Test case 11: Don't Fold clamp(-1, 0) > -1
5109     InstructionFoldingCase<uint32_t>(
5110         Header() + "%main = OpFunction %void None %void_func\n" +
5111             "%main_lab = OpLabel\n" +
5112             "%n = OpVariable %_ptr_float Function\n" +
5113             "%ld = OpLoad %float %n\n" +
5114             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5115             "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
5116             "OpReturn\n" +
5117             "OpFunctionEnd",
5118         2, 0)
5119 ));
5120 
5121 INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
5122                         ::testing::Values(
5123     // Test case 0: Fold int(3.0)
5124     InstructionFoldingCase<uint32_t>(
5125         Header() + "%main = OpFunction %void None %void_func\n" +
5126             "%main_lab = OpLabel\n" +
5127             "%2 = OpConvertFToS %int %float_3\n" +
5128             "OpReturn\n" +
5129             "OpFunctionEnd",
5130         2, 3),
5131     // Test case 1: Fold uint(3.0)
5132     InstructionFoldingCase<uint32_t>(
5133         Header() + "%main = OpFunction %void None %void_func\n" +
5134             "%main_lab = OpLabel\n" +
5135             "%2 = OpConvertFToU %int %float_3\n" +
5136             "OpReturn\n" +
5137             "OpFunctionEnd",
5138         2, 3)
5139 ));
5140 
5141 INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
5142                         ::testing::Values(
5143     // Test case 0: Fold float(3)
5144     InstructionFoldingCase<float>(
5145         Header() + "%main = OpFunction %void None %void_func\n" +
5146             "%main_lab = OpLabel\n" +
5147             "%2 = OpConvertSToF %float %int_3\n" +
5148             "OpReturn\n" +
5149             "OpFunctionEnd",
5150         2, 3.0),
5151     // Test case 1: Fold float(3u)
5152     InstructionFoldingCase<float>(
5153         Header() + "%main = OpFunction %void None %void_func\n" +
5154             "%main_lab = OpLabel\n" +
5155             "%2 = OpConvertUToF %float %uint_3\n" +
5156             "OpReturn\n" +
5157             "OpFunctionEnd",
5158         2, 3.0)
5159 ));
5160 // clang-format on
5161 
5162 using ToNegateFoldingTest =
5163     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
5164 
TEST_P(ToNegateFoldingTest, Case)5165 TEST_P(ToNegateFoldingTest, Case) {
5166   const auto& tc = GetParam();
5167 
5168   // Build module.
5169   std::unique_ptr<IRContext> context =
5170       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5171                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5172   ASSERT_NE(nullptr, context);
5173 
5174   // Fold the instruction to test.
5175   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
5176   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
5177   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5178   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5179 
5180   // Make sure the instruction folded as expected.
5181   EXPECT_EQ(inst->result_id(), original_inst->result_id());
5182   EXPECT_EQ(inst->type_id(), original_inst->type_id());
5183   EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
5184   if (succeeded) {
5185     EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate);
5186     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
5187   } else {
5188     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
5189     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
5190       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
5191     }
5192   }
5193 }
5194 
5195 // clang-format off
5196 INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
5197                         ::testing::Values(
5198     // Test case 0: Don't fold 1.0 - n
5199     InstructionFoldingCase<uint32_t>(
5200         Header() + "%main = OpFunction %void None %void_func\n" +
5201             "%main_lab = OpLabel\n" +
5202             "%n = OpVariable %_ptr_float Function\n" +
5203             "%3 = OpLoad %float %n\n" +
5204             "%2 = OpFSub %float %float_1 %3\n" +
5205             "OpReturn\n" +
5206             "OpFunctionEnd",
5207         2, 0),
5208     // Test case 1: Fold 0.0 - n
5209     InstructionFoldingCase<uint32_t>(
5210         Header() + "%main = OpFunction %void None %void_func\n" +
5211             "%main_lab = OpLabel\n" +
5212             "%n = OpVariable %_ptr_float Function\n" +
5213             "%3 = OpLoad %float %n\n" +
5214             "%2 = OpFSub %float %float_0 %3\n" +
5215             "OpReturn\n" +
5216             "OpFunctionEnd",
5217         2, 3),
5218 	// Test case 2: Don't fold (0,0,0,1) - n
5219     InstructionFoldingCase<uint32_t>(
5220         Header() + "%main = OpFunction %void None %void_func\n" +
5221             "%main_lab = OpLabel\n" +
5222             "%n = OpVariable %_ptr_v4float Function\n" +
5223             "%3 = OpLoad %v4float %n\n" +
5224             "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
5225             "OpReturn\n" +
5226             "OpFunctionEnd",
5227         2, 0),
5228 	// Test case 3: Fold (0,0,0,0) - n
5229     InstructionFoldingCase<uint32_t>(
5230         Header() + "%main = OpFunction %void None %void_func\n" +
5231             "%main_lab = OpLabel\n" +
5232             "%n = OpVariable %_ptr_v4float Function\n" +
5233             "%3 = OpLoad %v4float %n\n" +
5234             "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
5235             "OpReturn\n" +
5236             "OpFunctionEnd",
5237         2, 3)
5238 ));
5239 
5240 INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
5241                         ::testing::Values(
5242     // Test case 0: Don't fold 1.0 - n
5243     InstructionFoldingCase<uint32_t>(
5244         Header() + "%main = OpFunction %void None %void_func\n" +
5245             "%main_lab = OpLabel\n" +
5246             "%n = OpVariable %_ptr_double Function\n" +
5247             "%3 = OpLoad %double %n\n" +
5248             "%2 = OpFSub %double %double_1 %3\n" +
5249             "OpReturn\n" +
5250             "OpFunctionEnd",
5251         2, 0),
5252     // Test case 1: Fold 0.0 - n
5253     InstructionFoldingCase<uint32_t>(
5254         Header() + "%main = OpFunction %void None %void_func\n" +
5255             "%main_lab = OpLabel\n" +
5256             "%n = OpVariable %_ptr_double Function\n" +
5257             "%3 = OpLoad %double %n\n" +
5258             "%2 = OpFSub %double %double_0 %3\n" +
5259             "OpReturn\n" +
5260             "OpFunctionEnd",
5261         2, 3),
5262 	// Test case 2: Don't fold (0,0,0,1) - n
5263     InstructionFoldingCase<uint32_t>(
5264         Header() + "%main = OpFunction %void None %void_func\n" +
5265             "%main_lab = OpLabel\n" +
5266             "%n = OpVariable %_ptr_v4double Function\n" +
5267             "%3 = OpLoad %v4double %n\n" +
5268             "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
5269             "OpReturn\n" +
5270             "OpFunctionEnd",
5271         2, 0),
5272 	// Test case 3: Fold (0,0,0,0) - n
5273     InstructionFoldingCase<uint32_t>(
5274         Header() + "%main = OpFunction %void None %void_func\n" +
5275             "%main_lab = OpLabel\n" +
5276             "%n = OpVariable %_ptr_v4double Function\n" +
5277             "%3 = OpLoad %v4double %n\n" +
5278             "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
5279             "OpReturn\n" +
5280             "OpFunctionEnd",
5281         2, 3)
5282 ));
5283 
5284 using MatchingInstructionFoldingTest =
5285     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
5286 
TEST_P(MatchingInstructionFoldingTest, Case)5287 TEST_P(MatchingInstructionFoldingTest, Case) {
5288   const auto& tc = GetParam();
5289 
5290   // Build module.
5291   std::unique_ptr<IRContext> context =
5292       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5293                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5294   ASSERT_NE(nullptr, context);
5295 
5296   // Fold the instruction to test.
5297   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
5298   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
5299   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5300   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5301   EXPECT_EQ(succeeded, tc.expected_result);
5302   if (succeeded) {
5303     Match(tc.test_body, context.get());
5304   }
5305 }
5306 
5307 INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
5308 ::testing::Values(
5309     // Test case 0: Fold 0 + n (change sign)
5310     InstructionFoldingCase<bool>(
5311         Header() +
5312             "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5313             "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
5314             "%main = OpFunction %void None %void_func\n" +
5315             "%main_lab = OpLabel\n" +
5316             "%n = OpVariable %_ptr_int Function\n" +
5317             "%3 = OpLoad %uint %n\n" +
5318             "%2 = OpIAdd %uint %int_0 %3\n" +
5319             "OpReturn\n" +
5320             "OpFunctionEnd\n",
5321         2, true),
5322     // Test case 0: Fold 0 + n (change sign)
5323     InstructionFoldingCase<bool>(
5324         Header() +
5325             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5326             "; CHECK: %2 = OpBitcast [[int]] %3\n" +
5327             "%main = OpFunction %void None %void_func\n" +
5328             "%main_lab = OpLabel\n" +
5329             "%n = OpVariable %_ptr_int Function\n" +
5330             "%3 = OpLoad %int %n\n" +
5331             "%2 = OpIAdd %int %uint_0 %3\n" +
5332             "OpReturn\n" +
5333             "OpFunctionEnd\n",
5334         2, true)
5335 ));
5336 
5337 INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest,
5338 ::testing::Values(
5339   // Test case 0: fold consecutive fnegate
5340   // -(-x) = x
5341   InstructionFoldingCase<bool>(
5342     Header() +
5343       "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
5344       "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
5345       "%main = OpFunction %void None %void_func\n" +
5346       "%main_lab = OpLabel\n" +
5347       "%var = OpVariable %_ptr_float Function\n" +
5348       "%2 = OpLoad %float %var\n" +
5349       "%3 = OpFNegate %float %2\n" +
5350       "%4 = OpFNegate %float %3\n" +
5351       "OpReturn\n" +
5352       "OpFunctionEnd",
5353     4, true),
5354   // Test case 1: fold fnegate(fmul with const).
5355   // -(x * 2.0) = x * -2.0
5356   InstructionFoldingCase<bool>(
5357     Header() +
5358       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5359       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5360       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5361       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5362       "%main = OpFunction %void None %void_func\n" +
5363       "%main_lab = OpLabel\n" +
5364       "%var = OpVariable %_ptr_float Function\n" +
5365       "%2 = OpLoad %float %var\n" +
5366       "%3 = OpFMul %float %2 %float_2\n" +
5367       "%4 = OpFNegate %float %3\n" +
5368       "OpReturn\n" +
5369       "OpFunctionEnd",
5370     4, true),
5371   // Test case 2: fold fnegate(fmul with const).
5372   // -(2.0 * x) = x * 2.0
5373   InstructionFoldingCase<bool>(
5374     Header() +
5375       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5376       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5377       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5378       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5379       "%main = OpFunction %void None %void_func\n" +
5380       "%main_lab = OpLabel\n" +
5381       "%var = OpVariable %_ptr_float Function\n" +
5382       "%2 = OpLoad %float %var\n" +
5383       "%3 = OpFMul %float %float_2 %2\n" +
5384       "%4 = OpFNegate %float %3\n" +
5385       "OpReturn\n" +
5386       "OpFunctionEnd",
5387     4, true),
5388   // Test case 3: fold fnegate(fdiv with const).
5389   // -(x / 2.0) = x * -0.5
5390   InstructionFoldingCase<bool>(
5391     Header() +
5392       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5393       "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
5394       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5395       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
5396       "%main = OpFunction %void None %void_func\n" +
5397       "%main_lab = OpLabel\n" +
5398       "%var = OpVariable %_ptr_float Function\n" +
5399       "%2 = OpLoad %float %var\n" +
5400       "%3 = OpFDiv %float %2 %float_2\n" +
5401       "%4 = OpFNegate %float %3\n" +
5402       "OpReturn\n" +
5403       "OpFunctionEnd",
5404     4, true),
5405   // Test case 4: fold fnegate(fdiv with const).
5406   // -(2.0 / x) = -2.0 / x
5407   InstructionFoldingCase<bool>(
5408     Header() +
5409       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5410       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5411       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5412       "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
5413       "%main = OpFunction %void None %void_func\n" +
5414       "%main_lab = OpLabel\n" +
5415       "%var = OpVariable %_ptr_float Function\n" +
5416       "%2 = OpLoad %float %var\n" +
5417       "%3 = OpFDiv %float %float_2 %2\n" +
5418       "%4 = OpFNegate %float %3\n" +
5419       "OpReturn\n" +
5420       "OpFunctionEnd",
5421     4, true),
5422   // Test case 5: fold fnegate(fadd with const).
5423   // -(2.0 + x) = -2.0 - x
5424   InstructionFoldingCase<bool>(
5425     Header() +
5426       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5427       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5428       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5429       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5430       "%main = OpFunction %void None %void_func\n" +
5431       "%main_lab = OpLabel\n" +
5432       "%var = OpVariable %_ptr_float Function\n" +
5433       "%2 = OpLoad %float %var\n" +
5434       "%3 = OpFAdd %float %float_2 %2\n" +
5435       "%4 = OpFNegate %float %3\n" +
5436       "OpReturn\n" +
5437       "OpFunctionEnd",
5438     4, true),
5439   // Test case 6: fold fnegate(fadd with const).
5440   // -(x + 2.0) = -2.0 - x
5441   InstructionFoldingCase<bool>(
5442     Header() +
5443       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5444       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5445       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5446       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5447       "%main = OpFunction %void None %void_func\n" +
5448       "%main_lab = OpLabel\n" +
5449       "%var = OpVariable %_ptr_float Function\n" +
5450       "%2 = OpLoad %float %var\n" +
5451       "%3 = OpFAdd %float %2 %float_2\n" +
5452       "%4 = OpFNegate %float %3\n" +
5453       "OpReturn\n" +
5454       "OpFunctionEnd",
5455     4, true),
5456   // Test case 7: fold fnegate(fsub with const).
5457   // -(2.0 - x) = x - 2.0
5458   InstructionFoldingCase<bool>(
5459     Header() +
5460       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5461       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5462       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5463       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
5464       "%main = OpFunction %void None %void_func\n" +
5465       "%main_lab = OpLabel\n" +
5466       "%var = OpVariable %_ptr_float Function\n" +
5467       "%2 = OpLoad %float %var\n" +
5468       "%3 = OpFSub %float %float_2 %2\n" +
5469       "%4 = OpFNegate %float %3\n" +
5470       "OpReturn\n" +
5471       "OpFunctionEnd",
5472     4, true),
5473   // Test case 8: fold fnegate(fsub with const).
5474   // -(x - 2.0) = 2.0 - x
5475   InstructionFoldingCase<bool>(
5476     Header() +
5477       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5478       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5479       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5480       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5481       "%main = OpFunction %void None %void_func\n" +
5482       "%main_lab = OpLabel\n" +
5483       "%var = OpVariable %_ptr_float Function\n" +
5484       "%2 = OpLoad %float %var\n" +
5485       "%3 = OpFSub %float %2 %float_2\n" +
5486       "%4 = OpFNegate %float %3\n" +
5487       "OpReturn\n" +
5488       "OpFunctionEnd",
5489     4, true),
5490   // Test case 9: fold consecutive snegate
5491   // -(-x) = x
5492   InstructionFoldingCase<bool>(
5493     Header() +
5494       "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
5495       "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
5496       "%main = OpFunction %void None %void_func\n" +
5497       "%main_lab = OpLabel\n" +
5498       "%var = OpVariable %_ptr_int Function\n" +
5499       "%2 = OpLoad %int %var\n" +
5500       "%3 = OpSNegate %int %2\n" +
5501       "%4 = OpSNegate %int %3\n" +
5502       "OpReturn\n" +
5503       "OpFunctionEnd",
5504     4, true),
5505   // Test case 10: fold consecutive vector negate
5506   // -(-x) = x
5507   InstructionFoldingCase<bool>(
5508     Header() +
5509       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
5510       "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
5511       "%main = OpFunction %void None %void_func\n" +
5512       "%main_lab = OpLabel\n" +
5513       "%var = OpVariable %_ptr_v2float Function\n" +
5514       "%2 = OpLoad %v2float %var\n" +
5515       "%3 = OpFNegate %v2float %2\n" +
5516       "%4 = OpFNegate %v2float %3\n" +
5517       "OpReturn\n" +
5518       "OpFunctionEnd",
5519     4, true),
5520   // Test case 11: fold snegate(iadd with const).
5521   // -(2 + x) = -2 - x
5522   InstructionFoldingCase<bool>(
5523     Header() +
5524       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5525       "; CHECK: OpConstant [[int]] -2147483648\n" +
5526       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5527       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5528       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5529       "%main = OpFunction %void None %void_func\n" +
5530       "%main_lab = OpLabel\n" +
5531       "%var = OpVariable %_ptr_int Function\n" +
5532       "%2 = OpLoad %int %var\n" +
5533       "%3 = OpIAdd %int %int_2 %2\n" +
5534       "%4 = OpSNegate %int %3\n" +
5535       "OpReturn\n" +
5536       "OpFunctionEnd",
5537     4, true),
5538   // Test case 12: fold snegate(iadd with const).
5539   // -(x + 2) = -2 - x
5540   InstructionFoldingCase<bool>(
5541     Header() +
5542       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5543       "; CHECK: OpConstant [[int]] -2147483648\n" +
5544       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5545       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5546       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5547       "%main = OpFunction %void None %void_func\n" +
5548       "%main_lab = OpLabel\n" +
5549       "%var = OpVariable %_ptr_int Function\n" +
5550       "%2 = OpLoad %int %var\n" +
5551       "%3 = OpIAdd %int %2 %int_2\n" +
5552       "%4 = OpSNegate %int %3\n" +
5553       "OpReturn\n" +
5554       "OpFunctionEnd",
5555     4, true),
5556   // Test case 13: fold snegate(isub with const).
5557   // -(2 - x) = x - 2
5558   InstructionFoldingCase<bool>(
5559     Header() +
5560       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5561       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5562       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5563       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
5564       "%main = OpFunction %void None %void_func\n" +
5565       "%main_lab = OpLabel\n" +
5566       "%var = OpVariable %_ptr_int Function\n" +
5567       "%2 = OpLoad %int %var\n" +
5568       "%3 = OpISub %int %int_2 %2\n" +
5569       "%4 = OpSNegate %int %3\n" +
5570       "OpReturn\n" +
5571       "OpFunctionEnd",
5572     4, true),
5573   // Test case 14: fold snegate(isub with const).
5574   // -(x - 2) = 2 - x
5575   InstructionFoldingCase<bool>(
5576     Header() +
5577       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5578       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5579       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5580       "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
5581       "%main = OpFunction %void None %void_func\n" +
5582       "%main_lab = OpLabel\n" +
5583       "%var = OpVariable %_ptr_int Function\n" +
5584       "%2 = OpLoad %int %var\n" +
5585       "%3 = OpISub %int %2 %int_2\n" +
5586       "%4 = OpSNegate %int %3\n" +
5587       "OpReturn\n" +
5588       "OpFunctionEnd",
5589     4, true),
5590   // Test case 15: fold snegate(iadd with const).
5591   // -(x + 2) = -2 - x
5592   InstructionFoldingCase<bool>(
5593     Header() +
5594       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5595       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
5596       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5597       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5598       "%main = OpFunction %void None %void_func\n" +
5599       "%main_lab = OpLabel\n" +
5600       "%var = OpVariable %_ptr_long Function\n" +
5601       "%2 = OpLoad %long %var\n" +
5602       "%3 = OpIAdd %long %2 %long_2\n" +
5603       "%4 = OpSNegate %long %3\n" +
5604       "OpReturn\n" +
5605       "OpFunctionEnd",
5606     4, true),
5607   // Test case 16: fold snegate(isub with const).
5608   // -(2 - x) = x - 2
5609   InstructionFoldingCase<bool>(
5610     Header() +
5611       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5612       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5613       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5614       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
5615       "%main = OpFunction %void None %void_func\n" +
5616       "%main_lab = OpLabel\n" +
5617       "%var = OpVariable %_ptr_long Function\n" +
5618       "%2 = OpLoad %long %var\n" +
5619       "%3 = OpISub %long %long_2 %2\n" +
5620       "%4 = OpSNegate %long %3\n" +
5621       "OpReturn\n" +
5622       "OpFunctionEnd",
5623     4, true),
5624   // Test case 17: fold snegate(isub with const).
5625   // -(x - 2) = 2 - x
5626   InstructionFoldingCase<bool>(
5627     Header() +
5628       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5629       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5630       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5631       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\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 = OpISub %long %2 %long_2\n" +
5637       "%4 = OpSNegate %long %3\n" +
5638       "OpReturn\n" +
5639       "OpFunctionEnd",
5640     4, true),
5641     // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
5642     InstructionFoldingCase<bool>(
5643         Header() +
5644       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5645       "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" +
5646       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" +
5647       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" +
5648       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5649       "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" +
5650       "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
5651       "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
5652         "%main = OpFunction %void None %void_func\n" +
5653             "%main_lab = OpLabel\n" +
5654             "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
5655             "OpReturn\n" +
5656             "OpFunctionEnd",
5657         2, true),
5658     // Test case 19: fold vector fnegate with null
5659     InstructionFoldingCase<bool>(
5660         Header() +
5661       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5662       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5663       "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
5664       "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
5665       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5666         "%main = OpFunction %void None %void_func\n" +
5667             "%main_lab = OpLabel\n" +
5668             "%2 = OpFNegate %v2double %v2double_null\n" +
5669             "OpReturn\n" +
5670             "OpFunctionEnd",
5671         2, true)
5672 ));
5673 
5674 INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
5675 ::testing::Values(
5676   // Test case 0: scalar reicprocal
5677   // x / 0.5 = x * 2.0
5678   InstructionFoldingCase<bool>(
5679     Header() +
5680       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5681       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5682       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5683       "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
5684       "%main = OpFunction %void None %void_func\n" +
5685       "%main_lab = OpLabel\n" +
5686       "%var = OpVariable %_ptr_float Function\n" +
5687       "%2 = OpLoad %float %var\n" +
5688       "%3 = OpFDiv %float %2 %float_0p5\n" +
5689       "OpReturn\n" +
5690       "OpFunctionEnd\n",
5691     3, true),
5692   // Test case 1: Unfoldable
5693   InstructionFoldingCase<bool>(
5694     Header() +
5695       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5696       "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
5697       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5698       "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
5699       "%main = OpFunction %void None %void_func\n" +
5700       "%main_lab = OpLabel\n" +
5701       "%var = OpVariable %_ptr_float Function\n" +
5702       "%2 = OpLoad %float %var\n" +
5703       "%3 = OpFDiv %float %2 %104\n" +
5704       "OpReturn\n" +
5705       "OpFunctionEnd\n",
5706     3, false),
5707   // Test case 2: Vector reciprocal
5708   // x / {2.0, 0.5} = x * {0.5, 2.0}
5709   InstructionFoldingCase<bool>(
5710     Header() +
5711       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5712       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5713       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5714       "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
5715       "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
5716       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5717       "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
5718       "%main = OpFunction %void None %void_func\n" +
5719       "%main_lab = OpLabel\n" +
5720       "%var = OpVariable %_ptr_v2float Function\n" +
5721       "%2 = OpLoad %v2float %var\n" +
5722       "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
5723       "OpReturn\n" +
5724       "OpFunctionEnd\n",
5725     3, true),
5726   // Test case 3: double reciprocal
5727   // x / 2.0 = x * 0.5
5728   InstructionFoldingCase<bool>(
5729     Header() +
5730       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5731       "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
5732       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5733       "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
5734       "%main = OpFunction %void None %void_func\n" +
5735       "%main_lab = OpLabel\n" +
5736       "%var = OpVariable %_ptr_double Function\n" +
5737       "%2 = OpLoad %double %var\n" +
5738       "%3 = OpFDiv %double %2 %double_2\n" +
5739       "OpReturn\n" +
5740       "OpFunctionEnd\n",
5741     3, true),
5742   // Test case 4: don't fold x / 0.
5743   InstructionFoldingCase<bool>(
5744     Header() +
5745       "%main = OpFunction %void None %void_func\n" +
5746       "%main_lab = OpLabel\n" +
5747       "%var = OpVariable %_ptr_v2float Function\n" +
5748       "%2 = OpLoad %v2float %var\n" +
5749       "%3 = OpFDiv %v2float %2 %v2float_null\n" +
5750       "OpReturn\n" +
5751       "OpFunctionEnd\n",
5752     3, false)
5753 ));
5754 
5755 INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest,
5756 ::testing::Values(
5757   // Test case 0: fold consecutive fmuls
5758   // (x * 3.0) * 2.0 = x * 6.0
5759   InstructionFoldingCase<bool>(
5760     Header() +
5761       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5762       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5763       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5764       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5765       "%main = OpFunction %void None %void_func\n" +
5766       "%main_lab = OpLabel\n" +
5767       "%var = OpVariable %_ptr_float Function\n" +
5768       "%2 = OpLoad %float %var\n" +
5769       "%3 = OpFMul %float %2 %float_3\n" +
5770       "%4 = OpFMul %float %3 %float_2\n" +
5771       "OpReturn\n" +
5772       "OpFunctionEnd\n",
5773     4, true),
5774   // Test case 1: fold consecutive fmuls
5775   // 2.0 * (x * 3.0) = x * 6.0
5776   InstructionFoldingCase<bool>(
5777     Header() +
5778       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5779       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5780       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5781       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5782       "%main = OpFunction %void None %void_func\n" +
5783       "%main_lab = OpLabel\n" +
5784       "%var = OpVariable %_ptr_float Function\n" +
5785       "%2 = OpLoad %float %var\n" +
5786       "%3 = OpFMul %float %2 %float_3\n" +
5787       "%4 = OpFMul %float %float_2 %3\n" +
5788       "OpReturn\n" +
5789       "OpFunctionEnd\n",
5790     4, true),
5791   // Test case 2: fold consecutive fmuls
5792   // (3.0 * x) * 2.0 = x * 6.0
5793   InstructionFoldingCase<bool>(
5794     Header() +
5795       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5796       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5797       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5798       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5799       "%main = OpFunction %void None %void_func\n" +
5800       "%main_lab = OpLabel\n" +
5801       "%var = OpVariable %_ptr_float Function\n" +
5802       "%2 = OpLoad %float %var\n" +
5803       "%3 = OpFMul %float %float_3 %2\n" +
5804       "%4 = OpFMul %float %float_2 %3\n" +
5805       "OpReturn\n" +
5806       "OpFunctionEnd\n",
5807     4, true),
5808   // Test case 3: fold vector fmul
5809   InstructionFoldingCase<bool>(
5810     Header() +
5811       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5812       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5813       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5814       "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
5815       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5816       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
5817       "%main = OpFunction %void None %void_func\n" +
5818       "%main_lab = OpLabel\n" +
5819       "%var = OpVariable %_ptr_v2float Function\n" +
5820       "%2 = OpLoad %v2float %var\n" +
5821       "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
5822       "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
5823       "OpReturn\n" +
5824       "OpFunctionEnd\n",
5825     4, true),
5826   // Test case 4: fold double fmuls
5827   // (x * 3.0) * 2.0 = x * 6.0
5828   InstructionFoldingCase<bool>(
5829     Header() +
5830       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5831       "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
5832       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5833       "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
5834       "%main = OpFunction %void None %void_func\n" +
5835       "%main_lab = OpLabel\n" +
5836       "%var = OpVariable %_ptr_double Function\n" +
5837       "%2 = OpLoad %double %var\n" +
5838       "%3 = OpFMul %double %2 %double_3\n" +
5839       "%4 = OpFMul %double %3 %double_2\n" +
5840       "OpReturn\n" +
5841       "OpFunctionEnd\n",
5842     4, true),
5843   // Test case 5: fold 32 bit imuls
5844   // (x * 3) * 2 = x * 6
5845   InstructionFoldingCase<bool>(
5846     Header() +
5847       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5848       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5849       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5850       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
5851       "%main = OpFunction %void None %void_func\n" +
5852       "%main_lab = OpLabel\n" +
5853       "%var = OpVariable %_ptr_int Function\n" +
5854       "%2 = OpLoad %int %var\n" +
5855       "%3 = OpIMul %int %2 %int_3\n" +
5856       "%4 = OpIMul %int %3 %int_2\n" +
5857       "OpReturn\n" +
5858       "OpFunctionEnd\n",
5859     4, true),
5860   // Test case 6: fold 64 bit imuls
5861   // (x * 3) * 2 = x * 6
5862   InstructionFoldingCase<bool>(
5863     Header() +
5864       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5865       "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
5866       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5867       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
5868       "%main = OpFunction %void None %void_func\n" +
5869       "%main_lab = OpLabel\n" +
5870       "%var = OpVariable %_ptr_long Function\n" +
5871       "%2 = OpLoad %long %var\n" +
5872       "%3 = OpIMul %long %2 %long_3\n" +
5873       "%4 = OpIMul %long %3 %long_2\n" +
5874       "OpReturn\n" +
5875       "OpFunctionEnd\n",
5876     4, true),
5877   // Test case 7: merge vector integer mults
5878   InstructionFoldingCase<bool>(
5879     Header() +
5880       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5881       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5882       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5883       "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
5884       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5885       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
5886       "%main = OpFunction %void None %void_func\n" +
5887       "%main_lab = OpLabel\n" +
5888       "%var = OpVariable %_ptr_v2int Function\n" +
5889       "%2 = OpLoad %v2int %var\n" +
5890       "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
5891       "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
5892       "OpReturn\n" +
5893       "OpFunctionEnd\n",
5894     4, true),
5895   // Test case 8: merge fmul of fdiv
5896   // 2.0 * (2.0 / x) = 4.0 / x
5897   InstructionFoldingCase<bool>(
5898     Header() +
5899       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5900       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5901       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5902       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5903       "%main = OpFunction %void None %void_func\n" +
5904       "%main_lab = OpLabel\n" +
5905       "%var = OpVariable %_ptr_float Function\n" +
5906       "%2 = OpLoad %float %var\n" +
5907       "%3 = OpFDiv %float %float_2 %2\n" +
5908       "%4 = OpFMul %float %float_2 %3\n" +
5909       "OpReturn\n" +
5910       "OpFunctionEnd\n",
5911     4, true),
5912   // Test case 9: merge fmul of fdiv
5913   // (2.0 / x) * 2.0 = 4.0 / x
5914   InstructionFoldingCase<bool>(
5915     Header() +
5916       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5917       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5918       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5919       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5920       "%main = OpFunction %void None %void_func\n" +
5921       "%main_lab = OpLabel\n" +
5922       "%var = OpVariable %_ptr_float Function\n" +
5923       "%2 = OpLoad %float %var\n" +
5924       "%3 = OpFDiv %float %float_2 %2\n" +
5925       "%4 = OpFMul %float %3 %float_2\n" +
5926       "OpReturn\n" +
5927       "OpFunctionEnd\n",
5928     4, true),
5929   // Test case 10: Do not merge imul of sdiv
5930   // 4 * (x / 2)
5931   InstructionFoldingCase<bool>(
5932     Header() +
5933       "%main = OpFunction %void None %void_func\n" +
5934       "%main_lab = OpLabel\n" +
5935       "%var = OpVariable %_ptr_int Function\n" +
5936       "%2 = OpLoad %int %var\n" +
5937       "%3 = OpSDiv %int %2 %int_2\n" +
5938       "%4 = OpIMul %int %int_4 %3\n" +
5939       "OpReturn\n" +
5940       "OpFunctionEnd\n",
5941     4, false),
5942   // Test case 11: Do not merge imul of sdiv
5943   // (x / 2) * 4
5944   InstructionFoldingCase<bool>(
5945     Header() +
5946       "%main = OpFunction %void None %void_func\n" +
5947       "%main_lab = OpLabel\n" +
5948       "%var = OpVariable %_ptr_int Function\n" +
5949       "%2 = OpLoad %int %var\n" +
5950       "%3 = OpSDiv %int %2 %int_2\n" +
5951       "%4 = OpIMul %int %3 %int_4\n" +
5952       "OpReturn\n" +
5953       "OpFunctionEnd\n",
5954     4, false),
5955   // Test case 12: Do not merge imul of udiv
5956   // 4 * (x / 2)
5957   InstructionFoldingCase<bool>(
5958     Header() +
5959       "%main = OpFunction %void None %void_func\n" +
5960       "%main_lab = OpLabel\n" +
5961       "%var = OpVariable %_ptr_uint Function\n" +
5962       "%2 = OpLoad %uint %var\n" +
5963       "%3 = OpUDiv %uint %2 %uint_2\n" +
5964       "%4 = OpIMul %uint %uint_4 %3\n" +
5965       "OpReturn\n" +
5966       "OpFunctionEnd\n",
5967     4, false),
5968   // Test case 13: Do not merge imul of udiv
5969   // (x / 2) * 4
5970   InstructionFoldingCase<bool>(
5971     Header() +
5972       "%main = OpFunction %void None %void_func\n" +
5973       "%main_lab = OpLabel\n" +
5974       "%var = OpVariable %_ptr_uint Function\n" +
5975       "%2 = OpLoad %uint %var\n" +
5976       "%3 = OpUDiv %uint %2 %uint_2\n" +
5977       "%4 = OpIMul %uint %3 %uint_4\n" +
5978       "OpReturn\n" +
5979       "OpFunctionEnd\n",
5980     4, false),
5981   // Test case 14: Don't fold
5982   // (x / 3) * 4
5983   InstructionFoldingCase<bool>(
5984     Header() +
5985       "%main = OpFunction %void None %void_func\n" +
5986       "%main_lab = OpLabel\n" +
5987       "%var = OpVariable %_ptr_uint Function\n" +
5988       "%2 = OpLoad %uint %var\n" +
5989       "%3 = OpUDiv %uint %2 %uint_3\n" +
5990       "%4 = OpIMul %uint %3 %uint_4\n" +
5991       "OpReturn\n" +
5992       "OpFunctionEnd\n",
5993     4, false),
5994   // Test case 15: merge vector fmul of fdiv
5995   // (x / {2,2}) * {4,4} = x * {2,2}
5996   InstructionFoldingCase<bool>(
5997     Header() +
5998       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5999       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6000       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6001       "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
6002       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
6003       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
6004       "%main = OpFunction %void None %void_func\n" +
6005       "%main_lab = OpLabel\n" +
6006       "%var = OpVariable %_ptr_v2float Function\n" +
6007       "%2 = OpLoad %v2float %var\n" +
6008       "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
6009       "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
6010       "OpReturn\n" +
6011       "OpFunctionEnd\n",
6012     4, true),
6013   // Test case 16: merge vector imul of snegate
6014   // (-x) * {2,2} = x * {-2,-2}
6015   InstructionFoldingCase<bool>(
6016     Header() +
6017       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6018       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6019       "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6020       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6021       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6022       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6023       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6024       "%main = OpFunction %void None %void_func\n" +
6025       "%main_lab = OpLabel\n" +
6026       "%var = OpVariable %_ptr_v2int Function\n" +
6027       "%2 = OpLoad %v2int %var\n" +
6028       "%3 = OpSNegate %v2int %2\n" +
6029       "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
6030       "OpReturn\n" +
6031       "OpFunctionEnd\n",
6032     4, true),
6033   // Test case 17: merge vector imul of snegate
6034   // {2,2} * (-x) = x * {-2,-2}
6035   InstructionFoldingCase<bool>(
6036     Header() +
6037       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6038       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6039       "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6040       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6041       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6042       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6043       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6044       "%main = OpFunction %void None %void_func\n" +
6045       "%main_lab = OpLabel\n" +
6046       "%var = OpVariable %_ptr_v2int Function\n" +
6047       "%2 = OpLoad %v2int %var\n" +
6048       "%3 = OpSNegate %v2int %2\n" +
6049       "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
6050       "OpReturn\n" +
6051       "OpFunctionEnd\n",
6052     4, true),
6053   // Test case 18: Fold OpVectorTimesScalar
6054   // {4,4} = OpVectorTimesScalar v2float {2,2} 2
6055   InstructionFoldingCase<bool>(
6056     Header() +
6057       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6058       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6059       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
6060       "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
6061       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
6062       "%main = OpFunction %void None %void_func\n" +
6063       "%main_lab = OpLabel\n" +
6064       "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
6065       "OpReturn\n" +
6066       "OpFunctionEnd",
6067     2, true),
6068   // Test case 19: Fold OpVectorTimesScalar
6069   // {0,0} = OpVectorTimesScalar v2float v2float_null -1
6070   InstructionFoldingCase<bool>(
6071     Header() +
6072       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6073       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6074       "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
6075       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
6076       "%main = OpFunction %void None %void_func\n" +
6077       "%main_lab = OpLabel\n" +
6078       "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
6079       "OpReturn\n" +
6080       "OpFunctionEnd",
6081     2, true),
6082   // Test case 20: Fold OpVectorTimesScalar
6083   // {4,4} = OpVectorTimesScalar v2double {2,2} 2
6084   InstructionFoldingCase<bool>(
6085     Header() +
6086       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6087       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6088       "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
6089       "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
6090       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
6091       "%main = OpFunction %void None %void_func\n" +
6092       "%main_lab = OpLabel\n" +
6093       "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
6094       "OpReturn\n" +
6095       "OpFunctionEnd",
6096     2, true),
6097   // Test case 21: Fold OpVectorTimesScalar
6098   // {0,0} = OpVectorTimesScalar v2double {0,0} n
6099   InstructionFoldingCase<bool>(
6100     Header() +
6101         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6102         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6103         "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
6104         "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
6105         "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
6106         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
6107         "%main = OpFunction %void None %void_func\n" +
6108         "%main_lab = OpLabel\n" +
6109         "%n = OpVariable %_ptr_double Function\n" +
6110         "%load = OpLoad %double %n\n" +
6111         "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
6112         "OpReturn\n" +
6113         "OpFunctionEnd",
6114     2, true),
6115   // Test case 22: Fold OpVectorTimesScalar
6116   // {0,0} = OpVectorTimesScalar v2double n 0
6117   InstructionFoldingCase<bool>(
6118     Header() +
6119         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6120         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6121         "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
6122         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
6123         "%main = OpFunction %void None %void_func\n" +
6124         "%main_lab = OpLabel\n" +
6125         "%n = OpVariable %_ptr_v2double Function\n" +
6126         "%load = OpLoad %v2double %n\n" +
6127         "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
6128         "OpReturn\n" +
6129         "OpFunctionEnd",
6130     2, true),
6131   // Test case 23: merge fmul of fdiv
6132   // x * (y / x) = y
6133   InstructionFoldingCase<bool>(
6134     Header() +
6135         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6136         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6137         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6138         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6139         "%main = OpFunction %void None %void_func\n" +
6140         "%main_lab = OpLabel\n" +
6141         "%x = OpVariable %_ptr_float Function\n" +
6142         "%y = OpVariable %_ptr_float Function\n" +
6143         "%2 = OpLoad %float %x\n" +
6144         "%3 = OpLoad %float %y\n" +
6145         "%4 = OpFDiv %float %3 %2\n" +
6146         "%5 = OpFMul %float %2 %4\n" +
6147         "OpReturn\n" +
6148         "OpFunctionEnd\n",
6149     5, true),
6150   // Test case 24: merge fmul of fdiv
6151   // (y / x) * x = y
6152   InstructionFoldingCase<bool>(
6153     Header() +
6154         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6155         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6156         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6157         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6158         "%main = OpFunction %void None %void_func\n" +
6159         "%main_lab = OpLabel\n" +
6160         "%x = OpVariable %_ptr_float Function\n" +
6161         "%y = OpVariable %_ptr_float Function\n" +
6162         "%2 = OpLoad %float %x\n" +
6163         "%3 = OpLoad %float %y\n" +
6164         "%4 = OpFDiv %float %3 %2\n" +
6165         "%5 = OpFMul %float %4 %2\n" +
6166         "OpReturn\n" +
6167         "OpFunctionEnd\n",
6168     5, true),
6169   // Test case 25: fold overflowing signed 32 bit imuls
6170   // (x * 1073741824) * 2 = x * int_min
6171   InstructionFoldingCase<bool>(
6172     Header() +
6173       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6174       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6175       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6176       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" +
6177       "%main = OpFunction %void None %void_func\n" +
6178       "%main_lab = OpLabel\n" +
6179       "%var = OpVariable %_ptr_int Function\n" +
6180       "%2 = OpLoad %int %var\n" +
6181       "%3 = OpIMul %int %2 %int_1073741824\n" +
6182       "%4 = OpIMul %int %3 %int_2\n" +
6183       "OpReturn\n" +
6184       "OpFunctionEnd\n",
6185     4, true),
6186   // Test case 26: fold overflowing signed 64 bit imuls
6187   // (x * 4611686018427387904) * 2 = x * long_min
6188   InstructionFoldingCase<bool>(
6189     Header() +
6190       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6191       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6192       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6193       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" +
6194       "%main = OpFunction %void None %void_func\n" +
6195       "%main_lab = OpLabel\n" +
6196       "%var = OpVariable %_ptr_long Function\n" +
6197       "%2 = OpLoad %long %var\n" +
6198       "%3 = OpIMul %long %2 %long_4611686018427387904\n" +
6199       "%4 = OpIMul %long %3 %long_2\n" +
6200       "OpReturn\n" +
6201       "OpFunctionEnd\n",
6202     4, true),
6203   // Test case 27: fold overflowing 32 bit unsigned imuls
6204   // (x * 2147483649) * 2 = x * 2
6205   InstructionFoldingCase<bool>(
6206     Header() +
6207       "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6208       "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" +
6209       "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6210       "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" +
6211       "%main = OpFunction %void None %void_func\n" +
6212       "%main_lab = OpLabel\n" +
6213       "%var = OpVariable %_ptr_uint Function\n" +
6214       "%2 = OpLoad %uint %var\n" +
6215       "%3 = OpIMul %uint %2 %uint_2147483649\n" +
6216       "%4 = OpIMul %uint %3 %uint_2\n" +
6217       "OpReturn\n" +
6218       "OpFunctionEnd\n",
6219     4, true),
6220   // Test case 28: fold overflowing 64 bit unsigned imuls
6221   // (x * 9223372036854775809) * 2 = x * 2
6222   InstructionFoldingCase<bool>(
6223     Header() +
6224       "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6225       "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" +
6226       "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6227       "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" +
6228       "%main = OpFunction %void None %void_func\n" +
6229       "%main_lab = OpLabel\n" +
6230       "%var = OpVariable %_ptr_ulong Function\n" +
6231       "%2 = OpLoad %ulong %var\n" +
6232       "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" +
6233       "%4 = OpIMul %ulong %3 %ulong_2\n" +
6234       "OpReturn\n" +
6235       "OpFunctionEnd\n",
6236     4, true),
6237   // Test case 29: fold underflowing signed 32 bit imuls
6238   // (x * (-858993459)) * 10 = x * 2
6239   InstructionFoldingCase<bool>(
6240     Header() +
6241       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6242       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
6243       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6244       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" +
6245       "%main = OpFunction %void None %void_func\n" +
6246       "%main_lab = OpLabel\n" +
6247       "%var = OpVariable %_ptr_int Function\n" +
6248       "%2 = OpLoad %int %var\n" +
6249       "%3 = OpIMul %int %2 %int_n858993459\n" +
6250       "%4 = OpIMul %int %3 %int_10\n" +
6251       "OpReturn\n" +
6252       "OpFunctionEnd\n",
6253     4, true),
6254   // Test case 30: fold underflowing signed 64 bit imuls
6255   // (x * (-3689348814741910323)) * 10 = x * 2
6256   InstructionFoldingCase<bool>(
6257     Header() +
6258       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6259       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6260       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6261       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" +
6262       "%main = OpFunction %void None %void_func\n" +
6263       "%main_lab = OpLabel\n" +
6264       "%var = OpVariable %_ptr_long Function\n" +
6265       "%2 = OpLoad %long %var\n" +
6266       "%3 = OpIMul %long %2 %long_n3689348814741910323\n" +
6267       "%4 = OpIMul %long %3 %long_10\n" +
6268       "OpReturn\n" +
6269       "OpFunctionEnd\n",
6270     4, true)
6271 ));
6272 
6273 INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest,
6274 ::testing::Values(
6275   // Test case 0: merge consecutive fdiv
6276   // 4.0 / (2.0 / x) = 2.0 * x
6277   InstructionFoldingCase<bool>(
6278     Header() +
6279       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6280       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6281       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6282       "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
6283       "%main = OpFunction %void None %void_func\n" +
6284       "%main_lab = OpLabel\n" +
6285       "%var = OpVariable %_ptr_float Function\n" +
6286       "%2 = OpLoad %float %var\n" +
6287       "%3 = OpFDiv %float %float_2 %2\n" +
6288       "%4 = OpFDiv %float %float_4 %3\n" +
6289       "OpReturn\n" +
6290       "OpFunctionEnd\n",
6291     4, true),
6292   // Test case 1: merge consecutive fdiv
6293   // 4.0 / (x / 2.0) = 8.0 / x
6294   InstructionFoldingCase<bool>(
6295     Header() +
6296       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6297       "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
6298       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6299       "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
6300       "%main = OpFunction %void None %void_func\n" +
6301       "%main_lab = OpLabel\n" +
6302       "%var = OpVariable %_ptr_float Function\n" +
6303       "%2 = OpLoad %float %var\n" +
6304       "%3 = OpFDiv %float %2 %float_2\n" +
6305       "%4 = OpFDiv %float %float_4 %3\n" +
6306       "OpReturn\n" +
6307       "OpFunctionEnd\n",
6308     4, true),
6309   // Test case 2: merge consecutive fdiv
6310   // (4.0 / x) / 2.0 = 2.0 / x
6311   InstructionFoldingCase<bool>(
6312     Header() +
6313       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6314       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6315       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6316       "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
6317       "%main = OpFunction %void None %void_func\n" +
6318       "%main_lab = OpLabel\n" +
6319       "%var = OpVariable %_ptr_float Function\n" +
6320       "%2 = OpLoad %float %var\n" +
6321       "%3 = OpFDiv %float %float_4 %2\n" +
6322       "%4 = OpFDiv %float %3 %float_2\n" +
6323       "OpReturn\n" +
6324       "OpFunctionEnd\n",
6325     4, true),
6326   // Test case 3: Do not merge consecutive sdiv
6327   // 4 / (2 / x)
6328   InstructionFoldingCase<bool>(
6329     Header() +
6330       "%main = OpFunction %void None %void_func\n" +
6331       "%main_lab = OpLabel\n" +
6332       "%var = OpVariable %_ptr_int Function\n" +
6333       "%2 = OpLoad %int %var\n" +
6334       "%3 = OpSDiv %int %int_2 %2\n" +
6335       "%4 = OpSDiv %int %int_4 %3\n" +
6336       "OpReturn\n" +
6337       "OpFunctionEnd\n",
6338     4, false),
6339   // Test case 4: Do not merge consecutive sdiv
6340   // 4 / (x / 2)
6341   InstructionFoldingCase<bool>(
6342     Header() +
6343       "%main = OpFunction %void None %void_func\n" +
6344       "%main_lab = OpLabel\n" +
6345       "%var = OpVariable %_ptr_int Function\n" +
6346       "%2 = OpLoad %int %var\n" +
6347       "%3 = OpSDiv %int %2 %int_2\n" +
6348       "%4 = OpSDiv %int %int_4 %3\n" +
6349       "OpReturn\n" +
6350       "OpFunctionEnd\n",
6351     4, false),
6352   // Test case 5: Do not merge consecutive sdiv
6353   // (4 / x) / 2
6354   InstructionFoldingCase<bool>(
6355     Header() +
6356       "%main = OpFunction %void None %void_func\n" +
6357       "%main_lab = OpLabel\n" +
6358       "%var = OpVariable %_ptr_int Function\n" +
6359       "%2 = OpLoad %int %var\n" +
6360       "%3 = OpSDiv %int %int_4 %2\n" +
6361       "%4 = OpSDiv %int %3 %int_2\n" +
6362       "OpReturn\n" +
6363       "OpFunctionEnd\n",
6364     4, false),
6365   // Test case 6: Do not merge consecutive sdiv
6366   // (x / 4) / 2
6367   InstructionFoldingCase<bool>(
6368     Header() +
6369       "%main = OpFunction %void None %void_func\n" +
6370       "%main_lab = OpLabel\n" +
6371       "%var = OpVariable %_ptr_int Function\n" +
6372       "%2 = OpLoad %int %var\n" +
6373       "%3 = OpSDiv %int %2 %int_4\n" +
6374       "%4 = OpSDiv %int %3 %int_2\n" +
6375       "OpReturn\n" +
6376       "OpFunctionEnd\n",
6377     4, false),
6378   // Test case 7: Do not merge sdiv of imul
6379   // 4 / (2 * x)
6380   InstructionFoldingCase<bool>(
6381     Header() +
6382       "%main = OpFunction %void None %void_func\n" +
6383       "%main_lab = OpLabel\n" +
6384       "%var = OpVariable %_ptr_int Function\n" +
6385       "%2 = OpLoad %int %var\n" +
6386       "%3 = OpIMul %int %int_2 %2\n" +
6387       "%4 = OpSDiv %int %int_4 %3\n" +
6388       "OpReturn\n" +
6389       "OpFunctionEnd\n",
6390     4, false),
6391   // Test case 8: Do not merge sdiv of imul
6392   // 4 / (x * 2)
6393   InstructionFoldingCase<bool>(
6394     Header() +
6395       "%main = OpFunction %void None %void_func\n" +
6396       "%main_lab = OpLabel\n" +
6397       "%var = OpVariable %_ptr_int Function\n" +
6398       "%2 = OpLoad %int %var\n" +
6399       "%3 = OpIMul %int %2 %int_2\n" +
6400       "%4 = OpSDiv %int %int_4 %3\n" +
6401       "OpReturn\n" +
6402       "OpFunctionEnd\n",
6403     4, false),
6404   // Test case 9: Do not merge sdiv of imul
6405   // (4 * x) / 2
6406   InstructionFoldingCase<bool>(
6407     Header() +
6408       "%main = OpFunction %void None %void_func\n" +
6409       "%main_lab = OpLabel\n" +
6410       "%var = OpVariable %_ptr_int Function\n" +
6411       "%2 = OpLoad %int %var\n" +
6412       "%3 = OpIMul %int %int_4 %2\n" +
6413       "%4 = OpSDiv %int %3 %int_2\n" +
6414       "OpReturn\n" +
6415       "OpFunctionEnd\n",
6416     4, false),
6417   // Test case 10: Do not merge sdiv of imul
6418   // (x * 4) / 2
6419   InstructionFoldingCase<bool>(
6420     Header() +
6421       "%main = OpFunction %void None %void_func\n" +
6422       "%main_lab = OpLabel\n" +
6423       "%var = OpVariable %_ptr_int Function\n" +
6424       "%2 = OpLoad %int %var\n" +
6425       "%3 = OpIMul %int %2 %int_4\n" +
6426       "%4 = OpSDiv %int %3 %int_2\n" +
6427       "OpReturn\n" +
6428       "OpFunctionEnd\n",
6429     4, false),
6430   // Test case 11: Do not merge sdiv of snegate.  If %2 is INT_MIN, then the
6431   // sign of %3 will be the same as %2.  This cannot be accounted for in OpSDiv.
6432   // Specifically, (-INT_MIN) / 2 != INT_MIN / -2.
6433   InstructionFoldingCase<bool>(
6434     Header() +
6435       "%main = OpFunction %void None %void_func\n" +
6436       "%main_lab = OpLabel\n" +
6437       "%var = OpVariable %_ptr_int Function\n" +
6438       "%2 = OpLoad %int %var\n" +
6439       "%3 = OpSNegate %int %2\n" +
6440       "%4 = OpSDiv %int %3 %int_2\n" +
6441       "OpReturn\n" +
6442       "OpFunctionEnd\n",
6443     4, false),
6444   // Test case 12: Do not merge sdiv of snegate.  If %2 is INT_MIN, then the
6445   // sign of %3 will be the same as %2.  This cannot be accounted for in OpSDiv.
6446   // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN.
6447   InstructionFoldingCase<bool>(
6448     Header() +
6449       "%main = OpFunction %void None %void_func\n" +
6450       "%main_lab = OpLabel\n" +
6451       "%var = OpVariable %_ptr_int Function\n" +
6452       "%2 = OpLoad %int %var\n" +
6453       "%3 = OpSNegate %int %2\n" +
6454       "%4 = OpSDiv %int %int_2 %3\n" +
6455       "OpReturn\n" +
6456       "OpFunctionEnd\n",
6457     4, false),
6458   // Test case 13: Don't merge
6459   // (x / {null}) / {null}
6460   InstructionFoldingCase<bool>(
6461     Header() +
6462       "%main = OpFunction %void None %void_func\n" +
6463       "%main_lab = OpLabel\n" +
6464       "%var = OpVariable %_ptr_v2float Function\n" +
6465       "%2 = OpLoad %float %var\n" +
6466       "%3 = OpFDiv %float %2 %v2float_null\n" +
6467       "%4 = OpFDiv %float %3 %v2float_null\n" +
6468       "OpReturn\n" +
6469       "OpFunctionEnd\n",
6470     4, false),
6471   // Test case 14: merge fmul of fdiv
6472   // (y * x) / x = y
6473   InstructionFoldingCase<bool>(
6474     Header() +
6475         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6476         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6477         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6478         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6479         "%main = OpFunction %void None %void_func\n" +
6480         "%main_lab = OpLabel\n" +
6481         "%x = OpVariable %_ptr_float Function\n" +
6482         "%y = OpVariable %_ptr_float Function\n" +
6483         "%2 = OpLoad %float %x\n" +
6484         "%3 = OpLoad %float %y\n" +
6485         "%4 = OpFMul %float %3 %2\n" +
6486         "%5 = OpFDiv %float %4 %2\n" +
6487         "OpReturn\n" +
6488         "OpFunctionEnd\n",
6489     5, true),
6490   // Test case 15: merge fmul of fdiv
6491   // (x * y) / x = y
6492   InstructionFoldingCase<bool>(
6493     Header() +
6494         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6495         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6496         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6497         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6498         "%main = OpFunction %void None %void_func\n" +
6499         "%main_lab = OpLabel\n" +
6500         "%x = OpVariable %_ptr_float Function\n" +
6501         "%y = OpVariable %_ptr_float Function\n" +
6502         "%2 = OpLoad %float %x\n" +
6503         "%3 = OpLoad %float %y\n" +
6504         "%4 = OpFMul %float %2 %3\n" +
6505         "%5 = OpFDiv %float %4 %2\n" +
6506         "OpReturn\n" +
6507         "OpFunctionEnd\n",
6508     5, true),
6509   // Test case 16: Do not merge udiv of snegate
6510   // (-x) / 2u
6511   InstructionFoldingCase<bool>(
6512     Header() +
6513       "%main = OpFunction %void None %void_func\n" +
6514       "%main_lab = OpLabel\n" +
6515       "%var = OpVariable %_ptr_uint Function\n" +
6516       "%2 = OpLoad %uint %var\n" +
6517       "%3 = OpSNegate %uint %2\n" +
6518       "%4 = OpUDiv %uint %3 %uint_2\n" +
6519       "OpReturn\n" +
6520       "OpFunctionEnd\n",
6521     4, false),
6522   // Test case 17: Do not merge udiv of snegate
6523   // 2u / (-x)
6524   InstructionFoldingCase<bool>(
6525     Header() +
6526       "%main = OpFunction %void None %void_func\n" +
6527       "%main_lab = OpLabel\n" +
6528       "%var = OpVariable %_ptr_uint Function\n" +
6529       "%2 = OpLoad %uint %var\n" +
6530       "%3 = OpSNegate %uint %2\n" +
6531       "%4 = OpUDiv %uint %uint_2 %3\n" +
6532       "OpReturn\n" +
6533       "OpFunctionEnd\n",
6534     4, false)
6535 ));
6536 
6537 INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest,
6538 ::testing::Values(
6539   // Test case 0: merge add of negate
6540   // (-x) + 2 = 2 - x
6541   InstructionFoldingCase<bool>(
6542     Header() +
6543       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6544       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6545       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6546       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6547       "%main = OpFunction %void None %void_func\n" +
6548       "%main_lab = OpLabel\n" +
6549       "%var = OpVariable %_ptr_float Function\n" +
6550       "%2 = OpLoad %float %var\n" +
6551       "%3 = OpFNegate %float %2\n" +
6552       "%4 = OpFAdd %float %3 %float_2\n" +
6553       "OpReturn\n" +
6554       "OpFunctionEnd\n",
6555     4, true),
6556   // Test case 1: merge add of negate
6557   // 2 + (-x) = 2 - x
6558   InstructionFoldingCase<bool>(
6559     Header() +
6560       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6561       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6562       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6563       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6564       "%main = OpFunction %void None %void_func\n" +
6565       "%main_lab = OpLabel\n" +
6566       "%var = OpVariable %_ptr_float Function\n" +
6567       "%2 = OpLoad %float %var\n" +
6568       "%3 = OpSNegate %float %2\n" +
6569       "%4 = OpIAdd %float %float_2 %3\n" +
6570       "OpReturn\n" +
6571       "OpFunctionEnd\n",
6572     4, true),
6573   // Test case 2: merge add of negate
6574   // (-x) + 2 = 2 - x
6575   InstructionFoldingCase<bool>(
6576     Header() +
6577       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6578       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6579       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6580       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6581       "%main = OpFunction %void None %void_func\n" +
6582       "%main_lab = OpLabel\n" +
6583       "%var = OpVariable %_ptr_long Function\n" +
6584       "%2 = OpLoad %long %var\n" +
6585       "%3 = OpSNegate %long %2\n" +
6586       "%4 = OpIAdd %long %3 %long_2\n" +
6587       "OpReturn\n" +
6588       "OpFunctionEnd\n",
6589     4, true),
6590   // Test case 3: merge add of negate
6591   // 2 + (-x) = 2 - x
6592   InstructionFoldingCase<bool>(
6593     Header() +
6594       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6595       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6596       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6597       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6598       "%main = OpFunction %void None %void_func\n" +
6599       "%main_lab = OpLabel\n" +
6600       "%var = OpVariable %_ptr_long Function\n" +
6601       "%2 = OpLoad %long %var\n" +
6602       "%3 = OpSNegate %long %2\n" +
6603       "%4 = OpIAdd %long %long_2 %3\n" +
6604       "OpReturn\n" +
6605       "OpFunctionEnd\n",
6606     4, true),
6607   // Test case 4: merge add of subtract
6608   // (x - 1) + 2 = x + 1
6609   InstructionFoldingCase<bool>(
6610     Header() +
6611       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6612       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6613       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6614       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6615       "%main = OpFunction %void None %void_func\n" +
6616       "%main_lab = OpLabel\n" +
6617       "%var = OpVariable %_ptr_float Function\n" +
6618       "%2 = OpLoad %float %var\n" +
6619       "%3 = OpFSub %float %2 %float_1\n" +
6620       "%4 = OpFAdd %float %3 %float_2\n" +
6621       "OpReturn\n" +
6622       "OpFunctionEnd\n",
6623     4, true),
6624   // Test case 5: merge add of subtract
6625   // (1 - x) + 2 = 3 - x
6626   InstructionFoldingCase<bool>(
6627     Header() +
6628       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6629       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6630       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6631       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6632       "%main = OpFunction %void None %void_func\n" +
6633       "%main_lab = OpLabel\n" +
6634       "%var = OpVariable %_ptr_float Function\n" +
6635       "%2 = OpLoad %float %var\n" +
6636       "%3 = OpFSub %float %float_1 %2\n" +
6637       "%4 = OpFAdd %float %3 %float_2\n" +
6638       "OpReturn\n" +
6639       "OpFunctionEnd\n",
6640     4, true),
6641   // Test case 6: merge add of subtract
6642   // 2 + (x - 1) = x + 1
6643   InstructionFoldingCase<bool>(
6644     Header() +
6645       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6646       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6647       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6648       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6649       "%main = OpFunction %void None %void_func\n" +
6650       "%main_lab = OpLabel\n" +
6651       "%var = OpVariable %_ptr_float Function\n" +
6652       "%2 = OpLoad %float %var\n" +
6653       "%3 = OpFSub %float %2 %float_1\n" +
6654       "%4 = OpFAdd %float %float_2 %3\n" +
6655       "OpReturn\n" +
6656       "OpFunctionEnd\n",
6657     4, true),
6658   // Test case 7: merge add of subtract
6659   // 2 + (1 - x) = 3 - x
6660   InstructionFoldingCase<bool>(
6661     Header() +
6662       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6663       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6664       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6665       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6666       "%main = OpFunction %void None %void_func\n" +
6667       "%main_lab = OpLabel\n" +
6668       "%var = OpVariable %_ptr_float Function\n" +
6669       "%2 = OpLoad %float %var\n" +
6670       "%3 = OpFSub %float %float_1 %2\n" +
6671       "%4 = OpFAdd %float %float_2 %3\n" +
6672       "OpReturn\n" +
6673       "OpFunctionEnd\n",
6674     4, true),
6675   // Test case 8: merge add of add
6676   // (x + 1) + 2 = x + 3
6677   InstructionFoldingCase<bool>(
6678     Header() +
6679       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6680       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6681       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6682       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6683       "%main = OpFunction %void None %void_func\n" +
6684       "%main_lab = OpLabel\n" +
6685       "%var = OpVariable %_ptr_float Function\n" +
6686       "%2 = OpLoad %float %var\n" +
6687       "%3 = OpFAdd %float %2 %float_1\n" +
6688       "%4 = OpFAdd %float %3 %float_2\n" +
6689       "OpReturn\n" +
6690       "OpFunctionEnd\n",
6691     4, true),
6692   // Test case 9: merge add of add
6693   // (1 + x) + 2 = 3 + x
6694   InstructionFoldingCase<bool>(
6695     Header() +
6696       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6697       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6698       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6699       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6700       "%main = OpFunction %void None %void_func\n" +
6701       "%main_lab = OpLabel\n" +
6702       "%var = OpVariable %_ptr_float Function\n" +
6703       "%2 = OpLoad %float %var\n" +
6704       "%3 = OpFAdd %float %float_1 %2\n" +
6705       "%4 = OpFAdd %float %3 %float_2\n" +
6706       "OpReturn\n" +
6707       "OpFunctionEnd\n",
6708     4, true),
6709   // Test case 10: merge add of add
6710   // 2 + (x + 1) = x + 1
6711   InstructionFoldingCase<bool>(
6712     Header() +
6713       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6714       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6715       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6716       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6717       "%main = OpFunction %void None %void_func\n" +
6718       "%main_lab = OpLabel\n" +
6719       "%var = OpVariable %_ptr_float Function\n" +
6720       "%2 = OpLoad %float %var\n" +
6721       "%3 = OpFAdd %float %2 %float_1\n" +
6722       "%4 = OpFAdd %float %float_2 %3\n" +
6723       "OpReturn\n" +
6724       "OpFunctionEnd\n",
6725     4, true),
6726   // Test case 11: merge add of add
6727   // 2 + (1 + x) = 3 - x
6728   InstructionFoldingCase<bool>(
6729     Header() +
6730       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6731       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6732       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6733       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6734       "%main = OpFunction %void None %void_func\n" +
6735       "%main_lab = OpLabel\n" +
6736       "%var = OpVariable %_ptr_float Function\n" +
6737       "%2 = OpLoad %float %var\n" +
6738       "%3 = OpFAdd %float %float_1 %2\n" +
6739       "%4 = OpFAdd %float %float_2 %3\n" +
6740       "OpReturn\n" +
6741       "OpFunctionEnd\n",
6742     4, true),
6743   // Test case 12: fold overflowing signed 32 bit iadds
6744   // (x + int_max) + 1 = x + int_min
6745   InstructionFoldingCase<bool>(
6746     Header() +
6747       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6748       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6749       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6750       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" +
6751       "%main = OpFunction %void None %void_func\n" +
6752       "%main_lab = OpLabel\n" +
6753       "%var = OpVariable %_ptr_int Function\n" +
6754       "%2 = OpLoad %int %var\n" +
6755       "%3 = OpIAdd %int %2 %int_max\n" +
6756       "%4 = OpIAdd %int %3 %int_1\n" +
6757       "OpReturn\n" +
6758       "OpFunctionEnd\n",
6759     4, true),
6760   // Test case 13: fold overflowing signed 64 bit iadds
6761   // (x + long_max) + 1 = x + long_min
6762   InstructionFoldingCase<bool>(
6763     Header() +
6764       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6765       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6766       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6767       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" +
6768       "%main = OpFunction %void None %void_func\n" +
6769       "%main_lab = OpLabel\n" +
6770       "%var = OpVariable %_ptr_long Function\n" +
6771       "%2 = OpLoad %long %var\n" +
6772       "%3 = OpIAdd %long %2 %long_max\n" +
6773       "%4 = OpIAdd %long %3 %long_1\n" +
6774       "OpReturn\n" +
6775       "OpFunctionEnd\n",
6776     4, true),
6777   // Test case 14: fold overflowing 32 bit unsigned iadds
6778   // (x + uint_max) + 2 = x + 1
6779   InstructionFoldingCase<bool>(
6780     Header() +
6781       "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6782       "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
6783       "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6784       "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" +
6785       "%main = OpFunction %void None %void_func\n" +
6786       "%main_lab = OpLabel\n" +
6787       "%var = OpVariable %_ptr_uint Function\n" +
6788       "%2 = OpLoad %uint %var\n" +
6789       "%3 = OpIAdd %uint %2 %uint_max\n" +
6790       "%4 = OpIAdd %uint %3 %uint_2\n" +
6791       "OpReturn\n" +
6792       "OpFunctionEnd\n",
6793     4, true),
6794   // Test case 15: fold overflowing 64 bit unsigned iadds
6795   // (x + ulong_max) + 2 = x + 1
6796   InstructionFoldingCase<bool>(
6797     Header() +
6798       "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6799       "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" +
6800       "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6801       "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" +
6802       "%main = OpFunction %void None %void_func\n" +
6803       "%main_lab = OpLabel\n" +
6804       "%var = OpVariable %_ptr_ulong Function\n" +
6805       "%2 = OpLoad %ulong %var\n" +
6806       "%3 = OpIAdd %ulong %2 %ulong_max\n" +
6807       "%4 = OpIAdd %ulong %3 %ulong_2\n" +
6808       "OpReturn\n" +
6809       "OpFunctionEnd\n",
6810     4, true),
6811   // Test case 16: fold underflowing signed 32 bit iadds
6812   // (x + int_min) + (-1) = x + int_max
6813   InstructionFoldingCase<bool>(
6814     Header() +
6815       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6816       "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" +
6817       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6818       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" +
6819       "%main = OpFunction %void None %void_func\n" +
6820       "%main_lab = OpLabel\n" +
6821       "%var = OpVariable %_ptr_int Function\n" +
6822       "%2 = OpLoad %int %var\n" +
6823       "%3 = OpIAdd %int %2 %int_min\n" +
6824       "%4 = OpIAdd %int %3 %int_n1\n" +
6825       "OpReturn\n" +
6826       "OpFunctionEnd\n",
6827     4, true),
6828   // Test case 17: fold underflowing signed 64 bit iadds
6829   // (x + long_min) + (-1) = x + long_max
6830   InstructionFoldingCase<bool>(
6831     Header() +
6832       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6833       "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" +
6834       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6835       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" +
6836       "%main = OpFunction %void None %void_func\n" +
6837       "%main_lab = OpLabel\n" +
6838       "%var = OpVariable %_ptr_long Function\n" +
6839       "%2 = OpLoad %long %var\n" +
6840       "%3 = OpIAdd %long %2 %long_min\n" +
6841       "%4 = OpIAdd %long %3 %long_n1\n" +
6842       "OpReturn\n" +
6843       "OpFunctionEnd\n",
6844     4, true)
6845 ));
6846 
6847 INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
6848 ::testing::Values(
6849     // Test case 0: merge of add of sub
6850     // (a - b) + b => a
6851     InstructionFoldingCase<bool>(
6852       Header() +
6853       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6854       "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6855       "%main = OpFunction %void None %void_func\n" +
6856       "%main_lab = OpLabel\n" +
6857       "%var0 = OpVariable %_ptr_float Function\n" +
6858       "%var1 = OpVariable %_ptr_float Function\n" +
6859       "%3 = OpLoad %float %var0\n" +
6860       "%4 = OpLoad %float %var1\n" +
6861       "%5 = OpFSub %float %3 %4\n" +
6862       "%6 = OpFAdd %float %5 %4\n" +
6863       "OpReturn\n" +
6864       "OpFunctionEnd\n",
6865       6, true),
6866   // Test case 1: merge of add of sub
6867   // b + (a - b) => a
6868   InstructionFoldingCase<bool>(
6869     Header() +
6870     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6871     "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6872     "%main = OpFunction %void None %void_func\n" +
6873     "%main_lab = OpLabel\n" +
6874     "%var0 = OpVariable %_ptr_float Function\n" +
6875     "%var1 = OpVariable %_ptr_float Function\n" +
6876     "%3 = OpLoad %float %var0\n" +
6877     "%4 = OpLoad %float %var1\n" +
6878     "%5 = OpFSub %float %3 %4\n" +
6879     "%6 = OpFAdd %float %4 %5\n" +
6880     "OpReturn\n" +
6881     "OpFunctionEnd\n",
6882     6, true)
6883 ));
6884 
6885 INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
6886 ::testing::Values(
6887     // Test case 0: factor of add of muls
6888     // (a * b) + (a * c) => a * (b + c)
6889     InstructionFoldingCase<bool>(
6890       Header() +
6891       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6892       "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6893       "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6894       "%main = OpFunction %void None %void_func\n" +
6895       "%main_lab = OpLabel\n" +
6896       "%var0 = OpVariable %_ptr_float Function\n" +
6897       "%var1 = OpVariable %_ptr_float Function\n" +
6898       "%var2 = OpVariable %_ptr_float Function\n" +
6899       "%4 = OpLoad %float %var0\n" +
6900       "%5 = OpLoad %float %var1\n" +
6901       "%6 = OpLoad %float %var2\n" +
6902       "%7 = OpFMul %float %6 %4\n" +
6903       "%8 = OpFMul %float %6 %5\n" +
6904       "%9 = OpFAdd %float %7 %8\n" +
6905       "OpReturn\n" +
6906       "OpFunctionEnd\n",
6907       9, true),
6908   // Test case 1: factor of add of muls
6909   // (b * a) + (a * c) => a * (b + c)
6910   InstructionFoldingCase<bool>(
6911     Header() +
6912     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6913     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6914     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6915     "%main = OpFunction %void None %void_func\n" +
6916     "%main_lab = OpLabel\n" +
6917     "%var0 = OpVariable %_ptr_float Function\n" +
6918     "%var1 = OpVariable %_ptr_float Function\n" +
6919     "%var2 = OpVariable %_ptr_float Function\n" +
6920     "%4 = OpLoad %float %var0\n" +
6921     "%5 = OpLoad %float %var1\n" +
6922     "%6 = OpLoad %float %var2\n" +
6923     "%7 = OpFMul %float %4 %6\n" +
6924     "%8 = OpFMul %float %6 %5\n" +
6925     "%9 = OpFAdd %float %7 %8\n" +
6926     "OpReturn\n" +
6927     "OpFunctionEnd\n",
6928     9, true),
6929   // Test case 2: factor of add of muls
6930   // (a * b) + (c * a) => a * (b + c)
6931   InstructionFoldingCase<bool>(
6932     Header() +
6933     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6934     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6935     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6936     "%main = OpFunction %void None %void_func\n" +
6937     "%main_lab = OpLabel\n" +
6938     "%var0 = OpVariable %_ptr_float Function\n" +
6939     "%var1 = OpVariable %_ptr_float Function\n" +
6940     "%var2 = OpVariable %_ptr_float Function\n" +
6941     "%4 = OpLoad %float %var0\n" +
6942     "%5 = OpLoad %float %var1\n" +
6943     "%6 = OpLoad %float %var2\n" +
6944     "%7 = OpFMul %float %6 %4\n" +
6945     "%8 = OpFMul %float %5 %6\n" +
6946     "%9 = OpFAdd %float %7 %8\n" +
6947     "OpReturn\n" +
6948     "OpFunctionEnd\n",
6949     9, true),
6950   // Test case 3: factor of add of muls
6951   // (b * a) + (c * a) => a * (b + c)
6952   InstructionFoldingCase<bool>(
6953     Header() +
6954     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6955     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6956     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6957     "%main = OpFunction %void None %void_func\n" +
6958     "%main_lab = OpLabel\n" +
6959     "%var0 = OpVariable %_ptr_float Function\n" +
6960     "%var1 = OpVariable %_ptr_float Function\n" +
6961     "%var2 = OpVariable %_ptr_float Function\n" +
6962     "%4 = OpLoad %float %var0\n" +
6963     "%5 = OpLoad %float %var1\n" +
6964     "%6 = OpLoad %float %var2\n" +
6965     "%7 = OpFMul %float %4 %6\n" +
6966     "%8 = OpFMul %float %5 %6\n" +
6967     "%9 = OpFAdd %float %7 %8\n" +
6968     "OpReturn\n" +
6969     "OpFunctionEnd\n",
6970     9, true)
6971 ));
6972 
6973 INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
6974 ::testing::Values(
6975   // Test case 0: merge sub of negate
6976   // (-x) - 2 = -2 - x
6977   InstructionFoldingCase<bool>(
6978     Header() +
6979       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6980       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
6981       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6982       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
6983       "%main = OpFunction %void None %void_func\n" +
6984       "%main_lab = OpLabel\n" +
6985       "%var = OpVariable %_ptr_float Function\n" +
6986       "%2 = OpLoad %float %var\n" +
6987       "%3 = OpFNegate %float %2\n" +
6988       "%4 = OpFSub %float %3 %float_2\n" +
6989       "OpReturn\n" +
6990       "OpFunctionEnd\n",
6991     4, true),
6992   // Test case 1: merge sub of negate
6993   // 2 - (-x) = x + 2
6994   InstructionFoldingCase<bool>(
6995     Header() +
6996       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6997       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6998       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6999       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
7000       "%main = OpFunction %void None %void_func\n" +
7001       "%main_lab = OpLabel\n" +
7002       "%var = OpVariable %_ptr_float Function\n" +
7003       "%2 = OpLoad %float %var\n" +
7004       "%3 = OpFNegate %float %2\n" +
7005       "%4 = OpFSub %float %float_2 %3\n" +
7006       "OpReturn\n" +
7007       "OpFunctionEnd\n",
7008     4, true),
7009   // Test case 2: merge sub of negate
7010   // (-x) - 2 = -2 - x
7011   InstructionFoldingCase<bool>(
7012     Header() +
7013       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7014       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
7015       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7016       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
7017       "%main = OpFunction %void None %void_func\n" +
7018       "%main_lab = OpLabel\n" +
7019       "%var = OpVariable %_ptr_long Function\n" +
7020       "%2 = OpLoad %long %var\n" +
7021       "%3 = OpSNegate %long %2\n" +
7022       "%4 = OpISub %long %3 %long_2\n" +
7023       "OpReturn\n" +
7024       "OpFunctionEnd\n",
7025     4, true),
7026   // Test case 3: merge sub of negate
7027   // 2 - (-x) = x + 2
7028   InstructionFoldingCase<bool>(
7029     Header() +
7030       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7031       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
7032       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7033       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
7034       "%main = OpFunction %void None %void_func\n" +
7035       "%main_lab = OpLabel\n" +
7036       "%var = OpVariable %_ptr_long Function\n" +
7037       "%2 = OpLoad %long %var\n" +
7038       "%3 = OpSNegate %long %2\n" +
7039       "%4 = OpISub %long %long_2 %3\n" +
7040       "OpReturn\n" +
7041       "OpFunctionEnd\n",
7042     4, true),
7043   // Test case 4: merge add of subtract
7044   // (x + 2) - 1 = x + 1
7045   InstructionFoldingCase<bool>(
7046     Header() +
7047       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7048       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7049       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7050       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7051       "%main = OpFunction %void None %void_func\n" +
7052       "%main_lab = OpLabel\n" +
7053       "%var = OpVariable %_ptr_float Function\n" +
7054       "%2 = OpLoad %float %var\n" +
7055       "%3 = OpFAdd %float %2 %float_2\n" +
7056       "%4 = OpFSub %float %3 %float_1\n" +
7057       "OpReturn\n" +
7058       "OpFunctionEnd\n",
7059     4, true),
7060   // Test case 5: merge add of subtract
7061   // (2 + x) - 1 = x + 1
7062   InstructionFoldingCase<bool>(
7063     Header() +
7064       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7065       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7066       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7067       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7068       "%main = OpFunction %void None %void_func\n" +
7069       "%main_lab = OpLabel\n" +
7070       "%var = OpVariable %_ptr_float Function\n" +
7071       "%2 = OpLoad %float %var\n" +
7072       "%3 = OpFAdd %float %float_2 %2\n" +
7073       "%4 = OpFSub %float %3 %float_1\n" +
7074       "OpReturn\n" +
7075       "OpFunctionEnd\n",
7076     4, true),
7077   // Test case 6: merge add of subtract
7078   // 2 - (x + 1) = 1 - x
7079   InstructionFoldingCase<bool>(
7080     Header() +
7081       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7082       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7083       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7084       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7085       "%main = OpFunction %void None %void_func\n" +
7086       "%main_lab = OpLabel\n" +
7087       "%var = OpVariable %_ptr_float Function\n" +
7088       "%2 = OpLoad %float %var\n" +
7089       "%3 = OpFAdd %float %2 %float_1\n" +
7090       "%4 = OpFSub %float %float_2 %3\n" +
7091       "OpReturn\n" +
7092       "OpFunctionEnd\n",
7093     4, true),
7094   // Test case 7: merge add of subtract
7095   // 2 - (1 + x) = 1 - x
7096   InstructionFoldingCase<bool>(
7097     Header() +
7098       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7099       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7100       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7101       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7102       "%main = OpFunction %void None %void_func\n" +
7103       "%main_lab = OpLabel\n" +
7104       "%var = OpVariable %_ptr_float Function\n" +
7105       "%2 = OpLoad %float %var\n" +
7106       "%3 = OpFAdd %float %float_1 %2\n" +
7107       "%4 = OpFSub %float %float_2 %3\n" +
7108       "OpReturn\n" +
7109       "OpFunctionEnd\n",
7110     4, true),
7111   // Test case 8: merge subtract of subtract
7112   // (x - 2) - 1 = x - 3
7113   InstructionFoldingCase<bool>(
7114     Header() +
7115       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7116       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7117       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7118       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
7119       "%main = OpFunction %void None %void_func\n" +
7120       "%main_lab = OpLabel\n" +
7121       "%var = OpVariable %_ptr_float Function\n" +
7122       "%2 = OpLoad %float %var\n" +
7123       "%3 = OpFSub %float %2 %float_2\n" +
7124       "%4 = OpFSub %float %3 %float_1\n" +
7125       "OpReturn\n" +
7126       "OpFunctionEnd\n",
7127     4, true),
7128   // Test case 9: merge subtract of subtract
7129   // (2 - x) - 1 = 1 - x
7130   InstructionFoldingCase<bool>(
7131     Header() +
7132       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7133       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7134       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7135       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7136       "%main = OpFunction %void None %void_func\n" +
7137       "%main_lab = OpLabel\n" +
7138       "%var = OpVariable %_ptr_float Function\n" +
7139       "%2 = OpLoad %float %var\n" +
7140       "%3 = OpFSub %float %float_2 %2\n" +
7141       "%4 = OpFSub %float %3 %float_1\n" +
7142       "OpReturn\n" +
7143       "OpFunctionEnd\n",
7144     4, true),
7145   // Test case 10: merge subtract of subtract
7146   // 2 - (x - 1) = 3 - x
7147   InstructionFoldingCase<bool>(
7148     Header() +
7149       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7150       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7151       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7152       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
7153       "%main = OpFunction %void None %void_func\n" +
7154       "%main_lab = OpLabel\n" +
7155       "%var = OpVariable %_ptr_float Function\n" +
7156       "%2 = OpLoad %float %var\n" +
7157       "%3 = OpFSub %float %2 %float_1\n" +
7158       "%4 = OpFSub %float %float_2 %3\n" +
7159       "OpReturn\n" +
7160       "OpFunctionEnd\n",
7161     4, true),
7162   // Test case 11: merge subtract of subtract
7163   // 1 - (2 - x) = x + (-1)
7164   InstructionFoldingCase<bool>(
7165     Header() +
7166       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7167       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
7168       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7169       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
7170       "%main = OpFunction %void None %void_func\n" +
7171       "%main_lab = OpLabel\n" +
7172       "%var = OpVariable %_ptr_float Function\n" +
7173       "%2 = OpLoad %float %var\n" +
7174       "%3 = OpFSub %float %float_2 %2\n" +
7175       "%4 = OpFSub %float %float_1 %3\n" +
7176       "OpReturn\n" +
7177       "OpFunctionEnd\n",
7178     4, true),
7179   // Test case 12: merge subtract of subtract
7180   // 2 - (1 - x) = x + 1
7181   InstructionFoldingCase<bool>(
7182     Header() +
7183       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7184       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7185       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7186       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7187       "%main = OpFunction %void None %void_func\n" +
7188       "%main_lab = OpLabel\n" +
7189       "%var = OpVariable %_ptr_float Function\n" +
7190       "%2 = OpLoad %float %var\n" +
7191       "%3 = OpFSub %float %float_1 %2\n" +
7192       "%4 = OpFSub %float %float_2 %3\n" +
7193       "OpReturn\n" +
7194       "OpFunctionEnd\n",
7195     4, true),
7196   // Test case 13: merge subtract of subtract with mixed types.
7197   // 2 - (1 - x) = x + 1
7198   InstructionFoldingCase<bool>(
7199     Header() +
7200       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7201       "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" +
7202       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7203       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" +
7204       "%main = OpFunction %void None %void_func\n" +
7205       "%main_lab = OpLabel\n" +
7206       "%var = OpVariable %_ptr_int Function\n" +
7207       "%2 = OpLoad %int %var\n" +
7208       "%3 = OpISub %int %uint_1 %2\n" +
7209       "%4 = OpISub %int %int_2 %3\n" +
7210       "OpReturn\n" +
7211       "OpFunctionEnd\n",
7212     4, true),
7213   // Test case 14: fold overflowing signed 32 bit isubs
7214   // (x - int_max) - 1 = x - int_min
7215   InstructionFoldingCase<bool>(
7216     Header() +
7217       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
7218       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
7219       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7220       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" +
7221       "%main = OpFunction %void None %void_func\n" +
7222       "%main_lab = OpLabel\n" +
7223       "%var = OpVariable %_ptr_int Function\n" +
7224       "%2 = OpLoad %int %var\n" +
7225       "%3 = OpISub %int %2 %int_max\n" +
7226       "%4 = OpISub %int %3 %int_1\n" +
7227       "OpReturn\n" +
7228       "OpFunctionEnd\n",
7229     4, true),
7230   // Test case 15: fold overflowing signed 64 bit isubs
7231   // (x - long_max) - 1 = x - long_min
7232   InstructionFoldingCase<bool>(
7233     Header() +
7234       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
7235       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
7236       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7237       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" +
7238       "%main = OpFunction %void None %void_func\n" +
7239       "%main_lab = OpLabel\n" +
7240       "%var = OpVariable %_ptr_long Function\n" +
7241       "%2 = OpLoad %long %var\n" +
7242       "%3 = OpISub %long %2 %long_max\n" +
7243       "%4 = OpISub %long %3 %long_1\n" +
7244       "OpReturn\n" +
7245       "OpFunctionEnd\n",
7246     4, true)
7247 ));
7248 
7249 INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
7250 ::testing::Values(
7251   // Test case 0: Fold select with the same values for both sides
7252   InstructionFoldingCase<bool>(
7253       Header() +
7254           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7255           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7256           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7257           "%main = OpFunction %void None %void_func\n" +
7258           "%main_lab = OpLabel\n" +
7259           "%n = OpVariable %_ptr_bool Function\n" +
7260           "%load = OpLoad %bool %n\n" +
7261           "%2 = OpSelect %int %load %100 %100\n" +
7262           "OpReturn\n" +
7263           "OpFunctionEnd",
7264       2, true),
7265   // Test case 1: Fold select true to left side
7266   InstructionFoldingCase<bool>(
7267       Header() +
7268           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7269           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7270           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7271           "%main = OpFunction %void None %void_func\n" +
7272           "%main_lab = OpLabel\n" +
7273           "%n = OpVariable %_ptr_int Function\n" +
7274           "%load = OpLoad %bool %n\n" +
7275           "%2 = OpSelect %int %true %100 %n\n" +
7276           "OpReturn\n" +
7277           "OpFunctionEnd",
7278       2, true),
7279   // Test case 2: Fold select false to right side
7280   InstructionFoldingCase<bool>(
7281       Header() +
7282           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7283           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7284           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7285           "%main = OpFunction %void None %void_func\n" +
7286           "%main_lab = OpLabel\n" +
7287           "%n = OpVariable %_ptr_int Function\n" +
7288           "%load = OpLoad %bool %n\n" +
7289           "%2 = OpSelect %int %false %n %100\n" +
7290           "OpReturn\n" +
7291           "OpFunctionEnd",
7292       2, true),
7293   // Test case 3: Fold select null to right side
7294   InstructionFoldingCase<bool>(
7295       Header() +
7296           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7297           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7298           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7299           "%main = OpFunction %void None %void_func\n" +
7300           "%main_lab = OpLabel\n" +
7301           "%n = OpVariable %_ptr_int Function\n" +
7302           "%load = OpLoad %int %n\n" +
7303           "%2 = OpSelect %int %bool_null %load %100\n" +
7304           "OpReturn\n" +
7305           "OpFunctionEnd",
7306       2, true),
7307   // Test case 4: vector null
7308   InstructionFoldingCase<bool>(
7309       Header() +
7310           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7311           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7312           "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7313           "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
7314           "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
7315           "%main = OpFunction %void None %void_func\n" +
7316           "%main_lab = OpLabel\n" +
7317           "%n = OpVariable %_ptr_v2int Function\n" +
7318           "%load = OpLoad %v2int %n\n" +
7319           "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
7320           "OpReturn\n" +
7321           "OpFunctionEnd",
7322       2, true),
7323   // Test case 5: vector select
7324   InstructionFoldingCase<bool>(
7325       Header() +
7326           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7327           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7328           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
7329           "%main = OpFunction %void None %void_func\n" +
7330           "%main_lab = OpLabel\n" +
7331           "%m = OpVariable %_ptr_v2int Function\n" +
7332           "%n = OpVariable %_ptr_v2int Function\n" +
7333           "%2 = OpLoad %v2int %n\n" +
7334           "%3 = OpLoad %v2int %n\n" +
7335           "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
7336           "OpReturn\n" +
7337           "OpFunctionEnd",
7338       4, true),
7339   // Test case 6: vector select
7340   InstructionFoldingCase<bool>(
7341       Header() +
7342           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7343           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7344           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
7345           "%main = OpFunction %void None %void_func\n" +
7346           "%main_lab = OpLabel\n" +
7347           "%m = OpVariable %_ptr_v2int Function\n" +
7348           "%n = OpVariable %_ptr_v2int Function\n" +
7349           "%2 = OpLoad %v2int %n\n" +
7350           "%3 = OpLoad %v2int %n\n" +
7351           "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
7352           "OpReturn\n" +
7353           "OpFunctionEnd",
7354       4, true)
7355 ));
7356 
7357 INSTANTIATE_TEST_SUITE_P(CompositeExtractOrInsertMatchingTest, MatchingInstructionFoldingTest,
7358 ::testing::Values(
7359     // Test case 0: Extracting from result of consecutive shuffles of differing
7360     // size.
7361     InstructionFoldingCase<bool>(
7362         Header() +
7363             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7364             "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
7365             "%main = OpFunction %void None %void_func\n" +
7366             "%main_lab = OpLabel\n" +
7367             "%n = OpVariable %_ptr_v4int Function\n" +
7368             "%2 = OpLoad %v4int %n\n" +
7369             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7370             "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
7371             "%5 = OpCompositeExtract %int %4 1\n" +
7372             "OpReturn\n" +
7373             "OpFunctionEnd",
7374         5, true),
7375     // Test case 1: Extracting from result of vector shuffle of differing
7376     // input and result sizes.
7377     InstructionFoldingCase<bool>(
7378         Header() +
7379             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7380             "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
7381             "%main = OpFunction %void None %void_func\n" +
7382             "%main_lab = OpLabel\n" +
7383             "%n = OpVariable %_ptr_v4int Function\n" +
7384             "%2 = OpLoad %v4int %n\n" +
7385             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7386             "%4 = OpCompositeExtract %int %3 0\n" +
7387             "OpReturn\n" +
7388             "OpFunctionEnd",
7389         4, true),
7390     // Test case 2: Extracting from result of vector shuffle of differing
7391     // input and result sizes.
7392     InstructionFoldingCase<bool>(
7393         Header() +
7394             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7395             "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
7396             "%main = OpFunction %void None %void_func\n" +
7397             "%main_lab = OpLabel\n" +
7398             "%n = OpVariable %_ptr_v4int Function\n" +
7399             "%2 = OpLoad %v4int %n\n" +
7400             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7401             "%4 = OpCompositeExtract %int %3 1\n" +
7402             "OpReturn\n" +
7403             "OpFunctionEnd",
7404         4, true),
7405     // Test case 3: Using fmix feeding extract with a 1 in the a position.
7406     InstructionFoldingCase<bool>(
7407         Header() +
7408             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7409             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7410             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7411             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7412             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7413             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
7414             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
7415             "%main = OpFunction %void None %void_func\n" +
7416             "%main_lab = OpLabel\n" +
7417             "%m = OpVariable %_ptr_v4double Function\n" +
7418             "%n = OpVariable %_ptr_v4double Function\n" +
7419             "%2 = OpLoad %v4double %m\n" +
7420             "%3 = OpLoad %v4double %n\n" +
7421             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7422             "%5 = OpCompositeExtract %double %4 1\n" +
7423             "OpReturn\n" +
7424             "OpFunctionEnd",
7425         5, true),
7426     // Test case 4: Using fmix feeding extract with a 0 in the a position.
7427     InstructionFoldingCase<bool>(
7428         Header() +
7429             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7430             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7431             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7432             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7433             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7434             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7435             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
7436             "%main = OpFunction %void None %void_func\n" +
7437             "%main_lab = OpLabel\n" +
7438             "%m = OpVariable %_ptr_v4double Function\n" +
7439             "%n = OpVariable %_ptr_v4double Function\n" +
7440             "%2 = OpLoad %v4double %m\n" +
7441             "%3 = OpLoad %v4double %n\n" +
7442             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7443             "%5 = OpCompositeExtract %double %4 2\n" +
7444             "OpReturn\n" +
7445             "OpFunctionEnd",
7446         5, true),
7447     // Test case 5: Using fmix feeding extract with a null for the alpha
7448     InstructionFoldingCase<bool>(
7449         Header() +
7450             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7451             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7452             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7453             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7454             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7455             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7456             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
7457             "%main = OpFunction %void None %void_func\n" +
7458             "%main_lab = OpLabel\n" +
7459             "%m = OpVariable %_ptr_v4double Function\n" +
7460             "%n = OpVariable %_ptr_v4double Function\n" +
7461             "%2 = OpLoad %v4double %m\n" +
7462             "%3 = OpLoad %v4double %n\n" +
7463             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
7464             "%5 = OpCompositeExtract %double %4 0\n" +
7465             "OpReturn\n" +
7466             "OpFunctionEnd",
7467         5, true),
7468     // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
7469     // position.
7470     InstructionFoldingCase<bool>(
7471         Header() +
7472             "%main = OpFunction %void None %void_func\n" +
7473             "%main_lab = OpLabel\n" +
7474             "%m = OpVariable %_ptr_v4double Function\n" +
7475             "%n = OpVariable %_ptr_v4double Function\n" +
7476             "%2 = OpLoad %v4double %m\n" +
7477             "%3 = OpLoad %v4double %n\n" +
7478             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
7479             "%5 = OpCompositeExtract %double %4 3\n" +
7480             "OpReturn\n" +
7481             "OpFunctionEnd",
7482         5, false),
7483     // Test case 7: Extracting the undefined literal value from a vector
7484     // shuffle.
7485     InstructionFoldingCase<bool>(
7486         Header() +
7487             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7488             "; CHECK: %4 = OpUndef [[int]]\n" +
7489             "%main = OpFunction %void None %void_func\n" +
7490             "%main_lab = OpLabel\n" +
7491             "%n = OpVariable %_ptr_v4int Function\n" +
7492             "%2 = OpLoad %v4int %n\n" +
7493             "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
7494             "%4 = OpCompositeExtract %int %3 1\n" +
7495             "OpReturn\n" +
7496             "OpFunctionEnd",
7497         4, true),
7498     // Test case 8: Inserting every element of a vector turns into a composite construct.
7499     InstructionFoldingCase<bool>(
7500         Header() +
7501             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7502             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7503             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7504             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7505             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7506             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7507             "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7508             "%main = OpFunction %void None %void_func\n" +
7509             "%main_lab = OpLabel\n" +
7510             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7511             "%3 = OpCompositeInsert %v4int %int_1 %2 1\n" +
7512             "%4 = OpCompositeInsert %v4int %int_2 %3 2\n" +
7513             "%5 = OpCompositeInsert %v4int %int_3 %4 3\n" +
7514             "OpReturn\n" +
7515             "OpFunctionEnd",
7516         5, true),
7517     // Test case 9: Inserting every element of a vector turns into a composite construct in a different order.
7518     InstructionFoldingCase<bool>(
7519         Header() +
7520             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7521             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7522             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7523             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7524             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7525             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7526             "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7527             "%main = OpFunction %void None %void_func\n" +
7528             "%main_lab = OpLabel\n" +
7529             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7530             "%4 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7531             "%3 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7532             "%5 = OpCompositeInsert %v4int %int_3 %3 3\n" +
7533             "OpReturn\n" +
7534             "OpFunctionEnd",
7535         5, true),
7536     // Test case 10: Check multiple inserts to the same position are handled correctly.
7537     InstructionFoldingCase<bool>(
7538         Header() +
7539             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7540             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7541             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7542             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7543             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7544             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7545             "; CHECK: %6 = OpCopyObject [[v4]] [[construct]]\n" +
7546             "%main = OpFunction %void None %void_func\n" +
7547             "%main_lab = OpLabel\n" +
7548             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7549             "%3 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7550             "%4 = OpCompositeInsert %v4int %int_4 %3 1\n" +
7551             "%5 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7552             "%6 = OpCompositeInsert %v4int %int_3 %5 3\n" +
7553             "OpReturn\n" +
7554             "OpFunctionEnd",
7555         6, true),
7556     // Test case 11: The last indexes are 0 and 1, but they have different first indexes.  This should not be folded.
7557     InstructionFoldingCase<bool>(
7558         Header() +
7559             "%main = OpFunction %void None %void_func\n" +
7560             "%main_lab = OpLabel\n" +
7561             "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7562             "%3 = OpCompositeInsert %m2x2int %int_1 %2 1 1\n" +
7563             "OpReturn\n" +
7564             "OpFunctionEnd",
7565         3, false),
7566     // Test case 12: Don't fold when there is a partial insertion.
7567     InstructionFoldingCase<bool>(
7568         Header() +
7569             "%main = OpFunction %void None %void_func\n" +
7570             "%main_lab = OpLabel\n" +
7571             "%2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0\n" +
7572             "%3 = OpCompositeInsert %m2x2int %int_4 %2 0 0\n" +
7573             "%4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1\n" +
7574             "OpReturn\n" +
7575             "OpFunctionEnd",
7576         4, false),
7577     // Test case 13: Insert into a column of a matrix
7578     InstructionFoldingCase<bool>(
7579         Header() +
7580             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7581             "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7582             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7583             "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7584             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7585 // We keep this insert in the chain.  DeadInsertElimPass should remove it.
7586             "; CHECK: [[insert:%\\w+]] = OpCompositeInsert [[m2x2]] %100 [[m2x2_undef]] 0 0\n" +
7587             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7588             "; CHECK: %3 = OpCompositeInsert [[m2x2]] [[construct]] [[insert]] 0\n" +
7589             "%main = OpFunction %void None %void_func\n" +
7590             "%main_lab = OpLabel\n" +
7591             "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7592             "%3 = OpCompositeInsert %m2x2int %int_1 %2 0 1\n" +
7593             "OpReturn\n" +
7594             "OpFunctionEnd",
7595         3, true),
7596     // Test case 14: Insert all elements of the matrix.
7597     InstructionFoldingCase<bool>(
7598         Header() +
7599             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7600             "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7601             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7602             "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7603             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7604             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7605             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7606             "; CHECK: [[c0:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7607             "; CHECK: [[c1:%\\w+]] = OpCompositeConstruct [[v2]] [[int2]] [[int3]]\n" +
7608             "; CHECK: [[matrix:%\\w+]] = OpCompositeConstruct [[m2x2]] [[c0]] [[c1]]\n" +
7609             "; CHECK: %5 = OpCopyObject [[m2x2]] [[matrix]]\n" +
7610             "%main = OpFunction %void None %void_func\n" +
7611             "%main_lab = OpLabel\n" +
7612             "%2 = OpCompositeConstruct %v2int %100 %int_1\n" +
7613             "%3 = OpCompositeInsert %m2x2int %2 %m2x2int_undef 0\n" +
7614             "%4 = OpCompositeInsert %m2x2int %int_2 %3 1 0\n" +
7615             "%5 = OpCompositeInsert %m2x2int %int_3 %4 1 1\n" +
7616             "OpReturn\n" +
7617             "OpFunctionEnd",
7618         5, true),
7619     // Test case 15: Replace construct with extract when reconstructing a member
7620     // of another object.
7621     InstructionFoldingCase<bool>(
7622         Header() +
7623             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7624             "; CHECK: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7625             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7626             "; CHECK: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7627             "; CHECK: %5 = OpCompositeExtract [[v2]] [[m2x2_undef]]\n" +
7628             "%main = OpFunction %void None %void_func\n" +
7629             "%main_lab = OpLabel\n" +
7630             "%3 = OpCompositeExtract %int %m2x2int_undef 1 0\n" +
7631             "%4 = OpCompositeExtract %int %m2x2int_undef 1 1\n" +
7632             "%5 = OpCompositeConstruct %v2int %3 %4\n" +
7633             "OpReturn\n" +
7634             "OpFunctionEnd",
7635         5, true),
7636     // Test case 16: Don't fold when type cannot be deduced to a constant.
7637     InstructionFoldingCase<bool>(
7638         Header() +
7639             "%main = OpFunction %void None %void_func\n" +
7640             "%main_lab = OpLabel\n" +
7641             "%4 = OpCompositeInsert %struct_v2int_int_int %int_1 %struct_v2int_int_int_null 2\n" +
7642             "OpReturn\n" +
7643             "OpFunctionEnd",
7644         4, false),
7645     // Test case 17: Don't fold when index into composite is out of bounds.
7646     InstructionFoldingCase<bool>(
7647 	Header() +
7648             "%main = OpFunction %void None %void_func\n" +
7649 	    "%main_lab = OpLabel\n" +
7650 	    "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" +
7651 	    "OpReturn\n" +
7652 	    "OpFunctionEnd",
7653 	4, false),
7654     // Test case 18: Fold when every element of an array is inserted.
7655     InstructionFoldingCase<bool>(
7656         Header() +
7657             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7658             "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7659             "; CHECK-DAG: [[arr_type:%\\w+]] = OpTypeArray [[int]] [[int2]]\n" +
7660             "; CHECK-DAG: [[int10:%\\w+]] = OpConstant [[int]] 10\n" +
7661             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7662             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[arr_type]] [[int10]] [[int1]]\n" +
7663             "; CHECK: %5 = OpCopyObject [[arr_type]] [[construct]]\n" +
7664             "%main = OpFunction %void None %void_func\n" +
7665             "%main_lab = OpLabel\n" +
7666             "%4 = OpCompositeInsert %int_arr_2 %int_10 %int_arr_2_undef 0\n" +
7667             "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" +
7668             "OpReturn\n" +
7669             "OpFunctionEnd",
7670         5, true)
7671 ));
7672 
7673 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
7674 ::testing::Values(
7675     // Test case 0: Using OpDot to extract last element.
7676     InstructionFoldingCase<bool>(
7677         Header() +
7678             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7679             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7680             "%main = OpFunction %void None %void_func\n" +
7681             "%main_lab = OpLabel\n" +
7682             "%n = OpVariable %_ptr_v4float Function\n" +
7683             "%2 = OpLoad %v4float %n\n" +
7684             "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
7685             "OpReturn\n" +
7686             "OpFunctionEnd",
7687         3, true),
7688     // Test case 1: Using OpDot to extract last element.
7689     InstructionFoldingCase<bool>(
7690         Header() +
7691             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7692             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7693             "%main = OpFunction %void None %void_func\n" +
7694             "%main_lab = OpLabel\n" +
7695             "%n = OpVariable %_ptr_v4float Function\n" +
7696             "%2 = OpLoad %v4float %n\n" +
7697             "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
7698             "OpReturn\n" +
7699             "OpFunctionEnd",
7700         3, true),
7701     // Test case 2: Using OpDot to extract second element.
7702     InstructionFoldingCase<bool>(
7703         Header() +
7704             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7705             "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
7706             "%main = OpFunction %void None %void_func\n" +
7707             "%main_lab = OpLabel\n" +
7708             "%n = OpVariable %_ptr_v4float Function\n" +
7709             "%2 = OpLoad %v4float %n\n" +
7710             "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
7711             "OpReturn\n" +
7712             "OpFunctionEnd",
7713         3, true),
7714     // Test case 3: Using OpDot to extract last element.
7715     InstructionFoldingCase<bool>(
7716         Header() +
7717             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7718             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7719             "%main = OpFunction %void None %void_func\n" +
7720             "%main_lab = OpLabel\n" +
7721             "%n = OpVariable %_ptr_v4double Function\n" +
7722             "%2 = OpLoad %v4double %n\n" +
7723             "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
7724             "OpReturn\n" +
7725             "OpFunctionEnd",
7726         3, true),
7727     // Test case 4: Using OpDot to extract last element.
7728     InstructionFoldingCase<bool>(
7729         Header() +
7730             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7731             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7732             "%main = OpFunction %void None %void_func\n" +
7733             "%main_lab = OpLabel\n" +
7734             "%n = OpVariable %_ptr_v4double Function\n" +
7735             "%2 = OpLoad %v4double %n\n" +
7736             "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
7737             "OpReturn\n" +
7738             "OpFunctionEnd",
7739         3, true),
7740     // Test case 5: Using OpDot to extract second element.
7741     InstructionFoldingCase<bool>(
7742         Header() +
7743             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7744             "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
7745             "%main = OpFunction %void None %void_func\n" +
7746             "%main_lab = OpLabel\n" +
7747             "%n = OpVariable %_ptr_v4double Function\n" +
7748             "%2 = OpLoad %v4double %n\n" +
7749             "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
7750             "OpReturn\n" +
7751             "OpFunctionEnd",
7752         3, true)
7753 ));
7754 
7755 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionFoldingTest,
7756 ::testing::Values(
7757     // Test case 0: Using OpDot to extract last element.
7758     InstructionFoldingCase<bool>(
7759         Header() +
7760             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7761             "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
7762             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v2int]]\n" +
7763             "; CHECK: OpVectorShuffle\n" +
7764             "; CHECK: %3 = OpVectorShuffle [[v2int]] [[null]] {{%\\w+}} 4294967295 2\n" +
7765             "%main = OpFunction %void None %void_func\n" +
7766             "%main_lab = OpLabel\n" +
7767             "%n = OpVariable %_ptr_int Function\n" +
7768             "%load = OpLoad %int %n\n" +
7769             "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 3 0xFFFFFFFF \n" +
7770             "%3 = OpVectorShuffle %v2int %2 %v2int_2_3 1 2 \n" +
7771             "OpReturn\n" +
7772             "OpFunctionEnd",
7773         3, true)
7774  ));
7775 
7776 INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest,
7777 ::testing::Values(
7778    // Test case 0: (x * y) + a = Fma(x, y, a)
7779    InstructionFoldingCase<bool>(
7780        Header() +
7781            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7782            "; CHECK: OpFunction\n" +
7783            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7784            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7785            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7786            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7787            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7788            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7789            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7790            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7791            "%main = OpFunction %void None %void_func\n" +
7792            "%main_lab = OpLabel\n" +
7793            "%x = OpVariable %_ptr_float Function\n" +
7794            "%y = OpVariable %_ptr_float Function\n" +
7795            "%a = OpVariable %_ptr_float Function\n" +
7796            "%lx = OpLoad %float %x\n" +
7797            "%ly = OpLoad %float %y\n" +
7798            "%mul = OpFMul %float %lx %ly\n" +
7799            "%la = OpLoad %float %a\n" +
7800            "%3 = OpFAdd %float %mul %la\n" +
7801            "OpStore %a %3\n" +
7802            "OpReturn\n" +
7803            "OpFunctionEnd",
7804        3, true),
7805     // Test case 1:  a + (x * y) = Fma(x, y, a)
7806    InstructionFoldingCase<bool>(
7807        Header() +
7808            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7809            "; CHECK: OpFunction\n" +
7810            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7811            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7812            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7813            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7814            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7815            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7816            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7817            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7818            "%main = OpFunction %void None %void_func\n" +
7819            "%main_lab = OpLabel\n" +
7820            "%x = OpVariable %_ptr_float Function\n" +
7821            "%y = OpVariable %_ptr_float Function\n" +
7822            "%a = OpVariable %_ptr_float Function\n" +
7823            "%lx = OpLoad %float %x\n" +
7824            "%ly = OpLoad %float %y\n" +
7825            "%mul = OpFMul %float %lx %ly\n" +
7826            "%la = OpLoad %float %a\n" +
7827            "%3 = OpFAdd %float %la %mul\n" +
7828            "OpStore %a %3\n" +
7829            "OpReturn\n" +
7830            "OpFunctionEnd",
7831        3, true),
7832    // Test case 2: (x * y) + a = Fma(x, y, a) with vectors
7833    InstructionFoldingCase<bool>(
7834        Header() +
7835            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7836            "; CHECK: OpFunction\n" +
7837            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7838            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7839            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7840            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7841            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7842            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7843            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7844            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7845            "%main = OpFunction %void None %void_func\n" +
7846            "%main_lab = OpLabel\n" +
7847            "%x = OpVariable %_ptr_v4float Function\n" +
7848            "%y = OpVariable %_ptr_v4float Function\n" +
7849            "%a = OpVariable %_ptr_v4float Function\n" +
7850            "%lx = OpLoad %v4float %x\n" +
7851            "%ly = OpLoad %v4float %y\n" +
7852            "%mul = OpFMul %v4float %lx %ly\n" +
7853            "%la = OpLoad %v4float %a\n" +
7854            "%3 = OpFAdd %v4float %mul %la\n" +
7855            "OpStore %a %3\n" +
7856            "OpReturn\n" +
7857            "OpFunctionEnd",
7858        3, true),
7859     // Test case 3:  a + (x * y) = Fma(x, y, a) with vectors
7860    InstructionFoldingCase<bool>(
7861        Header() +
7862            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7863            "; CHECK: OpFunction\n" +
7864            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7865            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7866            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7867            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7868            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7869            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7870            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7871            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7872            "%main = OpFunction %void None %void_func\n" +
7873            "%main_lab = OpLabel\n" +
7874            "%x = OpVariable %_ptr_float Function\n" +
7875            "%y = OpVariable %_ptr_float Function\n" +
7876            "%a = OpVariable %_ptr_float Function\n" +
7877            "%lx = OpLoad %float %x\n" +
7878            "%ly = OpLoad %float %y\n" +
7879            "%mul = OpFMul %float %lx %ly\n" +
7880            "%la = OpLoad %float %a\n" +
7881            "%3 = OpFAdd %float %la %mul\n" +
7882            "OpStore %a %3\n" +
7883            "OpReturn\n" +
7884            "OpFunctionEnd",
7885        3, true),
7886     // Test 4: that the OpExtInstImport instruction is generated if it is missing.
7887    InstructionFoldingCase<bool>(
7888            std::string() +
7889            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7890            "; CHECK: OpFunction\n" +
7891            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7892            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7893            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7894            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7895            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7896            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7897            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7898            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7899            "OpCapability Shader\n" +
7900            "OpMemoryModel Logical GLSL450\n" +
7901            "OpEntryPoint Fragment %main \"main\"\n" +
7902            "OpExecutionMode %main OriginUpperLeft\n" +
7903            "OpSource GLSL 140\n" +
7904            "OpName %main \"main\"\n" +
7905            "%void = OpTypeVoid\n" +
7906            "%void_func = OpTypeFunction %void\n" +
7907            "%bool = OpTypeBool\n" +
7908            "%float = OpTypeFloat 32\n" +
7909            "%_ptr_float = OpTypePointer Function %float\n" +
7910            "%main = OpFunction %void None %void_func\n" +
7911            "%main_lab = OpLabel\n" +
7912            "%x = OpVariable %_ptr_float Function\n" +
7913            "%y = OpVariable %_ptr_float Function\n" +
7914            "%a = OpVariable %_ptr_float Function\n" +
7915            "%lx = OpLoad %float %x\n" +
7916            "%ly = OpLoad %float %y\n" +
7917            "%mul = OpFMul %float %lx %ly\n" +
7918            "%la = OpLoad %float %a\n" +
7919            "%3 = OpFAdd %float %mul %la\n" +
7920            "OpStore %a %3\n" +
7921            "OpReturn\n" +
7922            "OpFunctionEnd",
7923        3, true),
7924    // Test 5: Don't fold if the multiple is marked no contract.
7925    InstructionFoldingCase<bool>(
7926        std::string() +
7927            "OpCapability Shader\n" +
7928            "OpMemoryModel Logical GLSL450\n" +
7929            "OpEntryPoint Fragment %main \"main\"\n" +
7930            "OpExecutionMode %main OriginUpperLeft\n" +
7931            "OpSource GLSL 140\n" +
7932            "OpName %main \"main\"\n" +
7933            "OpDecorate %mul NoContraction\n" +
7934            "%void = OpTypeVoid\n" +
7935            "%void_func = OpTypeFunction %void\n" +
7936            "%bool = OpTypeBool\n" +
7937            "%float = OpTypeFloat 32\n" +
7938            "%_ptr_float = OpTypePointer Function %float\n" +
7939            "%main = OpFunction %void None %void_func\n" +
7940            "%main_lab = OpLabel\n" +
7941            "%x = OpVariable %_ptr_float Function\n" +
7942            "%y = OpVariable %_ptr_float Function\n" +
7943            "%a = OpVariable %_ptr_float Function\n" +
7944            "%lx = OpLoad %float %x\n" +
7945            "%ly = OpLoad %float %y\n" +
7946            "%mul = OpFMul %float %lx %ly\n" +
7947            "%la = OpLoad %float %a\n" +
7948            "%3 = OpFAdd %float %mul %la\n" +
7949            "OpStore %a %3\n" +
7950            "OpReturn\n" +
7951            "OpFunctionEnd",
7952        3, false),
7953        // Test 6: Don't fold if the add is marked no contract.
7954        InstructionFoldingCase<bool>(
7955            std::string() +
7956                "OpCapability Shader\n" +
7957                "OpMemoryModel Logical GLSL450\n" +
7958                "OpEntryPoint Fragment %main \"main\"\n" +
7959                "OpExecutionMode %main OriginUpperLeft\n" +
7960                "OpSource GLSL 140\n" +
7961                "OpName %main \"main\"\n" +
7962                "OpDecorate %3 NoContraction\n" +
7963                "%void = OpTypeVoid\n" +
7964                "%void_func = OpTypeFunction %void\n" +
7965                "%bool = OpTypeBool\n" +
7966                "%float = OpTypeFloat 32\n" +
7967                "%_ptr_float = OpTypePointer Function %float\n" +
7968                "%main = OpFunction %void None %void_func\n" +
7969                "%main_lab = OpLabel\n" +
7970                "%x = OpVariable %_ptr_float Function\n" +
7971                "%y = OpVariable %_ptr_float Function\n" +
7972                "%a = OpVariable %_ptr_float Function\n" +
7973                "%lx = OpLoad %float %x\n" +
7974                "%ly = OpLoad %float %y\n" +
7975                "%mul = OpFMul %float %lx %ly\n" +
7976                "%la = OpLoad %float %a\n" +
7977                "%3 = OpFAdd %float %mul %la\n" +
7978                "OpStore %a %3\n" +
7979                "OpReturn\n" +
7980                "OpFunctionEnd",
7981            3, false),
7982     // Test case 7: (x * y) - a = Fma(x, y, -a)
7983     InstructionFoldingCase<bool>(
7984        Header() +
7985            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7986            "; CHECK: OpFunction\n" +
7987            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7988            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7989            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7990            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7991            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7992            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7993            "; CHECK: [[na:%\\w+]] = OpFNegate {{%\\w+}} [[la]]\n" +
7994            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[na]]\n" +
7995            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7996            "%main = OpFunction %void None %void_func\n" +
7997            "%main_lab = OpLabel\n" +
7998            "%x = OpVariable %_ptr_float Function\n" +
7999            "%y = OpVariable %_ptr_float Function\n" +
8000            "%a = OpVariable %_ptr_float Function\n" +
8001            "%lx = OpLoad %float %x\n" +
8002            "%ly = OpLoad %float %y\n" +
8003            "%mul = OpFMul %float %lx %ly\n" +
8004            "%la = OpLoad %float %a\n" +
8005            "%3 = OpFSub %float %mul %la\n" +
8006            "OpStore %a %3\n" +
8007            "OpReturn\n" +
8008            "OpFunctionEnd",
8009        3, true),
8010    // Test case 8: a - (x * y) = Fma(-x, y, a)
8011    InstructionFoldingCase<bool>(
8012        Header() +
8013            "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
8014            "; CHECK: OpFunction\n" +
8015            "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8016            "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8017            "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8018            "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
8019            "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
8020            "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
8021            "; CHECK: [[nx:%\\w+]] = OpFNegate {{%\\w+}} [[lx]]\n" +
8022            "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[nx]] [[ly]] [[la]]\n" +
8023            "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
8024            "%main = OpFunction %void None %void_func\n" +
8025            "%main_lab = OpLabel\n" +
8026            "%x = OpVariable %_ptr_float Function\n" +
8027            "%y = OpVariable %_ptr_float Function\n" +
8028            "%a = OpVariable %_ptr_float Function\n" +
8029            "%lx = OpLoad %float %x\n" +
8030            "%ly = OpLoad %float %y\n" +
8031            "%mul = OpFMul %float %lx %ly\n" +
8032            "%la = OpLoad %float %a\n" +
8033            "%3 = OpFSub %float %la %mul\n" +
8034            "OpStore %a %3\n" +
8035            "OpReturn\n" +
8036            "OpFunctionEnd",
8037        3, true)
8038 ));
8039 
8040 using MatchingInstructionWithNoResultFoldingTest =
8041 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8042 
8043 // Test folding instructions that do not have a result.  The instruction
8044 // that will be folded is the last instruction before the return.  If there
8045 // are multiple returns, there is not guarantee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest, Case)8046 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
8047   const auto& tc = GetParam();
8048 
8049   // Build module.
8050   std::unique_ptr<IRContext> context =
8051       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8052                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8053   ASSERT_NE(nullptr, context);
8054 
8055   // Fold the instruction to test.
8056   Instruction* inst = nullptr;
8057   Function* func = &*context->module()->begin();
8058   for (auto& bb : *func) {
8059     Instruction* terminator = bb.terminator();
8060     if (terminator->IsReturnOrAbort()) {
8061       inst = terminator->PreviousNode();
8062       break;
8063     }
8064   }
8065   assert(inst && "Invalid test.  Could not find instruction to fold.");
8066   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8067   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8068   EXPECT_EQ(succeeded, tc.expected_result);
8069   if (succeeded) {
8070     Match(tc.test_body, context.get());
8071   }
8072 }
8073 
8074 INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8075 ::testing::Values(
8076     // Test case 0: Remove store of undef.
8077     InstructionFoldingCase<bool>(
8078         Header() +
8079             "; CHECK: OpLabel\n" +
8080             "; CHECK-NOT: OpStore\n" +
8081             "; CHECK: OpReturn\n" +
8082             "%main = OpFunction %void None %void_func\n" +
8083             "%main_lab = OpLabel\n" +
8084             "%n = OpVariable %_ptr_v4double Function\n" +
8085             "%undef = OpUndef %v4double\n" +
8086             "OpStore %n %undef\n" +
8087             "OpReturn\n" +
8088             "OpFunctionEnd",
8089         0 /* OpStore */, true),
8090     // Test case 1: Keep volatile store.
8091     InstructionFoldingCase<bool>(
8092         Header() +
8093             "%main = OpFunction %void None %void_func\n" +
8094             "%main_lab = OpLabel\n" +
8095             "%n = OpVariable %_ptr_v4double Function\n" +
8096             "%undef = OpUndef %v4double\n" +
8097             "OpStore %n %undef Volatile\n" +
8098             "OpReturn\n" +
8099             "OpFunctionEnd",
8100         0 /* OpStore */, false)
8101 ));
8102 
8103 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8104 ::testing::Values(
8105     // Test case 0: Basic test 1
8106     InstructionFoldingCase<bool>(
8107         Header() +
8108             "; CHECK: OpVectorShuffle\n" +
8109             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
8110             "; CHECK: OpReturn\n" +
8111             "%main = OpFunction %void None %void_func\n" +
8112             "%main_lab = OpLabel\n" +
8113             "%2 = OpVariable %_ptr_v4double Function\n" +
8114             "%3 = OpVariable %_ptr_v4double Function\n" +
8115             "%4 = OpVariable %_ptr_v4double Function\n" +
8116             "%5 = OpLoad %v4double %2\n" +
8117             "%6 = OpLoad %v4double %3\n" +
8118             "%7 = OpLoad %v4double %4\n" +
8119             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8120             "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
8121             "OpReturn\n" +
8122             "OpFunctionEnd",
8123         9, true),
8124     // Test case 1: Basic test 2
8125     InstructionFoldingCase<bool>(
8126         Header() +
8127             "; CHECK: OpVectorShuffle\n" +
8128             "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
8129             "; CHECK: OpReturn\n" +
8130             "%main = OpFunction %void None %void_func\n" +
8131             "%main_lab = OpLabel\n" +
8132             "%2 = OpVariable %_ptr_v4double Function\n" +
8133             "%3 = OpVariable %_ptr_v4double Function\n" +
8134             "%4 = OpVariable %_ptr_v4double Function\n" +
8135             "%5 = OpLoad %v4double %2\n" +
8136             "%6 = OpLoad %v4double %3\n" +
8137             "%7 = OpLoad %v4double %4\n" +
8138             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8139             "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
8140             "OpReturn\n" +
8141             "OpFunctionEnd",
8142         9, true),
8143     // Test case 2: Basic test 3
8144     InstructionFoldingCase<bool>(
8145         Header() +
8146             "; CHECK: OpVectorShuffle\n" +
8147             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
8148             "; CHECK: OpReturn\n" +
8149             "%main = OpFunction %void None %void_func\n" +
8150             "%main_lab = OpLabel\n" +
8151             "%2 = OpVariable %_ptr_v4double Function\n" +
8152             "%3 = OpVariable %_ptr_v4double Function\n" +
8153             "%4 = OpVariable %_ptr_v4double Function\n" +
8154             "%5 = OpLoad %v4double %2\n" +
8155             "%6 = OpLoad %v4double %3\n" +
8156             "%7 = OpLoad %v4double %4\n" +
8157             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8158             "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
8159             "OpReturn\n" +
8160             "OpFunctionEnd",
8161         9, true),
8162     // Test case 3: Basic test 4
8163     InstructionFoldingCase<bool>(
8164         Header() +
8165             "; CHECK: OpVectorShuffle\n" +
8166             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
8167             "; CHECK: OpReturn\n" +
8168             "%main = OpFunction %void None %void_func\n" +
8169             "%main_lab = OpLabel\n" +
8170             "%2 = OpVariable %_ptr_v4double Function\n" +
8171             "%3 = OpVariable %_ptr_v4double Function\n" +
8172             "%4 = OpVariable %_ptr_v4double Function\n" +
8173             "%5 = OpLoad %v4double %2\n" +
8174             "%6 = OpLoad %v4double %3\n" +
8175             "%7 = OpLoad %v4double %4\n" +
8176             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8177             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
8178             "OpReturn\n" +
8179             "OpFunctionEnd",
8180         9, true),
8181     // Test case 4: Don't fold, need both operands of the feeder.
8182     InstructionFoldingCase<bool>(
8183         Header() +
8184             "%main = OpFunction %void None %void_func\n" +
8185             "%main_lab = OpLabel\n" +
8186             "%2 = OpVariable %_ptr_v4double Function\n" +
8187             "%3 = OpVariable %_ptr_v4double Function\n" +
8188             "%4 = OpVariable %_ptr_v4double Function\n" +
8189             "%5 = OpLoad %v4double %2\n" +
8190             "%6 = OpLoad %v4double %3\n" +
8191             "%7 = OpLoad %v4double %4\n" +
8192             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8193             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
8194             "OpReturn\n" +
8195             "OpFunctionEnd",
8196         9, false),
8197     // Test case 5: Don't fold, need both operands of the feeder.
8198     InstructionFoldingCase<bool>(
8199         Header() +
8200             "%main = OpFunction %void None %void_func\n" +
8201             "%main_lab = OpLabel\n" +
8202             "%2 = OpVariable %_ptr_v4double Function\n" +
8203             "%3 = OpVariable %_ptr_v4double Function\n" +
8204             "%4 = OpVariable %_ptr_v4double Function\n" +
8205             "%5 = OpLoad %v4double %2\n" +
8206             "%6 = OpLoad %v4double %3\n" +
8207             "%7 = OpLoad %v4double %4\n" +
8208             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8209             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8210             "OpReturn\n" +
8211             "OpFunctionEnd",
8212         9, false),
8213     // Test case 6: Fold, need both operands of the feeder, but they are the same.
8214     InstructionFoldingCase<bool>(
8215         Header() +
8216             "; CHECK: OpVectorShuffle\n" +
8217             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
8218             "; CHECK: OpReturn\n" +
8219             "%main = OpFunction %void None %void_func\n" +
8220             "%main_lab = OpLabel\n" +
8221             "%2 = OpVariable %_ptr_v4double Function\n" +
8222             "%3 = OpVariable %_ptr_v4double Function\n" +
8223             "%4 = OpVariable %_ptr_v4double Function\n" +
8224             "%5 = OpLoad %v4double %2\n" +
8225             "%6 = OpLoad %v4double %3\n" +
8226             "%7 = OpLoad %v4double %4\n" +
8227             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8228             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8229             "OpReturn\n" +
8230             "OpFunctionEnd",
8231         9, true),
8232     // Test case 7: Fold, need both operands of the feeder, but they are the same.
8233     InstructionFoldingCase<bool>(
8234         Header() +
8235             "; CHECK: OpVectorShuffle\n" +
8236             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
8237             "; CHECK: OpReturn\n" +
8238             "%main = OpFunction %void None %void_func\n" +
8239             "%main_lab = OpLabel\n" +
8240             "%2 = OpVariable %_ptr_v4double Function\n" +
8241             "%3 = OpVariable %_ptr_v4double Function\n" +
8242             "%4 = OpVariable %_ptr_v4double Function\n" +
8243             "%5 = OpLoad %v4double %2\n" +
8244             "%6 = OpLoad %v4double %3\n" +
8245             "%7 = OpLoad %v4double %4\n" +
8246             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8247             "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
8248             "OpReturn\n" +
8249             "OpFunctionEnd",
8250         9, true),
8251     // Test case 8: Replace first operand with a smaller vector.
8252     InstructionFoldingCase<bool>(
8253         Header() +
8254             "; CHECK: OpVectorShuffle\n" +
8255             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
8256             "; CHECK: OpReturn\n" +
8257             "%main = OpFunction %void None %void_func\n" +
8258             "%main_lab = OpLabel\n" +
8259             "%2 = OpVariable %_ptr_v2double Function\n" +
8260             "%3 = OpVariable %_ptr_v4double Function\n" +
8261             "%4 = OpVariable %_ptr_v4double Function\n" +
8262             "%5 = OpLoad %v2double %2\n" +
8263             "%6 = OpLoad %v4double %3\n" +
8264             "%7 = OpLoad %v4double %4\n" +
8265             "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
8266             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8267             "OpReturn\n" +
8268             "OpFunctionEnd",
8269         9, true),
8270     // Test case 9: Replace first operand with a larger vector.
8271     InstructionFoldingCase<bool>(
8272         Header() +
8273             "; CHECK: OpVectorShuffle\n" +
8274             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
8275             "; CHECK: OpReturn\n" +
8276             "%main = OpFunction %void None %void_func\n" +
8277             "%main_lab = OpLabel\n" +
8278             "%2 = OpVariable %_ptr_v4double Function\n" +
8279             "%3 = OpVariable %_ptr_v4double Function\n" +
8280             "%4 = OpVariable %_ptr_v4double Function\n" +
8281             "%5 = OpLoad %v4double %2\n" +
8282             "%6 = OpLoad %v4double %3\n" +
8283             "%7 = OpLoad %v4double %4\n" +
8284             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8285             "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
8286             "OpReturn\n" +
8287             "OpFunctionEnd",
8288         9, true),
8289     // Test case 10: Replace unused operand with null.
8290     InstructionFoldingCase<bool>(
8291         Header() +
8292             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8293             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8294             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8295             "; CHECK: OpVectorShuffle\n" +
8296             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
8297             "; CHECK: OpReturn\n" +
8298             "%main = OpFunction %void None %void_func\n" +
8299             "%main_lab = OpLabel\n" +
8300             "%2 = OpVariable %_ptr_v4double Function\n" +
8301             "%3 = OpVariable %_ptr_v4double Function\n" +
8302             "%4 = OpVariable %_ptr_v4double Function\n" +
8303             "%5 = OpLoad %v4double %2\n" +
8304             "%6 = OpLoad %v4double %3\n" +
8305             "%7 = OpLoad %v4double %4\n" +
8306             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8307             "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
8308             "OpReturn\n" +
8309             "OpFunctionEnd",
8310         9, true),
8311     // Test case 11: Replace unused operand with null.
8312     InstructionFoldingCase<bool>(
8313         Header() +
8314             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8315             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8316             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8317             "; CHECK: OpVectorShuffle\n" +
8318             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
8319             "; CHECK: OpReturn\n" +
8320             "%main = OpFunction %void None %void_func\n" +
8321             "%main_lab = OpLabel\n" +
8322             "%2 = OpVariable %_ptr_v4double Function\n" +
8323             "%3 = OpVariable %_ptr_v4double Function\n" +
8324             "%5 = OpLoad %v4double %2\n" +
8325             "%6 = OpLoad %v4double %3\n" +
8326             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8327             "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
8328             "OpReturn\n" +
8329             "OpFunctionEnd",
8330         9, true),
8331     // Test case 12: Replace unused operand with null.
8332     InstructionFoldingCase<bool>(
8333         Header() +
8334             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8335             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8336             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8337             "; CHECK: OpVectorShuffle\n" +
8338             "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
8339             "; CHECK: OpReturn\n" +
8340             "%main = OpFunction %void None %void_func\n" +
8341             "%main_lab = OpLabel\n" +
8342             "%2 = OpVariable %_ptr_v4double Function\n" +
8343             "%3 = OpVariable %_ptr_v4double Function\n" +
8344             "%4 = OpVariable %_ptr_v4double Function\n" +
8345             "%5 = OpLoad %v4double %2\n" +
8346             "%6 = OpLoad %v4double %3\n" +
8347             "%7 = OpLoad %v4double %4\n" +
8348             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8349             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
8350             "OpReturn\n" +
8351             "OpFunctionEnd",
8352         9, true),
8353     // Test case 13: Shuffle with undef literal.
8354     InstructionFoldingCase<bool>(
8355         Header() +
8356             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8357             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8358             "; CHECK: OpVectorShuffle\n" +
8359             "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
8360             "; CHECK: OpReturn\n" +
8361             "%main = OpFunction %void None %void_func\n" +
8362             "%main_lab = OpLabel\n" +
8363             "%2 = OpVariable %_ptr_v4double Function\n" +
8364             "%3 = OpVariable %_ptr_v4double Function\n" +
8365             "%4 = OpVariable %_ptr_v4double Function\n" +
8366             "%5 = OpLoad %v4double %2\n" +
8367             "%6 = OpLoad %v4double %3\n" +
8368             "%7 = OpLoad %v4double %4\n" +
8369             "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8370             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
8371             "OpReturn\n" +
8372             "OpFunctionEnd",
8373         9, true),
8374     // Test case 14: Shuffle with undef literal and change size of first input vector.
8375     InstructionFoldingCase<bool>(
8376         Header() +
8377             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8378             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8379             "; CHECK: OpVectorShuffle\n" +
8380             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 1 4 4294967295\n" +
8381             "; CHECK: OpReturn\n" +
8382             "%main = OpFunction %void None %void_func\n" +
8383             "%main_lab = OpLabel\n" +
8384             "%2 = OpVariable %_ptr_v4double Function\n" +
8385             "%3 = OpVariable %_ptr_v4double Function\n" +
8386             "%4 = OpVariable %_ptr_v4double Function\n" +
8387             "%5 = OpLoad %v4double %2\n" +
8388             "%6 = OpLoad %v4double %3\n" +
8389             "%7 = OpLoad %v4double %4\n" +
8390             "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8391             "%9 = OpVectorShuffle %v4double %8 %7 0 1 2 4294967295\n" +
8392             "OpReturn\n" +
8393             "OpFunctionEnd",
8394         9, true)
8395 ));
8396 
8397 using EntryPointFoldingTest =
8398 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8399 
TEST_P(EntryPointFoldingTest, Case)8400 TEST_P(EntryPointFoldingTest, Case) {
8401   const auto& tc = GetParam();
8402 
8403   // Build module.
8404   std::unique_ptr<IRContext> context =
8405       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8406                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8407   ASSERT_NE(nullptr, context);
8408 
8409   // Fold the instruction to test.
8410   Instruction* inst = nullptr;
8411   inst = &*context->module()->entry_points().begin();
8412   assert(inst && "Invalid test.  Could not find entry point instruction to fold.");
8413   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8414   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8415   EXPECT_EQ(succeeded, tc.expected_result);
8416   if (succeeded) {
8417     Match(tc.test_body, context.get());
8418   }
8419 }
8420 
8421 INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest,
8422 ::testing::Values(
8423     // Test case 0: Basic test 1
8424     InstructionFoldingCase<bool>(std::string() +
8425                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" +
8426                              "OpCapability Shader\n" +
8427                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8428                              "OpMemoryModel Logical GLSL450\n" +
8429                              "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" +
8430                              "OpExecutionMode %2 OriginUpperLeft\n" +
8431                              "OpSource GLSL 430\n" +
8432                              "OpDecorate %3 Location 0\n" +
8433                      "%void = OpTypeVoid\n" +
8434                         "%5 = OpTypeFunction %void\n" +
8435                     "%float = OpTypeFloat 32\n" +
8436                   "%v4float = OpTypeVector %float 4\n" +
8437       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8438                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8439                       "%int = OpTypeInt 32 1\n" +
8440                     "%int_0 = OpConstant %int 0\n" +
8441 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8442                         "%2 = OpFunction %void None %5\n" +
8443                        "%12 = OpLabel\n" +
8444                              "OpReturn\n" +
8445                              "OpFunctionEnd\n",
8446         9, true),
8447     InstructionFoldingCase<bool>(std::string() +
8448                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" +
8449                              "OpCapability Shader\n" +
8450                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8451                              "OpMemoryModel Logical GLSL450\n" +
8452                              "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" +
8453                              "OpExecutionMode %2 OriginUpperLeft\n" +
8454                              "OpSource GLSL 430\n" +
8455                              "OpDecorate %3 Location 0\n" +
8456                      "%void = OpTypeVoid\n" +
8457                         "%5 = OpTypeFunction %void\n" +
8458                     "%float = OpTypeFloat 32\n" +
8459                   "%v4float = OpTypeVector %float 4\n" +
8460       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8461                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8462                         "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8463                       "%int = OpTypeInt 32 1\n" +
8464                     "%int_0 = OpConstant %int 0\n" +
8465 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8466                         "%2 = OpFunction %void None %5\n" +
8467                        "%12 = OpLabel\n" +
8468                              "OpReturn\n" +
8469                              "OpFunctionEnd\n",
8470         9, true),
8471     InstructionFoldingCase<bool>(std::string() +
8472                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" +
8473                              "OpCapability Shader\n" +
8474                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8475                              "OpMemoryModel Logical GLSL450\n" +
8476                              "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" +
8477                              "OpExecutionMode %2 OriginUpperLeft\n" +
8478                              "OpSource GLSL 430\n" +
8479                              "OpDecorate %3 Location 0\n" +
8480                      "%void = OpTypeVoid\n" +
8481                         "%5 = OpTypeFunction %void\n" +
8482                     "%float = OpTypeFloat 32\n" +
8483                   "%v4float = OpTypeVector %float 4\n" +
8484       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8485                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8486                         "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8487                       "%int = OpTypeInt 32 1\n" +
8488                     "%int_0 = OpConstant %int 0\n" +
8489 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8490                         "%2 = OpFunction %void None %5\n" +
8491                        "%12 = OpLabel\n" +
8492                              "OpReturn\n" +
8493                              "OpFunctionEnd\n",
8494         9, true)
8495 ));
8496 
8497 using SPV14FoldingTest =
8498 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8499 
TEST_P(SPV14FoldingTest, Case)8500 TEST_P(SPV14FoldingTest, Case) {
8501   const auto& tc = GetParam();
8502 
8503   // Build module.
8504   std::unique_ptr<IRContext> context =
8505       BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8506                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8507   ASSERT_NE(nullptr, context);
8508 
8509   // Fold the instruction to test.
8510   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8511   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8512   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8513   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8514   EXPECT_EQ(succeeded, tc.expected_result);
8515   if (succeeded) {
8516     Match(tc.test_body, context.get());
8517   }
8518 }
8519 
8520 INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest,
8521 ::testing::Values(
8522     // Test case 0: select vectors with scalar condition.
8523     InstructionFoldingCase<bool>(std::string() +
8524 "; CHECK-NOT: OpSelect\n" +
8525 "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" +
8526 "OpCapability Shader\n" +
8527 "OpCapability Linkage\n" +
8528 "%void = OpTypeVoid\n" +
8529 "%bool = OpTypeBool\n" +
8530 "%true = OpConstantTrue %bool\n" +
8531 "%int = OpTypeInt 32 0\n" +
8532 "%int4 = OpTypeVector %int 4\n" +
8533 "%int_0 = OpConstant %int 0\n" +
8534 "%int_1 = OpConstant %int 1\n" +
8535 "%1 = OpUndef %int4\n" +
8536 "%2 = OpUndef %int4\n" +
8537 "%void_fn = OpTypeFunction %void\n" +
8538 "%func = OpFunction %void None %void_fn\n" +
8539 "%entry = OpLabel\n" +
8540 "%3 = OpSelect %int4 %true %1 %2\n" +
8541 "OpReturn\n" +
8542 "OpFunctionEnd\n"
8543 ,
8544                                  3, true),
8545     // Test case 1: select struct with scalar condition.
8546     InstructionFoldingCase<bool>(std::string() +
8547 "; CHECK-NOT: OpSelect\n" +
8548 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8549 "OpCapability Shader\n" +
8550 "OpCapability Linkage\n" +
8551 "%void = OpTypeVoid\n" +
8552 "%bool = OpTypeBool\n" +
8553 "%true = OpConstantFalse %bool\n" +
8554 "%int = OpTypeInt 32 0\n" +
8555 "%struct = OpTypeStruct %int %int %int %int\n" +
8556 "%int_0 = OpConstant %int 0\n" +
8557 "%int_1 = OpConstant %int 1\n" +
8558 "%1 = OpUndef %struct\n" +
8559 "%2 = OpUndef %struct\n" +
8560 "%void_fn = OpTypeFunction %void\n" +
8561 "%func = OpFunction %void None %void_fn\n" +
8562 "%entry = OpLabel\n" +
8563 "%3 = OpSelect %struct %true %1 %2\n" +
8564 "OpReturn\n" +
8565 "OpFunctionEnd\n"
8566 ,
8567                                  3, true),
8568     // Test case 1: select array with scalar condition.
8569     InstructionFoldingCase<bool>(std::string() +
8570 "; CHECK-NOT: OpSelect\n" +
8571 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8572 "OpCapability Shader\n" +
8573 "OpCapability Linkage\n" +
8574 "%void = OpTypeVoid\n" +
8575 "%bool = OpTypeBool\n" +
8576 "%true = OpConstantFalse %bool\n" +
8577 "%int = OpTypeInt 32 0\n" +
8578 "%int_0 = OpConstant %int 0\n" +
8579 "%int_1 = OpConstant %int 1\n" +
8580 "%int_4 = OpConstant %int 4\n" +
8581 "%array = OpTypeStruct %int %int %int %int\n" +
8582 "%1 = OpUndef %array\n" +
8583 "%2 = OpUndef %array\n" +
8584 "%void_fn = OpTypeFunction %void\n" +
8585 "%func = OpFunction %void None %void_fn\n" +
8586 "%entry = OpLabel\n" +
8587 "%3 = OpSelect %array %true %1 %2\n" +
8588 "OpReturn\n" +
8589 "OpFunctionEnd\n"
8590 ,
8591                                  3, true)
8592 ));
8593 
FloatControlsHeader(const std::string& capabilities)8594 std::string FloatControlsHeader(const std::string& capabilities) {
8595   std::string header = R"(
8596 OpCapability Shader
8597 )" + capabilities + R"(
8598 %void = OpTypeVoid
8599 %float = OpTypeFloat 32
8600 %float_0 = OpConstant %float 0
8601 %float_1 = OpConstant %float 1
8602 %void_fn = OpTypeFunction %void
8603 %func = OpFunction %void None %void_fn
8604 %entry = OpLabel
8605 )";
8606 
8607   return header;
8608 }
8609 
8610 using FloatControlsFoldingTest =
8611 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8612 
TEST_P(FloatControlsFoldingTest, Case)8613 TEST_P(FloatControlsFoldingTest, Case) {
8614   const auto& tc = GetParam();
8615 
8616   // Build module.
8617   std::unique_ptr<IRContext> context =
8618       BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8619                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8620   ASSERT_NE(nullptr, context);
8621 
8622   // Fold the instruction to test.
8623   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8624   Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8625   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8626   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8627   EXPECT_EQ(succeeded, tc.expected_result);
8628   if (succeeded) {
8629     Match(tc.test_body, context.get());
8630   }
8631 }
8632 
8633 INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
8634 ::testing::Values(
8635     // Test case 0: no folding with DenormPreserve
8636     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormPreserve") +
8637                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8638                                  "OpReturn\n" +
8639                                  "OpFunctionEnd\n"
8640 ,
8641                                  1, false),
8642     // Test case 1: no folding with DenormFlushToZero
8643     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormFlushToZero") +
8644                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8645                                  "OpReturn\n" +
8646                                  "OpFunctionEnd\n"
8647 ,
8648                                  1, false),
8649     // Test case 2: no folding with SignedZeroInfNanPreserve
8650     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") +
8651                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8652                                  "OpReturn\n" +
8653                                  "OpFunctionEnd\n"
8654 ,
8655                                  1, false),
8656     // Test case 3: no folding with RoundingModeRTE
8657     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTE") +
8658                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8659                                  "OpReturn\n" +
8660                                  "OpFunctionEnd\n"
8661 ,
8662                                  1, false),
8663     // Test case 4: no folding with RoundingModeRTZ
8664     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTZ") +
8665                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8666                                  "OpReturn\n" +
8667                                  "OpFunctionEnd\n"
8668 ,
8669                                  1, false)
8670 ));
8671 
ImageOperandsTestBody(const std::string& image_instruction)8672 std::string ImageOperandsTestBody(const std::string& image_instruction) {
8673   std::string body = R"(
8674                OpCapability Shader
8675                OpCapability ImageGatherExtended
8676                OpMemoryModel Logical GLSL450
8677                OpEntryPoint Fragment %main "main"
8678                OpExecutionMode %main OriginUpperLeft
8679                OpDecorate %Texture DescriptorSet 0
8680                OpDecorate %Texture Binding 0
8681         %int = OpTypeInt 32 1
8682      %int_n1 = OpConstant %int -1
8683           %5 = OpConstant %int 0
8684       %float = OpTypeFloat 32
8685     %float_0 = OpConstant %float 0
8686 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
8687 %type_sampled_image = OpTypeSampledImage %type_2d_image
8688 %type_sampler = OpTypeSampler
8689 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
8690 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
8691    %_ptr_int = OpTypePointer Function %int
8692       %v2int = OpTypeVector %int 2
8693          %10 = OpTypeVector %float 4
8694        %void = OpTypeVoid
8695          %22 = OpTypeFunction %void
8696     %v2float = OpTypeVector %float 2
8697       %v3int = OpTypeVector %int 3
8698     %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
8699    %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
8700         %110 = OpConstantComposite %v2int %5 %5
8701         %101 = OpConstantComposite %v2int %int_n1 %int_n1
8702          %20 = OpConstantComposite %v2float %float_0 %float_0
8703        %main = OpFunction %void None %22
8704          %23 = OpLabel
8705         %var = OpVariable %_ptr_int Function
8706          %88 = OpLoad %type_2d_image %Texture
8707         %val = OpLoad %int %var
8708     %sampler = OpLoad %type_sampler %gSampler
8709          %26 = OpSampledImage %type_sampled_image %88 %sampler
8710 )" + image_instruction + R"(
8711                OpReturn
8712                OpFunctionEnd
8713 )";
8714 
8715   return body;
8716 }
8717 
8718 INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
8719 ::testing::Values(
8720     // Test case 0: OpImageFetch without Offset
8721     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8722         "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
8723         , 89, false),
8724     // Test case 1: OpImageFetch with non-const offset
8725     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8726         "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
8727         , 89, false),
8728     // Test case 2: OpImageFetch with Lod and Offset
8729     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8730       "         %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101      \n"
8731       "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
8732       , 89, true),
8733     // Test case 3: OpImageFetch with Bias and Offset
8734     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8735       "         %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101      \n"
8736       "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
8737       , 89, true),
8738     // Test case 4: OpImageFetch with Grad and Offset.
8739     // Grad adds 2 operands to the instruction.
8740     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8741       "         %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101      \n"
8742       "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
8743       , 89, true),
8744     // Test case 5: OpImageFetch with Offset and MinLod.
8745     // This is an example of a case where the bitmask bit-offset is larger than
8746     // that of the Offset.
8747     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8748       "         %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5      \n"
8749       "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
8750       , 89, true),
8751     // Test case 6: OpImageGather with constant Offset
8752     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8753       "         %89 = OpImageGather %10 %26 %20 %5 Offset %101      \n"
8754       "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
8755       , 89, true),
8756     // Test case 7: OpImageWrite with constant Offset
8757     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8758       "         OpImageWrite %88 %5 %101 Offset %101      \n"
8759       "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
8760       , 0 /* No result-id */, true),
8761     // Test case 8: OpImageFetch with zero constant Offset
8762     InstructionFoldingCase<bool>(ImageOperandsTestBody(
8763         "         %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %110      \n"
8764         "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod %5 \n")
8765         , 89, true)
8766 ));
8767 
8768 }  // namespace
8769 }  // namespace opt
8770 }  // namespace spvtools
8771