• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "source/opt/fold.h"
15 
16 #include <limits>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 
21 #include "effcee/effcee.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "source/opt/build_module.h"
25 #include "source/opt/def_use_manager.h"
26 #include "source/opt/ir_context.h"
27 #include "source/opt/module.h"
28 #include "spirv-tools/libspirv.hpp"
29 
30 namespace spvtools {
31 namespace opt {
32 namespace {
33 
34 using ::testing::Contains;
35 
Disassemble(const std::string & original,IRContext * context,uint32_t disassemble_options=0)36 std::string Disassemble(const std::string& original, IRContext* context,
37                         uint32_t disassemble_options = 0) {
38   std::vector<uint32_t> optimized_bin;
39   context->module()->ToBinary(&optimized_bin, true);
40   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
41   SpirvTools tools(target_env);
42   std::string optimized_asm;
43   EXPECT_TRUE(
44       tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
45       << "Disassembling failed for shader:\n"
46       << original << std::endl;
47   return optimized_asm;
48 }
49 
Match(const std::string & original,IRContext * context,uint32_t disassemble_options=0)50 void Match(const std::string& original, IRContext* context,
51            uint32_t disassemble_options = 0) {
52   std::string disassembly = Disassemble(original, context, disassemble_options);
53   auto match_result = effcee::Match(disassembly, original);
54   EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
55       << match_result.message() << "\nChecking result:\n"
56       << disassembly;
57 }
58 
59 template <class ResultType>
60 struct InstructionFoldingCase {
InstructionFoldingCasespvtools::opt::__anonb0a5c4000111::InstructionFoldingCase61   InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
62       : test_body(tb), id_to_fold(id), expected_result(result) {}
63 
64   std::string test_body;
65   uint32_t id_to_fold;
66   ResultType expected_result;
67 };
68 
GetInstructionToFold(const std::string test_body,const uint32_t id_to_fold,spv_target_env spv_env)69 std::tuple<std::unique_ptr<IRContext>, Instruction*> GetInstructionToFold(
70     const std::string test_body, const uint32_t id_to_fold,
71     spv_target_env spv_env) {
72   // Build module.
73   std::unique_ptr<IRContext> context =
74       BuildModule(spv_env, nullptr, test_body,
75                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
76   EXPECT_NE(nullptr, context);
77   if (context == nullptr) {
78     return {nullptr, nullptr};
79   }
80 
81   // Fold the instruction to test.
82   if (id_to_fold != 0) {
83     analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
84     Instruction* inst = def_use_mgr->GetDef(id_to_fold);
85     return {std::move(context), inst};
86   }
87 
88   // If there is not ID, we get the instruction just before a terminator
89   // instruction. That could be a return or abort. This is used for cases where
90   // the instruction we want to fold does not have a result id.
91   Function* func = &*context->module()->begin();
92   for (auto& bb : *func) {
93     Instruction* terminator = bb.terminator();
94     if (terminator->IsReturnOrAbort()) {
95       return {std::move(context), terminator->PreviousNode()};
96     }
97   }
98   return {nullptr, nullptr};
99 }
100 
FoldInstruction(const std::string test_body,const uint32_t id_to_fold,spv_target_env spv_env)101 std::tuple<std::unique_ptr<IRContext>, Instruction*> FoldInstruction(
102     const std::string test_body, const uint32_t id_to_fold,
103     spv_target_env spv_env) {
104   // Build module.
105   std::unique_ptr<IRContext> context;
106   Instruction* inst = nullptr;
107   std::tie(context, inst) =
108       GetInstructionToFold(test_body, id_to_fold, spv_env);
109 
110   if (context == nullptr) {
111     return {nullptr, nullptr};
112   }
113 
114   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
115   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
116   EXPECT_EQ(inst->result_id(), original_inst->result_id());
117   EXPECT_EQ(inst->type_id(), original_inst->type_id());
118 
119   if (!succeeded && inst != nullptr) {
120     EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
121     for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
122       EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
123     }
124   }
125 
126   return {std::move(context), succeeded ? inst : nullptr};
127 }
128 
129 template <class ElementType, class Function>
CheckForExpectedScalarConstant(Instruction * inst,ElementType expected_result,Function GetValue)130 void CheckForExpectedScalarConstant(Instruction* inst,
131                                     ElementType expected_result,
132                                     Function GetValue) {
133   ASSERT_TRUE(inst);
134 
135   IRContext* context = inst->context();
136   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
137   while (inst->opcode() == spv::Op::OpCopyObject) {
138     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
139   }
140 
141   // Make sure we have a constant.
142   analysis::ConstantManager* const_mrg = context->get_constant_mgr();
143   const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
144   ASSERT_TRUE(constant);
145 
146   // Make sure the constant is a scalar.
147   const analysis::ScalarConstant* result = constant->AsScalarConstant();
148   ASSERT_TRUE(result);
149 
150   // Check if the result matches the expected value.
151   // If ExpectedType is not a float type, it should cast the value to a double
152   // and never get a nan.
153   if (!std::isnan(static_cast<double>(expected_result))) {
154     EXPECT_EQ(expected_result, GetValue(result));
155   } else {
156     EXPECT_TRUE(std::isnan(static_cast<double>(GetValue(result))));
157   }
158 }
159 
160 template <class ElementType, class Function>
CheckForExpectedVectorConstant(Instruction * inst,std::vector<ElementType> expected_result,Function GetValue)161 void CheckForExpectedVectorConstant(Instruction* inst,
162                                     std::vector<ElementType> expected_result,
163                                     Function GetValue) {
164   ASSERT_TRUE(inst);
165 
166   IRContext* context = inst->context();
167   EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
168   analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
169   inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
170   std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
171   EXPECT_THAT(opcodes, Contains(inst->opcode()));
172   analysis::ConstantManager* const_mrg = context->get_constant_mgr();
173   const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
174   EXPECT_NE(result, nullptr);
175   if (result != nullptr) {
176     const std::vector<const analysis::Constant*>& componenets =
177         result->AsVectorConstant()->GetComponents();
178     EXPECT_EQ(componenets.size(), expected_result.size());
179     for (size_t i = 0; i < componenets.size(); i++) {
180       EXPECT_EQ(expected_result[i], GetValue(componenets[i]));
181     }
182   }
183 }
184 
185 using IntegerInstructionFoldingTest =
186     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
187 
TEST_P(IntegerInstructionFoldingTest,Case)188 TEST_P(IntegerInstructionFoldingTest, Case) {
189   const auto& tc = GetParam();
190 
191   std::unique_ptr<IRContext> context;
192   Instruction* inst;
193   std::tie(context, inst) =
194       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
195   CheckForExpectedScalarConstant(
196       inst, tc.expected_result, [](const analysis::Constant* c) {
197         return c->AsScalarConstant()->GetU32BitValue();
198       });
199 }
200 
201 // Returns a common SPIR-V header for all of the test that follow.
202 #define INT_0_ID 100
203 #define TRUE_ID 101
204 #define VEC2_0_ID 102
205 #define INT_7_ID 103
206 #define FLOAT_0_ID 104
207 #define DOUBLE_0_ID 105
208 #define VEC4_0_ID 106
209 #define DVEC4_0_ID 106
210 #define HALF_0_ID 108
Header()211 const std::string& Header() {
212   static const std::string header = R"(OpCapability Shader
213 OpCapability Float16
214 OpCapability Float64
215 OpCapability Int8
216 OpCapability Int16
217 OpCapability Int64
218 OpCapability CooperativeMatrixKHR
219 OpExtension "SPV_KHR_cooperative_matrix"
220 %1 = OpExtInstImport "GLSL.std.450"
221 OpMemoryModel Logical GLSL450
222 OpEntryPoint Fragment %main "main"
223 OpExecutionMode %main OriginUpperLeft
224 OpSource GLSL 140
225 OpName %main "main"
226 %void = OpTypeVoid
227 %void_func = OpTypeFunction %void
228 %bool = OpTypeBool
229 %float = OpTypeFloat 32
230 %double = OpTypeFloat 64
231 %half = OpTypeFloat 16
232 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
233 %true = OpConstantTrue %bool
234 %false = OpConstantFalse %bool
235 %bool_null = OpConstantNull %bool
236 %short = OpTypeInt 16 1
237 %ushort = OpTypeInt 16 0
238 %byte = OpTypeInt 8 1
239 %ubyte = OpTypeInt 8 0
240 %int = OpTypeInt 32 1
241 %long = OpTypeInt 64 1
242 %uint = OpTypeInt 32 0
243 %ulong = OpTypeInt 64 0
244 %v2int = OpTypeVector %int 2
245 %v4int = OpTypeVector %int 4
246 %v2short = OpTypeVector %short 2
247 %v2long = OpTypeVector %long 2
248 %v4long = OpTypeVector %long 4
249 %v4float = OpTypeVector %float 4
250 %v4double = OpTypeVector %double 4
251 %v2uint = OpTypeVector %uint 2
252 %v2ulong = OpTypeVector %ulong 2
253 %v2float = OpTypeVector %float 2
254 %v2double = OpTypeVector %double 2
255 %v2half = OpTypeVector %half 2
256 %v2bool = OpTypeVector %bool 2
257 %m2x2int = OpTypeMatrix %v2int 2
258 %mat4v2float = OpTypeMatrix %v2float 4
259 %mat2v4float = OpTypeMatrix %v4float 2
260 %mat4v4float = OpTypeMatrix %v4float 4
261 %mat4v4double = OpTypeMatrix %v4double 4
262 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
263 %_ptr_int = OpTypePointer Function %int
264 %_ptr_uint = OpTypePointer Function %uint
265 %_ptr_bool = OpTypePointer Function %bool
266 %_ptr_float = OpTypePointer Function %float
267 %_ptr_double = OpTypePointer Function %double
268 %_ptr_half = OpTypePointer Function %half
269 %_ptr_long = OpTypePointer Function %long
270 %_ptr_ulong = OpTypePointer Function %ulong
271 %_ptr_v2int = OpTypePointer Function %v2int
272 %_ptr_v4int = OpTypePointer Function %v4int
273 %_ptr_v4float = OpTypePointer Function %v4float
274 %_ptr_v4double = OpTypePointer Function %v4double
275 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
276 %_ptr_v2float = OpTypePointer Function %v2float
277 %_ptr_v2double = OpTypePointer Function %v2double
278 %int_2 = OpConstant %int 2
279 %int_arr_2 = OpTypeArray %int %int_2
280 %short_0 = OpConstant %short 0
281 %short_2 = OpConstant %short 2
282 %short_3 = OpConstant %short 3
283 %short_n5 = OpConstant %short -5
284 %ubyte_1 = OpConstant %ubyte 1
285 %byte_n1 = OpConstant %byte -1
286 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
287 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
288 %int_0 = OpConstant %int 0
289 %int_1 = OpConstant %int 1
290 %int_3 = OpConstant %int 3
291 %int_4 = OpConstant %int 4
292 %int_10 = OpConstant %int 10
293 %int_1073741824 = OpConstant %int 1073741824
294 %int_n1 = OpConstant %int -1
295 %int_n24 = OpConstant %int -24
296 %int_n858993459 = OpConstant %int -858993459
297 %int_min = OpConstant %int -2147483648
298 %int_max = OpConstant %int 2147483647
299 %long_0 = OpConstant %long 0
300 %long_1 = OpConstant %long 1
301 %long_2 = OpConstant %long 2
302 %long_3 = OpConstant %long 3
303 %long_n3 = OpConstant %long -3
304 %long_7 = OpConstant %long 7
305 %long_n7 = OpConstant %long -7
306 %long_10 = OpConstant %long 10
307 %long_32768 = OpConstant %long 32768
308 %long_n57344 = OpConstant %long -57344
309 %long_n4611686018427387904 = OpConstant %long -4611686018427387904
310 %long_4611686018427387904 = OpConstant %long 4611686018427387904
311 %long_n1 = OpConstant %long -1
312 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
313 %long_min = OpConstant %long -9223372036854775808
314 %long_max = OpConstant %long 9223372036854775807
315 %ulong_7 = OpConstant %ulong 7
316 %ulong_4611686018427387904 = OpConstant %ulong 4611686018427387904
317 %uint_0 = OpConstant %uint 0
318 %uint_1 = OpConstant %uint 1
319 %uint_2 = OpConstant %uint 2
320 %uint_3 = OpConstant %uint 3
321 %uint_4 = OpConstant %uint 4
322 %uint_32 = OpConstant %uint 32
323 %uint_42 = OpConstant %uint 42
324 %uint_2147483649 = OpConstant %uint 2147483649
325 %uint_max = OpConstant %uint 4294967295
326 %ulong_0 = OpConstant %ulong 0
327 %ulong_1 = OpConstant %ulong 1
328 %ulong_2 = OpConstant %ulong 2
329 %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809
330 %ulong_max = OpConstant %ulong 18446744073709551615
331 %v2int_undef = OpUndef %v2int
332 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
333 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
334 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
335 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
336 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
337 %v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24
338 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
339 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
340 %v2short_2_n5 = OpConstantComposite %v2short %short_2 %short_n5
341 %v2long_2_2 = OpConstantComposite %v2long %long_2 %long_2
342 %v2long_2_3 = OpConstantComposite %v2long %long_2 %long_3
343 %v2bool_null = OpConstantNull %v2bool
344 %v2bool_true_false = OpConstantComposite %v2bool %true %false
345 %v2bool_false_true = OpConstantComposite %v2bool %false %true
346 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
347 %v2int_null = OpConstantNull %v2int
348 %102 = OpConstantComposite %v2int %103 %103
349 %v4int_undef = OpUndef %v4int
350 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
351 %m2x2int_undef = OpUndef %m2x2int
352 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
353 %float_n1 = OpConstant %float -1
354 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
355 %float_null = OpConstantNull %float
356 %float_0 = OpConstant %float 0
357 %float_n0 = OpConstant %float -0.0
358 %float_1 = OpConstant %float 1
359 %float_2 = OpConstant %float 2
360 %float_3 = OpConstant %float 3
361 %float_4 = OpConstant %float 4
362 %float_2049 = OpConstant %float 2049
363 %float_n2049 = OpConstant %float -2049
364 %float_0p5 = OpConstant %float 0.5
365 %float_0p2 = OpConstant %float 0.2
366 %float_pi = OpConstant %float 1.5555
367 %float_1e16 = OpConstant %float 1e16
368 %float_n1e16 = OpConstant %float -1e16
369 %float_1en16 = OpConstant %float 1e-16
370 %float_n1en16 = OpConstant %float -1e-16
371 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
372 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
373 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
374 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
375 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
376 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
377 %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
378 %v2float_null = OpConstantNull %v2float
379 %double_n1 = OpConstant %double -1
380 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
381 %double_null = OpConstantNull %double
382 %double_0 = OpConstant %double 0
383 %double_n0 = OpConstant %double -0.0
384 %double_1 = OpConstant %double 1
385 %double_2 = OpConstant %double 2
386 %double_3 = OpConstant %double 3
387 %double_4 = OpConstant %double 4
388 %double_5 = OpConstant %double 5
389 %double_0p5 = OpConstant %double 0.5
390 %double_0p2 = OpConstant %double 0.2
391 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
392 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
393 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
394 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
395 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
396 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
397 %v2double_null = OpConstantNull %v2double
398 %108 = OpConstant %half 0
399 %half_1 = OpConstant %half 1
400 %half_2 = OpConstant %half 2
401 %half_0_1 = OpConstantComposite %v2half %108 %half_1
402 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
403 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
404 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
405 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
406 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
407 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
408 %v4float_null = OpConstantNull %v4float
409 %mat2v4float_null = OpConstantNull %mat2v4float
410 %mat4v4float_null = OpConstantNull %mat4v4float
411 %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
412 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null
413 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
414 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
415 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
416 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
417 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
418 %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4
419 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
420 %v4double_null = OpConstantNull %v4double
421 %mat4v4double_null = OpConstantNull %mat4v4double
422 %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
423 %mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null
424 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
425 %uint_0x3f800000 = OpConstant %uint 0x3f800000
426 %uint_0xbf800000 = OpConstant %uint 0xbf800000
427 %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000
428 %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000
429 %int_0x3FF00000 = OpConstant %int 0x3FF00000
430 %int_0x00000000 = OpConstant %int 0x00000000
431 %int_0xC05FD666 = OpConstant %int 0xC05FD666
432 %int_0x66666666 = OpConstant %int 0x66666666
433 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
434 %ushort_0x4400 = OpConstant %ushort 0x4400
435 %short_0x4400 = OpConstant %short 0x4400
436 %ushort_0xBC00 = OpConstant %ushort 0xBC00
437 %short_0xBC00 = OpConstant %short 0xBC00
438 %int_arr_2_undef = OpUndef %int_arr_2
439 %int_coop_matrix = OpTypeCooperativeMatrixKHR %int %uint_3 %uint_3 %uint_32 %uint_0
440 %undef_int_coop_matrix = OpUndef %int_coop_matrix
441 %uint_coop_matrix = OpTypeCooperativeMatrixKHR %uint %uint_3 %uint_3 %uint_32 %uint_0
442 %undef_uint_coop_matrix = OpUndef %uint_coop_matrix
443 %float_coop_matrix = OpTypeCooperativeMatrixKHR %float %uint_3 %uint_3 %uint_32 %uint_0
444 %undef_float_coop_matrix = OpUndef %float_coop_matrix
445 )";
446 
447   return header;
448 }
449 
450 // Returns the header with definitions of float NaN and double NaN. Since FC
451 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
452 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
453 // %double_n0 = OpConstant %double -0,
454 // we separates those definitions from Header().
HeaderWithNaN()455 const std::string& HeaderWithNaN() {
456   static const std::string headerWithNaN =
457       Header() +
458       R"(%float_nan = OpConstant %float -0x1.8p+128
459 %double_nan = OpConstant %double -0x1.8p+1024
460 )";
461 
462   return headerWithNaN;
463 }
464 
465 // clang-format off
466 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
467                         ::testing::Values(
468   // Test case 0: fold 0*n
469   InstructionFoldingCase<uint32_t>(
470     Header() + "%main = OpFunction %void None %void_func\n" +
471     "%main_lab = OpLabel\n" +
472            "%n = OpVariable %_ptr_int Function\n" +
473         "%load = OpLoad %int %n\n" +
474            "%2 = OpIMul %int %int_0 %load\n" +
475                 "OpReturn\n" +
476                 "OpFunctionEnd",
477     2, 0),
478   // Test case 1: fold n*0
479   InstructionFoldingCase<uint32_t>(
480     Header() + "%main = OpFunction %void None %void_func\n" +
481         "%main_lab = OpLabel\n" +
482         "%n = OpVariable %_ptr_int Function\n" +
483         "%load = OpLoad %int %n\n" +
484         "%2 = OpIMul %int %load %int_0\n" +
485         "OpReturn\n" +
486         "OpFunctionEnd",
487     2, 0),
488   // Test case 2: fold 0/n (signed)
489   InstructionFoldingCase<uint32_t>(
490     Header() + "%main = OpFunction %void None %void_func\n" +
491         "%main_lab = OpLabel\n" +
492         "%n = OpVariable %_ptr_int Function\n" +
493         "%load = OpLoad %int %n\n" +
494         "%2 = OpSDiv %int %int_0 %load\n" +
495         "OpReturn\n" +
496         "OpFunctionEnd",
497         2, 0),
498   // Test case 3: fold n/0 (signed)
499   InstructionFoldingCase<uint32_t>(
500     Header() + "%main = OpFunction %void None %void_func\n" +
501         "%main_lab = OpLabel\n" +
502         "%n = OpVariable %_ptr_int Function\n" +
503         "%load = OpLoad %int %n\n" +
504         "%2 = OpSDiv %int %load %int_0\n" +
505         "OpReturn\n" +
506         "OpFunctionEnd",
507     2, 0),
508   // Test case 4: fold 0/n (unsigned)
509   InstructionFoldingCase<uint32_t>(
510     Header() + "%main = OpFunction %void None %void_func\n" +
511         "%main_lab = OpLabel\n" +
512         "%n = OpVariable %_ptr_uint Function\n" +
513         "%load = OpLoad %uint %n\n" +
514         "%2 = OpUDiv %uint %uint_0 %load\n" +
515         "OpReturn\n" +
516         "OpFunctionEnd",
517     2, 0),
518   // Test case 5: fold n/0 (unsigned)
519   InstructionFoldingCase<uint32_t>(
520     Header() + "%main = OpFunction %void None %void_func\n" +
521         "%main_lab = OpLabel\n" +
522         "%n = OpVariable %_ptr_int Function\n" +
523         "%load = OpLoad %int %n\n" +
524         "%2 = OpSDiv %int %load %int_0\n" +
525         "OpReturn\n" +
526         "OpFunctionEnd",
527     2, 0),
528   // Test case 6: fold 0 remainder n
529   InstructionFoldingCase<uint32_t>(
530     Header() + "%main = OpFunction %void None %void_func\n" +
531         "%main_lab = OpLabel\n" +
532         "%n = OpVariable %_ptr_int Function\n" +
533         "%load = OpLoad %int %n\n" +
534         "%2 = OpSRem %int %int_0 %load\n" +
535         "OpReturn\n" +
536         "OpFunctionEnd",
537     2, 0),
538   // Test case 7: fold n remainder 0
539   InstructionFoldingCase<uint32_t>(
540     Header() + "%main = OpFunction %void None %void_func\n" +
541         "%main_lab = OpLabel\n" +
542         "%n = OpVariable %_ptr_int Function\n" +
543         "%load = OpLoad %int %n\n" +
544         "%2 = OpSRem %int %load %int_0\n" +
545         "OpReturn\n" +
546         "OpFunctionEnd",
547     2, 0),
548   // Test case 8: fold 0%n (signed)
549   InstructionFoldingCase<uint32_t>(
550     Header() + "%main = OpFunction %void None %void_func\n" +
551         "%main_lab = OpLabel\n" +
552         "%n = OpVariable %_ptr_int Function\n" +
553         "%load = OpLoad %int %n\n" +
554         "%2 = OpSMod %int %int_0 %load\n" +
555         "OpReturn\n" +
556         "OpFunctionEnd",
557     2, 0),
558   // Test case 9: fold n%0 (signed)
559   InstructionFoldingCase<uint32_t>(
560     Header() + "%main = OpFunction %void None %void_func\n" +
561         "%main_lab = OpLabel\n" +
562         "%n = OpVariable %_ptr_int Function\n" +
563         "%load = OpLoad %int %n\n" +
564         "%2 = OpSMod %int %load %int_0\n" +
565         "OpReturn\n" +
566         "OpFunctionEnd",
567     2, 0),
568   // Test case 10: fold 0%n (unsigned)
569   InstructionFoldingCase<uint32_t>(
570     Header() + "%main = OpFunction %void None %void_func\n" +
571         "%main_lab = OpLabel\n" +
572         "%n = OpVariable %_ptr_uint Function\n" +
573         "%load = OpLoad %uint %n\n" +
574         "%2 = OpUMod %uint %uint_0 %load\n" +
575         "OpReturn\n" +
576         "OpFunctionEnd",
577     2, 0),
578   // Test case 11: fold n%0 (unsigned)
579   InstructionFoldingCase<uint32_t>(
580     Header() + "%main = OpFunction %void None %void_func\n" +
581         "%main_lab = OpLabel\n" +
582         "%n = OpVariable %_ptr_uint Function\n" +
583         "%load = OpLoad %uint %n\n" +
584         "%2 = OpUMod %uint %load %uint_0\n" +
585         "OpReturn\n" +
586         "OpFunctionEnd",
587     2, 0),
588   // Test case 12: fold n << 32
589   InstructionFoldingCase<uint32_t>(
590       Header() + "%main = OpFunction %void None %void_func\n" +
591           "%main_lab = OpLabel\n" +
592           "%n = OpVariable %_ptr_uint Function\n" +
593           "%load = OpLoad %uint %n\n" +
594           "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
595           "OpReturn\n" +
596           "OpFunctionEnd",
597       2, 0),
598   // Test case 13: fold n >> 32
599   InstructionFoldingCase<uint32_t>(
600       Header() + "%main = OpFunction %void None %void_func\n" +
601           "%main_lab = OpLabel\n" +
602           "%n = OpVariable %_ptr_uint Function\n" +
603           "%load = OpLoad %uint %n\n" +
604           "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
605           "OpReturn\n" +
606           "OpFunctionEnd",
607       2, 0),
608   // Test case 14: fold n | 0xFFFFFFFF
609   InstructionFoldingCase<uint32_t>(
610       Header() + "%main = OpFunction %void None %void_func\n" +
611   "%main_lab = OpLabel\n" +
612   "%n = OpVariable %_ptr_uint Function\n" +
613   "%load = OpLoad %uint %n\n" +
614   "%2 = OpBitwiseOr %uint %load %uint_max\n" +
615   "OpReturn\n" +
616   "OpFunctionEnd",
617   2, 0xFFFFFFFF),
618   // Test case 15: fold 0xFFFFFFFF | n
619   InstructionFoldingCase<uint32_t>(
620       Header() + "%main = OpFunction %void None %void_func\n" +
621           "%main_lab = OpLabel\n" +
622           "%n = OpVariable %_ptr_uint Function\n" +
623           "%load = OpLoad %uint %n\n" +
624           "%2 = OpBitwiseOr %uint %uint_max %load\n" +
625           "OpReturn\n" +
626           "OpFunctionEnd",
627       2, 0xFFFFFFFF),
628   // Test case 16: fold n & 0
629   InstructionFoldingCase<uint32_t>(
630       Header() + "%main = OpFunction %void None %void_func\n" +
631           "%main_lab = OpLabel\n" +
632           "%n = OpVariable %_ptr_uint Function\n" +
633           "%load = OpLoad %uint %n\n" +
634           "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
635           "OpReturn\n" +
636           "OpFunctionEnd",
637       2, 0),
638   // Test case 17: fold 1/0 (signed)
639   InstructionFoldingCase<uint32_t>(
640       Header() + "%main = OpFunction %void None %void_func\n" +
641           "%main_lab = OpLabel\n" +
642           "%2 = OpSDiv %int %int_1 %int_0\n" +
643           "OpReturn\n" +
644           "OpFunctionEnd",
645       2, 0),
646   // Test case 18: fold 1/0 (unsigned)
647   InstructionFoldingCase<uint32_t>(
648       Header() + "%main = OpFunction %void None %void_func\n" +
649           "%main_lab = OpLabel\n" +
650           "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
651           "OpReturn\n" +
652           "OpFunctionEnd",
653       2, 0),
654   // Test case 19: fold OpSRem 1 0 (signed)
655   InstructionFoldingCase<uint32_t>(
656       Header() + "%main = OpFunction %void None %void_func\n" +
657           "%main_lab = OpLabel\n" +
658           "%2 = OpSRem %int %int_1 %int_0\n" +
659           "OpReturn\n" +
660           "OpFunctionEnd",
661       2, 0),
662   // Test case 20: fold 1%0 (signed)
663   InstructionFoldingCase<uint32_t>(
664       Header() + "%main = OpFunction %void None %void_func\n" +
665           "%main_lab = OpLabel\n" +
666           "%2 = OpSMod %int %int_1 %int_0\n" +
667           "OpReturn\n" +
668           "OpFunctionEnd",
669       2, 0),
670   // Test case 21: fold 1%0 (unsigned)
671   InstructionFoldingCase<uint32_t>(
672       Header() + "%main = OpFunction %void None %void_func\n" +
673           "%main_lab = OpLabel\n" +
674           "%2 = OpUMod %uint %uint_1 %uint_0\n" +
675           "OpReturn\n" +
676           "OpFunctionEnd",
677       2, 0),
678   // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
679   InstructionFoldingCase<uint32_t>(
680       Header() + "%main = OpFunction %void None %void_func\n" +
681           "%main_lab = OpLabel\n" +
682           "%n = OpVariable %_ptr_uint Function\n" +
683           "%load = OpLoad %uint %n\n" +
684           "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
685           "OpReturn\n" +
686           "OpFunctionEnd",
687       2, 0),
688   // Test case 23: fold signed n >> 42 (undefined, so set to zero).
689   InstructionFoldingCase<uint32_t>(
690       Header() + "%main = OpFunction %void None %void_func\n" +
691           "%main_lab = OpLabel\n" +
692           "%n = OpVariable %_ptr_int Function\n" +
693           "%load = OpLoad %int %n\n" +
694           "%2 = OpShiftRightLogical %int %load %uint_42\n" +
695           "OpReturn\n" +
696           "OpFunctionEnd",
697       2, 0),
698   // Test case 24: fold n << 42 (undefined, so set to zero).
699   InstructionFoldingCase<uint32_t>(
700       Header() + "%main = OpFunction %void None %void_func\n" +
701           "%main_lab = OpLabel\n" +
702           "%n = OpVariable %_ptr_int Function\n" +
703           "%load = OpLoad %int %n\n" +
704           "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
705           "OpReturn\n" +
706           "OpFunctionEnd",
707       2, 0),
708   // Test case 25: fold -24 >> 32 (defined as -1)
709   InstructionFoldingCase<uint32_t>(
710       Header() + "%main = OpFunction %void None %void_func\n" +
711           "%main_lab = OpLabel\n" +
712           "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
713           "OpReturn\n" +
714           "OpFunctionEnd",
715       2, -1),
716   // Test case 26: fold 2 >> 32 (signed)
717   InstructionFoldingCase<uint32_t>(
718       Header() + "%main = OpFunction %void None %void_func\n" +
719           "%main_lab = OpLabel\n" +
720           "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
721           "OpReturn\n" +
722           "OpFunctionEnd",
723       2, 0),
724   // Test case 27: fold 2 >> 32 (unsigned)
725   InstructionFoldingCase<uint32_t>(
726       Header() + "%main = OpFunction %void None %void_func\n" +
727           "%main_lab = OpLabel\n" +
728           "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
729           "OpReturn\n" +
730           "OpFunctionEnd",
731       2, 0),
732   // Test case 28: fold 2 << 32
733   InstructionFoldingCase<uint32_t>(
734       Header() + "%main = OpFunction %void None %void_func\n" +
735           "%main_lab = OpLabel\n" +
736           "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
737           "OpReturn\n" +
738           "OpFunctionEnd",
739       2, 0),
740   // Test case 29: fold -INT_MIN
741   InstructionFoldingCase<uint32_t>(
742       Header() + "%main = OpFunction %void None %void_func\n" +
743           "%main_lab = OpLabel\n" +
744           "%2 = OpSNegate %int %int_min\n" +
745           "OpReturn\n" +
746           "OpFunctionEnd",
747       2, std::numeric_limits<int32_t>::min()),
748   // Test case 30: fold UMin 3 4
749   InstructionFoldingCase<uint32_t>(
750       Header() + "%main = OpFunction %void None %void_func\n" +
751           "%main_lab = OpLabel\n" +
752           "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
753           "OpReturn\n" +
754           "OpFunctionEnd",
755       2, 3),
756   // Test case 31: fold UMin 4 2
757   InstructionFoldingCase<uint32_t>(
758       Header() + "%main = OpFunction %void None %void_func\n" +
759           "%main_lab = OpLabel\n" +
760           "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
761           "OpReturn\n" +
762           "OpFunctionEnd",
763       2, 2),
764   // Test case 32: fold SMin 3 4
765   InstructionFoldingCase<uint32_t>(
766       Header() + "%main = OpFunction %void None %void_func\n" +
767           "%main_lab = OpLabel\n" +
768           "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
769           "OpReturn\n" +
770           "OpFunctionEnd",
771       2, 3),
772   // Test case 33: fold SMin 4 2
773   InstructionFoldingCase<uint32_t>(
774       Header() + "%main = OpFunction %void None %void_func\n" +
775           "%main_lab = OpLabel\n" +
776           "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
777           "OpReturn\n" +
778           "OpFunctionEnd",
779       2, 2),
780   // Test case 34: fold UMax 3 4
781   InstructionFoldingCase<uint32_t>(
782       Header() + "%main = OpFunction %void None %void_func\n" +
783           "%main_lab = OpLabel\n" +
784           "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
785           "OpReturn\n" +
786           "OpFunctionEnd",
787       2, 4),
788   // Test case 35: fold UMax 3 2
789   InstructionFoldingCase<uint32_t>(
790       Header() + "%main = OpFunction %void None %void_func\n" +
791           "%main_lab = OpLabel\n" +
792           "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
793           "OpReturn\n" +
794           "OpFunctionEnd",
795       2, 3),
796   // Test case 36: fold SMax 3 4
797   InstructionFoldingCase<uint32_t>(
798       Header() + "%main = OpFunction %void None %void_func\n" +
799           "%main_lab = OpLabel\n" +
800           "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
801           "OpReturn\n" +
802           "OpFunctionEnd",
803       2, 4),
804   // Test case 37: fold SMax 3 2
805   InstructionFoldingCase<uint32_t>(
806       Header() + "%main = OpFunction %void None %void_func\n" +
807           "%main_lab = OpLabel\n" +
808           "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
809           "OpReturn\n" +
810           "OpFunctionEnd",
811       2, 3),
812   // Test case 38: fold UClamp 2 3 4
813   InstructionFoldingCase<uint32_t>(
814       Header() + "%main = OpFunction %void None %void_func\n" +
815           "%main_lab = OpLabel\n" +
816           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
817           "OpReturn\n" +
818           "OpFunctionEnd",
819       2, 3),
820   // Test case 39: fold UClamp 2 0 4
821   InstructionFoldingCase<uint32_t>(
822       Header() + "%main = OpFunction %void None %void_func\n" +
823           "%main_lab = OpLabel\n" +
824           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
825           "OpReturn\n" +
826           "OpFunctionEnd",
827       2, 2),
828   // Test case 40: fold UClamp 2 0 1
829   InstructionFoldingCase<uint32_t>(
830       Header() + "%main = OpFunction %void None %void_func\n" +
831           "%main_lab = OpLabel\n" +
832           "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
833           "OpReturn\n" +
834           "OpFunctionEnd",
835       2, 1),
836   // Test case 41: fold SClamp 2 3 4
837   InstructionFoldingCase<uint32_t>(
838       Header() + "%main = OpFunction %void None %void_func\n" +
839           "%main_lab = OpLabel\n" +
840           "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
841           "OpReturn\n" +
842           "OpFunctionEnd",
843       2, 3),
844   // Test case 42: fold SClamp 2 0 4
845   InstructionFoldingCase<uint32_t>(
846       Header() + "%main = OpFunction %void None %void_func\n" +
847           "%main_lab = OpLabel\n" +
848           "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
849           "OpReturn\n" +
850           "OpFunctionEnd",
851       2, 2),
852   // Test case 43: fold SClamp 2 0 1
853   InstructionFoldingCase<uint32_t>(
854       Header() + "%main = OpFunction %void None %void_func\n" +
855           "%main_lab = OpLabel\n" +
856           "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
857           "OpReturn\n" +
858           "OpFunctionEnd",
859       2, 1),
860   // Test case 44: SClamp 1 2 x
861   InstructionFoldingCase<uint32_t>(
862       Header() + "%main = OpFunction %void None %void_func\n" +
863           "%main_lab = OpLabel\n" +
864           "%undef = OpUndef %int\n" +
865           "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
866           "OpReturn\n" +
867           "OpFunctionEnd",
868       2, 2),
869   // Test case 45: SClamp 2 x 1
870   InstructionFoldingCase<uint32_t>(
871       Header() + "%main = OpFunction %void None %void_func\n" +
872           "%main_lab = OpLabel\n" +
873           "%undef = OpUndef %int\n" +
874           "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
875           "OpReturn\n" +
876           "OpFunctionEnd",
877       2, 1),
878   // Test case 46: UClamp 1 2 x
879   InstructionFoldingCase<uint32_t>(
880       Header() + "%main = OpFunction %void None %void_func\n" +
881           "%main_lab = OpLabel\n" +
882           "%undef = OpUndef %uint\n" +
883           "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
884           "OpReturn\n" +
885           "OpFunctionEnd",
886       2, 2),
887   // Test case 47: UClamp 2 x 1
888   InstructionFoldingCase<uint32_t>(
889       Header() + "%main = OpFunction %void None %void_func\n" +
890           "%main_lab = OpLabel\n" +
891           "%undef = OpUndef %uint\n" +
892           "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
893           "OpReturn\n" +
894           "OpFunctionEnd",
895       2, 1),
896     // Test case 48: Bit-cast int 0 to unsigned int
897     InstructionFoldingCase<uint32_t>(
898         Header() + "%main = OpFunction %void None %void_func\n" +
899             "%main_lab = OpLabel\n" +
900             "%2 = OpBitcast %uint %int_0\n" +
901             "OpReturn\n" +
902             "OpFunctionEnd",
903         2, 0),
904     // Test case 49: Bit-cast int -24 to unsigned int
905     InstructionFoldingCase<uint32_t>(
906         Header() + "%main = OpFunction %void None %void_func\n" +
907             "%main_lab = OpLabel\n" +
908             "%2 = OpBitcast %uint %int_n24\n" +
909             "OpReturn\n" +
910             "OpFunctionEnd",
911         2, static_cast<uint32_t>(-24)),
912     // Test case 50: Bit-cast float 1.0f to unsigned int
913     InstructionFoldingCase<uint32_t>(
914         Header() + "%main = OpFunction %void None %void_func\n" +
915             "%main_lab = OpLabel\n" +
916             "%2 = OpBitcast %uint %float_1\n" +
917             "OpReturn\n" +
918             "OpFunctionEnd",
919         2, static_cast<uint32_t>(0x3f800000)),
920     // Test case 51: Bit-cast ushort 0xBC00 to ushort
921     InstructionFoldingCase<uint32_t>(
922         Header() + "%main = OpFunction %void None %void_func\n" +
923             "%main_lab = OpLabel\n" +
924             "%2 = OpBitcast %ushort %ushort_0xBC00\n" +
925             "OpReturn\n" +
926             "OpFunctionEnd",
927         2, 0xBC00),
928     // Test case 52: Bit-cast short 0xBC00 to ushort
929     InstructionFoldingCase<uint32_t>(
930         Header() + "%main = OpFunction %void None %void_func\n" +
931             "%main_lab = OpLabel\n" +
932             "%2 = OpBitcast %ushort %short_0xBC00\n" +
933             "OpReturn\n" +
934             "OpFunctionEnd",
935         2, 0xBC00),
936     // Test case 53: Bit-cast half 1 to ushort
937     InstructionFoldingCase<uint32_t>(
938         Header() + "%main = OpFunction %void None %void_func\n" +
939             "%main_lab = OpLabel\n" +
940             "%2 = OpBitcast %ushort %half_1\n" +
941             "OpReturn\n" +
942             "OpFunctionEnd",
943         2, 0x3C00),
944     // Test case 54: Bit-cast ushort 0xBC00 to short
945     InstructionFoldingCase<uint32_t>(
946         Header() + "%main = OpFunction %void None %void_func\n" +
947             "%main_lab = OpLabel\n" +
948             "%2 = OpBitcast %short %ushort_0xBC00\n" +
949             "OpReturn\n" +
950             "OpFunctionEnd",
951         2, 0xFFFFBC00),
952     // Test case 55: Bit-cast short 0xBC00 to short
953     InstructionFoldingCase<uint32_t>(
954         Header() + "%main = OpFunction %void None %void_func\n" +
955             "%main_lab = OpLabel\n" +
956             "%2 = OpBitcast %short %short_0xBC00\n" +
957             "OpReturn\n" +
958             "OpFunctionEnd",
959         2, 0xFFFFBC00),
960     // Test case 56: Bit-cast half 1 to short
961     InstructionFoldingCase<uint32_t>(
962         Header() + "%main = OpFunction %void None %void_func\n" +
963             "%main_lab = OpLabel\n" +
964             "%2 = OpBitcast %short %half_1\n" +
965             "OpReturn\n" +
966             "OpFunctionEnd",
967         2, 0x3C00),
968     // Test case 57: Bit-cast ushort 0xBC00 to half
969     InstructionFoldingCase<uint32_t>(
970         Header() + "%main = OpFunction %void None %void_func\n" +
971             "%main_lab = OpLabel\n" +
972             "%2 = OpBitcast %half %ushort_0xBC00\n" +
973             "OpReturn\n" +
974             "OpFunctionEnd",
975         2, 0xBC00),
976     // Test case 58: Bit-cast short 0xBC00 to half
977     InstructionFoldingCase<uint32_t>(
978         Header() + "%main = OpFunction %void None %void_func\n" +
979             "%main_lab = OpLabel\n" +
980             "%2 = OpBitcast %half %short_0xBC00\n" +
981             "OpReturn\n" +
982             "OpFunctionEnd",
983         2, 0xFFFFBC00),
984     // Test case 59: Bit-cast half 1 to half
985     InstructionFoldingCase<uint32_t>(
986         Header() + "%main = OpFunction %void None %void_func\n" +
987             "%main_lab = OpLabel\n" +
988             "%2 = OpBitcast %half %half_1\n" +
989             "OpReturn\n" +
990             "OpFunctionEnd",
991         2, 0x3C00),
992     // Test case 60: Bit-cast ubyte 1 to byte
993     InstructionFoldingCase<uint32_t>(
994         Header() + "%main = OpFunction %void None %void_func\n" +
995             "%main_lab = OpLabel\n" +
996             "%2 = OpBitcast %byte %ubyte_1\n" +
997             "OpReturn\n" +
998             "OpFunctionEnd",
999         2, 1),
1000     // Test case 61: Bit-cast byte -1 to ubyte
1001     InstructionFoldingCase<uint32_t>(
1002         Header() + "%main = OpFunction %void None %void_func\n" +
1003             "%main_lab = OpLabel\n" +
1004             "%2 = OpBitcast %ubyte %byte_n1\n" +
1005             "OpReturn\n" +
1006             "OpFunctionEnd",
1007         2, 0xFF),
1008     // Test case 62: Negate 2.
1009     InstructionFoldingCase<uint32_t>(
1010         Header() + "%main = OpFunction %void None %void_func\n" +
1011             "%main_lab = OpLabel\n" +
1012             "%2 = OpSNegate %int %int_2\n" +
1013             "OpReturn\n" +
1014             "OpFunctionEnd",
1015         2, -2),
1016     // Test case 63: Negate negative short.
1017     InstructionFoldingCase<uint32_t>(
1018         Header() + "%main = OpFunction %void None %void_func\n" +
1019             "%main_lab = OpLabel\n" +
1020             "%2 = OpSNegate %short %short_0xBC00\n" +
1021             "OpReturn\n" +
1022             "OpFunctionEnd",
1023         2, 0x4400 /* expected to be sign extended. */),
1024     // Test case 64: Negate positive short.
1025     InstructionFoldingCase<uint32_t>(
1026         Header() + "%main = OpFunction %void None %void_func\n" +
1027             "%main_lab = OpLabel\n" +
1028             "%2 = OpSNegate %short %short_0x4400\n" +
1029             "OpReturn\n" +
1030             "OpFunctionEnd",
1031         2, 0xFFFFBC00 /* expected to be sign extended. */),
1032     // Test case 65: Negate a negative short.
1033     InstructionFoldingCase<uint32_t>(
1034         Header() + "%main = OpFunction %void None %void_func\n" +
1035             "%main_lab = OpLabel\n" +
1036             "%2 = OpSNegate %ushort %ushort_0xBC00\n" +
1037             "OpReturn\n" +
1038             "OpFunctionEnd",
1039         2, 0x4400 /* expected to be zero extended. */),
1040     // Test case 66: Negate positive short.
1041     InstructionFoldingCase<uint32_t>(
1042         Header() + "%main = OpFunction %void None %void_func\n" +
1043             "%main_lab = OpLabel\n" +
1044             "%2 = OpSNegate %ushort %ushort_0x4400\n" +
1045             "OpReturn\n" +
1046             "OpFunctionEnd",
1047         2, 0xBC00 /* expected to be zero extended. */),
1048     // Test case 67: Fold 2 + 3 (short)
1049     InstructionFoldingCase<uint32_t>(
1050         Header() + "%main = OpFunction %void None %void_func\n" +
1051             "%main_lab = OpLabel\n" +
1052             "%2 = OpIAdd %short %short_2 %short_3\n" +
1053             "OpReturn\n" +
1054             "OpFunctionEnd",
1055         2, 5),
1056     // Test case 68: Fold 2 + -5 (short)
1057     InstructionFoldingCase<uint32_t>(
1058         Header() + "%main = OpFunction %void None %void_func\n" +
1059             "%main_lab = OpLabel\n" +
1060             "%2 = OpIAdd %short %short_2 %short_n5\n" +
1061             "OpReturn\n" +
1062             "OpFunctionEnd",
1063         2, -3),
1064   // Test case 69: Fold int(3ll)
1065   InstructionFoldingCase<uint32_t>(
1066       Header() + "%main = OpFunction %void None %void_func\n" +
1067           "%main_lab = OpLabel\n" +
1068           "%2 = OpSConvert %int %long_3\n" +
1069           "OpReturn\n" +
1070           "OpFunctionEnd",
1071       2, 3),
1072   // Test case 70: Fold short(-3ll)
1073   InstructionFoldingCase<uint32_t>(
1074       Header() + "%main = OpFunction %void None %void_func\n" +
1075           "%main_lab = OpLabel\n" +
1076           "%2 = OpSConvert %short %long_n3\n" +
1077           "OpReturn\n" +
1078           "OpFunctionEnd",
1079       2, -3),
1080   // Test case 71: Fold short(32768ll) - This should do a sign extend when
1081   // converting to short.
1082   InstructionFoldingCase<uint32_t>(
1083       Header() + "%main = OpFunction %void None %void_func\n" +
1084           "%main_lab = OpLabel\n" +
1085           "%2 = OpSConvert %short %long_32768\n" +
1086           "OpReturn\n" +
1087           "OpFunctionEnd",
1088       2, -32768),
1089   // Test case 72: Fold short(-57344) - This should do a sign extend when
1090   // converting to short making the upper bits 0.
1091   InstructionFoldingCase<uint32_t>(
1092       Header() + "%main = OpFunction %void None %void_func\n" +
1093           "%main_lab = OpLabel\n" +
1094           "%2 = OpSConvert %short %long_n57344\n" +
1095           "OpReturn\n" +
1096           "OpFunctionEnd",
1097       2, 8192),
1098   // Test case 73: Fold int(-5(short)). The -5 should be interpreted as an unsigned value, and be zero extended to 32-bits.
1099   InstructionFoldingCase<uint32_t>(
1100       Header() + "%main = OpFunction %void None %void_func\n" +
1101           "%main_lab = OpLabel\n" +
1102           "%2 = OpUConvert %uint %short_n5\n" +
1103           "OpReturn\n" +
1104           "OpFunctionEnd",
1105       2, 65531),
1106   // Test case 74: Fold short(-24(int)). The upper bits should be cleared. So 0xFFFFFFE8 should become 0x0000FFE8.
1107   InstructionFoldingCase<uint32_t>(
1108       Header() + "%main = OpFunction %void None %void_func\n" +
1109           "%main_lab = OpLabel\n" +
1110           "%2 = OpUConvert %ushort %int_n24\n" +
1111           "OpReturn\n" +
1112           "OpFunctionEnd",
1113       2, 65512)
1114 ));
1115 // clang-format on
1116 
1117 using LongIntegerInstructionFoldingTest =
1118     ::testing::TestWithParam<InstructionFoldingCase<uint64_t>>;
1119 
TEST_P(LongIntegerInstructionFoldingTest,Case)1120 TEST_P(LongIntegerInstructionFoldingTest, Case) {
1121   const auto& tc = GetParam();
1122 
1123   std::unique_ptr<IRContext> context;
1124   Instruction* inst;
1125   std::tie(context, inst) =
1126       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1127   CheckForExpectedScalarConstant(
1128       inst, tc.expected_result, [](const analysis::Constant* c) {
1129         return c->AsScalarConstant()->GetU64BitValue();
1130       });
1131 }
1132 
1133 INSTANTIATE_TEST_SUITE_P(
1134     TestCase, LongIntegerInstructionFoldingTest,
1135     ::testing::Values(
1136         // Test case 0: fold 1+4611686018427387904
1137         InstructionFoldingCase<uint64_t>(
1138             Header() + "%main = OpFunction %void None %void_func\n" +
1139                 "%main_lab = OpLabel\n" +
1140                 "%n = OpVariable %_ptr_int Function\n" +
1141                 "%load = OpLoad %int %n\n" +
1142                 "%2 = OpIAdd %long %long_1 %long_4611686018427387904\n" +
1143                 "OpReturn\n" + "OpFunctionEnd",
1144             2, 1 + 4611686018427387904),
1145         // Test case 1: fold 1-4611686018427387904
1146         InstructionFoldingCase<uint64_t>(
1147             Header() + "%main = OpFunction %void None %void_func\n" +
1148                 "%main_lab = OpLabel\n" +
1149                 "%n = OpVariable %_ptr_int Function\n" +
1150                 "%load = OpLoad %int %n\n" +
1151                 "%2 = OpISub %long %long_1 %long_4611686018427387904\n" +
1152                 "OpReturn\n" + "OpFunctionEnd",
1153             2, 1 - 4611686018427387904),
1154         // Test case 2: fold 2*4611686018427387904
1155         InstructionFoldingCase<uint64_t>(
1156             Header() + "%main = OpFunction %void None %void_func\n" +
1157                 "%main_lab = OpLabel\n" +
1158                 "%n = OpVariable %_ptr_int Function\n" +
1159                 "%load = OpLoad %int %n\n" +
1160                 "%2 = OpIMul %long %long_2 %long_4611686018427387904\n" +
1161                 "OpReturn\n" + "OpFunctionEnd",
1162             2, 9223372036854775808ull),
1163         // Test case 3: fold 4611686018427387904/2 (unsigned)
1164         InstructionFoldingCase<uint64_t>(
1165             Header() + "%main = OpFunction %void None %void_func\n" +
1166                 "%main_lab = OpLabel\n" +
1167                 "%n = OpVariable %_ptr_int Function\n" +
1168                 "%load = OpLoad %int %n\n" +
1169                 "%2 = OpUDiv %ulong %ulong_4611686018427387904 %ulong_2\n" +
1170                 "OpReturn\n" + "OpFunctionEnd",
1171             2, 4611686018427387904 / 2),
1172         // Test case 4: fold 4611686018427387904/2 (signed)
1173         InstructionFoldingCase<uint64_t>(
1174             Header() + "%main = OpFunction %void None %void_func\n" +
1175                 "%main_lab = OpLabel\n" +
1176                 "%n = OpVariable %_ptr_int Function\n" +
1177                 "%load = OpLoad %int %n\n" +
1178                 "%2 = OpSDiv %long %long_4611686018427387904 %long_2\n" +
1179                 "OpReturn\n" + "OpFunctionEnd",
1180             2, 4611686018427387904 / 2),
1181         // Test case 5: fold -4611686018427387904/2 (signed)
1182         InstructionFoldingCase<uint64_t>(
1183             Header() + "%main = OpFunction %void None %void_func\n" +
1184                 "%main_lab = OpLabel\n" +
1185                 "%n = OpVariable %_ptr_int Function\n" +
1186                 "%load = OpLoad %int %n\n" +
1187                 "%2 = OpSDiv %long %long_n4611686018427387904 %long_2\n" +
1188                 "OpReturn\n" + "OpFunctionEnd",
1189             2, -4611686018427387904 / 2),
1190         // Test case 6: fold 4611686018427387904 mod 7 (unsigned)
1191         InstructionFoldingCase<uint64_t>(
1192             Header() + "%main = OpFunction %void None %void_func\n" +
1193                 "%main_lab = OpLabel\n" +
1194                 "%n = OpVariable %_ptr_int Function\n" +
1195                 "%load = OpLoad %int %n\n" +
1196                 "%2 = OpUMod %ulong %ulong_4611686018427387904 %ulong_7\n" +
1197                 "OpReturn\n" + "OpFunctionEnd",
1198             2, 4611686018427387904ull % 7ull),
1199         // Test case 7: fold 7 mod 3 (signed)
1200         InstructionFoldingCase<uint64_t>(
1201             Header() + "%main = OpFunction %void None %void_func\n" +
1202                 "%main_lab = OpLabel\n" +
1203                 "%n = OpVariable %_ptr_int Function\n" +
1204                 "%load = OpLoad %int %n\n" +
1205                 "%2 = OpSMod %long %long_7 %long_3\n" + "OpReturn\n" +
1206                 "OpFunctionEnd",
1207             2, 1ull),
1208         // Test case 8: fold 7 rem 3 (signed)
1209         InstructionFoldingCase<uint64_t>(
1210             Header() + "%main = OpFunction %void None %void_func\n" +
1211                 "%main_lab = OpLabel\n" +
1212                 "%n = OpVariable %_ptr_int Function\n" +
1213                 "%load = OpLoad %int %n\n" +
1214                 "%2 = OpSRem %long %long_7 %long_3\n" + "OpReturn\n" +
1215                 "OpFunctionEnd",
1216             2, 1ull),
1217         // Test case 9: fold 7 mod -3 (signed)
1218         InstructionFoldingCase<uint64_t>(
1219             Header() + "%main = OpFunction %void None %void_func\n" +
1220                 "%main_lab = OpLabel\n" +
1221                 "%n = OpVariable %_ptr_int Function\n" +
1222                 "%load = OpLoad %int %n\n" +
1223                 "%2 = OpSMod %long %long_7 %long_n3\n" + "OpReturn\n" +
1224                 "OpFunctionEnd",
1225             2, -2ll),
1226         // Test case 10: fold 7 rem 3 (signed)
1227         InstructionFoldingCase<uint64_t>(
1228             Header() + "%main = OpFunction %void None %void_func\n" +
1229                 "%main_lab = OpLabel\n" +
1230                 "%n = OpVariable %_ptr_int Function\n" +
1231                 "%load = OpLoad %int %n\n" +
1232                 "%2 = OpSRem %long %long_7 %long_n3\n" + "OpReturn\n" +
1233                 "OpFunctionEnd",
1234             2, 1ll),
1235         // Test case 11: fold -7 mod 3 (signed)
1236         InstructionFoldingCase<uint64_t>(
1237             Header() + "%main = OpFunction %void None %void_func\n" +
1238                 "%main_lab = OpLabel\n" +
1239                 "%n = OpVariable %_ptr_int Function\n" +
1240                 "%load = OpLoad %int %n\n" +
1241                 "%2 = OpSMod %long %long_n7 %long_3\n" + "OpReturn\n" +
1242                 "OpFunctionEnd",
1243             2, 2ll),
1244         // Test case 12: fold -7 rem 3 (signed)
1245         InstructionFoldingCase<uint64_t>(
1246             Header() + "%main = OpFunction %void None %void_func\n" +
1247                 "%main_lab = OpLabel\n" +
1248                 "%n = OpVariable %_ptr_int Function\n" +
1249                 "%load = OpLoad %int %n\n" +
1250                 "%2 = OpSRem %long %long_n7 %long_3\n" + "OpReturn\n" +
1251                 "OpFunctionEnd",
1252             2, -1ll),
1253         // Test case 13: fold long(-24)
1254         InstructionFoldingCase<uint64_t>(
1255             Header() + "%main = OpFunction %void None %void_func\n" +
1256                 "%main_lab = OpLabel\n" +
1257                 "%n = OpVariable %_ptr_int Function\n" +
1258                 "%load = OpLoad %int %n\n" +
1259                 "%2 = OpSConvert %long %int_n24\n" + "OpReturn\n" +
1260                 "OpFunctionEnd",
1261             2, -24ll),
1262         // Test case 14: fold long(-24)
1263         InstructionFoldingCase<uint64_t>(
1264             Header() + "%main = OpFunction %void None %void_func\n" +
1265                 "%main_lab = OpLabel\n" +
1266                 "%n = OpVariable %_ptr_int Function\n" +
1267                 "%load = OpLoad %int %n\n" + "%2 = OpSConvert %long %int_10\n" +
1268                 "OpReturn\n" + "OpFunctionEnd",
1269             2, 10ll),
1270         // Test case 15: fold long(-24(short)).
1271         // The upper bits should be cleared. So 0xFFFFFFE8 should become
1272         // 0x000000000000FFE8.
1273         InstructionFoldingCase<uint64_t>(
1274             Header() + "%main = OpFunction %void None %void_func\n" +
1275                 "%main_lab = OpLabel\n" + "%2 = OpUConvert %ulong %short_n5\n" +
1276                 "OpReturn\n" + "OpFunctionEnd",
1277             2, 65531ull)));
1278 
1279 using UIntVectorInstructionFoldingTest =
1280     ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
1281 
TEST_P(UIntVectorInstructionFoldingTest,Case)1282 TEST_P(UIntVectorInstructionFoldingTest, Case) {
1283   const auto& tc = GetParam();
1284 
1285   std::unique_ptr<IRContext> context;
1286   Instruction* inst;
1287   std::tie(context, inst) =
1288       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1289   CheckForExpectedVectorConstant(
1290       inst, tc.expected_result,
1291       [](const analysis::Constant* c) { return c->GetU32(); });
1292 }
1293 
1294 // clang-format off
1295 INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest,
1296 ::testing::Values(
1297     // Test case 0: fold 0*n
1298     InstructionFoldingCase<std::vector<uint32_t>>(
1299         Header() + "%main = OpFunction %void None %void_func\n" +
1300             "%main_lab = OpLabel\n" +
1301             "%n = OpVariable %_ptr_int Function\n" +
1302             "%load = OpLoad %int %n\n" +
1303             "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
1304             "OpReturn\n" +
1305             "OpFunctionEnd",
1306         2, {2,3}),
1307     InstructionFoldingCase<std::vector<uint32_t>>(
1308       Header() + "%main = OpFunction %void None %void_func\n" +
1309           "%main_lab = OpLabel\n" +
1310           "%n = OpVariable %_ptr_int Function\n" +
1311           "%load = OpLoad %int %n\n" +
1312           "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
1313           "OpReturn\n" +
1314           "OpFunctionEnd",
1315       2, {0,3}),
1316     // Test case 4: fold bit-cast int -24 to unsigned int
1317     InstructionFoldingCase<std::vector<uint32_t>>(
1318       Header() + "%main = OpFunction %void None %void_func\n" +
1319           "%main_lab = OpLabel\n" +
1320           "%n = OpVariable %_ptr_int Function\n" +
1321           "%load = OpLoad %int %n\n" +
1322           "%2 = OpBitcast %v2uint %v2int_min_max\n" +
1323           "OpReturn\n" +
1324           "OpFunctionEnd",
1325       2, {2147483648, 2147483647}),
1326     // Test case 5: fold SNegate vector of uint
1327     InstructionFoldingCase<std::vector<uint32_t>>(
1328       Header() + "%main = OpFunction %void None %void_func\n" +
1329           "%main_lab = OpLabel\n" +
1330           "%n = OpVariable %_ptr_int Function\n" +
1331           "%load = OpLoad %int %n\n" +
1332           "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" +
1333           "OpReturn\n" +
1334           "OpFunctionEnd",
1335       2, {static_cast<uint32_t>(-0x3f800000), static_cast<uint32_t>(-0xbf800000)}),
1336     // Test case 6: fold vector components of uint (including integer overflow)
1337     InstructionFoldingCase<std::vector<uint32_t>>(
1338       Header() + "%main = OpFunction %void None %void_func\n" +
1339           "%main_lab = OpLabel\n" +
1340           "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" +
1341           "OpReturn\n" +
1342           "OpFunctionEnd",
1343       2, {0x7f000000u, 0x7f000000u}),
1344     // Test case 6: fold vector components of uint
1345     InstructionFoldingCase<std::vector<uint32_t>>(
1346         Header() + "%main = OpFunction %void None %void_func\n" +
1347             "%main_lab = OpLabel\n" +
1348             "%2 = OpSConvert %v2int %v2short_2_n5\n" +
1349             "OpReturn\n" +
1350             "OpFunctionEnd",
1351         2, {2,static_cast<uint32_t>(-5)}),
1352     // Test case 6: fold vector components of uint (incuding integer overflow)
1353     InstructionFoldingCase<std::vector<uint32_t>>(
1354         Header() + "%main = OpFunction %void None %void_func\n" +
1355             "%main_lab = OpLabel\n" +
1356             "%2 = OpUConvert %v2uint %v2short_2_n5\n" +
1357             "OpReturn\n" +
1358             "OpFunctionEnd",
1359         2, {2,65531})
1360 ));
1361 // clang-format on
1362 
1363 using IntVectorInstructionFoldingTest =
1364     ::testing::TestWithParam<InstructionFoldingCase<std::vector<int32_t>>>;
1365 
TEST_P(IntVectorInstructionFoldingTest,Case)1366 TEST_P(IntVectorInstructionFoldingTest, Case) {
1367   const auto& tc = GetParam();
1368 
1369   std::unique_ptr<IRContext> context;
1370   Instruction* inst;
1371   std::tie(context, inst) =
1372       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1373 
1374   CheckForExpectedVectorConstant(
1375       inst, tc.expected_result,
1376       [](const analysis::Constant* c) { return c->GetS32(); });
1377 }
1378 
1379 // clang-format off
1380 INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
1381 ::testing::Values(
1382     // Test case 0: fold negate of a vector
1383     InstructionFoldingCase<std::vector<int32_t>>(
1384       Header() + "%main = OpFunction %void None %void_func\n" +
1385           "%main_lab = OpLabel\n" +
1386           "%2 = OpSNegate %v2int %v2int_2_3\n" +
1387           "OpReturn\n" +
1388           "OpFunctionEnd",
1389       2, {-2, -3}),
1390     // Test case 1: fold negate of a vector containing negative values.
1391     InstructionFoldingCase<std::vector<int32_t>>(
1392       Header() + "%main = OpFunction %void None %void_func\n" +
1393           "%main_lab = OpLabel\n" +
1394           "%2 = OpSNegate %v2int %v2int_n1_n24\n" +
1395           "OpReturn\n" +
1396           "OpFunctionEnd",
1397       2, {1, 24}),
1398     // Test case 2: fold negate of a vector at the limits
1399     InstructionFoldingCase<std::vector<int32_t>>(
1400       Header() + "%main = OpFunction %void None %void_func\n" +
1401           "%main_lab = OpLabel\n" +
1402           "%2 = OpSNegate %v2int %v2int_min_max\n" +
1403           "OpReturn\n" +
1404           "OpFunctionEnd",
1405       2, {INT_MIN, -INT_MAX}),
1406     // Test case 3: fold vector components of int
1407     InstructionFoldingCase<std::vector<int32_t>>(
1408       Header() + "%main = OpFunction %void None %void_func\n" +
1409           "%main_lab = OpLabel\n" +
1410           "%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" +
1411           "OpReturn\n" +
1412           "OpFunctionEnd",
1413       2, {4,9})
1414 ));
1415 // clang-format on
1416 
1417 using LongIntVectorInstructionFoldingTest =
1418     ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint64_t>>>;
1419 
TEST_P(LongIntVectorInstructionFoldingTest,Case)1420 TEST_P(LongIntVectorInstructionFoldingTest, Case) {
1421   const auto& tc = GetParam();
1422 
1423   std::unique_ptr<IRContext> context;
1424   Instruction* inst;
1425   std::tie(context, inst) =
1426       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1427   CheckForExpectedVectorConstant(
1428       inst, tc.expected_result,
1429       [](const analysis::Constant* c) { return c->GetU64(); });
1430 }
1431 
1432 // clang-format off
1433 INSTANTIATE_TEST_SUITE_P(TestCase, LongIntVectorInstructionFoldingTest,
1434   ::testing::Values(
1435      // Test case 0: fold {2,2} + {2,3} (Testing that the vector logic works
1436      // correctly. Scalar tests will check that the 64-bit values are correctly
1437      // folded.)
1438      InstructionFoldingCase<std::vector<uint64_t>>(
1439          Header() + "%main = OpFunction %void None %void_func\n" +
1440              "%main_lab = OpLabel\n" +
1441              "%n = OpVariable %_ptr_int Function\n" +
1442              "%load = OpLoad %int %n\n" +
1443              "%2 = OpIAdd %v2long %v2long_2_2 %v2long_2_3\n" +
1444              "OpReturn\n" +
1445              "OpFunctionEnd",
1446          2, {4,5}),
1447       // Test case 0: fold {2,2} / {2,3} (Testing that the vector logic works
1448       // correctly. Scalar tests will check that the 64-bit values are correctly
1449       // folded.)
1450      InstructionFoldingCase<std::vector<uint64_t>>(
1451          Header() + "%main = OpFunction %void None %void_func\n" +
1452              "%main_lab = OpLabel\n" +
1453              "%n = OpVariable %_ptr_int Function\n" +
1454              "%load = OpLoad %int %n\n" +
1455              "%2 = OpSDiv %v2long %v2long_2_2 %v2long_2_3\n" +
1456              "OpReturn\n" +
1457              "OpFunctionEnd",
1458          2, {1,0})
1459   ));
1460 // clang-format on
1461 
1462 using DoubleVectorInstructionFoldingTest =
1463     ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
1464 
TEST_P(DoubleVectorInstructionFoldingTest,Case)1465 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
1466   const auto& tc = GetParam();
1467 
1468   std::unique_ptr<IRContext> context;
1469   Instruction* inst;
1470   std::tie(context, inst) =
1471       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1472   CheckForExpectedVectorConstant(
1473       inst, tc.expected_result,
1474       [](const analysis::Constant* c) { return c->GetDouble(); });
1475 }
1476 
1477 // clang-format off
1478 INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
1479 ::testing::Values(
1480    // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
1481    //              to double vector
1482    InstructionFoldingCase<std::vector<double>>(
1483        Header() + "%main = OpFunction %void None %void_func\n" +
1484            "%main_lab = OpLabel\n" +
1485            "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
1486            "OpReturn\n" +
1487            "OpFunctionEnd",
1488        2, {1.0,-127.35}),
1489    // 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}
1490    InstructionFoldingCase<std::vector<double>>(
1491        Header() +
1492        "%main = OpFunction %void None %void_func\n" +
1493        "%main_lab = OpLabel\n" +
1494        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" +
1495        "OpReturn\n" +
1496        "OpFunctionEnd",
1497        2, {0.0,0.0,0.0,0.0}),
1498    // 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}
1499    InstructionFoldingCase<std::vector<double>>(
1500        Header() +
1501        "%main = OpFunction %void None %void_func\n" +
1502        "%main_lab = OpLabel\n" +
1503        "%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" +
1504        "OpReturn\n" +
1505        "OpFunctionEnd",
1506        2, {0.0,0.0,0.0,0.0}),
1507    // 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}
1508    InstructionFoldingCase<std::vector<double>>(
1509        Header() +
1510        "%main = OpFunction %void None %void_func\n" +
1511        "%main_lab = OpLabel\n" +
1512        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" +
1513        "OpReturn\n" +
1514        "OpFunctionEnd",
1515        2, {30.0,30.0,30.0,30.0}),
1516    // 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}
1517    InstructionFoldingCase<std::vector<double>>(
1518        Header() +
1519        "%main = OpFunction %void None %void_func\n" +
1520        "%main_lab = OpLabel\n" +
1521        "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null\n" +
1522        "OpReturn\n" +
1523        "OpFunctionEnd",
1524        2, {30.0,0.0,30.0,0.0}),
1525    // 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}
1526    InstructionFoldingCase<std::vector<double>>(
1527        Header() +
1528        "%main = OpFunction %void None %void_func\n" +
1529        "%main_lab = OpLabel\n" +
1530        "%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" +
1531        "OpReturn\n" +
1532        "OpFunctionEnd",
1533        2, {0.0,0.0,0.0,0.0}),
1534    // 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}
1535    InstructionFoldingCase<std::vector<double>>(
1536        Header() +
1537        "%main = OpFunction %void None %void_func\n" +
1538        "%main_lab = OpLabel\n" +
1539        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" +
1540        "OpReturn\n" +
1541        "OpFunctionEnd",
1542        2, {0.0,0.0,0.0,0.0}),
1543    // 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}
1544    InstructionFoldingCase<std::vector<double>>(
1545        Header() +
1546        "%main = OpFunction %void None %void_func\n" +
1547        "%main_lab = OpLabel\n" +
1548        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" +
1549        "OpReturn\n" +
1550        "OpFunctionEnd",
1551        2, {10.0,20.0,30.0,40.0}),
1552    // 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}
1553    InstructionFoldingCase<std::vector<double>>(
1554        Header() +
1555        "%main = OpFunction %void None %void_func\n" +
1556        "%main_lab = OpLabel\n" +
1557        "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4_null %v4double_1_2_3_4\n" +
1558        "OpReturn\n" +
1559        "OpFunctionEnd",
1560        2, {4.0,8.0,12.0,16.0})
1561 ));
1562 
1563 using FloatVectorInstructionFoldingTest =
1564     ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
1565 
TEST_P(FloatVectorInstructionFoldingTest,Case)1566 TEST_P(FloatVectorInstructionFoldingTest, Case) {
1567   const auto& tc = GetParam();
1568 
1569   std::unique_ptr<IRContext> context;
1570   Instruction* inst;
1571   std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
1572   CheckForExpectedVectorConstant(inst, tc.expected_result, [](const analysis::Constant* c){ return c->GetFloat();});
1573 }
1574 
1575 // clang-format off
1576 INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
1577 ::testing::Values(
1578    // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
1579    InstructionFoldingCase<std::vector<float>>(
1580        Header() + "%main = OpFunction %void None %void_func\n" +
1581            "%main_lab = OpLabel\n" +
1582            "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
1583            "OpReturn\n" +
1584            "OpFunctionEnd",
1585        2, {1.6f,1.5f}),
1586    // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
1587    //              float vector
1588    InstructionFoldingCase<std::vector<float>>(
1589        Header() + "%main = OpFunction %void None %void_func\n" +
1590            "%main_lab = OpLabel\n" +
1591            "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
1592            "OpReturn\n" +
1593            "OpFunctionEnd",
1594        2, {1.0f,-1.0f}),
1595    // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
1596    InstructionFoldingCase<std::vector<float>>(
1597        Header() + "%main = OpFunction %void None %void_func\n" +
1598            "%main_lab = OpLabel\n" +
1599            "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
1600            "OpReturn\n" +
1601            "OpFunctionEnd",
1602        2, {1.0f,-1.0f}),
1603    // 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}
1604    InstructionFoldingCase<std::vector<float>>(
1605        Header() +
1606        "%main = OpFunction %void None %void_func\n" +
1607        "%main_lab = OpLabel\n" +
1608        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" +
1609        "OpReturn\n" +
1610        "OpFunctionEnd",
1611        2, {0.0f,0.0f,0.0f,0.0f}),
1612    // 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}
1613    InstructionFoldingCase<std::vector<float>>(
1614        Header() +
1615        "%main = OpFunction %void None %void_func\n" +
1616        "%main_lab = OpLabel\n" +
1617        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null\n" +
1618        "OpReturn\n" +
1619        "OpFunctionEnd",
1620        2, {30.0,0.0,30.0,0.0}),
1621    // 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}
1622    InstructionFoldingCase<std::vector<float>>(
1623        Header() +
1624        "%main = OpFunction %void None %void_func\n" +
1625        "%main_lab = OpLabel\n" +
1626        "%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" +
1627        "OpReturn\n" +
1628        "OpFunctionEnd",
1629        2, {0.0f,0.0f,0.0f,0.0f}),
1630    // 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}
1631    InstructionFoldingCase<std::vector<float>>(
1632        Header() +
1633        "%main = OpFunction %void None %void_func\n" +
1634        "%main_lab = OpLabel\n" +
1635        "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" +
1636        "OpReturn\n" +
1637        "OpFunctionEnd",
1638        2, {30.0f,30.0f,30.0f,30.0f}),
1639    // 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}
1640    InstructionFoldingCase<std::vector<float>>(
1641        Header() +
1642        "%main = OpFunction %void None %void_func\n" +
1643        "%main_lab = OpLabel\n" +
1644        "%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" +
1645        "OpReturn\n" +
1646        "OpFunctionEnd",
1647        2, {0.0f,0.0f,0.0f,0.0f}),
1648    // 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}
1649    InstructionFoldingCase<std::vector<float>>(
1650        Header() +
1651        "%main = OpFunction %void None %void_func\n" +
1652        "%main_lab = OpLabel\n" +
1653        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" +
1654        "OpReturn\n" +
1655        "OpFunctionEnd",
1656        2, {0.0f,0.0f,0.0f,0.0f}),
1657    // 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}
1658    InstructionFoldingCase<std::vector<float>>(
1659        Header() +
1660        "%main = OpFunction %void None %void_func\n" +
1661        "%main_lab = OpLabel\n" +
1662        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" +
1663        "OpReturn\n" +
1664        "OpFunctionEnd",
1665        2, {10.0f,20.0f,30.0f,40.0f}),
1666    // 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}
1667    InstructionFoldingCase<std::vector<float>>(
1668        Header() +
1669        "%main = OpFunction %void None %void_func\n" +
1670        "%main_lab = OpLabel\n" +
1671        "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4_null %v4float_1_2_3_4\n" +
1672        "OpReturn\n" +
1673        "OpFunctionEnd",
1674        2, {4.0,8.0,12.0,16.0})
1675 ));
1676 // clang-format on
1677 
1678 using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam<
1679     InstructionFoldingCase<std::vector<std::vector<float>>>>;
1680 
TEST_P(FloatMatrixInstructionFoldingTest,Case)1681 TEST_P(FloatMatrixInstructionFoldingTest, Case) {
1682   const auto& tc = GetParam();
1683 
1684   std::unique_ptr<IRContext> context;
1685   Instruction* inst;
1686   std::tie(context, inst) =
1687       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1688 
1689   EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1690   if (inst->opcode() == spv::Op::OpCopyObject) {
1691     analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1692     inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1693     analysis::ConstantManager* const_mgr = context->get_constant_mgr();
1694     const analysis::Constant* result = const_mgr->GetConstantFromInst(inst);
1695     EXPECT_NE(result, nullptr);
1696     if (result != nullptr) {
1697       std::vector<const analysis::Constant*> matrix =
1698           result->AsMatrixConstant()->GetComponents();
1699       EXPECT_EQ(matrix.size(), tc.expected_result.size());
1700       for (size_t c = 0; c < matrix.size(); c++) {
1701         if (matrix[c]->AsNullConstant() != nullptr) {
1702           matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type());
1703         }
1704         const analysis::VectorConstant* column_const =
1705             matrix[c]->AsVectorConstant();
1706         ASSERT_NE(column_const, nullptr);
1707         const std::vector<const analysis::Constant*>& column =
1708             column_const->GetComponents();
1709         EXPECT_EQ(column.size(), tc.expected_result[c].size());
1710         for (size_t r = 0; r < column.size(); r++) {
1711           EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat());
1712         }
1713       }
1714     }
1715   }
1716 }
1717 
1718 // clang-format off
1719 INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest,
1720 ::testing::Values(
1721    // Test case 0: OpTranspose square null matrix
1722    InstructionFoldingCase<std::vector<std::vector<float>>>(
1723        Header() + "%main = OpFunction %void None %void_func\n" +
1724            "%main_lab = OpLabel\n" +
1725            "%2 = OpTranspose %mat4v4float %mat4v4float_null\n" +
1726            "OpReturn\n" +
1727            "OpFunctionEnd",
1728        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}}),
1729    // Test case 1: OpTranspose rectangular null matrix
1730    InstructionFoldingCase<std::vector<std::vector<float>>>(
1731        Header() + "%main = OpFunction %void None %void_func\n" +
1732            "%main_lab = OpLabel\n" +
1733            "%2 = OpTranspose %mat4v2float %mat2v4float_null\n" +
1734            "OpReturn\n" +
1735            "OpFunctionEnd",
1736        2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}),
1737    InstructionFoldingCase<std::vector<std::vector<float>>>(
1738        Header() + "%main = OpFunction %void None %void_func\n" +
1739            "%main_lab = OpLabel\n" +
1740            "%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" +
1741            "OpReturn\n" +
1742            "OpFunctionEnd",
1743        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}})
1744 ));
1745 // clang-format on
1746 
1747 using BooleanInstructionFoldingTest =
1748     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
1749 
TEST_P(BooleanInstructionFoldingTest,Case)1750 TEST_P(BooleanInstructionFoldingTest, Case) {
1751   const auto& tc = GetParam();
1752 
1753   std::unique_ptr<IRContext> context;
1754   Instruction* inst;
1755   std::tie(context, inst) =
1756       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
1757   CheckForExpectedScalarConstant(
1758       inst, tc.expected_result,
1759       [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); });
1760 }
1761 
1762 // clang-format off
1763 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
1764                         ::testing::Values(
1765   // Test case 0: fold true || n
1766   InstructionFoldingCase<bool>(
1767       Header() + "%main = OpFunction %void None %void_func\n" +
1768           "%main_lab = OpLabel\n" +
1769           "%n = OpVariable %_ptr_bool Function\n" +
1770           "%load = OpLoad %bool %n\n" +
1771           "%2 = OpLogicalOr %bool %true %load\n" +
1772           "OpReturn\n" +
1773           "OpFunctionEnd",
1774       2, true),
1775   // Test case 1: fold n || true
1776   InstructionFoldingCase<bool>(
1777       Header() + "%main = OpFunction %void None %void_func\n" +
1778           "%main_lab = OpLabel\n" +
1779           "%n = OpVariable %_ptr_bool Function\n" +
1780           "%load = OpLoad %bool %n\n" +
1781           "%2 = OpLogicalOr %bool %load %true\n" +
1782           "OpReturn\n" +
1783           "OpFunctionEnd",
1784       2, true),
1785   // Test case 2: fold false && n
1786   InstructionFoldingCase<bool>(
1787       Header() + "%main = OpFunction %void None %void_func\n" +
1788           "%main_lab = OpLabel\n" +
1789           "%n = OpVariable %_ptr_bool Function\n" +
1790           "%load = OpLoad %bool %n\n" +
1791           "%2 = OpLogicalAnd %bool %false %load\n" +
1792           "OpReturn\n" +
1793           "OpFunctionEnd",
1794       2, false),
1795   // Test case 3: fold n && false
1796   InstructionFoldingCase<bool>(
1797       Header() + "%main = OpFunction %void None %void_func\n" +
1798           "%main_lab = OpLabel\n" +
1799           "%n = OpVariable %_ptr_bool Function\n" +
1800           "%load = OpLoad %bool %n\n" +
1801           "%2 = OpLogicalAnd %bool %load %false\n" +
1802           "OpReturn\n" +
1803           "OpFunctionEnd",
1804       2, false),
1805   // Test case 4: fold n < 0 (unsigned)
1806   InstructionFoldingCase<bool>(
1807       Header() + "%main = OpFunction %void None %void_func\n" +
1808           "%main_lab = OpLabel\n" +
1809           "%n = OpVariable %_ptr_uint Function\n" +
1810           "%load = OpLoad %uint %n\n" +
1811           "%2 = OpULessThan %bool %load %uint_0\n" +
1812           "OpReturn\n" +
1813           "OpFunctionEnd",
1814       2, false),
1815   // Test case 5: fold UINT_MAX < n (unsigned)
1816   InstructionFoldingCase<bool>(
1817       Header() + "%main = OpFunction %void None %void_func\n" +
1818           "%main_lab = OpLabel\n" +
1819           "%n = OpVariable %_ptr_uint Function\n" +
1820           "%load = OpLoad %uint %n\n" +
1821           "%2 = OpULessThan %bool %uint_max %load\n" +
1822           "OpReturn\n" +
1823           "OpFunctionEnd",
1824       2, false),
1825   // Test case 6: fold INT_MAX < n (signed)
1826   InstructionFoldingCase<bool>(
1827       Header() + "%main = OpFunction %void None %void_func\n" +
1828           "%main_lab = OpLabel\n" +
1829           "%n = OpVariable %_ptr_int Function\n" +
1830           "%load = OpLoad %int %n\n" +
1831           "%2 = OpSLessThan %bool %int_max %load\n" +
1832           "OpReturn\n" +
1833           "OpFunctionEnd",
1834       2, false),
1835   // Test case 7: fold n < INT_MIN (signed)
1836   InstructionFoldingCase<bool>(
1837       Header() + "%main = OpFunction %void None %void_func\n" +
1838           "%main_lab = OpLabel\n" +
1839           "%n = OpVariable %_ptr_int Function\n" +
1840           "%load = OpLoad %int %n\n" +
1841           "%2 = OpSLessThan %bool %load %int_min\n" +
1842           "OpReturn\n" +
1843           "OpFunctionEnd",
1844       2, false),
1845   // Test case 8: fold 0 > n (unsigned)
1846   InstructionFoldingCase<bool>(
1847       Header() + "%main = OpFunction %void None %void_func\n" +
1848           "%main_lab = OpLabel\n" +
1849           "%n = OpVariable %_ptr_uint Function\n" +
1850           "%load = OpLoad %uint %n\n" +
1851           "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
1852           "OpReturn\n" +
1853           "OpFunctionEnd",
1854       2, false),
1855   // Test case 9: fold n > UINT_MAX (unsigned)
1856   InstructionFoldingCase<bool>(
1857       Header() + "%main = OpFunction %void None %void_func\n" +
1858           "%main_lab = OpLabel\n" +
1859           "%n = OpVariable %_ptr_uint Function\n" +
1860           "%load = OpLoad %uint %n\n" +
1861           "%2 = OpUGreaterThan %bool %load %uint_max\n" +
1862           "OpReturn\n" +
1863           "OpFunctionEnd",
1864       2, false),
1865   // Test case 10: fold n > INT_MAX (signed)
1866   InstructionFoldingCase<bool>(
1867       Header() + "%main = OpFunction %void None %void_func\n" +
1868           "%main_lab = OpLabel\n" +
1869           "%n = OpVariable %_ptr_int Function\n" +
1870           "%load = OpLoad %int %n\n" +
1871           "%2 = OpSGreaterThan %bool %load %int_max\n" +
1872           "OpReturn\n" +
1873           "OpFunctionEnd",
1874       2, false),
1875   // Test case 11: fold INT_MIN > n (signed)
1876   InstructionFoldingCase<bool>(
1877       Header() + "%main = OpFunction %void None %void_func\n" +
1878           "%main_lab = OpLabel\n" +
1879           "%n = OpVariable %_ptr_uint Function\n" +
1880           "%load = OpLoad %uint %n\n" +
1881           "%2 = OpSGreaterThan %bool %int_min %load\n" +
1882           "OpReturn\n" +
1883           "OpFunctionEnd",
1884       2, false),
1885   // Test case 12: fold 0 <= n (unsigned)
1886   InstructionFoldingCase<bool>(
1887       Header() + "%main = OpFunction %void None %void_func\n" +
1888           "%main_lab = OpLabel\n" +
1889           "%n = OpVariable %_ptr_uint Function\n" +
1890           "%load = OpLoad %uint %n\n" +
1891           "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
1892           "OpReturn\n" +
1893           "OpFunctionEnd",
1894       2, true),
1895   // Test case 13: fold n <= UINT_MAX (unsigned)
1896   InstructionFoldingCase<bool>(
1897       Header() + "%main = OpFunction %void None %void_func\n" +
1898           "%main_lab = OpLabel\n" +
1899           "%n = OpVariable %_ptr_uint Function\n" +
1900           "%load = OpLoad %uint %n\n" +
1901           "%2 = OpULessThanEqual %bool %load %uint_max\n" +
1902           "OpReturn\n" +
1903           "OpFunctionEnd",
1904       2, true),
1905   // Test case 14: fold INT_MIN <= n (signed)
1906   InstructionFoldingCase<bool>(
1907       Header() + "%main = OpFunction %void None %void_func\n" +
1908           "%main_lab = OpLabel\n" +
1909           "%n = OpVariable %_ptr_int Function\n" +
1910           "%load = OpLoad %int %n\n" +
1911           "%2 = OpSLessThanEqual %bool %int_min %load\n" +
1912           "OpReturn\n" +
1913           "OpFunctionEnd",
1914       2, true),
1915   // Test case 15: fold n <= INT_MAX (signed)
1916   InstructionFoldingCase<bool>(
1917       Header() + "%main = OpFunction %void None %void_func\n" +
1918           "%main_lab = OpLabel\n" +
1919           "%n = OpVariable %_ptr_int Function\n" +
1920           "%load = OpLoad %int %n\n" +
1921           "%2 = OpSLessThanEqual %bool %load %int_max\n" +
1922           "OpReturn\n" +
1923           "OpFunctionEnd",
1924       2, true),
1925   // Test case 16: fold n >= 0 (unsigned)
1926   InstructionFoldingCase<bool>(
1927       Header() + "%main = OpFunction %void None %void_func\n" +
1928           "%main_lab = OpLabel\n" +
1929           "%n = OpVariable %_ptr_uint Function\n" +
1930           "%load = OpLoad %uint %n\n" +
1931           "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
1932           "OpReturn\n" +
1933           "OpFunctionEnd",
1934       2, true),
1935   // Test case 17: fold UINT_MAX >= n (unsigned)
1936   InstructionFoldingCase<bool>(
1937       Header() + "%main = OpFunction %void None %void_func\n" +
1938           "%main_lab = OpLabel\n" +
1939           "%n = OpVariable %_ptr_uint Function\n" +
1940           "%load = OpLoad %uint %n\n" +
1941           "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
1942           "OpReturn\n" +
1943           "OpFunctionEnd",
1944       2, true),
1945   // Test case 18: fold n >= INT_MIN (signed)
1946   InstructionFoldingCase<bool>(
1947       Header() + "%main = OpFunction %void None %void_func\n" +
1948           "%main_lab = OpLabel\n" +
1949           "%n = OpVariable %_ptr_int Function\n" +
1950           "%load = OpLoad %int %n\n" +
1951           "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
1952           "OpReturn\n" +
1953           "OpFunctionEnd",
1954       2, true),
1955   // Test case 19: fold INT_MAX >= n (signed)
1956   InstructionFoldingCase<bool>(
1957       Header() + "%main = OpFunction %void None %void_func\n" +
1958           "%main_lab = OpLabel\n" +
1959           "%n = OpVariable %_ptr_int Function\n" +
1960           "%load = OpLoad %int %n\n" +
1961           "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
1962           "OpReturn\n" +
1963           "OpFunctionEnd",
1964       2, true)
1965 ));
1966 
1967 INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
1968 ::testing::Values(
1969     // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
1970     InstructionFoldingCase<bool>(
1971         Header() + "%main = OpFunction %void None %void_func\n" +
1972             "%main_lab = OpLabel\n" +
1973             "%n = OpVariable %_ptr_float Function\n" +
1974             "%ld = OpLoad %float %n\n" +
1975             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1976             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1977             "OpReturn\n" +
1978             "OpFunctionEnd",
1979         2, false),
1980     // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
1981     InstructionFoldingCase<bool>(
1982         Header() + "%main = OpFunction %void None %void_func\n" +
1983             "%main_lab = OpLabel\n" +
1984             "%n = OpVariable %_ptr_float Function\n" +
1985             "%ld = OpLoad %float %n\n" +
1986             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1987             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1988             "OpReturn\n" +
1989             "OpFunctionEnd",
1990         2, true),
1991     // Test case 2: fold 0.0 >= clamp(n, 1, 2)
1992     InstructionFoldingCase<bool>(
1993         Header() + "%main = OpFunction %void None %void_func\n" +
1994             "%main_lab = OpLabel\n" +
1995             "%n = OpVariable %_ptr_float Function\n" +
1996             "%ld = OpLoad %float %n\n" +
1997             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1998             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1999             "OpReturn\n" +
2000             "OpFunctionEnd",
2001         2, false),
2002     // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
2003     InstructionFoldingCase<bool>(
2004         Header() + "%main = OpFunction %void None %void_func\n" +
2005             "%main_lab = OpLabel\n" +
2006             "%n = OpVariable %_ptr_float Function\n" +
2007             "%ld = OpLoad %float %n\n" +
2008             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2009             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
2010             "OpReturn\n" +
2011             "OpFunctionEnd",
2012         2, true),
2013     // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
2014     InstructionFoldingCase<bool>(
2015         Header() + "%main = OpFunction %void None %void_func\n" +
2016             "%main_lab = OpLabel\n" +
2017             "%n = OpVariable %_ptr_float Function\n" +
2018             "%ld = OpLoad %float %n\n" +
2019             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2020             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
2021             "OpReturn\n" +
2022             "OpFunctionEnd",
2023         2, true),
2024     // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
2025     InstructionFoldingCase<bool>(
2026         Header() + "%main = OpFunction %void None %void_func\n" +
2027             "%main_lab = OpLabel\n" +
2028             "%n = OpVariable %_ptr_float Function\n" +
2029             "%ld = OpLoad %float %n\n" +
2030             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
2031             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
2032             "OpReturn\n" +
2033             "OpFunctionEnd",
2034         2, false),
2035     // Test case 6: fold 0.0 < clamp(n, 1, 2)
2036     InstructionFoldingCase<bool>(
2037         Header() + "%main = OpFunction %void None %void_func\n" +
2038             "%main_lab = OpLabel\n" +
2039             "%n = OpVariable %_ptr_float Function\n" +
2040             "%ld = OpLoad %float %n\n" +
2041             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2042             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
2043             "OpReturn\n" +
2044             "OpFunctionEnd",
2045         2, true),
2046     // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
2047     InstructionFoldingCase<bool>(
2048         Header() + "%main = OpFunction %void None %void_func\n" +
2049             "%main_lab = OpLabel\n" +
2050             "%n = OpVariable %_ptr_float Function\n" +
2051             "%ld = OpLoad %float %n\n" +
2052             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2053             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
2054             "OpReturn\n" +
2055             "OpFunctionEnd",
2056         2, false),
2057     // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
2058     InstructionFoldingCase<bool>(
2059         Header() + "%main = OpFunction %void None %void_func\n" +
2060             "%main_lab = OpLabel\n" +
2061             "%n = OpVariable %_ptr_float Function\n" +
2062             "%ld = OpLoad %float %n\n" +
2063             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2064             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
2065             "OpReturn\n" +
2066             "OpFunctionEnd",
2067         2, false),
2068     // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
2069     InstructionFoldingCase<bool>(
2070         Header() + "%main = OpFunction %void None %void_func\n" +
2071             "%main_lab = OpLabel\n" +
2072             "%n = OpVariable %_ptr_float Function\n" +
2073             "%ld = OpLoad %float %n\n" +
2074             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
2075             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
2076             "OpReturn\n" +
2077             "OpFunctionEnd",
2078         2, true),
2079     // Test case 10: fold 0.0 >= clamp(n, 1, 2)
2080     InstructionFoldingCase<bool>(
2081         Header() + "%main = OpFunction %void None %void_func\n" +
2082             "%main_lab = OpLabel\n" +
2083             "%n = OpVariable %_ptr_float Function\n" +
2084             "%ld = OpLoad %float %n\n" +
2085             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2086             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
2087             "OpReturn\n" +
2088             "OpFunctionEnd",
2089         2, false),
2090     // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
2091     InstructionFoldingCase<bool>(
2092         Header() + "%main = OpFunction %void None %void_func\n" +
2093             "%main_lab = OpLabel\n" +
2094             "%n = OpVariable %_ptr_float Function\n" +
2095             "%ld = OpLoad %float %n\n" +
2096             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2097             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
2098             "OpReturn\n" +
2099             "OpFunctionEnd",
2100         2, true),
2101     // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
2102     InstructionFoldingCase<bool>(
2103         Header() + "%main = OpFunction %void None %void_func\n" +
2104             "%main_lab = OpLabel\n" +
2105             "%n = OpVariable %_ptr_float Function\n" +
2106             "%ld = OpLoad %float %n\n" +
2107             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2108             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
2109             "OpReturn\n" +
2110             "OpFunctionEnd",
2111         2, true),
2112     // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
2113     InstructionFoldingCase<bool>(
2114         Header() + "%main = OpFunction %void None %void_func\n" +
2115             "%main_lab = OpLabel\n" +
2116             "%n = OpVariable %_ptr_float Function\n" +
2117             "%ld = OpLoad %float %n\n" +
2118             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
2119             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
2120             "OpReturn\n" +
2121             "OpFunctionEnd",
2122         2, false),
2123     // Test case 14: fold 0.0 < clamp(n, 1, 2)
2124     InstructionFoldingCase<bool>(
2125         Header() + "%main = OpFunction %void None %void_func\n" +
2126             "%main_lab = OpLabel\n" +
2127             "%n = OpVariable %_ptr_float Function\n" +
2128             "%ld = OpLoad %float %n\n" +
2129             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2130             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
2131             "OpReturn\n" +
2132             "OpFunctionEnd",
2133         2, true),
2134     // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
2135     InstructionFoldingCase<bool>(
2136         Header() + "%main = OpFunction %void None %void_func\n" +
2137             "%main_lab = OpLabel\n" +
2138             "%n = OpVariable %_ptr_float Function\n" +
2139             "%ld = OpLoad %float %n\n" +
2140             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2141             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
2142             "OpReturn\n" +
2143             "OpFunctionEnd",
2144         2, false)
2145 ));
2146 
2147 INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
2148 ::testing::Values(
2149     // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
2150     InstructionFoldingCase<bool>(
2151       Header() + "%main = OpFunction %void None %void_func\n" +
2152       "%main_lab = OpLabel\n" +
2153       "%n = OpVariable %_ptr_float Function\n" +
2154       "%ld = OpLoad %float %n\n" +
2155       "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2156       "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
2157       "OpReturn\n" +
2158       "OpFunctionEnd",
2159       2, false),
2160     // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
2161     InstructionFoldingCase<bool>(
2162       Header() + "%main = OpFunction %void None %void_func\n" +
2163       "%main_lab = OpLabel\n" +
2164       "%n = OpVariable %_ptr_float Function\n" +
2165       "%ld = OpLoad %float %n\n" +
2166       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
2167       "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
2168       "OpReturn\n" +
2169       "OpFunctionEnd",
2170       2, true),
2171     // Test case 2: fold clamp(n, 1, 2) >= 0.0
2172     InstructionFoldingCase<bool>(
2173       Header() + "%main = OpFunction %void None %void_func\n" +
2174       "%main_lab = OpLabel\n" +
2175       "%n = OpVariable %_ptr_float Function\n" +
2176       "%ld = OpLoad %float %n\n" +
2177       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2178       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
2179       "OpReturn\n" +
2180       "OpFunctionEnd",
2181       2, true),
2182     // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
2183     InstructionFoldingCase<bool>(
2184       Header() + "%main = OpFunction %void None %void_func\n" +
2185       "%main_lab = OpLabel\n" +
2186       "%n = OpVariable %_ptr_float Function\n" +
2187       "%ld = OpLoad %float %n\n" +
2188       "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2189       "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
2190       "OpReturn\n" +
2191       "OpFunctionEnd",
2192       2, false),
2193     // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
2194     InstructionFoldingCase<bool>(
2195         Header() + "%main = OpFunction %void None %void_func\n" +
2196             "%main_lab = OpLabel\n" +
2197             "%n = OpVariable %_ptr_float Function\n" +
2198             "%ld = OpLoad %float %n\n" +
2199             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2200             "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
2201             "OpReturn\n" +
2202             "OpFunctionEnd",
2203         2, true),
2204     // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
2205     InstructionFoldingCase<bool>(
2206         Header() + "%main = OpFunction %void None %void_func\n" +
2207             "%main_lab = OpLabel\n" +
2208             "%n = OpVariable %_ptr_float Function\n" +
2209             "%ld = OpLoad %float %n\n" +
2210             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2211             "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
2212             "OpReturn\n" +
2213             "OpFunctionEnd",
2214         2, false),
2215     // Test case 6: fold clamp(n, 1, 2) < 3
2216     InstructionFoldingCase<bool>(
2217         Header() + "%main = OpFunction %void None %void_func\n" +
2218             "%main_lab = OpLabel\n" +
2219             "%n = OpVariable %_ptr_float Function\n" +
2220             "%ld = OpLoad %float %n\n" +
2221             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2222             "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
2223             "OpReturn\n" +
2224             "OpFunctionEnd",
2225         2, true),
2226     // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
2227     InstructionFoldingCase<bool>(
2228         Header() + "%main = OpFunction %void None %void_func\n" +
2229             "%main_lab = OpLabel\n" +
2230             "%n = OpVariable %_ptr_float Function\n" +
2231             "%ld = OpLoad %float %n\n" +
2232             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2233             "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
2234             "OpReturn\n" +
2235             "OpFunctionEnd",
2236         2, false),
2237     // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
2238     InstructionFoldingCase<bool>(
2239         Header() + "%main = OpFunction %void None %void_func\n" +
2240             "%main_lab = OpLabel\n" +
2241             "%n = OpVariable %_ptr_float Function\n" +
2242             "%ld = OpLoad %float %n\n" +
2243             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2244             "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
2245             "OpReturn\n" +
2246             "OpFunctionEnd",
2247         2, false),
2248     // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
2249     InstructionFoldingCase<bool>(
2250         Header() + "%main = OpFunction %void None %void_func\n" +
2251             "%main_lab = OpLabel\n" +
2252             "%n = OpVariable %_ptr_float Function\n" +
2253             "%ld = OpLoad %float %n\n" +
2254             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2255             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
2256             "OpReturn\n" +
2257             "OpFunctionEnd",
2258         2, true),
2259     // Test case 10: fold clamp(n, 1, 2) >= 3.0
2260     InstructionFoldingCase<bool>(
2261         Header() + "%main = OpFunction %void None %void_func\n" +
2262             "%main_lab = OpLabel\n" +
2263             "%n = OpVariable %_ptr_float Function\n" +
2264             "%ld = OpLoad %float %n\n" +
2265             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2266             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
2267             "OpReturn\n" +
2268             "OpFunctionEnd",
2269         2, false),
2270     // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
2271     InstructionFoldingCase<bool>(
2272         Header() + "%main = OpFunction %void None %void_func\n" +
2273             "%main_lab = OpLabel\n" +
2274             "%n = OpVariable %_ptr_float Function\n" +
2275             "%ld = OpLoad %float %n\n" +
2276             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2277             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
2278             "OpReturn\n" +
2279             "OpFunctionEnd",
2280         2, true),
2281     // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
2282     InstructionFoldingCase<bool>(
2283         Header() + "%main = OpFunction %void None %void_func\n" +
2284             "%main_lab = OpLabel\n" +
2285             "%n = OpVariable %_ptr_float Function\n" +
2286             "%ld = OpLoad %float %n\n" +
2287             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2288             "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
2289             "OpReturn\n" +
2290             "OpFunctionEnd",
2291         2, true),
2292     // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
2293     InstructionFoldingCase<bool>(
2294         Header() + "%main = OpFunction %void None %void_func\n" +
2295             "%main_lab = OpLabel\n" +
2296             "%n = OpVariable %_ptr_float Function\n" +
2297             "%ld = OpLoad %float %n\n" +
2298             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
2299             "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
2300             "OpReturn\n" +
2301             "OpFunctionEnd",
2302         2, false),
2303     // Test case 14: fold clamp(n, 1, 2) < 3
2304     InstructionFoldingCase<bool>(
2305         Header() + "%main = OpFunction %void None %void_func\n" +
2306             "%main_lab = OpLabel\n" +
2307             "%n = OpVariable %_ptr_float Function\n" +
2308             "%ld = OpLoad %float %n\n" +
2309             "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2310             "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
2311             "OpReturn\n" +
2312             "OpFunctionEnd",
2313         2, true),
2314     // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
2315     InstructionFoldingCase<bool>(
2316         Header() + "%main = OpFunction %void None %void_func\n" +
2317             "%main_lab = OpLabel\n" +
2318             "%n = OpVariable %_ptr_float Function\n" +
2319             "%ld = OpLoad %float %n\n" +
2320             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2321             "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
2322             "OpReturn\n" +
2323             "OpFunctionEnd",
2324         2, false),
2325     // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
2326     InstructionFoldingCase<bool>(
2327         Header() + "%main = OpFunction %void None %void_func\n" +
2328             "%main_lab = OpLabel\n" +
2329             "%n = OpVariable %_ptr_double Function\n" +
2330             "%ld = OpLoad %double %n\n" +
2331             "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
2332             "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
2333             "OpReturn\n" +
2334             "OpFunctionEnd",
2335         2, false)
2336 ));
2337 // clang-format on
2338 
2339 using FloatInstructionFoldingTest =
2340     ::testing::TestWithParam<InstructionFoldingCase<float>>;
2341 
TEST_P(FloatInstructionFoldingTest,Case)2342 TEST_P(FloatInstructionFoldingTest, Case) {
2343   const auto& tc = GetParam();
2344 
2345   std::unique_ptr<IRContext> context;
2346   Instruction* inst;
2347   std::tie(context, inst) =
2348       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
2349 
2350   CheckForExpectedScalarConstant(inst, tc.expected_result,
2351                                  [](const analysis::Constant* c) {
2352                                    return c->AsFloatConstant()->GetFloatValue();
2353                                  });
2354 }
2355 
2356 // Not testing NaNs because there are no expectations concerning NaNs according
2357 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
2358 // specification.
2359 
2360 // clang-format off
2361 INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
2362 ::testing::Values(
2363     // Test case 0: Fold 2.0 - 1.0
2364     InstructionFoldingCase<float>(
2365         Header() + "%main = OpFunction %void None %void_func\n" +
2366             "%main_lab = OpLabel\n" +
2367             "%2 = OpFSub %float %float_2 %float_1\n" +
2368             "OpReturn\n" +
2369             "OpFunctionEnd",
2370         2, 1.0),
2371     // Test case 1: Fold 2.0 + 1.0
2372     InstructionFoldingCase<float>(
2373         Header() + "%main = OpFunction %void None %void_func\n" +
2374             "%main_lab = OpLabel\n" +
2375             "%2 = OpFAdd %float %float_2 %float_1\n" +
2376             "OpReturn\n" +
2377             "OpFunctionEnd",
2378         2, 3.0),
2379     // Test case 2: Fold 3.0 * 2.0
2380     InstructionFoldingCase<float>(
2381         Header() + "%main = OpFunction %void None %void_func\n" +
2382             "%main_lab = OpLabel\n" +
2383             "%2 = OpFMul %float %float_3 %float_2\n" +
2384             "OpReturn\n" +
2385             "OpFunctionEnd",
2386         2, 6.0),
2387     // Test case 3: Fold 1.0 / 2.0
2388     InstructionFoldingCase<float>(
2389         Header() + "%main = OpFunction %void None %void_func\n" +
2390             "%main_lab = OpLabel\n" +
2391             "%2 = OpFDiv %float %float_1 %float_2\n" +
2392             "OpReturn\n" +
2393             "OpFunctionEnd",
2394         2, 0.5),
2395     // Test case 4: Fold 1.0 / 0.0
2396     InstructionFoldingCase<float>(
2397         Header() + "%main = OpFunction %void None %void_func\n" +
2398             "%main_lab = OpLabel\n" +
2399             "%2 = OpFDiv %float %float_1 %float_0\n" +
2400             "OpReturn\n" +
2401             "OpFunctionEnd",
2402         2, std::numeric_limits<float>::infinity()),
2403     // Test case 5: Fold -1.0 / 0.0
2404     InstructionFoldingCase<float>(
2405         Header() + "%main = OpFunction %void None %void_func\n" +
2406             "%main_lab = OpLabel\n" +
2407             "%2 = OpFDiv %float %float_n1 %float_0\n" +
2408             "OpReturn\n" +
2409             "OpFunctionEnd",
2410         2, -std::numeric_limits<float>::infinity()),
2411     // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2412     InstructionFoldingCase<float>(
2413         Header() + "%main = OpFunction %void None %void_func\n" +
2414             "%main_lab = OpLabel\n" +
2415             "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
2416             "OpReturn\n" +
2417             "OpFunctionEnd",
2418         2, 5.5f),
2419     // Test case 7: Fold (0.0, 0.0) dot v
2420     InstructionFoldingCase<float>(
2421         Header() + "%main = OpFunction %void None %void_func\n" +
2422             "%main_lab = OpLabel\n" +
2423             "%v = OpVariable %_ptr_v2float Function\n" +
2424             "%2 = OpLoad %v2float %v\n" +
2425             "%3 = OpDot %float %v2float_0_0 %2\n" +
2426             "OpReturn\n" +
2427             "OpFunctionEnd",
2428         3, 0.0f),
2429     // Test case 8: Fold v dot (0.0, 0.0)
2430     InstructionFoldingCase<float>(
2431         Header() + "%main = OpFunction %void None %void_func\n" +
2432             "%main_lab = OpLabel\n" +
2433             "%v = OpVariable %_ptr_v2float Function\n" +
2434             "%2 = OpLoad %v2float %v\n" +
2435             "%3 = OpDot %float %2 %v2float_0_0\n" +
2436             "OpReturn\n" +
2437             "OpFunctionEnd",
2438         3, 0.0f),
2439     // Test case 9: Fold Null dot v
2440     InstructionFoldingCase<float>(
2441         Header() + "%main = OpFunction %void None %void_func\n" +
2442             "%main_lab = OpLabel\n" +
2443             "%v = OpVariable %_ptr_v2float Function\n" +
2444             "%2 = OpLoad %v2float %v\n" +
2445             "%3 = OpDot %float %v2float_null %2\n" +
2446             "OpReturn\n" +
2447             "OpFunctionEnd",
2448         3, 0.0f),
2449     // Test case 10: Fold v dot Null
2450     InstructionFoldingCase<float>(
2451         Header() + "%main = OpFunction %void None %void_func\n" +
2452             "%main_lab = OpLabel\n" +
2453             "%v = OpVariable %_ptr_v2float Function\n" +
2454             "%2 = OpLoad %v2float %v\n" +
2455             "%3 = OpDot %float %2 %v2float_null\n" +
2456             "OpReturn\n" +
2457             "OpFunctionEnd",
2458         3, 0.0f),
2459     // Test case 11: Fold -2.0
2460     InstructionFoldingCase<float>(
2461         Header() + "%main = OpFunction %void None %void_func\n" +
2462             "%main_lab = OpLabel\n" +
2463             "%2 = OpFNegate %float %float_2\n" +
2464             "OpReturn\n" +
2465             "OpFunctionEnd",
2466         2, -2),
2467     // Test case 12: QuantizeToF16 1.0
2468     InstructionFoldingCase<float>(
2469         Header() + "%main = OpFunction %void None %void_func\n" +
2470             "%main_lab = OpLabel\n" +
2471             "%2 = OpQuantizeToF16 %float %float_1\n" +
2472             "OpReturn\n" +
2473             "OpFunctionEnd",
2474         2, 1.0),
2475     // Test case 13: QuantizeToF16 positive non exact
2476     InstructionFoldingCase<float>(
2477         Header() + "%main = OpFunction %void None %void_func\n" +
2478             "%main_lab = OpLabel\n" +
2479             "%2 = OpQuantizeToF16 %float %float_2049\n" +
2480             "OpReturn\n" +
2481             "OpFunctionEnd",
2482         2, 2048),
2483     // Test case 14: QuantizeToF16 negative non exact
2484     InstructionFoldingCase<float>(
2485         Header() + "%main = OpFunction %void None %void_func\n" +
2486             "%main_lab = OpLabel\n" +
2487             "%2 = OpQuantizeToF16 %float %float_n2049\n" +
2488             "OpReturn\n" +
2489             "OpFunctionEnd",
2490         2, -2048),
2491     // Test case 15: QuantizeToF16 large positive
2492     InstructionFoldingCase<float>(
2493         Header() + "%main = OpFunction %void None %void_func\n" +
2494             "%main_lab = OpLabel\n" +
2495             "%2 = OpQuantizeToF16 %float %float_1e16\n" +
2496             "OpReturn\n" +
2497             "OpFunctionEnd",
2498         2, std::numeric_limits<float>::infinity()),
2499     // Test case 16: QuantizeToF16 large negative
2500     InstructionFoldingCase<float>(
2501         Header() + "%main = OpFunction %void None %void_func\n" +
2502             "%main_lab = OpLabel\n" +
2503             "%2 = OpQuantizeToF16 %float %float_n1e16\n" +
2504             "OpReturn\n" +
2505             "OpFunctionEnd",
2506         2, -std::numeric_limits<float>::infinity()),
2507     // Test case 17: QuantizeToF16 small positive
2508     InstructionFoldingCase<float>(
2509         Header() + "%main = OpFunction %void None %void_func\n" +
2510             "%main_lab = OpLabel\n" +
2511             "%2 = OpQuantizeToF16 %float %float_1en16\n" +
2512             "OpReturn\n" +
2513             "OpFunctionEnd",
2514         2, 0.0),
2515     // Test case 18: QuantizeToF16 small negative
2516     InstructionFoldingCase<float>(
2517         Header() + "%main = OpFunction %void None %void_func\n" +
2518             "%main_lab = OpLabel\n" +
2519             "%2 = OpQuantizeToF16 %float %float_n1en16\n" +
2520             "OpReturn\n" +
2521             "OpFunctionEnd",
2522         2, 0.0),
2523     // Test case 19: QuantizeToF16 nan
2524     InstructionFoldingCase<float>(
2525         HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2526             "%main_lab = OpLabel\n" +
2527             "%2 = OpQuantizeToF16 %float %float_nan\n" +
2528             "OpReturn\n" +
2529             "OpFunctionEnd",
2530         2, std::numeric_limits<float>::quiet_NaN()),
2531     // Test case 20: FMix 1.0 4.0 0.2
2532     InstructionFoldingCase<float>(
2533         Header() + "%main = OpFunction %void None %void_func\n" +
2534             "%main_lab = OpLabel\n" +
2535             "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
2536             "OpReturn\n" +
2537             "OpFunctionEnd",
2538         2, 1.6f),
2539     // Test case 21: FMin 1.0 4.0
2540     InstructionFoldingCase<float>(
2541         Header() + "%main = OpFunction %void None %void_func\n" +
2542             "%main_lab = OpLabel\n" +
2543             "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
2544             "OpReturn\n" +
2545             "OpFunctionEnd",
2546         2, 1.0f),
2547     // Test case 22: FMin 4.0 0.2
2548     InstructionFoldingCase<float>(
2549         Header() + "%main = OpFunction %void None %void_func\n" +
2550             "%main_lab = OpLabel\n" +
2551             "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
2552             "OpReturn\n" +
2553             "OpFunctionEnd",
2554         2, 0.2f),
2555     // Test case 23: FMax 1.0 4.0
2556     InstructionFoldingCase<float>(
2557         Header() + "%main = OpFunction %void None %void_func\n" +
2558             "%main_lab = OpLabel\n" +
2559             "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
2560             "OpReturn\n" +
2561             "OpFunctionEnd",
2562         2, 4.0f),
2563     // Test case 24: FMax 1.0 0.2
2564     InstructionFoldingCase<float>(
2565         Header() + "%main = OpFunction %void None %void_func\n" +
2566             "%main_lab = OpLabel\n" +
2567             "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
2568             "OpReturn\n" +
2569             "OpFunctionEnd",
2570         2, 1.0f),
2571     // Test case 25: FClamp 1.0 0.2 4.0
2572     InstructionFoldingCase<float>(
2573         Header() + "%main = OpFunction %void None %void_func\n" +
2574             "%main_lab = OpLabel\n" +
2575             "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
2576             "OpReturn\n" +
2577             "OpFunctionEnd",
2578         2, 1.0f),
2579     // Test case 26: FClamp 0.2 2.0 4.0
2580     InstructionFoldingCase<float>(
2581         Header() + "%main = OpFunction %void None %void_func\n" +
2582             "%main_lab = OpLabel\n" +
2583             "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
2584             "OpReturn\n" +
2585             "OpFunctionEnd",
2586         2, 2.0f),
2587     // Test case 27: FClamp 2049.0 2.0 4.0
2588     InstructionFoldingCase<float>(
2589         Header() + "%main = OpFunction %void None %void_func\n" +
2590             "%main_lab = OpLabel\n" +
2591             "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
2592             "OpReturn\n" +
2593             "OpFunctionEnd",
2594         2, 4.0f),
2595     // Test case 28: FClamp 1.0 2.0 x
2596     InstructionFoldingCase<float>(
2597         Header() + "%main = OpFunction %void None %void_func\n" +
2598             "%main_lab = OpLabel\n" +
2599             "%undef = OpUndef %float\n" +
2600             "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
2601             "OpReturn\n" +
2602             "OpFunctionEnd",
2603         2, 2.0),
2604     // Test case 29: FClamp 1.0 x 0.5
2605     InstructionFoldingCase<float>(
2606         Header() + "%main = OpFunction %void None %void_func\n" +
2607             "%main_lab = OpLabel\n" +
2608             "%undef = OpUndef %float\n" +
2609             "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
2610             "OpReturn\n" +
2611             "OpFunctionEnd",
2612         2, 0.5),
2613     // Test case 30: Sin 0.0
2614     InstructionFoldingCase<float>(
2615         Header() + "%main = OpFunction %void None %void_func\n" +
2616             "%main_lab = OpLabel\n" +
2617             "%2 = OpExtInst %float %1 Sin %float_0\n" +
2618             "OpReturn\n" +
2619             "OpFunctionEnd",
2620         2, 0.0),
2621     // Test case 31: Cos 0.0
2622     InstructionFoldingCase<float>(
2623         Header() + "%main = OpFunction %void None %void_func\n" +
2624             "%main_lab = OpLabel\n" +
2625             "%2 = OpExtInst %float %1 Cos %float_0\n" +
2626             "OpReturn\n" +
2627             "OpFunctionEnd",
2628         2, 1.0),
2629     // Test case 32: Tan 0.0
2630     InstructionFoldingCase<float>(
2631         Header() + "%main = OpFunction %void None %void_func\n" +
2632             "%main_lab = OpLabel\n" +
2633             "%2 = OpExtInst %float %1 Tan %float_0\n" +
2634             "OpReturn\n" +
2635             "OpFunctionEnd",
2636         2, 0.0),
2637     // Test case 33: Asin 0.0
2638     InstructionFoldingCase<float>(
2639         Header() + "%main = OpFunction %void None %void_func\n" +
2640             "%main_lab = OpLabel\n" +
2641             "%2 = OpExtInst %float %1 Asin %float_0\n" +
2642             "OpReturn\n" +
2643             "OpFunctionEnd",
2644         2, 0.0),
2645     // Test case 34: Acos 1.0
2646     InstructionFoldingCase<float>(
2647         Header() + "%main = OpFunction %void None %void_func\n" +
2648             "%main_lab = OpLabel\n" +
2649             "%2 = OpExtInst %float %1 Acos %float_1\n" +
2650             "OpReturn\n" +
2651             "OpFunctionEnd",
2652         2, 0.0),
2653     // Test case 35: Atan 0.0
2654     InstructionFoldingCase<float>(
2655         Header() + "%main = OpFunction %void None %void_func\n" +
2656             "%main_lab = OpLabel\n" +
2657             "%2 = OpExtInst %float %1 Atan %float_0\n" +
2658             "OpReturn\n" +
2659             "OpFunctionEnd",
2660         2, 0.0),
2661     // Test case 36: Exp 0.0
2662     InstructionFoldingCase<float>(
2663         Header() + "%main = OpFunction %void None %void_func\n" +
2664             "%main_lab = OpLabel\n" +
2665             "%2 = OpExtInst %float %1 Exp %float_0\n" +
2666             "OpReturn\n" +
2667             "OpFunctionEnd",
2668         2, 1.0),
2669     // Test case 37: Log 1.0
2670     InstructionFoldingCase<float>(
2671         Header() + "%main = OpFunction %void None %void_func\n" +
2672             "%main_lab = OpLabel\n" +
2673             "%2 = OpExtInst %float %1 Log %float_1\n" +
2674             "OpReturn\n" +
2675             "OpFunctionEnd",
2676         2, 0.0),
2677     // Test case 38: Exp2 2.0
2678     InstructionFoldingCase<float>(
2679         Header() + "%main = OpFunction %void None %void_func\n" +
2680             "%main_lab = OpLabel\n" +
2681             "%2 = OpExtInst %float %1 Exp2 %float_2\n" +
2682             "OpReturn\n" +
2683             "OpFunctionEnd",
2684         2, 4.0),
2685     // Test case 39: Log2 4.0
2686     InstructionFoldingCase<float>(
2687         Header() + "%main = OpFunction %void None %void_func\n" +
2688             "%main_lab = OpLabel\n" +
2689             "%2 = OpExtInst %float %1 Log2 %float_4\n" +
2690             "OpReturn\n" +
2691             "OpFunctionEnd",
2692         2, 2.0),
2693     // Test case 40: Sqrt 4.0
2694     InstructionFoldingCase<float>(
2695         Header() + "%main = OpFunction %void None %void_func\n" +
2696             "%main_lab = OpLabel\n" +
2697             "%2 = OpExtInst %float %1 Sqrt %float_4\n" +
2698             "OpReturn\n" +
2699             "OpFunctionEnd",
2700         2, 2.0),
2701     // Test case 41: Atan2 0.0 1.0
2702     InstructionFoldingCase<float>(
2703         Header() + "%main = OpFunction %void None %void_func\n" +
2704             "%main_lab = OpLabel\n" +
2705             "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
2706             "OpReturn\n" +
2707             "OpFunctionEnd",
2708         2, 0.0),
2709     // Test case 42: Pow 2.0 3.0
2710     InstructionFoldingCase<float>(
2711         Header() + "%main = OpFunction %void None %void_func\n" +
2712             "%main_lab = OpLabel\n" +
2713             "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
2714             "OpReturn\n" +
2715             "OpFunctionEnd",
2716         2, 8.0),
2717     // Test case 43: Fold 1.0 / -0.0.
2718     InstructionFoldingCase<float>(
2719         Header() + "%main = OpFunction %void None %void_func\n" +
2720             "%main_lab = OpLabel\n" +
2721             "%2 = OpFDiv %float %float_1 %float_n0\n" +
2722             "OpReturn\n" +
2723             "OpFunctionEnd",
2724         2, -std::numeric_limits<float>::infinity()),
2725     // Test case 44: Fold -1.0 / -0.0
2726     InstructionFoldingCase<float>(
2727         Header() + "%main = OpFunction %void None %void_func\n" +
2728             "%main_lab = OpLabel\n" +
2729             "%2 = OpFDiv %float %float_n1 %float_n0\n" +
2730             "OpReturn\n" +
2731             "OpFunctionEnd",
2732         2, std::numeric_limits<float>::infinity()),
2733     // Test case 45: Fold 0.0 / 0.0
2734     InstructionFoldingCase<float>(
2735         Header() + "%main = OpFunction %void None %void_func\n" +
2736             "%main_lab = OpLabel\n" +
2737             "%2 = OpFDiv %float %float_0 %float_0\n" +
2738             "OpReturn\n" +
2739             "OpFunctionEnd",
2740         2, std::numeric_limits<float>::quiet_NaN()),
2741     // Test case 46: Fold 0.0 / -0.0
2742     InstructionFoldingCase<float>(
2743         Header() + "%main = OpFunction %void None %void_func\n" +
2744             "%main_lab = OpLabel\n" +
2745             "%2 = OpFDiv %float %float_0 %float_n0\n" +
2746             "OpReturn\n" +
2747             "OpFunctionEnd",
2748         2, std::numeric_limits<float>::quiet_NaN())
2749 ));
2750 // clang-format on
2751 
2752 using DoubleInstructionFoldingTest =
2753     ::testing::TestWithParam<InstructionFoldingCase<double>>;
2754 
TEST_P(DoubleInstructionFoldingTest,Case)2755 TEST_P(DoubleInstructionFoldingTest, Case) {
2756   const auto& tc = GetParam();
2757 
2758   std::unique_ptr<IRContext> context;
2759   Instruction* inst;
2760   std::tie(context, inst) =
2761       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
2762   CheckForExpectedScalarConstant(
2763       inst, tc.expected_result, [](const analysis::Constant* c) {
2764         return c->AsFloatConstant()->GetDoubleValue();
2765       });
2766 }
2767 
2768 // clang-format off
2769 INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
2770 ::testing::Values(
2771     // Test case 0: Fold 2.0 - 1.0
2772     InstructionFoldingCase<double>(
2773         Header() + "%main = OpFunction %void None %void_func\n" +
2774             "%main_lab = OpLabel\n" +
2775             "%2 = OpFSub %double %double_2 %double_1\n" +
2776             "OpReturn\n" +
2777             "OpFunctionEnd",
2778         2, 1.0),
2779         // Test case 1: Fold 2.0 + 1.0
2780         InstructionFoldingCase<double>(
2781             Header() + "%main = OpFunction %void None %void_func\n" +
2782                 "%main_lab = OpLabel\n" +
2783                 "%2 = OpFAdd %double %double_2 %double_1\n" +
2784                 "OpReturn\n" +
2785                 "OpFunctionEnd",
2786             2, 3.0),
2787         // Test case 2: Fold 3.0 * 2.0
2788         InstructionFoldingCase<double>(
2789             Header() + "%main = OpFunction %void None %void_func\n" +
2790                 "%main_lab = OpLabel\n" +
2791                 "%2 = OpFMul %double %double_3 %double_2\n" +
2792                 "OpReturn\n" +
2793                 "OpFunctionEnd",
2794             2, 6.0),
2795         // Test case 3: Fold 1.0 / 2.0
2796         InstructionFoldingCase<double>(
2797             Header() + "%main = OpFunction %void None %void_func\n" +
2798                 "%main_lab = OpLabel\n" +
2799                 "%2 = OpFDiv %double %double_1 %double_2\n" +
2800                 "OpReturn\n" +
2801                 "OpFunctionEnd",
2802             2, 0.5),
2803         // Test case 4: Fold 1.0 / 0.0
2804         InstructionFoldingCase<double>(
2805             Header() + "%main = OpFunction %void None %void_func\n" +
2806                 "%main_lab = OpLabel\n" +
2807                 "%2 = OpFDiv %double %double_1 %double_0\n" +
2808                 "OpReturn\n" +
2809                 "OpFunctionEnd",
2810             2, std::numeric_limits<double>::infinity()),
2811         // Test case 5: Fold -1.0 / 0.0
2812         InstructionFoldingCase<double>(
2813             Header() + "%main = OpFunction %void None %void_func\n" +
2814                 "%main_lab = OpLabel\n" +
2815                 "%2 = OpFDiv %double %double_n1 %double_0\n" +
2816                 "OpReturn\n" +
2817                 "OpFunctionEnd",
2818             2, -std::numeric_limits<double>::infinity()),
2819         // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2820         InstructionFoldingCase<double>(
2821             Header() + "%main = OpFunction %void None %void_func\n" +
2822                 "%main_lab = OpLabel\n" +
2823                 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
2824                 "OpReturn\n" +
2825                 "OpFunctionEnd",
2826             2, 5.5f),
2827         // Test case 7: Fold (0.0, 0.0) dot v
2828         InstructionFoldingCase<double>(
2829             Header() + "%main = OpFunction %void None %void_func\n" +
2830                 "%main_lab = OpLabel\n" +
2831                 "%v = OpVariable %_ptr_v2double Function\n" +
2832                 "%2 = OpLoad %v2double %v\n" +
2833                 "%3 = OpDot %double %v2double_0_0 %2\n" +
2834                 "OpReturn\n" +
2835                 "OpFunctionEnd",
2836             3, 0.0f),
2837         // Test case 8: Fold v dot (0.0, 0.0)
2838         InstructionFoldingCase<double>(
2839             Header() + "%main = OpFunction %void None %void_func\n" +
2840                 "%main_lab = OpLabel\n" +
2841                 "%v = OpVariable %_ptr_v2double Function\n" +
2842                 "%2 = OpLoad %v2double %v\n" +
2843                 "%3 = OpDot %double %2 %v2double_0_0\n" +
2844                 "OpReturn\n" +
2845                 "OpFunctionEnd",
2846             3, 0.0f),
2847         // Test case 9: Fold Null dot v
2848         InstructionFoldingCase<double>(
2849             Header() + "%main = OpFunction %void None %void_func\n" +
2850                 "%main_lab = OpLabel\n" +
2851                 "%v = OpVariable %_ptr_v2double Function\n" +
2852                 "%2 = OpLoad %v2double %v\n" +
2853                 "%3 = OpDot %double %v2double_null %2\n" +
2854                 "OpReturn\n" +
2855                 "OpFunctionEnd",
2856             3, 0.0f),
2857         // Test case 10: Fold v dot Null
2858         InstructionFoldingCase<double>(
2859             Header() + "%main = OpFunction %void None %void_func\n" +
2860                 "%main_lab = OpLabel\n" +
2861                 "%v = OpVariable %_ptr_v2double Function\n" +
2862                 "%2 = OpLoad %v2double %v\n" +
2863                 "%3 = OpDot %double %2 %v2double_null\n" +
2864                 "OpReturn\n" +
2865                 "OpFunctionEnd",
2866             3, 0.0f),
2867         // Test case 11: Fold -2.0
2868         InstructionFoldingCase<double>(
2869             Header() + "%main = OpFunction %void None %void_func\n" +
2870                 "%main_lab = OpLabel\n" +
2871                 "%2 = OpFNegate %double %double_2\n" +
2872                 "OpReturn\n" +
2873                 "OpFunctionEnd",
2874             2, -2),
2875         // Test case 12: FMin 1.0 4.0
2876         InstructionFoldingCase<double>(
2877             Header() + "%main = OpFunction %void None %void_func\n" +
2878                 "%main_lab = OpLabel\n" +
2879                 "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
2880                 "OpReturn\n" +
2881                 "OpFunctionEnd",
2882             2, 1.0),
2883         // Test case 13: FMin 4.0 0.2
2884         InstructionFoldingCase<double>(
2885             Header() + "%main = OpFunction %void None %void_func\n" +
2886                 "%main_lab = OpLabel\n" +
2887                 "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
2888                 "OpReturn\n" +
2889                 "OpFunctionEnd",
2890             2, 0.2),
2891         // Test case 14: FMax 1.0 4.0
2892         InstructionFoldingCase<double>(
2893             Header() + "%main = OpFunction %void None %void_func\n" +
2894                 "%main_lab = OpLabel\n" +
2895                 "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
2896                 "OpReturn\n" +
2897                 "OpFunctionEnd",
2898             2, 4.0),
2899         // Test case 15: FMax 1.0 0.2
2900         InstructionFoldingCase<double>(
2901             Header() + "%main = OpFunction %void None %void_func\n" +
2902                 "%main_lab = OpLabel\n" +
2903                 "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
2904                 "OpReturn\n" +
2905                 "OpFunctionEnd",
2906             2, 1.0),
2907         // Test case 16: FClamp 1.0 0.2 4.0
2908         InstructionFoldingCase<double>(
2909             Header() + "%main = OpFunction %void None %void_func\n" +
2910                 "%main_lab = OpLabel\n" +
2911                 "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
2912                 "OpReturn\n" +
2913                 "OpFunctionEnd",
2914             2, 1.0),
2915         // Test case 17: FClamp 0.2 2.0 4.0
2916         InstructionFoldingCase<double>(
2917             Header() + "%main = OpFunction %void None %void_func\n" +
2918                 "%main_lab = OpLabel\n" +
2919                 "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
2920                 "OpReturn\n" +
2921                 "OpFunctionEnd",
2922             2, 2.0),
2923         // Test case 18: FClamp 5.0 2.0 4.0
2924         InstructionFoldingCase<double>(
2925             Header() + "%main = OpFunction %void None %void_func\n" +
2926                 "%main_lab = OpLabel\n" +
2927                 "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
2928                 "OpReturn\n" +
2929                 "OpFunctionEnd",
2930             2, 4.0),
2931         // Test case 19: FClamp 1.0 2.0 x
2932         InstructionFoldingCase<double>(
2933             Header() + "%main = OpFunction %void None %void_func\n" +
2934                 "%main_lab = OpLabel\n" +
2935                 "%undef = OpUndef %double\n" +
2936                 "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
2937                 "OpReturn\n" +
2938                 "OpFunctionEnd",
2939             2, 2.0),
2940         // Test case 20: FClamp 1.0 x 0.5
2941         InstructionFoldingCase<double>(
2942             Header() + "%main = OpFunction %void None %void_func\n" +
2943                 "%main_lab = OpLabel\n" +
2944                 "%undef = OpUndef %double\n" +
2945                 "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
2946                 "OpReturn\n" +
2947                 "OpFunctionEnd",
2948             2, 0.5),
2949         // Test case 21: Sqrt 4.0
2950         InstructionFoldingCase<double>(
2951             Header() + "%main = OpFunction %void None %void_func\n" +
2952                 "%main_lab = OpLabel\n" +
2953                 "%undef = OpUndef %double\n" +
2954                 "%2 = OpExtInst %double %1 Sqrt %double_4\n" +
2955                 "OpReturn\n" +
2956                 "OpFunctionEnd",
2957             2, 2.0),
2958         // Test case 22: Pow 2.0 3.0
2959         InstructionFoldingCase<double>(
2960             Header() + "%main = OpFunction %void None %void_func\n" +
2961                 "%main_lab = OpLabel\n" +
2962                 "%undef = OpUndef %double\n" +
2963                 "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" +
2964                 "OpReturn\n" +
2965                 "OpFunctionEnd",
2966             2, 8.0),
2967         // Test case 23: Fold 1.0 / -0.0.
2968         InstructionFoldingCase<double>(
2969             Header() + "%main = OpFunction %void None %void_func\n" +
2970                 "%main_lab = OpLabel\n" +
2971                 "%2 = OpFDiv %double %double_1 %double_n0\n" +
2972                 "OpReturn\n" +
2973                 "OpFunctionEnd",
2974             2, -std::numeric_limits<double>::infinity()),
2975         // Test case 24: Fold -1.0 / -0.0
2976         InstructionFoldingCase<double>(
2977             Header() + "%main = OpFunction %void None %void_func\n" +
2978                 "%main_lab = OpLabel\n" +
2979                 "%2 = OpFDiv %double %double_n1 %double_n0\n" +
2980                 "OpReturn\n" +
2981                 "OpFunctionEnd",
2982             2, std::numeric_limits<double>::infinity()),
2983         // Test case 25: Fold 0.0 / 0.0
2984         InstructionFoldingCase<double>(
2985             Header() + "%main = OpFunction %void None %void_func\n" +
2986                 "%main_lab = OpLabel\n" +
2987                 "%2 = OpFDiv %double %double_0 %double_0\n" +
2988                 "OpReturn\n" +
2989                 "OpFunctionEnd",
2990             2, std::numeric_limits<double>::quiet_NaN()),
2991         // Test case 26: Fold 0.0 / -0.0
2992         InstructionFoldingCase<double>(
2993             Header() + "%main = OpFunction %void None %void_func\n" +
2994                 "%main_lab = OpLabel\n" +
2995                 "%2 = OpFDiv %double %double_0 %double_n0\n" +
2996                 "OpReturn\n" +
2997                 "OpFunctionEnd",
2998             2, std::numeric_limits<double>::quiet_NaN())
2999 ));
3000 // clang-format on
3001 
3002 // clang-format off
3003 INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3004                         ::testing::Values(
3005   // Test case 0: fold 1.0 == 2.0
3006   InstructionFoldingCase<bool>(
3007       Header() + "%main = OpFunction %void None %void_func\n" +
3008           "%main_lab = OpLabel\n" +
3009           "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
3010           "OpReturn\n" +
3011           "OpFunctionEnd",
3012       2, false),
3013   // Test case 1: fold 1.0 != 2.0
3014   InstructionFoldingCase<bool>(
3015       Header() + "%main = OpFunction %void None %void_func\n" +
3016           "%main_lab = OpLabel\n" +
3017           "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
3018           "OpReturn\n" +
3019           "OpFunctionEnd",
3020       2, true),
3021   // Test case 2: fold 1.0 < 2.0
3022   InstructionFoldingCase<bool>(
3023       Header() + "%main = OpFunction %void None %void_func\n" +
3024           "%main_lab = OpLabel\n" +
3025           "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
3026           "OpReturn\n" +
3027           "OpFunctionEnd",
3028       2, true),
3029   // Test case 3: fold 1.0 > 2.0
3030   InstructionFoldingCase<bool>(
3031       Header() + "%main = OpFunction %void None %void_func\n" +
3032           "%main_lab = OpLabel\n" +
3033           "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
3034           "OpReturn\n" +
3035           "OpFunctionEnd",
3036       2, false),
3037   // Test case 4: fold 1.0 <= 2.0
3038   InstructionFoldingCase<bool>(
3039       Header() + "%main = OpFunction %void None %void_func\n" +
3040           "%main_lab = OpLabel\n" +
3041           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
3042           "OpReturn\n" +
3043           "OpFunctionEnd",
3044       2, true),
3045   // Test case 5: fold 1.0 >= 2.0
3046   InstructionFoldingCase<bool>(
3047       Header() + "%main = OpFunction %void None %void_func\n" +
3048           "%main_lab = OpLabel\n" +
3049           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
3050           "OpReturn\n" +
3051           "OpFunctionEnd",
3052       2, false),
3053   // Test case 6: fold 1.0 == 1.0
3054   InstructionFoldingCase<bool>(
3055       Header() + "%main = OpFunction %void None %void_func\n" +
3056           "%main_lab = OpLabel\n" +
3057           "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
3058           "OpReturn\n" +
3059           "OpFunctionEnd",
3060       2, true),
3061   // Test case 7: fold 1.0 != 1.0
3062   InstructionFoldingCase<bool>(
3063       Header() + "%main = OpFunction %void None %void_func\n" +
3064           "%main_lab = OpLabel\n" +
3065           "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
3066           "OpReturn\n" +
3067           "OpFunctionEnd",
3068       2, false),
3069   // Test case 8: fold 1.0 < 1.0
3070   InstructionFoldingCase<bool>(
3071       Header() + "%main = OpFunction %void None %void_func\n" +
3072           "%main_lab = OpLabel\n" +
3073           "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
3074           "OpReturn\n" +
3075           "OpFunctionEnd",
3076       2, false),
3077   // Test case 9: fold 1.0 > 1.0
3078   InstructionFoldingCase<bool>(
3079       Header() + "%main = OpFunction %void None %void_func\n" +
3080           "%main_lab = OpLabel\n" +
3081           "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
3082           "OpReturn\n" +
3083           "OpFunctionEnd",
3084       2, false),
3085   // Test case 10: fold 1.0 <= 1.0
3086   InstructionFoldingCase<bool>(
3087       Header() + "%main = OpFunction %void None %void_func\n" +
3088           "%main_lab = OpLabel\n" +
3089           "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
3090           "OpReturn\n" +
3091           "OpFunctionEnd",
3092       2, true),
3093   // Test case 11: fold 1.0 >= 1.0
3094   InstructionFoldingCase<bool>(
3095       Header() + "%main = OpFunction %void None %void_func\n" +
3096           "%main_lab = OpLabel\n" +
3097           "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
3098           "OpReturn\n" +
3099           "OpFunctionEnd",
3100       2, true),
3101   // Test case 12: fold 2.0 < 1.0
3102   InstructionFoldingCase<bool>(
3103       Header() + "%main = OpFunction %void None %void_func\n" +
3104           "%main_lab = OpLabel\n" +
3105           "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
3106           "OpReturn\n" +
3107           "OpFunctionEnd",
3108       2, false),
3109   // Test case 13: fold 2.0 > 1.0
3110   InstructionFoldingCase<bool>(
3111       Header() + "%main = OpFunction %void None %void_func\n" +
3112           "%main_lab = OpLabel\n" +
3113           "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
3114           "OpReturn\n" +
3115           "OpFunctionEnd",
3116       2, true),
3117   // Test case 14: fold 2.0 <= 1.0
3118   InstructionFoldingCase<bool>(
3119       Header() + "%main = OpFunction %void None %void_func\n" +
3120           "%main_lab = OpLabel\n" +
3121           "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
3122           "OpReturn\n" +
3123           "OpFunctionEnd",
3124       2, false),
3125   // Test case 15: fold 2.0 >= 1.0
3126   InstructionFoldingCase<bool>(
3127       Header() + "%main = OpFunction %void None %void_func\n" +
3128           "%main_lab = OpLabel\n" +
3129           "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
3130           "OpReturn\n" +
3131           "OpFunctionEnd",
3132       2, true)
3133 ));
3134 
3135 INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3136                         ::testing::Values(
3137   // Test case 0: fold 1.0 == 2.0
3138   InstructionFoldingCase<bool>(
3139       Header() + "%main = OpFunction %void None %void_func\n" +
3140           "%main_lab = OpLabel\n" +
3141           "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
3142           "OpReturn\n" +
3143           "OpFunctionEnd",
3144       2, false),
3145   // Test case 1: fold 1.0 != 2.0
3146   InstructionFoldingCase<bool>(
3147       Header() + "%main = OpFunction %void None %void_func\n" +
3148           "%main_lab = OpLabel\n" +
3149           "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
3150           "OpReturn\n" +
3151           "OpFunctionEnd",
3152       2, true),
3153   // Test case 2: fold 1.0 < 2.0
3154   InstructionFoldingCase<bool>(
3155       Header() + "%main = OpFunction %void None %void_func\n" +
3156           "%main_lab = OpLabel\n" +
3157           "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
3158           "OpReturn\n" +
3159           "OpFunctionEnd",
3160       2, true),
3161   // Test case 3: fold 1.0 > 2.0
3162   InstructionFoldingCase<bool>(
3163       Header() + "%main = OpFunction %void None %void_func\n" +
3164           "%main_lab = OpLabel\n" +
3165           "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
3166           "OpReturn\n" +
3167           "OpFunctionEnd",
3168       2, false),
3169   // Test case 4: fold 1.0 <= 2.0
3170   InstructionFoldingCase<bool>(
3171       Header() + "%main = OpFunction %void None %void_func\n" +
3172           "%main_lab = OpLabel\n" +
3173           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
3174           "OpReturn\n" +
3175           "OpFunctionEnd",
3176       2, true),
3177   // Test case 5: fold 1.0 >= 2.0
3178   InstructionFoldingCase<bool>(
3179       Header() + "%main = OpFunction %void None %void_func\n" +
3180           "%main_lab = OpLabel\n" +
3181           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
3182           "OpReturn\n" +
3183           "OpFunctionEnd",
3184       2, false),
3185   // Test case 6: fold 1.0 == 1.0
3186   InstructionFoldingCase<bool>(
3187       Header() + "%main = OpFunction %void None %void_func\n" +
3188           "%main_lab = OpLabel\n" +
3189           "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
3190           "OpReturn\n" +
3191           "OpFunctionEnd",
3192       2, true),
3193   // Test case 7: fold 1.0 != 1.0
3194   InstructionFoldingCase<bool>(
3195       Header() + "%main = OpFunction %void None %void_func\n" +
3196           "%main_lab = OpLabel\n" +
3197           "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
3198           "OpReturn\n" +
3199           "OpFunctionEnd",
3200       2, false),
3201   // Test case 8: fold 1.0 < 1.0
3202   InstructionFoldingCase<bool>(
3203       Header() + "%main = OpFunction %void None %void_func\n" +
3204           "%main_lab = OpLabel\n" +
3205           "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
3206           "OpReturn\n" +
3207           "OpFunctionEnd",
3208       2, false),
3209   // Test case 9: fold 1.0 > 1.0
3210   InstructionFoldingCase<bool>(
3211       Header() + "%main = OpFunction %void None %void_func\n" +
3212           "%main_lab = OpLabel\n" +
3213           "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
3214           "OpReturn\n" +
3215           "OpFunctionEnd",
3216       2, false),
3217   // Test case 10: fold 1.0 <= 1.0
3218   InstructionFoldingCase<bool>(
3219       Header() + "%main = OpFunction %void None %void_func\n" +
3220           "%main_lab = OpLabel\n" +
3221           "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
3222           "OpReturn\n" +
3223           "OpFunctionEnd",
3224       2, true),
3225   // Test case 11: fold 1.0 >= 1.0
3226   InstructionFoldingCase<bool>(
3227       Header() + "%main = OpFunction %void None %void_func\n" +
3228           "%main_lab = OpLabel\n" +
3229           "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
3230           "OpReturn\n" +
3231           "OpFunctionEnd",
3232       2, true),
3233   // Test case 12: fold 2.0 < 1.0
3234   InstructionFoldingCase<bool>(
3235       Header() + "%main = OpFunction %void None %void_func\n" +
3236           "%main_lab = OpLabel\n" +
3237           "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
3238           "OpReturn\n" +
3239           "OpFunctionEnd",
3240       2, false),
3241   // Test case 13: fold 2.0 > 1.0
3242   InstructionFoldingCase<bool>(
3243       Header() + "%main = OpFunction %void None %void_func\n" +
3244           "%main_lab = OpLabel\n" +
3245           "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
3246           "OpReturn\n" +
3247           "OpFunctionEnd",
3248       2, true),
3249   // Test case 14: fold 2.0 <= 1.0
3250   InstructionFoldingCase<bool>(
3251       Header() + "%main = OpFunction %void None %void_func\n" +
3252           "%main_lab = OpLabel\n" +
3253           "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
3254           "OpReturn\n" +
3255           "OpFunctionEnd",
3256       2, false),
3257   // Test case 15: fold 2.0 >= 1.0
3258   InstructionFoldingCase<bool>(
3259       Header() + "%main = OpFunction %void None %void_func\n" +
3260           "%main_lab = OpLabel\n" +
3261           "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
3262           "OpReturn\n" +
3263           "OpFunctionEnd",
3264       2, true)
3265 ));
3266 
3267 INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3268                         ::testing::Values(
3269   // Test case 0: fold 1.0 == 2.0
3270   InstructionFoldingCase<bool>(
3271       Header() + "%main = OpFunction %void None %void_func\n" +
3272           "%main_lab = OpLabel\n" +
3273           "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
3274           "OpReturn\n" +
3275           "OpFunctionEnd",
3276       2, false),
3277   // Test case 1: fold 1.0 != 2.0
3278   InstructionFoldingCase<bool>(
3279       Header() + "%main = OpFunction %void None %void_func\n" +
3280           "%main_lab = OpLabel\n" +
3281           "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
3282           "OpReturn\n" +
3283           "OpFunctionEnd",
3284       2, true),
3285   // Test case 2: fold 1.0 < 2.0
3286   InstructionFoldingCase<bool>(
3287       Header() + "%main = OpFunction %void None %void_func\n" +
3288           "%main_lab = OpLabel\n" +
3289           "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
3290           "OpReturn\n" +
3291           "OpFunctionEnd",
3292       2, true),
3293   // Test case 3: fold 1.0 > 2.0
3294   InstructionFoldingCase<bool>(
3295       Header() + "%main = OpFunction %void None %void_func\n" +
3296           "%main_lab = OpLabel\n" +
3297           "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
3298           "OpReturn\n" +
3299           "OpFunctionEnd",
3300       2, false),
3301   // Test case 4: fold 1.0 <= 2.0
3302   InstructionFoldingCase<bool>(
3303       Header() + "%main = OpFunction %void None %void_func\n" +
3304           "%main_lab = OpLabel\n" +
3305           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
3306           "OpReturn\n" +
3307           "OpFunctionEnd",
3308       2, true),
3309   // Test case 5: fold 1.0 >= 2.0
3310   InstructionFoldingCase<bool>(
3311       Header() + "%main = OpFunction %void None %void_func\n" +
3312           "%main_lab = OpLabel\n" +
3313           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
3314           "OpReturn\n" +
3315           "OpFunctionEnd",
3316       2, false),
3317   // Test case 6: fold 1.0 == 1.0
3318   InstructionFoldingCase<bool>(
3319       Header() + "%main = OpFunction %void None %void_func\n" +
3320           "%main_lab = OpLabel\n" +
3321           "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
3322           "OpReturn\n" +
3323           "OpFunctionEnd",
3324       2, true),
3325   // Test case 7: fold 1.0 != 1.0
3326   InstructionFoldingCase<bool>(
3327       Header() + "%main = OpFunction %void None %void_func\n" +
3328           "%main_lab = OpLabel\n" +
3329           "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
3330           "OpReturn\n" +
3331           "OpFunctionEnd",
3332       2, false),
3333   // Test case 8: fold 1.0 < 1.0
3334   InstructionFoldingCase<bool>(
3335       Header() + "%main = OpFunction %void None %void_func\n" +
3336           "%main_lab = OpLabel\n" +
3337           "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
3338           "OpReturn\n" +
3339           "OpFunctionEnd",
3340       2, false),
3341   // Test case 9: fold 1.0 > 1.0
3342   InstructionFoldingCase<bool>(
3343       Header() + "%main = OpFunction %void None %void_func\n" +
3344           "%main_lab = OpLabel\n" +
3345           "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
3346           "OpReturn\n" +
3347           "OpFunctionEnd",
3348       2, false),
3349   // Test case 10: fold 1.0 <= 1.0
3350   InstructionFoldingCase<bool>(
3351       Header() + "%main = OpFunction %void None %void_func\n" +
3352           "%main_lab = OpLabel\n" +
3353           "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
3354           "OpReturn\n" +
3355           "OpFunctionEnd",
3356       2, true),
3357   // Test case 11: fold 1.0 >= 1.0
3358   InstructionFoldingCase<bool>(
3359       Header() + "%main = OpFunction %void None %void_func\n" +
3360           "%main_lab = OpLabel\n" +
3361           "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
3362           "OpReturn\n" +
3363           "OpFunctionEnd",
3364       2, true),
3365   // Test case 12: fold 2.0 < 1.0
3366   InstructionFoldingCase<bool>(
3367       Header() + "%main = OpFunction %void None %void_func\n" +
3368           "%main_lab = OpLabel\n" +
3369           "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
3370           "OpReturn\n" +
3371           "OpFunctionEnd",
3372       2, false),
3373   // Test case 13: fold 2.0 > 1.0
3374   InstructionFoldingCase<bool>(
3375       Header() + "%main = OpFunction %void None %void_func\n" +
3376           "%main_lab = OpLabel\n" +
3377           "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
3378           "OpReturn\n" +
3379           "OpFunctionEnd",
3380       2, true),
3381   // Test case 14: fold 2.0 <= 1.0
3382   InstructionFoldingCase<bool>(
3383       Header() + "%main = OpFunction %void None %void_func\n" +
3384           "%main_lab = OpLabel\n" +
3385           "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
3386           "OpReturn\n" +
3387           "OpFunctionEnd",
3388       2, false),
3389   // Test case 15: fold 2.0 >= 1.0
3390   InstructionFoldingCase<bool>(
3391       Header() + "%main = OpFunction %void None %void_func\n" +
3392           "%main_lab = OpLabel\n" +
3393           "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
3394           "OpReturn\n" +
3395           "OpFunctionEnd",
3396       2, true)
3397 ));
3398 
3399 INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3400                         ::testing::Values(
3401   // Test case 0: fold 1.0 == 2.0
3402   InstructionFoldingCase<bool>(
3403       Header() + "%main = OpFunction %void None %void_func\n" +
3404           "%main_lab = OpLabel\n" +
3405           "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
3406           "OpReturn\n" +
3407           "OpFunctionEnd",
3408       2, false),
3409   // Test case 1: fold 1.0 != 2.0
3410   InstructionFoldingCase<bool>(
3411       Header() + "%main = OpFunction %void None %void_func\n" +
3412           "%main_lab = OpLabel\n" +
3413           "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
3414           "OpReturn\n" +
3415           "OpFunctionEnd",
3416       2, true),
3417   // Test case 2: fold 1.0 < 2.0
3418   InstructionFoldingCase<bool>(
3419       Header() + "%main = OpFunction %void None %void_func\n" +
3420           "%main_lab = OpLabel\n" +
3421           "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
3422           "OpReturn\n" +
3423           "OpFunctionEnd",
3424       2, true),
3425   // Test case 3: fold 1.0 > 2.0
3426   InstructionFoldingCase<bool>(
3427       Header() + "%main = OpFunction %void None %void_func\n" +
3428           "%main_lab = OpLabel\n" +
3429           "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
3430           "OpReturn\n" +
3431           "OpFunctionEnd",
3432       2, false),
3433   // Test case 4: fold 1.0 <= 2.0
3434   InstructionFoldingCase<bool>(
3435       Header() + "%main = OpFunction %void None %void_func\n" +
3436           "%main_lab = OpLabel\n" +
3437           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
3438           "OpReturn\n" +
3439           "OpFunctionEnd",
3440       2, true),
3441   // Test case 5: fold 1.0 >= 2.0
3442   InstructionFoldingCase<bool>(
3443       Header() + "%main = OpFunction %void None %void_func\n" +
3444           "%main_lab = OpLabel\n" +
3445           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
3446           "OpReturn\n" +
3447           "OpFunctionEnd",
3448       2, false),
3449   // Test case 6: fold 1.0 == 1.0
3450   InstructionFoldingCase<bool>(
3451       Header() + "%main = OpFunction %void None %void_func\n" +
3452           "%main_lab = OpLabel\n" +
3453           "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
3454           "OpReturn\n" +
3455           "OpFunctionEnd",
3456       2, true),
3457   // Test case 7: fold 1.0 != 1.0
3458   InstructionFoldingCase<bool>(
3459       Header() + "%main = OpFunction %void None %void_func\n" +
3460           "%main_lab = OpLabel\n" +
3461           "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
3462           "OpReturn\n" +
3463           "OpFunctionEnd",
3464       2, false),
3465   // Test case 8: fold 1.0 < 1.0
3466   InstructionFoldingCase<bool>(
3467       Header() + "%main = OpFunction %void None %void_func\n" +
3468           "%main_lab = OpLabel\n" +
3469           "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
3470           "OpReturn\n" +
3471           "OpFunctionEnd",
3472       2, false),
3473   // Test case 9: fold 1.0 > 1.0
3474   InstructionFoldingCase<bool>(
3475       Header() + "%main = OpFunction %void None %void_func\n" +
3476           "%main_lab = OpLabel\n" +
3477           "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
3478           "OpReturn\n" +
3479           "OpFunctionEnd",
3480       2, false),
3481   // Test case 10: fold 1.0 <= 1.0
3482   InstructionFoldingCase<bool>(
3483       Header() + "%main = OpFunction %void None %void_func\n" +
3484           "%main_lab = OpLabel\n" +
3485           "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
3486           "OpReturn\n" +
3487           "OpFunctionEnd",
3488       2, true),
3489   // Test case 11: fold 1.0 >= 1.0
3490   InstructionFoldingCase<bool>(
3491       Header() + "%main = OpFunction %void None %void_func\n" +
3492           "%main_lab = OpLabel\n" +
3493           "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
3494           "OpReturn\n" +
3495           "OpFunctionEnd",
3496       2, true),
3497   // Test case 12: fold 2.0 < 1.0
3498   InstructionFoldingCase<bool>(
3499       Header() + "%main = OpFunction %void None %void_func\n" +
3500           "%main_lab = OpLabel\n" +
3501           "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
3502           "OpReturn\n" +
3503           "OpFunctionEnd",
3504       2, false),
3505   // Test case 13: fold 2.0 > 1.0
3506   InstructionFoldingCase<bool>(
3507       Header() + "%main = OpFunction %void None %void_func\n" +
3508           "%main_lab = OpLabel\n" +
3509           "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
3510           "OpReturn\n" +
3511           "OpFunctionEnd",
3512       2, true),
3513   // Test case 14: fold 2.0 <= 1.0
3514   InstructionFoldingCase<bool>(
3515       Header() + "%main = OpFunction %void None %void_func\n" +
3516           "%main_lab = OpLabel\n" +
3517           "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
3518           "OpReturn\n" +
3519           "OpFunctionEnd",
3520       2, false),
3521   // Test case 15: fold 2.0 >= 1.0
3522   InstructionFoldingCase<bool>(
3523       Header() + "%main = OpFunction %void None %void_func\n" +
3524           "%main_lab = OpLabel\n" +
3525           "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
3526           "OpReturn\n" +
3527           "OpFunctionEnd",
3528       2, true)
3529 ));
3530 
3531 INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3532                         ::testing::Values(
3533   // Test case 0: fold NaN == 0 (ord)
3534   InstructionFoldingCase<bool>(
3535       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3536           "%main_lab = OpLabel\n" +
3537           "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
3538           "OpReturn\n" +
3539           "OpFunctionEnd",
3540       2, false),
3541   // Test case 1: fold NaN == NaN (unord)
3542   InstructionFoldingCase<bool>(
3543       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3544           "%main_lab = OpLabel\n" +
3545           "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
3546           "OpReturn\n" +
3547           "OpFunctionEnd",
3548       2, true),
3549   // Test case 2: fold NaN != NaN (ord)
3550   InstructionFoldingCase<bool>(
3551       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3552           "%main_lab = OpLabel\n" +
3553           "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
3554           "OpReturn\n" +
3555           "OpFunctionEnd",
3556       2, false),
3557   // Test case 3: fold NaN != NaN (unord)
3558   InstructionFoldingCase<bool>(
3559       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3560           "%main_lab = OpLabel\n" +
3561           "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
3562           "OpReturn\n" +
3563           "OpFunctionEnd",
3564       2, true)
3565 ));
3566 
3567 INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3568                         ::testing::Values(
3569   // Test case 0: fold NaN == 0 (ord)
3570   InstructionFoldingCase<bool>(
3571       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3572           "%main_lab = OpLabel\n" +
3573           "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
3574           "OpReturn\n" +
3575           "OpFunctionEnd",
3576       2, false),
3577   // Test case 1: fold NaN == NaN (unord)
3578   InstructionFoldingCase<bool>(
3579       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3580           "%main_lab = OpLabel\n" +
3581           "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
3582           "OpReturn\n" +
3583           "OpFunctionEnd",
3584       2, true),
3585   // Test case 2: fold NaN != NaN (ord)
3586   InstructionFoldingCase<bool>(
3587       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3588           "%main_lab = OpLabel\n" +
3589           "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
3590           "OpReturn\n" +
3591           "OpFunctionEnd",
3592       2, false),
3593   // Test case 3: fold NaN != NaN (unord)
3594   InstructionFoldingCase<bool>(
3595       HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3596           "%main_lab = OpLabel\n" +
3597           "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
3598           "OpReturn\n" +
3599           "OpFunctionEnd",
3600       2, true)
3601 ));
3602 // clang-format on
3603 
3604 template <class ResultType>
3605 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anonb0a5c4000111::InstructionFoldingCaseWithMap3606   InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
3607                                 ResultType result,
3608                                 std::function<uint32_t(uint32_t)> map)
3609       : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
3610 
3611   std::string test_body;
3612   uint32_t id_to_fold;
3613   ResultType expected_result;
3614   std::function<uint32_t(uint32_t)> id_map;
3615 };
3616 
3617 using IntegerInstructionFoldingTestWithMap =
3618     ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
3619 
TEST_P(IntegerInstructionFoldingTestWithMap,Case)3620 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
3621   const auto& tc = GetParam();
3622 
3623   std::unique_ptr<IRContext> context;
3624   Instruction* inst;
3625   std::tie(context, inst) =
3626       GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5);
3627 
3628   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3629                                                                      tc.id_map);
3630   EXPECT_NE(inst, nullptr);
3631 
3632   CheckForExpectedScalarConstant(inst, tc.expected_result,
3633                                  [](const analysis::Constant* c) {
3634                                    return c->AsIntConstant()->GetU32BitValue();
3635                                  });
3636 }
3637 // clang-format off
3638 
3639 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
3640   ::testing::Values(
3641       // Test case 0: fold %3 = 0; %3 * n
3642       InstructionFoldingCaseWithMap<uint32_t>(
3643           Header() + "%main = OpFunction %void None %void_func\n" +
3644               "%main_lab = OpLabel\n" +
3645               "%n = OpVariable %_ptr_int Function\n" +
3646               "%load = OpLoad %int %n\n" +
3647               "%3 = OpCopyObject %int %int_0\n"
3648               "%2 = OpIMul %int %3 %load\n" +
3649               "OpReturn\n" +
3650               "OpFunctionEnd",
__anonb0a5c4000d02(uint32_t id) 3651           2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
3652   ));
3653 // clang-format on
3654 
3655 using BooleanInstructionFoldingTestWithMap =
3656     ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
3657 
TEST_P(BooleanInstructionFoldingTestWithMap,Case)3658 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
3659   const auto& tc = GetParam();
3660 
3661   std::unique_ptr<IRContext> context;
3662   Instruction* inst;
3663   std::tie(context, inst) =
3664       GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5);
3665   inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3666                                                                      tc.id_map);
3667   ASSERT_NE(inst, nullptr);
3668   CheckForExpectedScalarConstant(
3669       inst, tc.expected_result,
3670       [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); });
3671 }
3672 
3673 // clang-format off
3674 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap,
3675   ::testing::Values(
3676       // Test case 0: fold %3 = true; %3 || n
3677       InstructionFoldingCaseWithMap<bool>(
3678           Header() + "%main = OpFunction %void None %void_func\n" +
3679               "%main_lab = OpLabel\n" +
3680               "%n = OpVariable %_ptr_bool Function\n" +
3681               "%load = OpLoad %bool %n\n" +
3682               "%3 = OpCopyObject %bool %true\n" +
3683               "%2 = OpLogicalOr %bool %3 %load\n" +
3684               "OpReturn\n" +
3685               "OpFunctionEnd",
__anonb0a5c4000f02(uint32_t id) 3686           2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
3687   ));
3688 // clang-format on
3689 
3690 using GeneralInstructionFoldingTest =
3691     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
3692 
TEST_P(GeneralInstructionFoldingTest,Case)3693 TEST_P(GeneralInstructionFoldingTest, Case) {
3694   const auto& tc = GetParam();
3695 
3696   std::unique_ptr<IRContext> context;
3697   Instruction* inst;
3698   std::tie(context, inst) =
3699       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
3700 
3701   EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0));
3702   if (inst != nullptr) {
3703     EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
3704     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
3705   }
3706 }
3707 
3708 // clang-format off
3709 INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
3710                         ::testing::Values(
3711     // Test case 0: Don't fold n * m
3712     InstructionFoldingCase<uint32_t>(
3713         Header() + "%main = OpFunction %void None %void_func\n" +
3714             "%main_lab = OpLabel\n" +
3715             "%n = OpVariable %_ptr_int Function\n" +
3716             "%m = OpVariable %_ptr_int Function\n" +
3717             "%load_n = OpLoad %int %n\n" +
3718             "%load_m = OpLoad %int %m\n" +
3719             "%2 = OpIMul %int %load_n %load_m\n" +
3720             "OpReturn\n" +
3721             "OpFunctionEnd",
3722         2, 0),
3723     // Test case 1: Don't fold n / m (unsigned)
3724     InstructionFoldingCase<uint32_t>(
3725         Header() + "%main = OpFunction %void None %void_func\n" +
3726             "%main_lab = OpLabel\n" +
3727             "%n = OpVariable %_ptr_uint Function\n" +
3728             "%m = OpVariable %_ptr_uint Function\n" +
3729             "%load_n = OpLoad %uint %n\n" +
3730             "%load_m = OpLoad %uint %m\n" +
3731             "%2 = OpUDiv %uint %load_n %load_m\n" +
3732             "OpReturn\n" +
3733             "OpFunctionEnd",
3734         2, 0),
3735     // Test case 2: Don't fold n / m (signed)
3736     InstructionFoldingCase<uint32_t>(
3737         Header() + "%main = OpFunction %void None %void_func\n" +
3738             "%main_lab = OpLabel\n" +
3739             "%n = OpVariable %_ptr_int Function\n" +
3740             "%m = OpVariable %_ptr_int Function\n" +
3741             "%load_n = OpLoad %int %n\n" +
3742             "%load_m = OpLoad %int %m\n" +
3743             "%2 = OpSDiv %int %load_n %load_m\n" +
3744             "OpReturn\n" +
3745             "OpFunctionEnd",
3746         2, 0),
3747     // Test case 3: Don't fold n remainder m
3748     InstructionFoldingCase<uint32_t>(
3749         Header() + "%main = OpFunction %void None %void_func\n" +
3750             "%main_lab = OpLabel\n" +
3751             "%n = OpVariable %_ptr_int Function\n" +
3752             "%m = OpVariable %_ptr_int Function\n" +
3753             "%load_n = OpLoad %int %n\n" +
3754             "%load_m = OpLoad %int %m\n" +
3755             "%2 = OpSRem %int %load_n %load_m\n" +
3756             "OpReturn\n" +
3757             "OpFunctionEnd",
3758         2, 0),
3759     // Test case 4: Don't fold n % m (signed)
3760     InstructionFoldingCase<uint32_t>(
3761         Header() + "%main = OpFunction %void None %void_func\n" +
3762             "%main_lab = OpLabel\n" +
3763             "%n = OpVariable %_ptr_int Function\n" +
3764             "%m = OpVariable %_ptr_int Function\n" +
3765             "%load_n = OpLoad %int %n\n" +
3766             "%load_m = OpLoad %int %m\n" +
3767             "%2 = OpSMod %int %load_n %load_m\n" +
3768             "OpReturn\n" +
3769             "OpFunctionEnd",
3770         2, 0),
3771     // Test case 5: Don't fold n % m (unsigned)
3772     InstructionFoldingCase<uint32_t>(
3773         Header() + "%main = OpFunction %void None %void_func\n" +
3774             "%main_lab = OpLabel\n" +
3775             "%n = OpVariable %_ptr_uint Function\n" +
3776             "%m = OpVariable %_ptr_uint Function\n" +
3777             "%load_n = OpLoad %uint %n\n" +
3778             "%load_m = OpLoad %uint %m\n" +
3779             "%2 = OpUMod %int %load_n %load_m\n" +
3780             "OpReturn\n" +
3781             "OpFunctionEnd",
3782         2, 0),
3783     // Test case 6: Don't fold n << m
3784     InstructionFoldingCase<uint32_t>(
3785         Header() + "%main = OpFunction %void None %void_func\n" +
3786             "%main_lab = OpLabel\n" +
3787             "%n = OpVariable %_ptr_uint Function\n" +
3788             "%m = OpVariable %_ptr_uint Function\n" +
3789             "%load_n = OpLoad %uint %n\n" +
3790             "%load_m = OpLoad %uint %m\n" +
3791             "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
3792             "OpReturn\n" +
3793             "OpFunctionEnd",
3794         2, 0),
3795     // Test case 7: Don't fold n >> m
3796     InstructionFoldingCase<uint32_t>(
3797         Header() + "%main = OpFunction %void None %void_func\n" +
3798             "%main_lab = OpLabel\n" +
3799             "%n = OpVariable %_ptr_uint Function\n" +
3800             "%m = OpVariable %_ptr_uint Function\n" +
3801             "%load_n = OpLoad %uint %n\n" +
3802             "%load_m = OpLoad %uint %m\n" +
3803             "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
3804             "OpReturn\n" +
3805             "OpFunctionEnd",
3806         2, 0),
3807     // Test case 8: Don't fold n | m
3808     InstructionFoldingCase<uint32_t>(
3809         Header() + "%main = OpFunction %void None %void_func\n" +
3810             "%main_lab = OpLabel\n" +
3811             "%n = OpVariable %_ptr_uint Function\n" +
3812             "%m = OpVariable %_ptr_uint Function\n" +
3813             "%load_n = OpLoad %uint %n\n" +
3814             "%load_m = OpLoad %uint %m\n" +
3815             "%2 = OpBitwiseOr %int %load_n %load_m\n" +
3816             "OpReturn\n" +
3817             "OpFunctionEnd",
3818         2, 0),
3819     // Test case 9: Don't fold n & m
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             "%m = OpVariable %_ptr_uint Function\n" +
3825             "%load_n = OpLoad %uint %n\n" +
3826             "%load_m = OpLoad %uint %m\n" +
3827             "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
3828             "OpReturn\n" +
3829             "OpFunctionEnd",
3830         2, 0),
3831     // Test case 10: Don't fold n < m (unsigned)
3832     InstructionFoldingCase<uint32_t>(
3833         Header() + "%main = OpFunction %void None %void_func\n" +
3834             "%main_lab = OpLabel\n" +
3835             "%n = OpVariable %_ptr_uint Function\n" +
3836             "%m = OpVariable %_ptr_uint Function\n" +
3837             "%load_n = OpLoad %uint %n\n" +
3838             "%load_m = OpLoad %uint %m\n" +
3839             "%2 = OpULessThan %bool %load_n %load_m\n" +
3840             "OpReturn\n" +
3841             "OpFunctionEnd",
3842         2, 0),
3843     // Test case 11: Don't fold n > m (unsigned)
3844     InstructionFoldingCase<uint32_t>(
3845         Header() + "%main = OpFunction %void None %void_func\n" +
3846             "%main_lab = OpLabel\n" +
3847             "%n = OpVariable %_ptr_uint Function\n" +
3848             "%m = OpVariable %_ptr_uint Function\n" +
3849             "%load_n = OpLoad %uint %n\n" +
3850             "%load_m = OpLoad %uint %m\n" +
3851             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3852             "OpReturn\n" +
3853             "OpFunctionEnd",
3854         2, 0),
3855     // Test case 12: Don't fold n <= m (unsigned)
3856     InstructionFoldingCase<uint32_t>(
3857         Header() + "%main = OpFunction %void None %void_func\n" +
3858             "%main_lab = OpLabel\n" +
3859             "%n = OpVariable %_ptr_uint Function\n" +
3860             "%m = OpVariable %_ptr_uint Function\n" +
3861             "%load_n = OpLoad %uint %n\n" +
3862             "%load_m = OpLoad %uint %m\n" +
3863             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3864             "OpReturn\n" +
3865             "OpFunctionEnd",
3866         2, 0),
3867     // Test case 13: Don't fold n >= m (unsigned)
3868     InstructionFoldingCase<uint32_t>(
3869         Header() + "%main = OpFunction %void None %void_func\n" +
3870             "%main_lab = OpLabel\n" +
3871             "%n = OpVariable %_ptr_uint Function\n" +
3872             "%m = OpVariable %_ptr_uint Function\n" +
3873             "%load_n = OpLoad %uint %n\n" +
3874             "%load_m = OpLoad %uint %m\n" +
3875             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3876             "OpReturn\n" +
3877             "OpFunctionEnd",
3878         2, 0),
3879     // Test case 14: Don't fold n < m (signed)
3880     InstructionFoldingCase<uint32_t>(
3881         Header() + "%main = OpFunction %void None %void_func\n" +
3882             "%main_lab = OpLabel\n" +
3883             "%n = OpVariable %_ptr_int Function\n" +
3884             "%m = OpVariable %_ptr_int Function\n" +
3885             "%load_n = OpLoad %int %n\n" +
3886             "%load_m = OpLoad %int %m\n" +
3887             "%2 = OpULessThan %bool %load_n %load_m\n" +
3888             "OpReturn\n" +
3889             "OpFunctionEnd",
3890         2, 0),
3891     // Test case 15: Don't fold n > m (signed)
3892     InstructionFoldingCase<uint32_t>(
3893         Header() + "%main = OpFunction %void None %void_func\n" +
3894             "%main_lab = OpLabel\n" +
3895             "%n = OpVariable %_ptr_int Function\n" +
3896             "%m = OpVariable %_ptr_int Function\n" +
3897             "%load_n = OpLoad %int %n\n" +
3898             "%load_m = OpLoad %int %m\n" +
3899             "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3900             "OpReturn\n" +
3901             "OpFunctionEnd",
3902         2, 0),
3903     // Test case 16: Don't fold n <= m (signed)
3904     InstructionFoldingCase<uint32_t>(
3905         Header() + "%main = OpFunction %void None %void_func\n" +
3906             "%main_lab = OpLabel\n" +
3907             "%n = OpVariable %_ptr_int Function\n" +
3908             "%m = OpVariable %_ptr_int Function\n" +
3909             "%load_n = OpLoad %int %n\n" +
3910             "%load_m = OpLoad %int %m\n" +
3911             "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3912             "OpReturn\n" +
3913             "OpFunctionEnd",
3914         2, 0),
3915     // Test case 17: Don't fold n >= m (signed)
3916     InstructionFoldingCase<uint32_t>(
3917         Header() + "%main = OpFunction %void None %void_func\n" +
3918             "%main_lab = OpLabel\n" +
3919             "%n = OpVariable %_ptr_int Function\n" +
3920             "%m = OpVariable %_ptr_int Function\n" +
3921             "%load_n = OpLoad %int %n\n" +
3922             "%load_m = OpLoad %int %m\n" +
3923             "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3924             "OpReturn\n" +
3925             "OpFunctionEnd",
3926         2, 0),
3927     // Test case 18: Don't fold n || m
3928     InstructionFoldingCase<uint32_t>(
3929         Header() + "%main = OpFunction %void None %void_func\n" +
3930             "%main_lab = OpLabel\n" +
3931             "%n = OpVariable %_ptr_bool Function\n" +
3932             "%m = OpVariable %_ptr_bool Function\n" +
3933             "%load_n = OpLoad %bool %n\n" +
3934             "%load_m = OpLoad %bool %m\n" +
3935             "%2 = OpLogicalOr %bool %load_n %load_m\n" +
3936             "OpReturn\n" +
3937             "OpFunctionEnd",
3938         2, 0),
3939     // Test case 19: Don't fold n && m
3940     InstructionFoldingCase<uint32_t>(
3941         Header() + "%main = OpFunction %void None %void_func\n" +
3942             "%main_lab = OpLabel\n" +
3943             "%n = OpVariable %_ptr_bool Function\n" +
3944             "%m = OpVariable %_ptr_bool Function\n" +
3945             "%load_n = OpLoad %bool %n\n" +
3946             "%load_m = OpLoad %bool %m\n" +
3947             "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
3948             "OpReturn\n" +
3949             "OpFunctionEnd",
3950         2, 0),
3951     // Test case 20: Don't fold n * 3
3952     InstructionFoldingCase<uint32_t>(
3953         Header() + "%main = OpFunction %void None %void_func\n" +
3954             "%main_lab = OpLabel\n" +
3955             "%n = OpVariable %_ptr_int Function\n" +
3956             "%load_n = OpLoad %int %n\n" +
3957             "%2 = OpIMul %int %load_n %int_3\n" +
3958             "OpReturn\n" +
3959             "OpFunctionEnd",
3960         2, 0),
3961     // Test case 21: Don't fold n / 3 (unsigned)
3962     InstructionFoldingCase<uint32_t>(
3963         Header() + "%main = OpFunction %void None %void_func\n" +
3964             "%main_lab = OpLabel\n" +
3965             "%n = OpVariable %_ptr_uint Function\n" +
3966             "%load_n = OpLoad %uint %n\n" +
3967             "%2 = OpUDiv %uint %load_n %uint_3\n" +
3968             "OpReturn\n" +
3969             "OpFunctionEnd",
3970         2, 0),
3971     // Test case 22: Don't fold n / 3 (signed)
3972     InstructionFoldingCase<uint32_t>(
3973         Header() + "%main = OpFunction %void None %void_func\n" +
3974             "%main_lab = OpLabel\n" +
3975             "%n = OpVariable %_ptr_int Function\n" +
3976             "%load_n = OpLoad %int %n\n" +
3977             "%2 = OpSDiv %int %load_n %int_3\n" +
3978             "OpReturn\n" +
3979             "OpFunctionEnd",
3980         2, 0),
3981     // Test case 23: Don't fold n remainder 3
3982     InstructionFoldingCase<uint32_t>(
3983         Header() + "%main = OpFunction %void None %void_func\n" +
3984             "%main_lab = OpLabel\n" +
3985             "%n = OpVariable %_ptr_int Function\n" +
3986             "%load_n = OpLoad %int %n\n" +
3987             "%2 = OpSRem %int %load_n %int_3\n" +
3988             "OpReturn\n" +
3989             "OpFunctionEnd",
3990         2, 0),
3991     // Test case 24: Don't fold n % 3 (signed)
3992     InstructionFoldingCase<uint32_t>(
3993         Header() + "%main = OpFunction %void None %void_func\n" +
3994             "%main_lab = OpLabel\n" +
3995             "%n = OpVariable %_ptr_int Function\n" +
3996             "%load_n = OpLoad %int %n\n" +
3997             "%2 = OpSMod %int %load_n %int_3\n" +
3998             "OpReturn\n" +
3999             "OpFunctionEnd",
4000         2, 0),
4001     // Test case 25: Don't fold n % 3 (unsigned)
4002     InstructionFoldingCase<uint32_t>(
4003         Header() + "%main = OpFunction %void None %void_func\n" +
4004             "%main_lab = OpLabel\n" +
4005             "%n = OpVariable %_ptr_uint Function\n" +
4006             "%load_n = OpLoad %uint %n\n" +
4007             "%2 = OpUMod %int %load_n %int_3\n" +
4008             "OpReturn\n" +
4009             "OpFunctionEnd",
4010         2, 0),
4011     // Test case 26: Don't fold n << 3
4012     InstructionFoldingCase<uint32_t>(
4013         Header() + "%main = OpFunction %void None %void_func\n" +
4014             "%main_lab = OpLabel\n" +
4015             "%n = OpVariable %_ptr_uint Function\n" +
4016             "%load_n = OpLoad %uint %n\n" +
4017             "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
4018             "OpReturn\n" +
4019             "OpFunctionEnd",
4020         2, 0),
4021     // Test case 27: Don't fold n >> 3
4022     InstructionFoldingCase<uint32_t>(
4023         Header() + "%main = OpFunction %void None %void_func\n" +
4024             "%main_lab = OpLabel\n" +
4025             "%n = OpVariable %_ptr_uint Function\n" +
4026             "%load_n = OpLoad %uint %n\n" +
4027             "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
4028             "OpReturn\n" +
4029             "OpFunctionEnd",
4030         2, 0),
4031     // Test case 28: Don't fold n | 3
4032     InstructionFoldingCase<uint32_t>(
4033         Header() + "%main = OpFunction %void None %void_func\n" +
4034             "%main_lab = OpLabel\n" +
4035             "%n = OpVariable %_ptr_uint Function\n" +
4036             "%load_n = OpLoad %uint %n\n" +
4037             "%2 = OpBitwiseOr %int %load_n %int_3\n" +
4038             "OpReturn\n" +
4039             "OpFunctionEnd",
4040         2, 0),
4041     // Test case 29: Don't fold n & 3
4042     InstructionFoldingCase<uint32_t>(
4043         Header() + "%main = OpFunction %void None %void_func\n" +
4044             "%main_lab = OpLabel\n" +
4045             "%n = OpVariable %_ptr_uint Function\n" +
4046             "%load_n = OpLoad %uint %n\n" +
4047             "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
4048             "OpReturn\n" +
4049             "OpFunctionEnd",
4050         2, 0),
4051     // Test case 30: Don't fold n < 3 (unsigned)
4052     InstructionFoldingCase<uint32_t>(
4053         Header() + "%main = OpFunction %void None %void_func\n" +
4054             "%main_lab = OpLabel\n" +
4055             "%n = OpVariable %_ptr_uint Function\n" +
4056             "%load_n = OpLoad %uint %n\n" +
4057             "%2 = OpULessThan %bool %load_n %uint_3\n" +
4058             "OpReturn\n" +
4059             "OpFunctionEnd",
4060         2, 0),
4061     // Test case 31: Don't fold n > 3 (unsigned)
4062     InstructionFoldingCase<uint32_t>(
4063         Header() + "%main = OpFunction %void None %void_func\n" +
4064             "%main_lab = OpLabel\n" +
4065             "%n = OpVariable %_ptr_uint Function\n" +
4066             "%load_n = OpLoad %uint %n\n" +
4067             "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
4068             "OpReturn\n" +
4069             "OpFunctionEnd",
4070         2, 0),
4071     // Test case 32: Don't fold n <= 3 (unsigned)
4072     InstructionFoldingCase<uint32_t>(
4073         Header() + "%main = OpFunction %void None %void_func\n" +
4074             "%main_lab = OpLabel\n" +
4075             "%n = OpVariable %_ptr_uint Function\n" +
4076             "%load_n = OpLoad %uint %n\n" +
4077             "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
4078             "OpReturn\n" +
4079             "OpFunctionEnd",
4080         2, 0),
4081     // Test case 33: Don't fold n >= 3 (unsigned)
4082     InstructionFoldingCase<uint32_t>(
4083         Header() + "%main = OpFunction %void None %void_func\n" +
4084             "%main_lab = OpLabel\n" +
4085             "%n = OpVariable %_ptr_uint Function\n" +
4086             "%load_n = OpLoad %uint %n\n" +
4087             "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
4088             "OpReturn\n" +
4089             "OpFunctionEnd",
4090         2, 0),
4091     // Test case 34: Don't fold n < 3 (signed)
4092     InstructionFoldingCase<uint32_t>(
4093         Header() + "%main = OpFunction %void None %void_func\n" +
4094             "%main_lab = OpLabel\n" +
4095             "%n = OpVariable %_ptr_int Function\n" +
4096             "%load_n = OpLoad %int %n\n" +
4097             "%2 = OpULessThan %bool %load_n %int_3\n" +
4098             "OpReturn\n" +
4099             "OpFunctionEnd",
4100         2, 0),
4101     // Test case 35: Don't fold n > 3 (signed)
4102     InstructionFoldingCase<uint32_t>(
4103         Header() + "%main = OpFunction %void None %void_func\n" +
4104             "%main_lab = OpLabel\n" +
4105             "%n = OpVariable %_ptr_int Function\n" +
4106             "%load_n = OpLoad %int %n\n" +
4107             "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
4108             "OpReturn\n" +
4109             "OpFunctionEnd",
4110         2, 0),
4111     // Test case 36: Don't fold n <= 3 (signed)
4112     InstructionFoldingCase<uint32_t>(
4113         Header() + "%main = OpFunction %void None %void_func\n" +
4114             "%main_lab = OpLabel\n" +
4115             "%n = OpVariable %_ptr_int Function\n" +
4116             "%load_n = OpLoad %int %n\n" +
4117             "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
4118             "OpReturn\n" +
4119             "OpFunctionEnd",
4120         2, 0),
4121     // Test case 37: Don't fold n >= 3 (signed)
4122     InstructionFoldingCase<uint32_t>(
4123         Header() + "%main = OpFunction %void None %void_func\n" +
4124             "%main_lab = OpLabel\n" +
4125             "%n = OpVariable %_ptr_int Function\n" +
4126             "%load_n = OpLoad %int %n\n" +
4127             "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
4128             "OpReturn\n" +
4129             "OpFunctionEnd",
4130         2, 0),
4131     // Test case 38: fold 1*n
4132     InstructionFoldingCase<uint32_t>(
4133         Header() + "%main = OpFunction %void None %void_func\n" +
4134             "%main_lab = OpLabel\n" +
4135             "%n = OpVariable %_ptr_int Function\n" +
4136             "%3 = OpLoad %int %n\n" +
4137             "%2 = OpIMul %int %int_1 %3\n" +
4138             "OpReturn\n" +
4139             "OpFunctionEnd",
4140         2, 3),
4141     // Test case 39: fold n*1
4142     InstructionFoldingCase<uint32_t>(
4143         Header() + "%main = OpFunction %void None %void_func\n" +
4144             "%main_lab = OpLabel\n" +
4145             "%n = OpVariable %_ptr_int Function\n" +
4146             "%3 = OpLoad %int %n\n" +
4147             "%2 = OpIMul %int %3 %int_1\n" +
4148             "OpReturn\n" +
4149             "OpFunctionEnd",
4150         2, 3),
4151     // Test case 40: Don't fold comparisons of 64-bit types
4152     // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
4153     InstructionFoldingCase<uint32_t>(
4154         Header() + "%main = OpFunction %void None %void_func\n" +
4155           "%main_lab = OpLabel\n" +
4156           "%2 = OpSLessThan %bool %long_0 %long_2\n" +
4157           "OpReturn\n" +
4158           "OpFunctionEnd",
4159         2, 0),
4160     // Test case 41: Don't fold OpSNegate for cooperative matrices.
4161     InstructionFoldingCase<uint32_t>(
4162         Header() + "%main = OpFunction %void None %void_func\n" +
4163             "%main_lab = OpLabel\n" +
4164             "%2 = OpSNegate %int_coop_matrix %undef_int_coop_matrix\n" +
4165             "OpReturn\n" +
4166             "OpFunctionEnd",
4167         2, 0),
4168     // Test case 42: Don't fold OpIAdd for cooperative matrices.
4169     InstructionFoldingCase<uint32_t>(
4170         Header() + "%main = OpFunction %void None %void_func\n" +
4171             "%main_lab = OpLabel\n" +
4172             "%2 = OpIAdd %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" +
4173             "OpReturn\n" +
4174             "OpFunctionEnd",
4175         2, 0),
4176     // Test case 43: Don't fold OpISub for cooperative matrices.
4177     InstructionFoldingCase<uint32_t>(
4178         Header() + "%main = OpFunction %void None %void_func\n" +
4179             "%main_lab = OpLabel\n" +
4180             "%2 = OpISub %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" +
4181             "OpReturn\n" +
4182             "OpFunctionEnd",
4183         2, 0),
4184     // Test case 44: Don't fold OpIMul for cooperative matrices.
4185     InstructionFoldingCase<uint32_t>(
4186         Header() + "%main = OpFunction %void None %void_func\n" +
4187             "%main_lab = OpLabel\n" +
4188             "%2 = OpIMul %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" +
4189             "OpReturn\n" +
4190             "OpFunctionEnd",
4191         2, 0),
4192     // Test case 45: Don't fold OpSDiv for cooperative matrices.
4193     InstructionFoldingCase<uint32_t>(
4194         Header() + "%main = OpFunction %void None %void_func\n" +
4195             "%main_lab = OpLabel\n" +
4196             "%2 = OpSDiv %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" +
4197             "OpReturn\n" +
4198             "OpFunctionEnd",
4199         2, 0),
4200     // Test case 46: Don't fold OpUDiv for cooperative matrices.
4201     InstructionFoldingCase<uint32_t>(
4202         Header() + "%main = OpFunction %void None %void_func\n" +
4203             "%main_lab = OpLabel\n" +
4204             "%2 = OpUDiv %uint_coop_matrix %undef_uint_coop_matrix %undef_uint_coop_matrix\n" +
4205             "OpReturn\n" +
4206             "OpFunctionEnd",
4207         2, 0),
4208     // Test case 47: Don't fold OpMatrixTimesScalar for cooperative matrices.
4209     InstructionFoldingCase<uint32_t>(
4210         Header() + "%main = OpFunction %void None %void_func\n" +
4211             "%main_lab = OpLabel\n" +
4212             "%2 = OpMatrixTimesScalar %uint_coop_matrix %undef_uint_coop_matrix %uint_3\n" +
4213             "OpReturn\n" +
4214             "OpFunctionEnd",
4215         2, 0)
4216 ));
4217 
4218 INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
4219 ::testing::Values(
4220     // Test case 0: fold Insert feeding extract
4221     InstructionFoldingCase<uint32_t>(
4222         Header() + "%main = OpFunction %void None %void_func\n" +
4223             "%main_lab = OpLabel\n" +
4224             "%n = OpVariable %_ptr_int Function\n" +
4225             "%2 = OpLoad %int %n\n" +
4226             "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
4227             "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
4228             "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
4229             "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
4230             "%7 = OpCompositeExtract %int %6 0\n" +
4231             "OpReturn\n" +
4232             "OpFunctionEnd",
4233         7, 2),
4234     // Test case 1: fold Composite construct feeding extract (position 0)
4235     InstructionFoldingCase<uint32_t>(
4236         Header() + "%main = OpFunction %void None %void_func\n" +
4237             "%main_lab = OpLabel\n" +
4238             "%n = OpVariable %_ptr_int Function\n" +
4239             "%2 = OpLoad %int %n\n" +
4240             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
4241             "%4 = OpCompositeExtract %int %3 0\n" +
4242             "OpReturn\n" +
4243             "OpFunctionEnd",
4244         4, 2),
4245     // Test case 2: fold Composite construct feeding extract (position 3)
4246     InstructionFoldingCase<uint32_t>(
4247         Header() + "%main = OpFunction %void None %void_func\n" +
4248             "%main_lab = OpLabel\n" +
4249             "%n = OpVariable %_ptr_int Function\n" +
4250             "%2 = OpLoad %int %n\n" +
4251             "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
4252             "%4 = OpCompositeExtract %int %3 3\n" +
4253             "OpReturn\n" +
4254             "OpFunctionEnd",
4255         4, INT_0_ID),
4256     // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
4257     InstructionFoldingCase<uint32_t>(
4258         Header() + "%main = OpFunction %void None %void_func\n" +
4259             "%main_lab = OpLabel\n" +
4260             "%n = OpVariable %_ptr_int Function\n" +
4261             "%2 = OpLoad %int %n\n" +
4262             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4263             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4264             "%5 = OpCompositeExtract %int %4 3\n" +
4265             "OpReturn\n" +
4266             "OpFunctionEnd",
4267         5, INT_0_ID),
4268     // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
4269     InstructionFoldingCase<uint32_t>(
4270         Header() + "%main = OpFunction %void None %void_func\n" +
4271             "%main_lab = OpLabel\n" +
4272             "%n = OpVariable %_ptr_int Function\n" +
4273             "%2 = OpLoad %int %n\n" +
4274             "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4275             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4276             "%5 = OpCompositeExtract %int %4 0\n" +
4277             "OpReturn\n" +
4278             "OpFunctionEnd",
4279         5, 2),
4280     // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
4281     InstructionFoldingCase<uint32_t>(
4282         Header() + "%main = OpFunction %void None %void_func\n" +
4283             "%main_lab = OpLabel\n" +
4284             "%n = OpVariable %_ptr_int Function\n" +
4285             "%2 = OpLoad %int %n\n" +
4286             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4287             "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4288             "%5 = OpCompositeExtract %int %4 1\n" +
4289             "OpReturn\n" +
4290             "OpFunctionEnd",
4291         5, 2),
4292     // Test case 6: fold Composite construct with multiple indices.
4293     InstructionFoldingCase<uint32_t>(
4294         Header() + "%main = OpFunction %void None %void_func\n" +
4295             "%main_lab = OpLabel\n" +
4296             "%n = OpVariable %_ptr_int Function\n" +
4297             "%2 = OpLoad %int %n\n" +
4298             "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4299             "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
4300             "%5 = OpCompositeExtract %int %4 0 1\n" +
4301             "OpReturn\n" +
4302             "OpFunctionEnd",
4303         5, 2),
4304     // Test case 7: fold constant extract.
4305     InstructionFoldingCase<uint32_t>(
4306         Header() + "%main = OpFunction %void None %void_func\n" +
4307             "%main_lab = OpLabel\n" +
4308             "%2 = OpCompositeExtract %int %102 1\n" +
4309             "OpReturn\n" +
4310             "OpFunctionEnd",
4311         2, INT_7_ID),
4312     // Test case 8: constant struct has OpUndef
4313     InstructionFoldingCase<uint32_t>(
4314         Header() + "%main = OpFunction %void None %void_func\n" +
4315             "%main_lab = OpLabel\n" +
4316             "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
4317             "OpReturn\n" +
4318             "OpFunctionEnd",
4319         2, 0),
4320     // Test case 9: Extracting a member of element inserted via Insert
4321     InstructionFoldingCase<uint32_t>(
4322         Header() + "%main = OpFunction %void None %void_func\n" +
4323             "%main_lab = OpLabel\n" +
4324             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4325             "%2 = OpLoad %struct_v2int_int_int %n\n" +
4326             "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
4327             "%4 = OpCompositeExtract %int %3 0 1\n" +
4328             "OpReturn\n" +
4329             "OpFunctionEnd",
4330         4, 103),
4331     // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
4332     InstructionFoldingCase<uint32_t>(
4333         Header() + "%main = OpFunction %void None %void_func\n" +
4334             "%main_lab = OpLabel\n" +
4335             "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4336             "%2 = OpLoad %struct_v2int_int_int %n\n" +
4337             "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
4338             "%4 = OpCompositeExtract %v2int %3 0\n" +
4339             "OpReturn\n" +
4340             "OpFunctionEnd",
4341         4, 0),
4342     // Test case 11: Extracting from result of vector shuffle (first input)
4343     InstructionFoldingCase<uint32_t>(
4344         Header() + "%main = OpFunction %void None %void_func\n" +
4345             "%main_lab = OpLabel\n" +
4346             "%n = OpVariable %_ptr_v2int Function\n" +
4347             "%2 = OpLoad %v2int %n\n" +
4348             "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
4349             "%4 = OpCompositeExtract %int %3 1\n" +
4350             "OpReturn\n" +
4351             "OpFunctionEnd",
4352         4, INT_7_ID),
4353     // Test case 12: Extracting from result of vector shuffle (second input)
4354     InstructionFoldingCase<uint32_t>(
4355         Header() + "%main = OpFunction %void None %void_func\n" +
4356             "%main_lab = OpLabel\n" +
4357             "%n = OpVariable %_ptr_v2int Function\n" +
4358             "%2 = OpLoad %v2int %n\n" +
4359             "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
4360             "%4 = OpCompositeExtract %int %3 0\n" +
4361             "OpReturn\n" +
4362             "OpFunctionEnd",
4363         4, INT_7_ID),
4364     // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608
4365     // Out of bounds access.  Do not fold.
4366     InstructionFoldingCase<uint32_t>(
4367         Header() + "%main = OpFunction %void None %void_func\n" +
4368             "%main_lab = OpLabel\n" +
4369             "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" +
4370             "%3 = OpCompositeExtract %float %2 4\n" +
4371             "OpReturn\n" +
4372             "OpFunctionEnd",
4373         3, 0),
4374     // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631
4375     // Extract the component right after the vector constituent.
4376     InstructionFoldingCase<uint32_t>(
4377         Header() + "%main = OpFunction %void None %void_func\n" +
4378             "%main_lab = OpLabel\n" +
4379             "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4380             "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4381             "%4 = OpCompositeExtract %int %3 2\n" +
4382             "OpReturn\n" +
4383             "OpFunctionEnd",
4384         4, INT_0_ID),
4385     // Test case 15:
4386     // Don't fold extract fed by construct with vector result if the index is
4387     // past the last element.
4388     InstructionFoldingCase<uint32_t>(
4389         Header() + "%main = OpFunction %void None %void_func\n" +
4390             "%main_lab = OpLabel\n" +
4391             "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4392             "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4393             "%4 = OpCompositeExtract %int %3 4\n" +
4394             "OpReturn\n" +
4395             "OpFunctionEnd",
4396         4, 0)
4397 ));
4398 
4399 INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
4400 ::testing::Values(
4401     // Test case 0: fold Extracts feeding construct
4402     InstructionFoldingCase<uint32_t>(
4403         Header() + "%main = OpFunction %void None %void_func\n" +
4404             "%main_lab = OpLabel\n" +
4405             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4406             "%3 = OpCompositeExtract %int %2 0\n" +
4407             "%4 = OpCompositeExtract %int %2 1\n" +
4408             "%5 = OpCompositeExtract %int %2 2\n" +
4409             "%6 = OpCompositeExtract %int %2 3\n" +
4410             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4411             "OpReturn\n" +
4412             "OpFunctionEnd",
4413         7, 2),
4414     // Test case 1: Don't fold Extracts feeding construct (Different source)
4415     InstructionFoldingCase<uint32_t>(
4416         Header() + "%main = OpFunction %void None %void_func\n" +
4417             "%main_lab = OpLabel\n" +
4418             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4419             "%3 = OpCompositeExtract %int %2 0\n" +
4420             "%4 = OpCompositeExtract %int %2 1\n" +
4421             "%5 = OpCompositeExtract %int %2 2\n" +
4422             "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
4423             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4424             "OpReturn\n" +
4425             "OpFunctionEnd",
4426         7, 0),
4427     // Test case 2: Don't fold Extracts feeding construct (bad indices)
4428     InstructionFoldingCase<uint32_t>(
4429         Header() + "%main = OpFunction %void None %void_func\n" +
4430             "%main_lab = OpLabel\n" +
4431             "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4432             "%3 = OpCompositeExtract %int %2 0\n" +
4433             "%4 = OpCompositeExtract %int %2 0\n" +
4434             "%5 = OpCompositeExtract %int %2 2\n" +
4435             "%6 = OpCompositeExtract %int %2 3\n" +
4436             "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4437             "OpReturn\n" +
4438             "OpFunctionEnd",
4439         7, 0),
4440     // Test case 3: Don't fold Extracts feeding construct (different type)
4441     InstructionFoldingCase<uint32_t>(
4442         Header() + "%main = OpFunction %void None %void_func\n" +
4443             "%main_lab = OpLabel\n" +
4444             "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
4445             "%3 = OpCompositeExtract %v2int %2 0\n" +
4446             "%4 = OpCompositeExtract %int %2 1\n" +
4447             "%5 = OpCompositeExtract %int %2 2\n" +
4448             "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
4449             "OpReturn\n" +
4450             "OpFunctionEnd",
4451         7, 0),
4452     // Test case 4: Fold construct with constants to constant.
4453     InstructionFoldingCase<uint32_t>(
4454         Header() + "%main = OpFunction %void None %void_func\n" +
4455             "%main_lab = OpLabel\n" +
4456             "%2 = OpCompositeConstruct %v2int %103 %103\n" +
4457             "OpReturn\n" +
4458             "OpFunctionEnd",
4459         2, VEC2_0_ID),
4460     // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct
4461     // for an empty struct, and we reached the id limit.
4462     InstructionFoldingCase<uint32_t>(
4463         Header() + "%empty_struct = OpTypeStruct\n" +
4464             "%main = OpFunction %void None %void_func\n" +
4465             "%main_lab = OpLabel\n" +
4466             "%4194303 = OpCompositeConstruct %empty_struct\n" +
4467             "OpReturn\n" +
4468             "OpFunctionEnd",
4469         4194303, 0)
4470 ));
4471 
4472 INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
4473 ::testing::Values(
4474   // Test case 0: Fold phi with the same values for all edges.
4475   InstructionFoldingCase<uint32_t>(
4476       Header() + "%main = OpFunction %void None %void_func\n" +
4477           "%main_lab = OpLabel\n" +
4478           "            OpBranchConditional %true %l1 %l2\n" +
4479           "%l1 = OpLabel\n" +
4480           "      OpBranch %merge_lab\n" +
4481           "%l2 = OpLabel\n" +
4482           "      OpBranch %merge_lab\n" +
4483           "%merge_lab = OpLabel\n" +
4484           "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
4485           "OpReturn\n" +
4486           "OpFunctionEnd",
4487       2, INT_0_ID),
4488   // Test case 1: Fold phi in pass through loop.
4489   InstructionFoldingCase<uint32_t>(
4490       Header() + "%main = OpFunction %void None %void_func\n" +
4491           "%main_lab = OpLabel\n" +
4492           "            OpBranch %l1\n" +
4493           "%l1 = OpLabel\n" +
4494           "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
4495           "      OpBranchConditional %true %l1 %merge_lab\n" +
4496           "%merge_lab = OpLabel\n" +
4497           "OpReturn\n" +
4498           "OpFunctionEnd",
4499       2, INT_0_ID),
4500   // Test case 2: Don't Fold phi because of different values.
4501   InstructionFoldingCase<uint32_t>(
4502       Header() + "%main = OpFunction %void None %void_func\n" +
4503           "%main_lab = OpLabel\n" +
4504           "            OpBranch %l1\n" +
4505           "%l1 = OpLabel\n" +
4506           "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
4507           "      OpBranchConditional %true %l1 %merge_lab\n" +
4508           "%merge_lab = OpLabel\n" +
4509           "OpReturn\n" +
4510           "OpFunctionEnd",
4511       2, 0)
4512 ));
4513 
4514 INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
4515                         ::testing::Values(
4516     // Test case 0: Don't fold n + 1.0
4517     InstructionFoldingCase<uint32_t>(
4518         Header() + "%main = OpFunction %void None %void_func\n" +
4519             "%main_lab = OpLabel\n" +
4520             "%n = OpVariable %_ptr_float Function\n" +
4521             "%3 = OpLoad %float %n\n" +
4522             "%2 = OpFAdd %float %3 %float_2\n" +
4523             "OpReturn\n" +
4524             "OpFunctionEnd",
4525         2, 0),
4526     // Test case 1: Don't fold n - 1.0
4527     InstructionFoldingCase<uint32_t>(
4528         Header() + "%main = OpFunction %void None %void_func\n" +
4529             "%main_lab = OpLabel\n" +
4530             "%n = OpVariable %_ptr_float Function\n" +
4531             "%3 = OpLoad %float %n\n" +
4532             "%2 = OpFSub %float %3 %float_2\n" +
4533             "OpReturn\n" +
4534             "OpFunctionEnd",
4535         2, 0),
4536     // Test case 2: Don't fold n * 2.0
4537     InstructionFoldingCase<uint32_t>(
4538         Header() + "%main = OpFunction %void None %void_func\n" +
4539             "%main_lab = OpLabel\n" +
4540             "%n = OpVariable %_ptr_float Function\n" +
4541             "%3 = OpLoad %float %n\n" +
4542             "%2 = OpFMul %float %3 %float_2\n" +
4543             "OpReturn\n" +
4544             "OpFunctionEnd",
4545         2, 0),
4546     // Test case 3: Fold n + 0.0
4547     InstructionFoldingCase<uint32_t>(
4548         Header() + "%main = OpFunction %void None %void_func\n" +
4549             "%main_lab = OpLabel\n" +
4550             "%n = OpVariable %_ptr_float Function\n" +
4551             "%3 = OpLoad %float %n\n" +
4552             "%2 = OpFAdd %float %3 %float_0\n" +
4553             "OpReturn\n" +
4554             "OpFunctionEnd",
4555         2, 3),
4556     // Test case 4: Fold 0.0 + n
4557     InstructionFoldingCase<uint32_t>(
4558         Header() + "%main = OpFunction %void None %void_func\n" +
4559             "%main_lab = OpLabel\n" +
4560             "%n = OpVariable %_ptr_float Function\n" +
4561             "%3 = OpLoad %float %n\n" +
4562             "%2 = OpFAdd %float %float_0 %3\n" +
4563             "OpReturn\n" +
4564             "OpFunctionEnd",
4565         2, 3),
4566     // Test case 5: Fold n - 0.0
4567     InstructionFoldingCase<uint32_t>(
4568         Header() + "%main = OpFunction %void None %void_func\n" +
4569             "%main_lab = OpLabel\n" +
4570             "%n = OpVariable %_ptr_float Function\n" +
4571             "%3 = OpLoad %float %n\n" +
4572             "%2 = OpFSub %float %3 %float_0\n" +
4573             "OpReturn\n" +
4574             "OpFunctionEnd",
4575         2, 3),
4576     // Test case 6: Fold n * 1.0
4577     InstructionFoldingCase<uint32_t>(
4578         Header() + "%main = OpFunction %void None %void_func\n" +
4579             "%main_lab = OpLabel\n" +
4580             "%n = OpVariable %_ptr_float Function\n" +
4581             "%3 = OpLoad %float %n\n" +
4582             "%2 = OpFMul %float %3 %float_1\n" +
4583             "OpReturn\n" +
4584             "OpFunctionEnd",
4585         2, 3),
4586     // Test case 7: Fold 1.0 * n
4587     InstructionFoldingCase<uint32_t>(
4588         Header() + "%main = OpFunction %void None %void_func\n" +
4589             "%main_lab = OpLabel\n" +
4590             "%n = OpVariable %_ptr_float Function\n" +
4591             "%3 = OpLoad %float %n\n" +
4592             "%2 = OpFMul %float %float_1 %3\n" +
4593             "OpReturn\n" +
4594             "OpFunctionEnd",
4595         2, 3),
4596     // Test case 8: Fold n / 1.0
4597     InstructionFoldingCase<uint32_t>(
4598         Header() + "%main = OpFunction %void None %void_func\n" +
4599             "%main_lab = OpLabel\n" +
4600             "%n = OpVariable %_ptr_float Function\n" +
4601             "%3 = OpLoad %float %n\n" +
4602             "%2 = OpFDiv %float %3 %float_1\n" +
4603             "OpReturn\n" +
4604             "OpFunctionEnd",
4605         2, 3),
4606     // Test case 9: Fold n * 0.0
4607     InstructionFoldingCase<uint32_t>(
4608         Header() + "%main = OpFunction %void None %void_func\n" +
4609             "%main_lab = OpLabel\n" +
4610             "%n = OpVariable %_ptr_float Function\n" +
4611             "%3 = OpLoad %float %n\n" +
4612             "%2 = OpFMul %float %3 %104\n" +
4613             "OpReturn\n" +
4614             "OpFunctionEnd",
4615         2, FLOAT_0_ID),
4616     // Test case 10: Fold 0.0 * n
4617     InstructionFoldingCase<uint32_t>(
4618         Header() + "%main = OpFunction %void None %void_func\n" +
4619             "%main_lab = OpLabel\n" +
4620             "%n = OpVariable %_ptr_float Function\n" +
4621             "%3 = OpLoad %float %n\n" +
4622             "%2 = OpFMul %float %104 %3\n" +
4623             "OpReturn\n" +
4624             "OpFunctionEnd",
4625         2, FLOAT_0_ID),
4626     // Test case 11: Fold 0.0 / n
4627     InstructionFoldingCase<uint32_t>(
4628         Header() + "%main = OpFunction %void None %void_func\n" +
4629             "%main_lab = OpLabel\n" +
4630             "%n = OpVariable %_ptr_float Function\n" +
4631             "%3 = OpLoad %float %n\n" +
4632             "%2 = OpFDiv %float %104 %3\n" +
4633             "OpReturn\n" +
4634             "OpFunctionEnd",
4635         2, FLOAT_0_ID),
4636     // Test case 12: Don't fold mix(a, b, 2.0)
4637     InstructionFoldingCase<uint32_t>(
4638         Header() + "%main = OpFunction %void None %void_func\n" +
4639             "%main_lab = OpLabel\n" +
4640             "%a = OpVariable %_ptr_float Function\n" +
4641             "%b = OpVariable %_ptr_float Function\n" +
4642             "%3 = OpLoad %float %a\n" +
4643             "%4 = OpLoad %float %b\n" +
4644             "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
4645             "OpReturn\n" +
4646             "OpFunctionEnd",
4647         2, 0),
4648     // Test case 13: Fold mix(a, b, 0.0)
4649     InstructionFoldingCase<uint32_t>(
4650         Header() + "%main = OpFunction %void None %void_func\n" +
4651             "%main_lab = OpLabel\n" +
4652             "%a = OpVariable %_ptr_float Function\n" +
4653             "%b = OpVariable %_ptr_float Function\n" +
4654             "%3 = OpLoad %float %a\n" +
4655             "%4 = OpLoad %float %b\n" +
4656             "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
4657             "OpReturn\n" +
4658             "OpFunctionEnd",
4659         2, 3),
4660     // Test case 14: Fold mix(a, b, 1.0)
4661     InstructionFoldingCase<uint32_t>(
4662         Header() + "%main = OpFunction %void None %void_func\n" +
4663             "%main_lab = OpLabel\n" +
4664             "%a = OpVariable %_ptr_float Function\n" +
4665             "%b = OpVariable %_ptr_float Function\n" +
4666             "%3 = OpLoad %float %a\n" +
4667             "%4 = OpLoad %float %b\n" +
4668             "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
4669             "OpReturn\n" +
4670             "OpFunctionEnd",
4671         2, 4),
4672     // Test case 15: Fold vector fadd with null
4673     InstructionFoldingCase<uint32_t>(
4674         Header() + "%main = OpFunction %void None %void_func\n" +
4675             "%main_lab = OpLabel\n" +
4676             "%a = OpVariable %_ptr_v2float Function\n" +
4677             "%2 = OpLoad %v2float %a\n" +
4678             "%3 = OpFAdd %v2float %2 %v2float_null\n" +
4679             "OpReturn\n" +
4680             "OpFunctionEnd",
4681         3, 2),
4682     // Test case 16: Fold vector fadd with null
4683     InstructionFoldingCase<uint32_t>(
4684         Header() + "%main = OpFunction %void None %void_func\n" +
4685             "%main_lab = OpLabel\n" +
4686             "%a = OpVariable %_ptr_v2float Function\n" +
4687             "%2 = OpLoad %v2float %a\n" +
4688             "%3 = OpFAdd %v2float %v2float_null %2\n" +
4689             "OpReturn\n" +
4690             "OpFunctionEnd",
4691         3, 2),
4692     // Test case 17: Fold vector fsub with null
4693     InstructionFoldingCase<uint32_t>(
4694         Header() + "%main = OpFunction %void None %void_func\n" +
4695             "%main_lab = OpLabel\n" +
4696             "%a = OpVariable %_ptr_v2float Function\n" +
4697             "%2 = OpLoad %v2float %a\n" +
4698             "%3 = OpFSub %v2float %2 %v2float_null\n" +
4699             "OpReturn\n" +
4700             "OpFunctionEnd",
4701         3, 2),
4702     // Test case 18: Fold 0.0(half) * n
4703     InstructionFoldingCase<uint32_t>(
4704         Header() + "%main = OpFunction %void None %void_func\n" +
4705             "%main_lab = OpLabel\n" +
4706             "%n = OpVariable %_ptr_half Function\n" +
4707             "%3 = OpLoad %half %n\n" +
4708             "%2 = OpFMul %half %108 %3\n" +
4709             "OpReturn\n" +
4710             "OpFunctionEnd",
4711         2, HALF_0_ID),
4712     // Test case 19: Don't fold 1.0(half) * n
4713     InstructionFoldingCase<uint32_t>(
4714         Header() + "%main = OpFunction %void None %void_func\n" +
4715             "%main_lab = OpLabel\n" +
4716             "%n = OpVariable %_ptr_half Function\n" +
4717             "%3 = OpLoad %half %n\n" +
4718             "%2 = OpFMul %half %half_1 %3\n" +
4719             "OpReturn\n" +
4720             "OpFunctionEnd",
4721         2, 0),
4722     // Test case 20: Don't fold 1.0 * 1.0 (half)
4723     InstructionFoldingCase<uint32_t>(
4724         Header() + "%main = OpFunction %void None %void_func\n" +
4725             "%main_lab = OpLabel\n" +
4726             "%2 = OpFMul %half %half_1 %half_1\n" +
4727             "OpReturn\n" +
4728             "OpFunctionEnd",
4729         2, 0),
4730     // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half)
4731     InstructionFoldingCase<uint32_t>(
4732         Header() + "%main = OpFunction %void None %void_func\n" +
4733             "%main_lab = OpLabel\n" +
4734             "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" +
4735             "OpReturn\n" +
4736             "OpFunctionEnd",
4737         2, 0),
4738     // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half)
4739     InstructionFoldingCase<uint32_t>(
4740         Header() + "%main = OpFunction %void None %void_func\n" +
4741             "%main_lab = OpLabel\n" +
4742             "%2 = OpDot %half %half_0_1 %half_0_1\n" +
4743             "OpReturn\n" +
4744             "OpFunctionEnd",
4745         2, 0),
4746     // Test case 23: Don't fold 1.0(half) / 2.0(half)
4747     // We do not have to code to emulate 16-bit float operations. Just make sure we do not crash.
4748     InstructionFoldingCase<uint32_t>(
4749         Header() + "%main = OpFunction %void None %void_func\n" +
4750             "%main_lab = OpLabel\n" +
4751             "%n = OpVariable %_ptr_half Function\n" +
4752             "%3 = OpLoad %half %n\n" +
4753             "%2 = OpFDiv %half %half_1 %half_2\n" +
4754             "OpReturn\n" +
4755             "OpFunctionEnd",
4756         2, 0),
4757     // Test case 24: Don't fold OpFNegate for cooperative matrices.
4758     InstructionFoldingCase<uint32_t>(
4759         Header() + "%main = OpFunction %void None %void_func\n" +
4760             "%main_lab = OpLabel\n" +
4761             "%2 = OpFNegate %float_coop_matrix %undef_float_coop_matrix\n" +
4762             "OpReturn\n" +
4763             "OpFunctionEnd",
4764         2, 0),
4765     // Test case 25: Don't fold OpIAdd for cooperative matrices.
4766     InstructionFoldingCase<uint32_t>(
4767         Header() + "%main = OpFunction %void None %void_func\n" +
4768             "%main_lab = OpLabel\n" +
4769             "%2 = OpFAdd %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" +
4770             "OpReturn\n" +
4771             "OpFunctionEnd",
4772         2, 0),
4773     // Test case 26: Don't fold OpISub for cooperative matrices.
4774     InstructionFoldingCase<uint32_t>(
4775         Header() + "%main = OpFunction %void None %void_func\n" +
4776             "%main_lab = OpLabel\n" +
4777             "%2 = OpFSub %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" +
4778             "OpReturn\n" +
4779             "OpFunctionEnd",
4780         2, 0),
4781     // Test case 27: Don't fold OpIMul for cooperative matrices.
4782     InstructionFoldingCase<uint32_t>(
4783         Header() + "%main = OpFunction %void None %void_func\n" +
4784             "%main_lab = OpLabel\n" +
4785             "%2 = OpFMul %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" +
4786             "OpReturn\n" +
4787             "OpFunctionEnd",
4788         2, 0),
4789     // Test case 28: Don't fold OpSDiv for cooperative matrices.
4790     InstructionFoldingCase<uint32_t>(
4791         Header() + "%main = OpFunction %void None %void_func\n" +
4792             "%main_lab = OpLabel\n" +
4793             "%2 = OpFDiv %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" +
4794             "OpReturn\n" +
4795             "OpFunctionEnd",
4796         2, 0),
4797     // Test case 29: Don't fold OpMatrixTimesScalar for cooperative matrices.
4798     InstructionFoldingCase<uint32_t>(
4799         Header() + "%main = OpFunction %void None %void_func\n" +
4800             "%main_lab = OpLabel\n" +
4801             "%2 = OpMatrixTimesScalar %float_coop_matrix %undef_float_coop_matrix %float_3\n" +
4802             "OpReturn\n" +
4803             "OpFunctionEnd",
4804         2, 0)
4805 ));
4806 
4807 INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
4808                         ::testing::Values(
4809     // Test case 0: Don't fold n + 1.0
4810     InstructionFoldingCase<uint32_t>(
4811         Header() + "%main = OpFunction %void None %void_func\n" +
4812             "%main_lab = OpLabel\n" +
4813             "%n = OpVariable %_ptr_double Function\n" +
4814             "%3 = OpLoad %double %n\n" +
4815             "%2 = OpFAdd %double %3 %double_2\n" +
4816             "OpReturn\n" +
4817             "OpFunctionEnd",
4818         2, 0),
4819     // Test case 1: Don't fold n - 1.0
4820     InstructionFoldingCase<uint32_t>(
4821         Header() + "%main = OpFunction %void None %void_func\n" +
4822             "%main_lab = OpLabel\n" +
4823             "%n = OpVariable %_ptr_double Function\n" +
4824             "%3 = OpLoad %double %n\n" +
4825             "%2 = OpFSub %double %3 %double_2\n" +
4826             "OpReturn\n" +
4827             "OpFunctionEnd",
4828         2, 0),
4829     // Test case 2: Don't fold n * 2.0
4830     InstructionFoldingCase<uint32_t>(
4831         Header() + "%main = OpFunction %void None %void_func\n" +
4832             "%main_lab = OpLabel\n" +
4833             "%n = OpVariable %_ptr_double Function\n" +
4834             "%3 = OpLoad %double %n\n" +
4835             "%2 = OpFMul %double %3 %double_2\n" +
4836             "OpReturn\n" +
4837             "OpFunctionEnd",
4838         2, 0),
4839     // Test case 3: Fold n + 0.0
4840     InstructionFoldingCase<uint32_t>(
4841         Header() + "%main = OpFunction %void None %void_func\n" +
4842             "%main_lab = OpLabel\n" +
4843             "%n = OpVariable %_ptr_double Function\n" +
4844             "%3 = OpLoad %double %n\n" +
4845             "%2 = OpFAdd %double %3 %double_0\n" +
4846             "OpReturn\n" +
4847             "OpFunctionEnd",
4848         2, 3),
4849     // Test case 4: Fold 0.0 + n
4850     InstructionFoldingCase<uint32_t>(
4851         Header() + "%main = OpFunction %void None %void_func\n" +
4852             "%main_lab = OpLabel\n" +
4853             "%n = OpVariable %_ptr_double Function\n" +
4854             "%3 = OpLoad %double %n\n" +
4855             "%2 = OpFAdd %double %double_0 %3\n" +
4856             "OpReturn\n" +
4857             "OpFunctionEnd",
4858         2, 3),
4859     // Test case 5: Fold n - 0.0
4860     InstructionFoldingCase<uint32_t>(
4861         Header() + "%main = OpFunction %void None %void_func\n" +
4862             "%main_lab = OpLabel\n" +
4863             "%n = OpVariable %_ptr_double Function\n" +
4864             "%3 = OpLoad %double %n\n" +
4865             "%2 = OpFSub %double %3 %double_0\n" +
4866             "OpReturn\n" +
4867             "OpFunctionEnd",
4868         2, 3),
4869     // Test case 6: Fold n * 1.0
4870     InstructionFoldingCase<uint32_t>(
4871         Header() + "%main = OpFunction %void None %void_func\n" +
4872             "%main_lab = OpLabel\n" +
4873             "%n = OpVariable %_ptr_double Function\n" +
4874             "%3 = OpLoad %double %n\n" +
4875             "%2 = OpFMul %double %3 %double_1\n" +
4876             "OpReturn\n" +
4877             "OpFunctionEnd",
4878         2, 3),
4879     // Test case 7: Fold 1.0 * n
4880     InstructionFoldingCase<uint32_t>(
4881         Header() + "%main = OpFunction %void None %void_func\n" +
4882             "%main_lab = OpLabel\n" +
4883             "%n = OpVariable %_ptr_double Function\n" +
4884             "%3 = OpLoad %double %n\n" +
4885             "%2 = OpFMul %double %double_1 %3\n" +
4886             "OpReturn\n" +
4887             "OpFunctionEnd",
4888         2, 3),
4889     // Test case 8: Fold n / 1.0
4890     InstructionFoldingCase<uint32_t>(
4891         Header() + "%main = OpFunction %void None %void_func\n" +
4892             "%main_lab = OpLabel\n" +
4893             "%n = OpVariable %_ptr_double Function\n" +
4894             "%3 = OpLoad %double %n\n" +
4895             "%2 = OpFDiv %double %3 %double_1\n" +
4896             "OpReturn\n" +
4897             "OpFunctionEnd",
4898         2, 3),
4899     // Test case 9: Fold n * 0.0
4900     InstructionFoldingCase<uint32_t>(
4901         Header() + "%main = OpFunction %void None %void_func\n" +
4902             "%main_lab = OpLabel\n" +
4903             "%n = OpVariable %_ptr_double Function\n" +
4904             "%3 = OpLoad %double %n\n" +
4905             "%2 = OpFMul %double %3 %105\n" +
4906             "OpReturn\n" +
4907             "OpFunctionEnd",
4908         2, DOUBLE_0_ID),
4909     // Test case 10: Fold 0.0 * n
4910     InstructionFoldingCase<uint32_t>(
4911         Header() + "%main = OpFunction %void None %void_func\n" +
4912             "%main_lab = OpLabel\n" +
4913             "%n = OpVariable %_ptr_double Function\n" +
4914             "%3 = OpLoad %double %n\n" +
4915             "%2 = OpFMul %double %105 %3\n" +
4916             "OpReturn\n" +
4917             "OpFunctionEnd",
4918         2, DOUBLE_0_ID),
4919     // Test case 11: Fold 0.0 / n
4920     InstructionFoldingCase<uint32_t>(
4921         Header() + "%main = OpFunction %void None %void_func\n" +
4922             "%main_lab = OpLabel\n" +
4923             "%n = OpVariable %_ptr_double Function\n" +
4924             "%3 = OpLoad %double %n\n" +
4925             "%2 = OpFDiv %double %105 %3\n" +
4926             "OpReturn\n" +
4927             "OpFunctionEnd",
4928         2, DOUBLE_0_ID),
4929     // Test case 12: Don't fold mix(a, b, 2.0)
4930     InstructionFoldingCase<uint32_t>(
4931         Header() + "%main = OpFunction %void None %void_func\n" +
4932             "%main_lab = OpLabel\n" +
4933             "%a = OpVariable %_ptr_double Function\n" +
4934             "%b = OpVariable %_ptr_double Function\n" +
4935             "%3 = OpLoad %double %a\n" +
4936             "%4 = OpLoad %double %b\n" +
4937             "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
4938             "OpReturn\n" +
4939             "OpFunctionEnd",
4940         2, 0),
4941     // Test case 13: Fold mix(a, b, 0.0)
4942     InstructionFoldingCase<uint32_t>(
4943         Header() + "%main = OpFunction %void None %void_func\n" +
4944             "%main_lab = OpLabel\n" +
4945             "%a = OpVariable %_ptr_double Function\n" +
4946             "%b = OpVariable %_ptr_double Function\n" +
4947             "%3 = OpLoad %double %a\n" +
4948             "%4 = OpLoad %double %b\n" +
4949             "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
4950             "OpReturn\n" +
4951             "OpFunctionEnd",
4952         2, 3),
4953     // Test case 14: Fold mix(a, b, 1.0)
4954     InstructionFoldingCase<uint32_t>(
4955         Header() + "%main = OpFunction %void None %void_func\n" +
4956             "%main_lab = OpLabel\n" +
4957             "%a = OpVariable %_ptr_double Function\n" +
4958             "%b = OpVariable %_ptr_double Function\n" +
4959             "%3 = OpLoad %double %a\n" +
4960             "%4 = OpLoad %double %b\n" +
4961             "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
4962             "OpReturn\n" +
4963             "OpFunctionEnd",
4964         2, 4)
4965 ));
4966 
4967 INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4968                         ::testing::Values(
4969     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4970     InstructionFoldingCase<uint32_t>(
4971         Header() + "%main = OpFunction %void None %void_func\n" +
4972             "%main_lab = OpLabel\n" +
4973             "%n = OpVariable %_ptr_v4float Function\n" +
4974             "%3 = OpLoad %v4float %n\n" +
4975             "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
4976             "OpReturn\n" +
4977             "OpFunctionEnd",
4978         2, 0),
4979     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4980     InstructionFoldingCase<uint32_t>(
4981         Header() + "%main = OpFunction %void None %void_func\n" +
4982             "%main_lab = OpLabel\n" +
4983             "%n = OpVariable %_ptr_v4float Function\n" +
4984             "%3 = OpLoad %v4float %n\n" +
4985             "%2 = OpFMul %v4float %3 %106\n" +
4986             "OpReturn\n" +
4987             "OpFunctionEnd",
4988         2, VEC4_0_ID),
4989     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4990     InstructionFoldingCase<uint32_t>(
4991         Header() + "%main = OpFunction %void None %void_func\n" +
4992             "%main_lab = OpLabel\n" +
4993             "%n = OpVariable %_ptr_v4float Function\n" +
4994             "%3 = OpLoad %v4float %n\n" +
4995             "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
4996             "OpReturn\n" +
4997             "OpFunctionEnd",
4998         2, 3)
4999 ));
5000 
5001 INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
5002                         ::testing::Values(
5003     // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
5004     InstructionFoldingCase<uint32_t>(
5005         Header() + "%main = OpFunction %void None %void_func\n" +
5006             "%main_lab = OpLabel\n" +
5007             "%n = OpVariable %_ptr_v4double Function\n" +
5008             "%3 = OpLoad %v4double %n\n" +
5009             "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
5010             "OpReturn\n" +
5011             "OpFunctionEnd",
5012         2, 0),
5013     // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
5014     InstructionFoldingCase<uint32_t>(
5015         Header() + "%main = OpFunction %void None %void_func\n" +
5016             "%main_lab = OpLabel\n" +
5017             "%n = OpVariable %_ptr_v4double Function\n" +
5018             "%3 = OpLoad %v4double %n\n" +
5019             "%2 = OpFMul %v4double %3 %106\n" +
5020             "OpReturn\n" +
5021             "OpFunctionEnd",
5022         2, DVEC4_0_ID),
5023     // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
5024     InstructionFoldingCase<uint32_t>(
5025         Header() + "%main = OpFunction %void None %void_func\n" +
5026             "%main_lab = OpLabel\n" +
5027             "%n = OpVariable %_ptr_v4double Function\n" +
5028             "%3 = OpLoad %v4double %n\n" +
5029             "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
5030             "OpReturn\n" +
5031             "OpFunctionEnd",
5032         2, 3)
5033 ));
5034 
5035 INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
5036                         ::testing::Values(
5037     // Test case 0: Don't fold n + 1
5038     InstructionFoldingCase<uint32_t>(
5039         Header() + "%main = OpFunction %void None %void_func\n" +
5040             "%main_lab = OpLabel\n" +
5041             "%n = OpVariable %_ptr_uint Function\n" +
5042             "%3 = OpLoad %uint %n\n" +
5043             "%2 = OpIAdd %uint %3 %uint_1\n" +
5044             "OpReturn\n" +
5045             "OpFunctionEnd",
5046         2, 0),
5047     // Test case 1: Don't fold 1 + n
5048     InstructionFoldingCase<uint32_t>(
5049         Header() + "%main = OpFunction %void None %void_func\n" +
5050             "%main_lab = OpLabel\n" +
5051             "%n = OpVariable %_ptr_uint Function\n" +
5052             "%3 = OpLoad %uint %n\n" +
5053             "%2 = OpIAdd %uint %uint_1 %3\n" +
5054             "OpReturn\n" +
5055             "OpFunctionEnd",
5056         2, 0),
5057     // Test case 2: Fold n + 0
5058     InstructionFoldingCase<uint32_t>(
5059         Header() + "%main = OpFunction %void None %void_func\n" +
5060             "%main_lab = OpLabel\n" +
5061             "%n = OpVariable %_ptr_uint Function\n" +
5062             "%3 = OpLoad %uint %n\n" +
5063             "%2 = OpIAdd %uint %3 %uint_0\n" +
5064             "OpReturn\n" +
5065             "OpFunctionEnd",
5066         2, 3),
5067     // Test case 3: Fold 0 + n
5068     InstructionFoldingCase<uint32_t>(
5069         Header() + "%main = OpFunction %void None %void_func\n" +
5070             "%main_lab = OpLabel\n" +
5071             "%n = OpVariable %_ptr_uint Function\n" +
5072             "%3 = OpLoad %uint %n\n" +
5073             "%2 = OpIAdd %uint %uint_0 %3\n" +
5074             "OpReturn\n" +
5075             "OpFunctionEnd",
5076         2, 3),
5077     // Test case 4: Don't fold n + (1,0)
5078     InstructionFoldingCase<uint32_t>(
5079         Header() + "%main = OpFunction %void None %void_func\n" +
5080             "%main_lab = OpLabel\n" +
5081             "%n = OpVariable %_ptr_v2int Function\n" +
5082             "%3 = OpLoad %v2int %n\n" +
5083             "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
5084             "OpReturn\n" +
5085             "OpFunctionEnd",
5086         2, 0),
5087     // Test case 5: Don't fold (1,0) + n
5088     InstructionFoldingCase<uint32_t>(
5089         Header() + "%main = OpFunction %void None %void_func\n" +
5090             "%main_lab = OpLabel\n" +
5091             "%n = OpVariable %_ptr_v2int Function\n" +
5092             "%3 = OpLoad %v2int %n\n" +
5093             "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
5094             "OpReturn\n" +
5095             "OpFunctionEnd",
5096         2, 0),
5097     // Test case 6: Fold n + (0,0)
5098     InstructionFoldingCase<uint32_t>(
5099         Header() + "%main = OpFunction %void None %void_func\n" +
5100             "%main_lab = OpLabel\n" +
5101             "%n = OpVariable %_ptr_v2int Function\n" +
5102             "%3 = OpLoad %v2int %n\n" +
5103             "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
5104             "OpReturn\n" +
5105             "OpFunctionEnd",
5106         2, 3),
5107     // Test case 7: Fold (0,0) + n
5108     InstructionFoldingCase<uint32_t>(
5109         Header() + "%main = OpFunction %void None %void_func\n" +
5110             "%main_lab = OpLabel\n" +
5111             "%n = OpVariable %_ptr_v2int Function\n" +
5112             "%3 = OpLoad %v2int %n\n" +
5113             "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
5114             "OpReturn\n" +
5115             "OpFunctionEnd",
5116         2, 3),
5117     // Test case 8: Don't fold because of undefined value. Using 4294967295
5118     // means that entry is undefined. We do not expect it to ever happen, so
5119     // not worth folding.
5120     InstructionFoldingCase<uint32_t>(
5121         Header() + "%main = OpFunction %void None %void_func\n" +
5122             "%main_lab = OpLabel\n" +
5123             "%n = OpVariable %_ptr_int Function\n" +
5124             "%load = OpLoad %int %n\n" +
5125             "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
5126             "OpReturn\n" +
5127             "OpFunctionEnd",
5128         2, 0),
5129     // Test case 9: Don't fold because of undefined value. Using 4294967295
5130     // means that entry is undefined. We do not expect it to ever happen, so
5131     // not worth folding.
5132     InstructionFoldingCase<uint32_t>(
5133         Header() + "%main = OpFunction %void None %void_func\n" +
5134             "%main_lab = OpLabel\n" +
5135             "%n = OpVariable %_ptr_int Function\n" +
5136             "%load = OpLoad %int %n\n" +
5137             "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
5138             "OpReturn\n" +
5139             "OpFunctionEnd",
5140         2, 0)
5141 ));
5142 
5143 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
5144 ::testing::Values(
5145     // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
5146     InstructionFoldingCase<uint32_t>(
5147         Header() + "%main = OpFunction %void None %void_func\n" +
5148             "%main_lab = OpLabel\n" +
5149             "%n = OpVariable %_ptr_float Function\n" +
5150             "%ld = OpLoad %float %n\n" +
5151             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5152             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
5153             "OpReturn\n" +
5154             "OpFunctionEnd",
5155         2, 0),
5156     // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
5157     InstructionFoldingCase<uint32_t>(
5158         Header() + "%main = OpFunction %void None %void_func\n" +
5159             "%main_lab = OpLabel\n" +
5160             "%n = OpVariable %_ptr_float Function\n" +
5161             "%ld = OpLoad %float %n\n" +
5162             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5163             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
5164             "OpReturn\n" +
5165             "OpFunctionEnd",
5166         2, 0),
5167     // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
5168     InstructionFoldingCase<uint32_t>(
5169         Header() + "%main = OpFunction %void None %void_func\n" +
5170             "%main_lab = OpLabel\n" +
5171             "%n = OpVariable %_ptr_float Function\n" +
5172             "%ld = OpLoad %float %n\n" +
5173             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5174             "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
5175             "OpReturn\n" +
5176             "OpFunctionEnd",
5177         2, 0),
5178     // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
5179     InstructionFoldingCase<uint32_t>(
5180         Header() + "%main = OpFunction %void None %void_func\n" +
5181             "%main_lab = OpLabel\n" +
5182             "%n = OpVariable %_ptr_float Function\n" +
5183             "%ld = OpLoad %float %n\n" +
5184             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5185             "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
5186             "OpReturn\n" +
5187             "OpFunctionEnd",
5188         2, 0),
5189     // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
5190     InstructionFoldingCase<uint32_t>(
5191         Header() + "%main = OpFunction %void None %void_func\n" +
5192             "%main_lab = OpLabel\n" +
5193             "%n = OpVariable %_ptr_float Function\n" +
5194             "%ld = OpLoad %float %n\n" +
5195             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5196             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
5197             "OpReturn\n" +
5198             "OpFunctionEnd",
5199         2, 0),
5200     // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
5201     InstructionFoldingCase<uint32_t>(
5202         Header() + "%main = OpFunction %void None %void_func\n" +
5203             "%main_lab = OpLabel\n" +
5204             "%n = OpVariable %_ptr_float Function\n" +
5205             "%ld = OpLoad %float %n\n" +
5206             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5207             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
5208             "OpReturn\n" +
5209             "OpFunctionEnd",
5210         2, 0),
5211     // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
5212     InstructionFoldingCase<uint32_t>(
5213         Header() + "%main = OpFunction %void None %void_func\n" +
5214             "%main_lab = OpLabel\n" +
5215             "%n = OpVariable %_ptr_float Function\n" +
5216             "%ld = OpLoad %float %n\n" +
5217             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5218             "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
5219             "OpReturn\n" +
5220             "OpFunctionEnd",
5221         2, 0),
5222     // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
5223     InstructionFoldingCase<uint32_t>(
5224         Header() + "%main = OpFunction %void None %void_func\n" +
5225             "%main_lab = OpLabel\n" +
5226             "%n = OpVariable %_ptr_float Function\n" +
5227             "%ld = OpLoad %float %n\n" +
5228             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5229             "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
5230             "OpReturn\n" +
5231             "OpFunctionEnd",
5232         2, 0),
5233     // Test case 8: Don't Fold 0.0 < clamp(0, 1)
5234     InstructionFoldingCase<uint32_t>(
5235         Header() + "%main = OpFunction %void None %void_func\n" +
5236             "%main_lab = OpLabel\n" +
5237             "%n = OpVariable %_ptr_float Function\n" +
5238             "%ld = OpLoad %float %n\n" +
5239             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
5240             "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
5241             "OpReturn\n" +
5242             "OpFunctionEnd",
5243         2, 0),
5244     // Test case 9: Don't Fold 0.0 < clamp(0, 1)
5245     InstructionFoldingCase<uint32_t>(
5246         Header() + "%main = OpFunction %void None %void_func\n" +
5247             "%main_lab = OpLabel\n" +
5248             "%n = OpVariable %_ptr_float Function\n" +
5249             "%ld = OpLoad %float %n\n" +
5250             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
5251             "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
5252             "OpReturn\n" +
5253             "OpFunctionEnd",
5254         2, 0),
5255     // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
5256     InstructionFoldingCase<uint32_t>(
5257         Header() + "%main = OpFunction %void None %void_func\n" +
5258             "%main_lab = OpLabel\n" +
5259             "%n = OpVariable %_ptr_float Function\n" +
5260             "%ld = OpLoad %float %n\n" +
5261             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5262             "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
5263             "OpReturn\n" +
5264             "OpFunctionEnd",
5265         2, 0),
5266     // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
5267     InstructionFoldingCase<uint32_t>(
5268         Header() + "%main = OpFunction %void None %void_func\n" +
5269             "%main_lab = OpLabel\n" +
5270             "%n = OpVariable %_ptr_float Function\n" +
5271             "%ld = OpLoad %float %n\n" +
5272             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5273             "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
5274             "OpReturn\n" +
5275             "OpFunctionEnd",
5276         2, 0)
5277 ));
5278 
5279 INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
5280 ::testing::Values(
5281     // Test case 0: Don't Fold clamp(-1, 1) < 0.0
5282     InstructionFoldingCase<uint32_t>(
5283       Header() + "%main = OpFunction %void None %void_func\n" +
5284           "%main_lab = OpLabel\n" +
5285           "%n = OpVariable %_ptr_float Function\n" +
5286           "%ld = OpLoad %float %n\n" +
5287           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5288           "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
5289           "OpReturn\n" +
5290           "OpFunctionEnd",
5291       2, 0),
5292     // Test case 1: Don't Fold clamp(-1, 1) < 0.0
5293     InstructionFoldingCase<uint32_t>(
5294       Header() + "%main = OpFunction %void None %void_func\n" +
5295           "%main_lab = OpLabel\n" +
5296           "%n = OpVariable %_ptr_float Function\n" +
5297           "%ld = OpLoad %float %n\n" +
5298           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5299           "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
5300           "OpReturn\n" +
5301           "OpFunctionEnd",
5302       2, 0),
5303     // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
5304     InstructionFoldingCase<uint32_t>(
5305       Header() + "%main = OpFunction %void None %void_func\n" +
5306           "%main_lab = OpLabel\n" +
5307           "%n = OpVariable %_ptr_float Function\n" +
5308           "%ld = OpLoad %float %n\n" +
5309           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5310           "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
5311           "OpReturn\n" +
5312           "OpFunctionEnd",
5313       2, 0),
5314     // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
5315     InstructionFoldingCase<uint32_t>(
5316       Header() + "%main = OpFunction %void None %void_func\n" +
5317           "%main_lab = OpLabel\n" +
5318           "%n = OpVariable %_ptr_float Function\n" +
5319           "%ld = OpLoad %float %n\n" +
5320           "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5321           "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
5322           "OpReturn\n" +
5323           "OpFunctionEnd",
5324       2, 0),
5325     // Test case 4: Don't Fold clamp(-1, 1) > 0.0
5326     InstructionFoldingCase<uint32_t>(
5327         Header() + "%main = OpFunction %void None %void_func\n" +
5328             "%main_lab = OpLabel\n" +
5329             "%n = OpVariable %_ptr_float Function\n" +
5330             "%ld = OpLoad %float %n\n" +
5331             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5332             "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
5333             "OpReturn\n" +
5334             "OpFunctionEnd",
5335         2, 0),
5336     // Test case 5: Don't Fold clamp(-1, 1) > 0.0
5337     InstructionFoldingCase<uint32_t>(
5338         Header() + "%main = OpFunction %void None %void_func\n" +
5339             "%main_lab = OpLabel\n" +
5340             "%n = OpVariable %_ptr_float Function\n" +
5341             "%ld = OpLoad %float %n\n" +
5342             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5343             "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
5344             "OpReturn\n" +
5345             "OpFunctionEnd",
5346         2, 0),
5347     // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
5348     InstructionFoldingCase<uint32_t>(
5349         Header() + "%main = OpFunction %void None %void_func\n" +
5350             "%main_lab = OpLabel\n" +
5351             "%n = OpVariable %_ptr_float Function\n" +
5352             "%ld = OpLoad %float %n\n" +
5353             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5354             "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
5355             "OpReturn\n" +
5356             "OpFunctionEnd",
5357         2, 0),
5358     // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
5359     InstructionFoldingCase<uint32_t>(
5360         Header() + "%main = OpFunction %void None %void_func\n" +
5361             "%main_lab = OpLabel\n" +
5362             "%n = OpVariable %_ptr_float Function\n" +
5363             "%ld = OpLoad %float %n\n" +
5364             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5365             "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
5366             "OpReturn\n" +
5367             "OpFunctionEnd",
5368         2, 0),
5369     // Test case 8: Don't Fold clamp(-1, 0) < 0.0
5370     InstructionFoldingCase<uint32_t>(
5371         Header() + "%main = OpFunction %void None %void_func\n" +
5372             "%main_lab = OpLabel\n" +
5373             "%n = OpVariable %_ptr_float Function\n" +
5374             "%ld = OpLoad %float %n\n" +
5375             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5376             "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
5377             "OpReturn\n" +
5378             "OpFunctionEnd",
5379         2, 0),
5380     // Test case 9: Don't Fold clamp(0, 1) < 1
5381     InstructionFoldingCase<uint32_t>(
5382         Header() + "%main = OpFunction %void None %void_func\n" +
5383             "%main_lab = OpLabel\n" +
5384             "%n = OpVariable %_ptr_float Function\n" +
5385             "%ld = OpLoad %float %n\n" +
5386             "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
5387             "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
5388             "OpReturn\n" +
5389             "OpFunctionEnd",
5390         2, 0),
5391     // Test case 10: Don't Fold clamp(-1, 0) > -1
5392     InstructionFoldingCase<uint32_t>(
5393         Header() + "%main = OpFunction %void None %void_func\n" +
5394             "%main_lab = OpLabel\n" +
5395             "%n = OpVariable %_ptr_float Function\n" +
5396             "%ld = OpLoad %float %n\n" +
5397             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5398             "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
5399             "OpReturn\n" +
5400             "OpFunctionEnd",
5401         2, 0),
5402     // Test case 11: Don't Fold clamp(-1, 0) > -1
5403     InstructionFoldingCase<uint32_t>(
5404         Header() + "%main = OpFunction %void None %void_func\n" +
5405             "%main_lab = OpLabel\n" +
5406             "%n = OpVariable %_ptr_float Function\n" +
5407             "%ld = OpLoad %float %n\n" +
5408             "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5409             "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
5410             "OpReturn\n" +
5411             "OpFunctionEnd",
5412         2, 0)
5413 ));
5414 
5415 INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
5416                         ::testing::Values(
5417     // Test case 0: Fold int(3.0)
5418     InstructionFoldingCase<uint32_t>(
5419         Header() + "%main = OpFunction %void None %void_func\n" +
5420             "%main_lab = OpLabel\n" +
5421             "%2 = OpConvertFToS %int %float_3\n" +
5422             "OpReturn\n" +
5423             "OpFunctionEnd",
5424         2, 3),
5425     // Test case 1: Fold uint(3.0)
5426     InstructionFoldingCase<uint32_t>(
5427         Header() + "%main = OpFunction %void None %void_func\n" +
5428             "%main_lab = OpLabel\n" +
5429             "%2 = OpConvertFToU %int %float_3\n" +
5430             "OpReturn\n" +
5431             "OpFunctionEnd",
5432         2, 3)
5433 ));
5434 
5435 INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
5436                         ::testing::Values(
5437     // Test case 0: Fold float(3)
5438     InstructionFoldingCase<float>(
5439         Header() + "%main = OpFunction %void None %void_func\n" +
5440             "%main_lab = OpLabel\n" +
5441             "%2 = OpConvertSToF %float %int_3\n" +
5442             "OpReturn\n" +
5443             "OpFunctionEnd",
5444         2, 3.0),
5445     // Test case 1: Fold float(3u)
5446     InstructionFoldingCase<float>(
5447         Header() + "%main = OpFunction %void None %void_func\n" +
5448             "%main_lab = OpLabel\n" +
5449             "%2 = OpConvertUToF %float %uint_3\n" +
5450             "OpReturn\n" +
5451             "OpFunctionEnd",
5452         2, 3.0)
5453 ));
5454 // clang-format on
5455 
5456 using ToNegateFoldingTest =
5457     ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
5458 
TEST_P(ToNegateFoldingTest,Case)5459 TEST_P(ToNegateFoldingTest, Case) {
5460   const auto& tc = GetParam();
5461 
5462   std::unique_ptr<IRContext> context;
5463   Instruction* inst;
5464   std::tie(context, inst) =
5465       FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
5466 
5467   EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0));
5468   if (inst != nullptr) {
5469     EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate);
5470     EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
5471   }
5472 }
5473 
5474 // clang-format off
5475 INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
5476                         ::testing::Values(
5477     // Test case 0: Don't fold 1.0 - n
5478     InstructionFoldingCase<uint32_t>(
5479         Header() + "%main = OpFunction %void None %void_func\n" +
5480             "%main_lab = OpLabel\n" +
5481             "%n = OpVariable %_ptr_float Function\n" +
5482             "%3 = OpLoad %float %n\n" +
5483             "%2 = OpFSub %float %float_1 %3\n" +
5484             "OpReturn\n" +
5485             "OpFunctionEnd",
5486         2, 0),
5487     // Test case 1: Fold 0.0 - n
5488     InstructionFoldingCase<uint32_t>(
5489         Header() + "%main = OpFunction %void None %void_func\n" +
5490             "%main_lab = OpLabel\n" +
5491             "%n = OpVariable %_ptr_float Function\n" +
5492             "%3 = OpLoad %float %n\n" +
5493             "%2 = OpFSub %float %float_0 %3\n" +
5494             "OpReturn\n" +
5495             "OpFunctionEnd",
5496         2, 3),
5497 	// Test case 2: Don't fold (0,0,0,1) - n
5498     InstructionFoldingCase<uint32_t>(
5499         Header() + "%main = OpFunction %void None %void_func\n" +
5500             "%main_lab = OpLabel\n" +
5501             "%n = OpVariable %_ptr_v4float Function\n" +
5502             "%3 = OpLoad %v4float %n\n" +
5503             "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
5504             "OpReturn\n" +
5505             "OpFunctionEnd",
5506         2, 0),
5507 	// Test case 3: Fold (0,0,0,0) - n
5508     InstructionFoldingCase<uint32_t>(
5509         Header() + "%main = OpFunction %void None %void_func\n" +
5510             "%main_lab = OpLabel\n" +
5511             "%n = OpVariable %_ptr_v4float Function\n" +
5512             "%3 = OpLoad %v4float %n\n" +
5513             "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
5514             "OpReturn\n" +
5515             "OpFunctionEnd",
5516         2, 3)
5517 ));
5518 
5519 INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
5520                         ::testing::Values(
5521     // Test case 0: Don't fold 1.0 - n
5522     InstructionFoldingCase<uint32_t>(
5523         Header() + "%main = OpFunction %void None %void_func\n" +
5524             "%main_lab = OpLabel\n" +
5525             "%n = OpVariable %_ptr_double Function\n" +
5526             "%3 = OpLoad %double %n\n" +
5527             "%2 = OpFSub %double %double_1 %3\n" +
5528             "OpReturn\n" +
5529             "OpFunctionEnd",
5530         2, 0),
5531     // Test case 1: Fold 0.0 - n
5532     InstructionFoldingCase<uint32_t>(
5533         Header() + "%main = OpFunction %void None %void_func\n" +
5534             "%main_lab = OpLabel\n" +
5535             "%n = OpVariable %_ptr_double Function\n" +
5536             "%3 = OpLoad %double %n\n" +
5537             "%2 = OpFSub %double %double_0 %3\n" +
5538             "OpReturn\n" +
5539             "OpFunctionEnd",
5540         2, 3),
5541 	// Test case 2: Don't fold (0,0,0,1) - n
5542     InstructionFoldingCase<uint32_t>(
5543         Header() + "%main = OpFunction %void None %void_func\n" +
5544             "%main_lab = OpLabel\n" +
5545             "%n = OpVariable %_ptr_v4double Function\n" +
5546             "%3 = OpLoad %v4double %n\n" +
5547             "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
5548             "OpReturn\n" +
5549             "OpFunctionEnd",
5550         2, 0),
5551 	// Test case 3: Fold (0,0,0,0) - n
5552     InstructionFoldingCase<uint32_t>(
5553         Header() + "%main = OpFunction %void None %void_func\n" +
5554             "%main_lab = OpLabel\n" +
5555             "%n = OpVariable %_ptr_v4double Function\n" +
5556             "%3 = OpLoad %v4double %n\n" +
5557             "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
5558             "OpReturn\n" +
5559             "OpFunctionEnd",
5560         2, 3)
5561 ));
5562 
5563 using MatchingInstructionFoldingTest =
5564     ::testing::TestWithParam<InstructionFoldingCase<bool>>;
5565 
TEST_P(MatchingInstructionFoldingTest,Case)5566 TEST_P(MatchingInstructionFoldingTest, Case) {
5567   const auto& tc = GetParam();
5568 
5569   std::unique_ptr<IRContext> context;
5570   Instruction* inst;
5571   std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
5572 
5573   EXPECT_EQ(inst != nullptr, tc.expected_result);
5574   if (inst != nullptr) {
5575     Match(tc.test_body, context.get());
5576   }
5577 }
5578 
5579 INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
5580 ::testing::Values(
5581     // Test case 0: Fold 0 + n (change sign)
5582     InstructionFoldingCase<bool>(
5583         Header() +
5584             "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5585             "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
5586             "%main = OpFunction %void None %void_func\n" +
5587             "%main_lab = OpLabel\n" +
5588             "%n = OpVariable %_ptr_int Function\n" +
5589             "%3 = OpLoad %uint %n\n" +
5590             "%2 = OpIAdd %uint %int_0 %3\n" +
5591             "OpReturn\n" +
5592             "OpFunctionEnd\n",
5593         2, true),
5594     // Test case 0: Fold 0 + n (change sign)
5595     InstructionFoldingCase<bool>(
5596         Header() +
5597             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5598             "; CHECK: %2 = OpBitcast [[int]] %3\n" +
5599             "%main = OpFunction %void None %void_func\n" +
5600             "%main_lab = OpLabel\n" +
5601             "%n = OpVariable %_ptr_int Function\n" +
5602             "%3 = OpLoad %int %n\n" +
5603             "%2 = OpIAdd %int %uint_0 %3\n" +
5604             "OpReturn\n" +
5605             "OpFunctionEnd\n",
5606         2, true)
5607 ));
5608 
5609 INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest,
5610 ::testing::Values(
5611   // Test case 0: fold consecutive fnegate
5612   // -(-x) = x
5613   InstructionFoldingCase<bool>(
5614     Header() +
5615       "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
5616       "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
5617       "%main = OpFunction %void None %void_func\n" +
5618       "%main_lab = OpLabel\n" +
5619       "%var = OpVariable %_ptr_float Function\n" +
5620       "%2 = OpLoad %float %var\n" +
5621       "%3 = OpFNegate %float %2\n" +
5622       "%4 = OpFNegate %float %3\n" +
5623       "OpReturn\n" +
5624       "OpFunctionEnd",
5625     4, true),
5626   // Test case 1: fold fnegate(fmul with const).
5627   // -(x * 2.0) = x * -2.0
5628   InstructionFoldingCase<bool>(
5629     Header() +
5630       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5631       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5632       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5633       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5634       "%main = OpFunction %void None %void_func\n" +
5635       "%main_lab = OpLabel\n" +
5636       "%var = OpVariable %_ptr_float Function\n" +
5637       "%2 = OpLoad %float %var\n" +
5638       "%3 = OpFMul %float %2 %float_2\n" +
5639       "%4 = OpFNegate %float %3\n" +
5640       "OpReturn\n" +
5641       "OpFunctionEnd",
5642     4, true),
5643   // Test case 2: fold fnegate(fmul with const).
5644   // -(2.0 * x) = x * 2.0
5645   InstructionFoldingCase<bool>(
5646     Header() +
5647       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5648       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5649       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5650       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5651       "%main = OpFunction %void None %void_func\n" +
5652       "%main_lab = OpLabel\n" +
5653       "%var = OpVariable %_ptr_float Function\n" +
5654       "%2 = OpLoad %float %var\n" +
5655       "%3 = OpFMul %float %float_2 %2\n" +
5656       "%4 = OpFNegate %float %3\n" +
5657       "OpReturn\n" +
5658       "OpFunctionEnd",
5659     4, true),
5660   // Test case 3: fold fnegate(fdiv with const).
5661   // -(x / 2.0) = x * -0.5
5662   InstructionFoldingCase<bool>(
5663     Header() +
5664       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5665       "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
5666       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5667       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
5668       "%main = OpFunction %void None %void_func\n" +
5669       "%main_lab = OpLabel\n" +
5670       "%var = OpVariable %_ptr_float Function\n" +
5671       "%2 = OpLoad %float %var\n" +
5672       "%3 = OpFDiv %float %2 %float_2\n" +
5673       "%4 = OpFNegate %float %3\n" +
5674       "OpReturn\n" +
5675       "OpFunctionEnd",
5676     4, true),
5677   // Test case 4: fold fnegate(fdiv with const).
5678   // -(2.0 / x) = -2.0 / x
5679   InstructionFoldingCase<bool>(
5680     Header() +
5681       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5682       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5683       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5684       "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
5685       "%main = OpFunction %void None %void_func\n" +
5686       "%main_lab = OpLabel\n" +
5687       "%var = OpVariable %_ptr_float Function\n" +
5688       "%2 = OpLoad %float %var\n" +
5689       "%3 = OpFDiv %float %float_2 %2\n" +
5690       "%4 = OpFNegate %float %3\n" +
5691       "OpReturn\n" +
5692       "OpFunctionEnd",
5693     4, true),
5694   // Test case 5: fold fnegate(fadd with const).
5695   // -(2.0 + x) = -2.0 - x
5696   InstructionFoldingCase<bool>(
5697     Header() +
5698       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5699       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5700       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5701       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5702       "%main = OpFunction %void None %void_func\n" +
5703       "%main_lab = OpLabel\n" +
5704       "%var = OpVariable %_ptr_float Function\n" +
5705       "%2 = OpLoad %float %var\n" +
5706       "%3 = OpFAdd %float %float_2 %2\n" +
5707       "%4 = OpFNegate %float %3\n" +
5708       "OpReturn\n" +
5709       "OpFunctionEnd",
5710     4, true),
5711   // Test case 6: fold fnegate(fadd with const).
5712   // -(x + 2.0) = -2.0 - x
5713   InstructionFoldingCase<bool>(
5714     Header() +
5715       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5716       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5717       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5718       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5719       "%main = OpFunction %void None %void_func\n" +
5720       "%main_lab = OpLabel\n" +
5721       "%var = OpVariable %_ptr_float Function\n" +
5722       "%2 = OpLoad %float %var\n" +
5723       "%3 = OpFAdd %float %2 %float_2\n" +
5724       "%4 = OpFNegate %float %3\n" +
5725       "OpReturn\n" +
5726       "OpFunctionEnd",
5727     4, true),
5728   // Test case 7: fold fnegate(fsub with const).
5729   // -(2.0 - x) = x - 2.0
5730   InstructionFoldingCase<bool>(
5731     Header() +
5732       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5733       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5734       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5735       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
5736       "%main = OpFunction %void None %void_func\n" +
5737       "%main_lab = OpLabel\n" +
5738       "%var = OpVariable %_ptr_float Function\n" +
5739       "%2 = OpLoad %float %var\n" +
5740       "%3 = OpFSub %float %float_2 %2\n" +
5741       "%4 = OpFNegate %float %3\n" +
5742       "OpReturn\n" +
5743       "OpFunctionEnd",
5744     4, true),
5745   // Test case 8: fold fnegate(fsub with const).
5746   // -(x - 2.0) = 2.0 - x
5747   InstructionFoldingCase<bool>(
5748     Header() +
5749       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5750       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5751       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5752       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5753       "%main = OpFunction %void None %void_func\n" +
5754       "%main_lab = OpLabel\n" +
5755       "%var = OpVariable %_ptr_float Function\n" +
5756       "%2 = OpLoad %float %var\n" +
5757       "%3 = OpFSub %float %2 %float_2\n" +
5758       "%4 = OpFNegate %float %3\n" +
5759       "OpReturn\n" +
5760       "OpFunctionEnd",
5761     4, true),
5762   // Test case 9: fold consecutive snegate
5763   // -(-x) = x
5764   InstructionFoldingCase<bool>(
5765     Header() +
5766       "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
5767       "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
5768       "%main = OpFunction %void None %void_func\n" +
5769       "%main_lab = OpLabel\n" +
5770       "%var = OpVariable %_ptr_int Function\n" +
5771       "%2 = OpLoad %int %var\n" +
5772       "%3 = OpSNegate %int %2\n" +
5773       "%4 = OpSNegate %int %3\n" +
5774       "OpReturn\n" +
5775       "OpFunctionEnd",
5776     4, true),
5777   // Test case 10: fold consecutive vector negate
5778   // -(-x) = x
5779   InstructionFoldingCase<bool>(
5780     Header() +
5781       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
5782       "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
5783       "%main = OpFunction %void None %void_func\n" +
5784       "%main_lab = OpLabel\n" +
5785       "%var = OpVariable %_ptr_v2float Function\n" +
5786       "%2 = OpLoad %v2float %var\n" +
5787       "%3 = OpFNegate %v2float %2\n" +
5788       "%4 = OpFNegate %v2float %3\n" +
5789       "OpReturn\n" +
5790       "OpFunctionEnd",
5791     4, true),
5792   // Test case 11: fold snegate(iadd with const).
5793   // -(2 + x) = -2 - x
5794   InstructionFoldingCase<bool>(
5795     Header() +
5796       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5797       "; CHECK: OpConstant [[int]] -2147483648\n" +
5798       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5799       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5800       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5801       "%main = OpFunction %void None %void_func\n" +
5802       "%main_lab = OpLabel\n" +
5803       "%var = OpVariable %_ptr_int Function\n" +
5804       "%2 = OpLoad %int %var\n" +
5805       "%3 = OpIAdd %int %int_2 %2\n" +
5806       "%4 = OpSNegate %int %3\n" +
5807       "OpReturn\n" +
5808       "OpFunctionEnd",
5809     4, true),
5810   // Test case 12: fold snegate(iadd with const).
5811   // -(x + 2) = -2 - x
5812   InstructionFoldingCase<bool>(
5813     Header() +
5814       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5815       "; CHECK: OpConstant [[int]] -2147483648\n" +
5816       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5817       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5818       "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5819       "%main = OpFunction %void None %void_func\n" +
5820       "%main_lab = OpLabel\n" +
5821       "%var = OpVariable %_ptr_int Function\n" +
5822       "%2 = OpLoad %int %var\n" +
5823       "%3 = OpIAdd %int %2 %int_2\n" +
5824       "%4 = OpSNegate %int %3\n" +
5825       "OpReturn\n" +
5826       "OpFunctionEnd",
5827     4, true),
5828   // Test case 13: fold snegate(isub with const).
5829   // -(2 - x) = x - 2
5830   InstructionFoldingCase<bool>(
5831     Header() +
5832       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5833       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5834       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5835       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
5836       "%main = OpFunction %void None %void_func\n" +
5837       "%main_lab = OpLabel\n" +
5838       "%var = OpVariable %_ptr_int Function\n" +
5839       "%2 = OpLoad %int %var\n" +
5840       "%3 = OpISub %int %int_2 %2\n" +
5841       "%4 = OpSNegate %int %3\n" +
5842       "OpReturn\n" +
5843       "OpFunctionEnd",
5844     4, true),
5845   // Test case 14: fold snegate(isub with const).
5846   // -(x - 2) = 2 - x
5847   InstructionFoldingCase<bool>(
5848     Header() +
5849       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5850       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5851       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5852       "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
5853       "%main = OpFunction %void None %void_func\n" +
5854       "%main_lab = OpLabel\n" +
5855       "%var = OpVariable %_ptr_int Function\n" +
5856       "%2 = OpLoad %int %var\n" +
5857       "%3 = OpISub %int %2 %int_2\n" +
5858       "%4 = OpSNegate %int %3\n" +
5859       "OpReturn\n" +
5860       "OpFunctionEnd",
5861     4, true),
5862   // Test case 15: fold snegate(iadd with const).
5863   // -(x + 2) = -2 - x
5864   InstructionFoldingCase<bool>(
5865     Header() +
5866       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5867       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
5868       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5869       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5870       "%main = OpFunction %void None %void_func\n" +
5871       "%main_lab = OpLabel\n" +
5872       "%var = OpVariable %_ptr_long Function\n" +
5873       "%2 = OpLoad %long %var\n" +
5874       "%3 = OpIAdd %long %2 %long_2\n" +
5875       "%4 = OpSNegate %long %3\n" +
5876       "OpReturn\n" +
5877       "OpFunctionEnd",
5878     4, true),
5879   // Test case 16: fold snegate(isub with const).
5880   // -(2 - x) = x - 2
5881   InstructionFoldingCase<bool>(
5882     Header() +
5883       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5884       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5885       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5886       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
5887       "%main = OpFunction %void None %void_func\n" +
5888       "%main_lab = OpLabel\n" +
5889       "%var = OpVariable %_ptr_long Function\n" +
5890       "%2 = OpLoad %long %var\n" +
5891       "%3 = OpISub %long %long_2 %2\n" +
5892       "%4 = OpSNegate %long %3\n" +
5893       "OpReturn\n" +
5894       "OpFunctionEnd",
5895     4, true),
5896   // Test case 17: fold snegate(isub with const).
5897   // -(x - 2) = 2 - x
5898   InstructionFoldingCase<bool>(
5899     Header() +
5900       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5901       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5902       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5903       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5904       "%main = OpFunction %void None %void_func\n" +
5905       "%main_lab = OpLabel\n" +
5906       "%var = OpVariable %_ptr_long Function\n" +
5907       "%2 = OpLoad %long %var\n" +
5908       "%3 = OpISub %long %2 %long_2\n" +
5909       "%4 = OpSNegate %long %3\n" +
5910       "OpReturn\n" +
5911       "OpFunctionEnd",
5912     4, true),
5913     // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
5914     InstructionFoldingCase<bool>(
5915         Header() +
5916       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5917       "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" +
5918       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" +
5919       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" +
5920       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5921       "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" +
5922       "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
5923       "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
5924         "%main = OpFunction %void None %void_func\n" +
5925             "%main_lab = OpLabel\n" +
5926             "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
5927             "OpReturn\n" +
5928             "OpFunctionEnd",
5929         2, true),
5930     // Test case 19: fold vector fnegate with null
5931     InstructionFoldingCase<bool>(
5932         Header() +
5933       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5934       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5935       "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
5936       "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
5937       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5938         "%main = OpFunction %void None %void_func\n" +
5939             "%main_lab = OpLabel\n" +
5940             "%2 = OpFNegate %v2double %v2double_null\n" +
5941             "OpReturn\n" +
5942             "OpFunctionEnd",
5943         2, true),
5944     // Test case 20: fold snegate with OpIMul.
5945     // -(x * 2) = x * -2
5946   InstructionFoldingCase<bool>(
5947       Header() +
5948           "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5949           "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
5950           "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5951           "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_n2]]\n" +
5952           "%main = OpFunction %void None %void_func\n" +
5953           "%main_lab = OpLabel\n" +
5954           "%var = OpVariable %_ptr_long Function\n" +
5955           "%2 = OpLoad %long %var\n" +
5956           "%3 = OpIMul %long %2 %long_2\n" +
5957           "%4 = OpSNegate %long %3\n" +
5958           "OpReturn\n" +
5959           "OpFunctionEnd",
5960       4, true),
5961     // Test case 21: fold snegate with OpIMul.
5962     // -(x * 2) = x * -2
5963   InstructionFoldingCase<bool>(
5964       Header() +
5965           "; CHECK-DAG: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5966           "; CHECK-DAG: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5967           "; CHECK: [[uint_n2:%\\w+]] = OpConstant [[uint]] 4294967294\n" +
5968           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5969           "; CHECK: %4 = OpIMul [[int]] [[ld]] [[uint_n2]]\n" +
5970           "%main = OpFunction %void None %void_func\n" +
5971           "%main_lab = OpLabel\n" +
5972           "%var = OpVariable %_ptr_int Function\n" +
5973           "%2 = OpLoad %int %var\n" +
5974           "%3 = OpIMul %int %2 %uint_2\n" +
5975           "%4 = OpSNegate %int %3\n" +
5976           "OpReturn\n" +
5977           "OpFunctionEnd",
5978       4, true),
5979     // Test case 22: fold snegate with OpIMul.
5980     // -(-24 * x) = x * 24
5981   InstructionFoldingCase<bool>(
5982       Header() +
5983           "; CHECK-DAG: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5984           "; CHECK: [[int_24:%\\w+]] = OpConstant [[int]] 24\n" +
5985           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5986           "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_24]]\n" +
5987           "%main = OpFunction %void None %void_func\n" +
5988           "%main_lab = OpLabel\n" +
5989           "%var = OpVariable %_ptr_int Function\n" +
5990           "%2 = OpLoad %int %var\n" +
5991           "%3 = OpIMul %int %int_n24 %2\n" +
5992           "%4 = OpSNegate %int %3\n" +
5993           "OpReturn\n" +
5994           "OpFunctionEnd",
5995       4, true),
5996     // Test case 23: fold snegate with OpIMul with UINT_MAX
5997     // -(UINT_MAX * x) = x
5998   InstructionFoldingCase<bool>(
5999       Header() +
6000           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6001           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6002           "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
6003           "%main = OpFunction %void None %void_func\n" +
6004           "%main_lab = OpLabel\n" +
6005           "%var = OpVariable %_ptr_int Function\n" +
6006           "%2 = OpLoad %int %var\n" +
6007           "%3 = OpIMul %int %uint_max %2\n" +
6008           "%4 = OpSNegate %int %3\n" +
6009           "OpReturn\n" +
6010           "OpFunctionEnd",
6011       4, true),
6012     // Test case 24: fold snegate with OpIMul using -INT_MAX
6013     // -(x * 2147483649u) = x * 2147483647u
6014   InstructionFoldingCase<bool>(
6015       Header() +
6016           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6017           "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6018           "; CHECK: [[uint_2147483647:%\\w+]] = OpConstant [[uint]] 2147483647\n" +
6019           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6020           "; CHECK: %4 = OpIMul [[int]] [[ld]] [[uint_2147483647]]\n" +
6021           "%main = OpFunction %void None %void_func\n" +
6022           "%main_lab = OpLabel\n" +
6023           "%var = OpVariable %_ptr_int Function\n" +
6024           "%2 = OpLoad %int %var\n" +
6025           "%3 = OpIMul %int %2 %uint_2147483649\n" +
6026           "%4 = OpSNegate %int %3\n" +
6027           "OpReturn\n" +
6028           "OpFunctionEnd",
6029       4, true),
6030     // Test case 25: fold snegate with OpSDiv (long).
6031     // -(x / 2) = x / -2
6032   InstructionFoldingCase<bool>(
6033       Header() +
6034           "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6035           "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" +
6036           "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6037           "; CHECK: %4 = OpSDiv [[long]] [[ld]] [[long_n2]]\n" +
6038           "%main = OpFunction %void None %void_func\n" +
6039           "%main_lab = OpLabel\n" +
6040           "%var = OpVariable %_ptr_long Function\n" +
6041           "%2 = OpLoad %long %var\n" +
6042           "%3 = OpSDiv %long %2 %long_2\n" +
6043           "%4 = OpSNegate %long %3\n" +
6044           "OpReturn\n" +
6045           "OpFunctionEnd",
6046       4, true),
6047     // Test case 26: fold snegate with OpSDiv (int).
6048     // -(x / 2) = x / -2
6049   InstructionFoldingCase<bool>(
6050       Header() +
6051           "; CHECK-DAG: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6052           "; CHECK-DAG: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6053           "; CHECK: [[uint_n2:%\\w+]] = OpConstant [[uint]] 4294967294\n" +
6054           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6055           "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[uint_n2]]\n" +
6056           "%main = OpFunction %void None %void_func\n" +
6057           "%main_lab = OpLabel\n" +
6058           "%var = OpVariable %_ptr_int Function\n" +
6059           "%2 = OpLoad %int %var\n" +
6060           "%3 = OpSDiv %int %2 %uint_2\n" +
6061           "%4 = OpSNegate %int %3\n" +
6062           "OpReturn\n" +
6063           "OpFunctionEnd",
6064       4, true),
6065     // Test case 27: fold snegate with OpSDiv.
6066     // -(-24 / x) = 24 / x
6067   InstructionFoldingCase<bool>(
6068       Header() +
6069           "; CHECK-DAG: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6070           "; CHECK: [[int_24:%\\w+]] = OpConstant [[int]] 24\n" +
6071           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6072           "; CHECK: %4 = OpSDiv [[int]] [[int_24]] [[ld]]\n" +
6073           "%main = OpFunction %void None %void_func\n" +
6074           "%main_lab = OpLabel\n" +
6075           "%var = OpVariable %_ptr_int Function\n" +
6076           "%2 = OpLoad %int %var\n" +
6077           "%3 = OpSDiv %int %int_n24 %2\n" +
6078           "%4 = OpSNegate %int %3\n" +
6079           "OpReturn\n" +
6080           "OpFunctionEnd",
6081       4, true),
6082     // Test case 28: fold snegate with OpSDiv with UINT_MAX
6083     // -(UINT_MAX / x) = (1 / x)
6084   InstructionFoldingCase<bool>(
6085       Header() +
6086           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6087           "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6088           "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
6089           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6090           "; CHECK: %4 = OpSDiv [[int]] [[uint_1]] [[ld]]\n" +
6091           "%main = OpFunction %void None %void_func\n" +
6092           "%main_lab = OpLabel\n" +
6093           "%var = OpVariable %_ptr_int Function\n" +
6094           "%2 = OpLoad %int %var\n" +
6095           "%3 = OpSDiv %int %uint_max %2\n" +
6096           "%4 = OpSNegate %int %3\n" +
6097           "OpReturn\n" +
6098           "OpFunctionEnd",
6099       4, true),
6100     // Test case 29: fold snegate with OpSDiv using -INT_MAX
6101     // -(x / 2147483647u) = x / 2147483647
6102   InstructionFoldingCase<bool>(
6103       Header() +
6104           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6105           "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6106           "; CHECK: [[uint_2147483647:%\\w+]] = OpConstant [[uint]] 2147483647\n" +
6107           "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6108           "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[uint_2147483647]]\n" +
6109           "%main = OpFunction %void None %void_func\n" +
6110           "%main_lab = OpLabel\n" +
6111           "%var = OpVariable %_ptr_int Function\n" +
6112           "%2 = OpLoad %int %var\n" +
6113           "%3 = OpSDiv %int %2 %uint_2147483649\n" +
6114           "%4 = OpSNegate %int %3\n" +
6115           "OpReturn\n" +
6116           "OpFunctionEnd",
6117       4, true),
6118     // Test case 30: Don't fold snegate int OpUDiv. The operands are interpreted
6119     // as unsigned, so negating an operand is not the same a negating the
6120     // result.
6121   InstructionFoldingCase<bool>(
6122       Header() +
6123           "%main = OpFunction %void None %void_func\n" +
6124           "%main_lab = OpLabel\n" +
6125           "%var = OpVariable %_ptr_int Function\n" +
6126           "%2 = OpLoad %int %var\n" +
6127           "%3 = OpUDiv %int %2 %uint_1\n" +
6128           "%4 = OpSNegate %int %3\n" +
6129           "OpReturn\n" +
6130           "OpFunctionEnd",
6131       4, false)
6132 ));
6133 
6134 INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
6135 ::testing::Values(
6136   // Test case 0: scalar reicprocal
6137   // x / 0.5 = x * 2.0
6138   InstructionFoldingCase<bool>(
6139     Header() +
6140       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6141       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6142       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6143       "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
6144       "%main = OpFunction %void None %void_func\n" +
6145       "%main_lab = OpLabel\n" +
6146       "%var = OpVariable %_ptr_float Function\n" +
6147       "%2 = OpLoad %float %var\n" +
6148       "%3 = OpFDiv %float %2 %float_0p5\n" +
6149       "OpReturn\n" +
6150       "OpFunctionEnd\n",
6151     3, true),
6152   // Test case 1: Unfoldable
6153   InstructionFoldingCase<bool>(
6154     Header() +
6155       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6156       "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
6157       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6158       "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
6159       "%main = OpFunction %void None %void_func\n" +
6160       "%main_lab = OpLabel\n" +
6161       "%var = OpVariable %_ptr_float Function\n" +
6162       "%2 = OpLoad %float %var\n" +
6163       "%3 = OpFDiv %float %2 %104\n" +
6164       "OpReturn\n" +
6165       "OpFunctionEnd\n",
6166     3, false),
6167   // Test case 2: Vector reciprocal
6168   // x / {2.0, 0.5} = x * {0.5, 2.0}
6169   InstructionFoldingCase<bool>(
6170     Header() +
6171       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6172       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6173       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6174       "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
6175       "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
6176       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
6177       "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
6178       "%main = OpFunction %void None %void_func\n" +
6179       "%main_lab = OpLabel\n" +
6180       "%var = OpVariable %_ptr_v2float Function\n" +
6181       "%2 = OpLoad %v2float %var\n" +
6182       "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
6183       "OpReturn\n" +
6184       "OpFunctionEnd\n",
6185     3, true),
6186   // Test case 3: double reciprocal
6187   // x / 2.0 = x * 0.5
6188   InstructionFoldingCase<bool>(
6189     Header() +
6190       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6191       "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
6192       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
6193       "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
6194       "%main = OpFunction %void None %void_func\n" +
6195       "%main_lab = OpLabel\n" +
6196       "%var = OpVariable %_ptr_double Function\n" +
6197       "%2 = OpLoad %double %var\n" +
6198       "%3 = OpFDiv %double %2 %double_2\n" +
6199       "OpReturn\n" +
6200       "OpFunctionEnd\n",
6201     3, true),
6202   // Test case 4: don't fold x / 0.
6203   InstructionFoldingCase<bool>(
6204     Header() +
6205       "%main = OpFunction %void None %void_func\n" +
6206       "%main_lab = OpLabel\n" +
6207       "%var = OpVariable %_ptr_v2float Function\n" +
6208       "%2 = OpLoad %v2float %var\n" +
6209       "%3 = OpFDiv %v2float %2 %v2float_null\n" +
6210       "OpReturn\n" +
6211       "OpFunctionEnd\n",
6212     3, false)
6213 ));
6214 
6215 INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest,
6216 ::testing::Values(
6217   // Test case 0: fold consecutive fmuls
6218   // (x * 3.0) * 2.0 = x * 6.0
6219   InstructionFoldingCase<bool>(
6220     Header() +
6221       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6222       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
6223       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6224       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
6225       "%main = OpFunction %void None %void_func\n" +
6226       "%main_lab = OpLabel\n" +
6227       "%var = OpVariable %_ptr_float Function\n" +
6228       "%2 = OpLoad %float %var\n" +
6229       "%3 = OpFMul %float %2 %float_3\n" +
6230       "%4 = OpFMul %float %3 %float_2\n" +
6231       "OpReturn\n" +
6232       "OpFunctionEnd\n",
6233     4, true),
6234   // Test case 1: fold consecutive fmuls
6235   // 2.0 * (x * 3.0) = x * 6.0
6236   InstructionFoldingCase<bool>(
6237     Header() +
6238       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6239       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
6240       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6241       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
6242       "%main = OpFunction %void None %void_func\n" +
6243       "%main_lab = OpLabel\n" +
6244       "%var = OpVariable %_ptr_float Function\n" +
6245       "%2 = OpLoad %float %var\n" +
6246       "%3 = OpFMul %float %2 %float_3\n" +
6247       "%4 = OpFMul %float %float_2 %3\n" +
6248       "OpReturn\n" +
6249       "OpFunctionEnd\n",
6250     4, true),
6251   // Test case 2: fold consecutive fmuls
6252   // (3.0 * x) * 2.0 = x * 6.0
6253   InstructionFoldingCase<bool>(
6254     Header() +
6255       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6256       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
6257       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6258       "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
6259       "%main = OpFunction %void None %void_func\n" +
6260       "%main_lab = OpLabel\n" +
6261       "%var = OpVariable %_ptr_float Function\n" +
6262       "%2 = OpLoad %float %var\n" +
6263       "%3 = OpFMul %float %float_3 %2\n" +
6264       "%4 = OpFMul %float %float_2 %3\n" +
6265       "OpReturn\n" +
6266       "OpFunctionEnd\n",
6267     4, true),
6268   // Test case 3: fold vector fmul
6269   InstructionFoldingCase<bool>(
6270     Header() +
6271       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6272       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6273       "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
6274       "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
6275       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
6276       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
6277       "%main = OpFunction %void None %void_func\n" +
6278       "%main_lab = OpLabel\n" +
6279       "%var = OpVariable %_ptr_v2float Function\n" +
6280       "%2 = OpLoad %v2float %var\n" +
6281       "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
6282       "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
6283       "OpReturn\n" +
6284       "OpFunctionEnd\n",
6285     4, true),
6286   // Test case 4: fold double fmuls
6287   // (x * 3.0) * 2.0 = x * 6.0
6288   InstructionFoldingCase<bool>(
6289     Header() +
6290       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6291       "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
6292       "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
6293       "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
6294       "%main = OpFunction %void None %void_func\n" +
6295       "%main_lab = OpLabel\n" +
6296       "%var = OpVariable %_ptr_double Function\n" +
6297       "%2 = OpLoad %double %var\n" +
6298       "%3 = OpFMul %double %2 %double_3\n" +
6299       "%4 = OpFMul %double %3 %double_2\n" +
6300       "OpReturn\n" +
6301       "OpFunctionEnd\n",
6302     4, true),
6303   // Test case 5: fold 32 bit imuls
6304   // (x * 3) * 2 = x * 6
6305   InstructionFoldingCase<bool>(
6306     Header() +
6307       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6308       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
6309       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6310       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
6311       "%main = OpFunction %void None %void_func\n" +
6312       "%main_lab = OpLabel\n" +
6313       "%var = OpVariable %_ptr_int Function\n" +
6314       "%2 = OpLoad %int %var\n" +
6315       "%3 = OpIMul %int %2 %int_3\n" +
6316       "%4 = OpIMul %int %3 %int_2\n" +
6317       "OpReturn\n" +
6318       "OpFunctionEnd\n",
6319     4, true),
6320   // Test case 6: fold 64 bit imuls
6321   // (x * 3) * 2 = x * 6
6322   InstructionFoldingCase<bool>(
6323     Header() +
6324       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6325       "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
6326       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6327       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
6328       "%main = OpFunction %void None %void_func\n" +
6329       "%main_lab = OpLabel\n" +
6330       "%var = OpVariable %_ptr_long Function\n" +
6331       "%2 = OpLoad %long %var\n" +
6332       "%3 = OpIMul %long %2 %long_3\n" +
6333       "%4 = OpIMul %long %3 %long_2\n" +
6334       "OpReturn\n" +
6335       "OpFunctionEnd\n",
6336     4, true),
6337   // Test case 7: merge vector integer mults
6338   InstructionFoldingCase<bool>(
6339     Header() +
6340       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6341       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
6342       "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
6343       "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
6344       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6345       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
6346       "%main = OpFunction %void None %void_func\n" +
6347       "%main_lab = OpLabel\n" +
6348       "%var = OpVariable %_ptr_v2int Function\n" +
6349       "%2 = OpLoad %v2int %var\n" +
6350       "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
6351       "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
6352       "OpReturn\n" +
6353       "OpFunctionEnd\n",
6354     4, true),
6355   // Test case 8: merge fmul of fdiv
6356   // 2.0 * (2.0 / x) = 4.0 / x
6357   InstructionFoldingCase<bool>(
6358     Header() +
6359       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6360       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
6361       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6362       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
6363       "%main = OpFunction %void None %void_func\n" +
6364       "%main_lab = OpLabel\n" +
6365       "%var = OpVariable %_ptr_float Function\n" +
6366       "%2 = OpLoad %float %var\n" +
6367       "%3 = OpFDiv %float %float_2 %2\n" +
6368       "%4 = OpFMul %float %float_2 %3\n" +
6369       "OpReturn\n" +
6370       "OpFunctionEnd\n",
6371     4, true),
6372   // Test case 9: merge fmul of fdiv
6373   // (2.0 / x) * 2.0 = 4.0 / x
6374   InstructionFoldingCase<bool>(
6375     Header() +
6376       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6377       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
6378       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6379       "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
6380       "%main = OpFunction %void None %void_func\n" +
6381       "%main_lab = OpLabel\n" +
6382       "%var = OpVariable %_ptr_float Function\n" +
6383       "%2 = OpLoad %float %var\n" +
6384       "%3 = OpFDiv %float %float_2 %2\n" +
6385       "%4 = OpFMul %float %3 %float_2\n" +
6386       "OpReturn\n" +
6387       "OpFunctionEnd\n",
6388     4, true),
6389   // Test case 10: Do not merge imul of sdiv
6390   // 4 * (x / 2)
6391   InstructionFoldingCase<bool>(
6392     Header() +
6393       "%main = OpFunction %void None %void_func\n" +
6394       "%main_lab = OpLabel\n" +
6395       "%var = OpVariable %_ptr_int Function\n" +
6396       "%2 = OpLoad %int %var\n" +
6397       "%3 = OpSDiv %int %2 %int_2\n" +
6398       "%4 = OpIMul %int %int_4 %3\n" +
6399       "OpReturn\n" +
6400       "OpFunctionEnd\n",
6401     4, false),
6402   // Test case 11: Do not merge imul of sdiv
6403   // (x / 2) * 4
6404   InstructionFoldingCase<bool>(
6405     Header() +
6406       "%main = OpFunction %void None %void_func\n" +
6407       "%main_lab = OpLabel\n" +
6408       "%var = OpVariable %_ptr_int Function\n" +
6409       "%2 = OpLoad %int %var\n" +
6410       "%3 = OpSDiv %int %2 %int_2\n" +
6411       "%4 = OpIMul %int %3 %int_4\n" +
6412       "OpReturn\n" +
6413       "OpFunctionEnd\n",
6414     4, false),
6415   // Test case 12: Do not merge imul of udiv
6416   // 4 * (x / 2)
6417   InstructionFoldingCase<bool>(
6418     Header() +
6419       "%main = OpFunction %void None %void_func\n" +
6420       "%main_lab = OpLabel\n" +
6421       "%var = OpVariable %_ptr_uint Function\n" +
6422       "%2 = OpLoad %uint %var\n" +
6423       "%3 = OpUDiv %uint %2 %uint_2\n" +
6424       "%4 = OpIMul %uint %uint_4 %3\n" +
6425       "OpReturn\n" +
6426       "OpFunctionEnd\n",
6427     4, false),
6428   // Test case 13: Do not merge imul of udiv
6429   // (x / 2) * 4
6430   InstructionFoldingCase<bool>(
6431     Header() +
6432       "%main = OpFunction %void None %void_func\n" +
6433       "%main_lab = OpLabel\n" +
6434       "%var = OpVariable %_ptr_uint Function\n" +
6435       "%2 = OpLoad %uint %var\n" +
6436       "%3 = OpUDiv %uint %2 %uint_2\n" +
6437       "%4 = OpIMul %uint %3 %uint_4\n" +
6438       "OpReturn\n" +
6439       "OpFunctionEnd\n",
6440     4, false),
6441   // Test case 14: Don't fold
6442   // (x / 3) * 4
6443   InstructionFoldingCase<bool>(
6444     Header() +
6445       "%main = OpFunction %void None %void_func\n" +
6446       "%main_lab = OpLabel\n" +
6447       "%var = OpVariable %_ptr_uint Function\n" +
6448       "%2 = OpLoad %uint %var\n" +
6449       "%3 = OpUDiv %uint %2 %uint_3\n" +
6450       "%4 = OpIMul %uint %3 %uint_4\n" +
6451       "OpReturn\n" +
6452       "OpFunctionEnd\n",
6453     4, false),
6454   // Test case 15: merge vector fmul of fdiv
6455   // (x / {2,2}) * {4,4} = x * {2,2}
6456   InstructionFoldingCase<bool>(
6457     Header() +
6458       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6459       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6460       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6461       "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
6462       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
6463       "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
6464       "%main = OpFunction %void None %void_func\n" +
6465       "%main_lab = OpLabel\n" +
6466       "%var = OpVariable %_ptr_v2float Function\n" +
6467       "%2 = OpLoad %v2float %var\n" +
6468       "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
6469       "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
6470       "OpReturn\n" +
6471       "OpFunctionEnd\n",
6472     4, true),
6473   // Test case 16: merge vector imul of snegate
6474   // (-x) * {2,2} = x * {-2,-2}
6475   InstructionFoldingCase<bool>(
6476     Header() +
6477       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6478       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6479       "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6480       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6481       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6482       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6483       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6484       "%main = OpFunction %void None %void_func\n" +
6485       "%main_lab = OpLabel\n" +
6486       "%var = OpVariable %_ptr_v2int Function\n" +
6487       "%2 = OpLoad %v2int %var\n" +
6488       "%3 = OpSNegate %v2int %2\n" +
6489       "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
6490       "OpReturn\n" +
6491       "OpFunctionEnd\n",
6492     4, true),
6493   // Test case 17: merge vector imul of snegate
6494   // {2,2} * (-x) = x * {-2,-2}
6495   InstructionFoldingCase<bool>(
6496     Header() +
6497       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6498       "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6499       "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6500       "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6501       "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6502       "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6503       "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6504       "%main = OpFunction %void None %void_func\n" +
6505       "%main_lab = OpLabel\n" +
6506       "%var = OpVariable %_ptr_v2int Function\n" +
6507       "%2 = OpLoad %v2int %var\n" +
6508       "%3 = OpSNegate %v2int %2\n" +
6509       "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
6510       "OpReturn\n" +
6511       "OpFunctionEnd\n",
6512     4, true),
6513   // Test case 18: Fold OpVectorTimesScalar
6514   // {4,4} = OpVectorTimesScalar v2float {2,2} 2
6515   InstructionFoldingCase<bool>(
6516     Header() +
6517       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6518       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6519       "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
6520       "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
6521       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
6522       "%main = OpFunction %void None %void_func\n" +
6523       "%main_lab = OpLabel\n" +
6524       "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
6525       "OpReturn\n" +
6526       "OpFunctionEnd",
6527     2, true),
6528   // Test case 19: Fold OpVectorTimesScalar
6529   // {0,0} = OpVectorTimesScalar v2float v2float_null -1
6530   InstructionFoldingCase<bool>(
6531     Header() +
6532       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6533       "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6534       "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
6535       "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
6536       "%main = OpFunction %void None %void_func\n" +
6537       "%main_lab = OpLabel\n" +
6538       "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
6539       "OpReturn\n" +
6540       "OpFunctionEnd",
6541     2, true),
6542   // Test case 20: Fold OpVectorTimesScalar
6543   // {4,4} = OpVectorTimesScalar v2double {2,2} 2
6544   InstructionFoldingCase<bool>(
6545     Header() +
6546       "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6547       "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6548       "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
6549       "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
6550       "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
6551       "%main = OpFunction %void None %void_func\n" +
6552       "%main_lab = OpLabel\n" +
6553       "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
6554       "OpReturn\n" +
6555       "OpFunctionEnd",
6556     2, true),
6557   // Test case 21: Fold OpVectorTimesScalar
6558   // {0,0} = OpVectorTimesScalar v2double {0,0} n
6559   InstructionFoldingCase<bool>(
6560     Header() +
6561         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6562         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6563         "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
6564         "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
6565         "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
6566         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
6567         "%main = OpFunction %void None %void_func\n" +
6568         "%main_lab = OpLabel\n" +
6569         "%n = OpVariable %_ptr_double Function\n" +
6570         "%load = OpLoad %double %n\n" +
6571         "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
6572         "OpReturn\n" +
6573         "OpFunctionEnd",
6574     2, true),
6575   // Test case 22: Fold OpVectorTimesScalar
6576   // {0,0} = OpVectorTimesScalar v2double n 0
6577   InstructionFoldingCase<bool>(
6578     Header() +
6579         "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6580         "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6581         "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
6582         "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
6583         "%main = OpFunction %void None %void_func\n" +
6584         "%main_lab = OpLabel\n" +
6585         "%n = OpVariable %_ptr_v2double Function\n" +
6586         "%load = OpLoad %v2double %n\n" +
6587         "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
6588         "OpReturn\n" +
6589         "OpFunctionEnd",
6590     2, true),
6591   // Test case 23: merge fmul of fdiv
6592   // x * (y / x) = y
6593   InstructionFoldingCase<bool>(
6594     Header() +
6595         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6596         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6597         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6598         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6599         "%main = OpFunction %void None %void_func\n" +
6600         "%main_lab = OpLabel\n" +
6601         "%x = OpVariable %_ptr_float Function\n" +
6602         "%y = OpVariable %_ptr_float Function\n" +
6603         "%2 = OpLoad %float %x\n" +
6604         "%3 = OpLoad %float %y\n" +
6605         "%4 = OpFDiv %float %3 %2\n" +
6606         "%5 = OpFMul %float %2 %4\n" +
6607         "OpReturn\n" +
6608         "OpFunctionEnd\n",
6609     5, true),
6610   // Test case 24: merge fmul of fdiv
6611   // (y / x) * x = y
6612   InstructionFoldingCase<bool>(
6613     Header() +
6614         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6615         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6616         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6617         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6618         "%main = OpFunction %void None %void_func\n" +
6619         "%main_lab = OpLabel\n" +
6620         "%x = OpVariable %_ptr_float Function\n" +
6621         "%y = OpVariable %_ptr_float Function\n" +
6622         "%2 = OpLoad %float %x\n" +
6623         "%3 = OpLoad %float %y\n" +
6624         "%4 = OpFDiv %float %3 %2\n" +
6625         "%5 = OpFMul %float %4 %2\n" +
6626         "OpReturn\n" +
6627         "OpFunctionEnd\n",
6628     5, true),
6629   // Test case 25: fold overflowing signed 32 bit imuls
6630   // (x * 1073741824) * 2 = x * int_min
6631   InstructionFoldingCase<bool>(
6632     Header() +
6633       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6634       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6635       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6636       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" +
6637       "%main = OpFunction %void None %void_func\n" +
6638       "%main_lab = OpLabel\n" +
6639       "%var = OpVariable %_ptr_int Function\n" +
6640       "%2 = OpLoad %int %var\n" +
6641       "%3 = OpIMul %int %2 %int_1073741824\n" +
6642       "%4 = OpIMul %int %3 %int_2\n" +
6643       "OpReturn\n" +
6644       "OpFunctionEnd\n",
6645     4, true),
6646   // Test case 26: fold overflowing signed 64 bit imuls
6647   // (x * 4611686018427387904) * 2 = x * long_min
6648   InstructionFoldingCase<bool>(
6649     Header() +
6650       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6651       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6652       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6653       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" +
6654       "%main = OpFunction %void None %void_func\n" +
6655       "%main_lab = OpLabel\n" +
6656       "%var = OpVariable %_ptr_long Function\n" +
6657       "%2 = OpLoad %long %var\n" +
6658       "%3 = OpIMul %long %2 %long_4611686018427387904\n" +
6659       "%4 = OpIMul %long %3 %long_2\n" +
6660       "OpReturn\n" +
6661       "OpFunctionEnd\n",
6662     4, true),
6663   // Test case 27: fold overflowing 32 bit unsigned imuls
6664   // (x * 2147483649) * 2 = x * 2
6665   InstructionFoldingCase<bool>(
6666     Header() +
6667       "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6668       "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" +
6669       "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6670       "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" +
6671       "%main = OpFunction %void None %void_func\n" +
6672       "%main_lab = OpLabel\n" +
6673       "%var = OpVariable %_ptr_uint Function\n" +
6674       "%2 = OpLoad %uint %var\n" +
6675       "%3 = OpIMul %uint %2 %uint_2147483649\n" +
6676       "%4 = OpIMul %uint %3 %uint_2\n" +
6677       "OpReturn\n" +
6678       "OpFunctionEnd\n",
6679     4, true),
6680   // Test case 28: fold overflowing 64 bit unsigned imuls
6681   // (x * 9223372036854775809) * 2 = x * 2
6682   InstructionFoldingCase<bool>(
6683     Header() +
6684       "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6685       "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" +
6686       "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6687       "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" +
6688       "%main = OpFunction %void None %void_func\n" +
6689       "%main_lab = OpLabel\n" +
6690       "%var = OpVariable %_ptr_ulong Function\n" +
6691       "%2 = OpLoad %ulong %var\n" +
6692       "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" +
6693       "%4 = OpIMul %ulong %3 %ulong_2\n" +
6694       "OpReturn\n" +
6695       "OpFunctionEnd\n",
6696     4, true),
6697   // Test case 29: fold underflowing signed 32 bit imuls
6698   // (x * (-858993459)) * 10 = x * 2
6699   InstructionFoldingCase<bool>(
6700     Header() +
6701       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6702       "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
6703       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6704       "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" +
6705       "%main = OpFunction %void None %void_func\n" +
6706       "%main_lab = OpLabel\n" +
6707       "%var = OpVariable %_ptr_int Function\n" +
6708       "%2 = OpLoad %int %var\n" +
6709       "%3 = OpIMul %int %2 %int_n858993459\n" +
6710       "%4 = OpIMul %int %3 %int_10\n" +
6711       "OpReturn\n" +
6712       "OpFunctionEnd\n",
6713     4, true),
6714   // Test case 30: fold underflowing signed 64 bit imuls
6715   // (x * (-3689348814741910323)) * 10 = x * 2
6716   InstructionFoldingCase<bool>(
6717     Header() +
6718       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6719       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6720       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6721       "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" +
6722       "%main = OpFunction %void None %void_func\n" +
6723       "%main_lab = OpLabel\n" +
6724       "%var = OpVariable %_ptr_long Function\n" +
6725       "%2 = OpLoad %long %var\n" +
6726       "%3 = OpIMul %long %2 %long_n3689348814741910323\n" +
6727       "%4 = OpIMul %long %3 %long_10\n" +
6728       "OpReturn\n" +
6729       "OpFunctionEnd\n",
6730     4, true)
6731 ));
6732 
6733 INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest,
6734 ::testing::Values(
6735   // Test case 0: merge consecutive fdiv
6736   // 4.0 / (2.0 / x) = 2.0 * x
6737   InstructionFoldingCase<bool>(
6738     Header() +
6739       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6740       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6741       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6742       "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
6743       "%main = OpFunction %void None %void_func\n" +
6744       "%main_lab = OpLabel\n" +
6745       "%var = OpVariable %_ptr_float Function\n" +
6746       "%2 = OpLoad %float %var\n" +
6747       "%3 = OpFDiv %float %float_2 %2\n" +
6748       "%4 = OpFDiv %float %float_4 %3\n" +
6749       "OpReturn\n" +
6750       "OpFunctionEnd\n",
6751     4, true),
6752   // Test case 1: merge consecutive fdiv
6753   // 4.0 / (x / 2.0) = 8.0 / x
6754   InstructionFoldingCase<bool>(
6755     Header() +
6756       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6757       "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
6758       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6759       "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
6760       "%main = OpFunction %void None %void_func\n" +
6761       "%main_lab = OpLabel\n" +
6762       "%var = OpVariable %_ptr_float Function\n" +
6763       "%2 = OpLoad %float %var\n" +
6764       "%3 = OpFDiv %float %2 %float_2\n" +
6765       "%4 = OpFDiv %float %float_4 %3\n" +
6766       "OpReturn\n" +
6767       "OpFunctionEnd\n",
6768     4, true),
6769   // Test case 2: merge consecutive fdiv
6770   // (4.0 / x) / 2.0 = 2.0 / x
6771   InstructionFoldingCase<bool>(
6772     Header() +
6773       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6774       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6775       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6776       "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
6777       "%main = OpFunction %void None %void_func\n" +
6778       "%main_lab = OpLabel\n" +
6779       "%var = OpVariable %_ptr_float Function\n" +
6780       "%2 = OpLoad %float %var\n" +
6781       "%3 = OpFDiv %float %float_4 %2\n" +
6782       "%4 = OpFDiv %float %3 %float_2\n" +
6783       "OpReturn\n" +
6784       "OpFunctionEnd\n",
6785     4, true),
6786   // Test case 3: Do not merge consecutive sdiv
6787   // 4 / (2 / x)
6788   InstructionFoldingCase<bool>(
6789     Header() +
6790       "%main = OpFunction %void None %void_func\n" +
6791       "%main_lab = OpLabel\n" +
6792       "%var = OpVariable %_ptr_int Function\n" +
6793       "%2 = OpLoad %int %var\n" +
6794       "%3 = OpSDiv %int %int_2 %2\n" +
6795       "%4 = OpSDiv %int %int_4 %3\n" +
6796       "OpReturn\n" +
6797       "OpFunctionEnd\n",
6798     4, false),
6799   // Test case 4: Do not merge consecutive sdiv
6800   // 4 / (x / 2)
6801   InstructionFoldingCase<bool>(
6802     Header() +
6803       "%main = OpFunction %void None %void_func\n" +
6804       "%main_lab = OpLabel\n" +
6805       "%var = OpVariable %_ptr_int Function\n" +
6806       "%2 = OpLoad %int %var\n" +
6807       "%3 = OpSDiv %int %2 %int_2\n" +
6808       "%4 = OpSDiv %int %int_4 %3\n" +
6809       "OpReturn\n" +
6810       "OpFunctionEnd\n",
6811     4, false),
6812   // Test case 5: Do not merge consecutive sdiv
6813   // (4 / x) / 2
6814   InstructionFoldingCase<bool>(
6815     Header() +
6816       "%main = OpFunction %void None %void_func\n" +
6817       "%main_lab = OpLabel\n" +
6818       "%var = OpVariable %_ptr_int Function\n" +
6819       "%2 = OpLoad %int %var\n" +
6820       "%3 = OpSDiv %int %int_4 %2\n" +
6821       "%4 = OpSDiv %int %3 %int_2\n" +
6822       "OpReturn\n" +
6823       "OpFunctionEnd\n",
6824     4, false),
6825   // Test case 6: Do not merge consecutive sdiv
6826   // (x / 4) / 2
6827   InstructionFoldingCase<bool>(
6828     Header() +
6829       "%main = OpFunction %void None %void_func\n" +
6830       "%main_lab = OpLabel\n" +
6831       "%var = OpVariable %_ptr_int Function\n" +
6832       "%2 = OpLoad %int %var\n" +
6833       "%3 = OpSDiv %int %2 %int_4\n" +
6834       "%4 = OpSDiv %int %3 %int_2\n" +
6835       "OpReturn\n" +
6836       "OpFunctionEnd\n",
6837     4, false),
6838   // Test case 7: Do not merge sdiv of imul
6839   // 4 / (2 * x)
6840   InstructionFoldingCase<bool>(
6841     Header() +
6842       "%main = OpFunction %void None %void_func\n" +
6843       "%main_lab = OpLabel\n" +
6844       "%var = OpVariable %_ptr_int Function\n" +
6845       "%2 = OpLoad %int %var\n" +
6846       "%3 = OpIMul %int %int_2 %2\n" +
6847       "%4 = OpSDiv %int %int_4 %3\n" +
6848       "OpReturn\n" +
6849       "OpFunctionEnd\n",
6850     4, false),
6851   // Test case 8: Do not merge sdiv of imul
6852   // 4 / (x * 2)
6853   InstructionFoldingCase<bool>(
6854     Header() +
6855       "%main = OpFunction %void None %void_func\n" +
6856       "%main_lab = OpLabel\n" +
6857       "%var = OpVariable %_ptr_int Function\n" +
6858       "%2 = OpLoad %int %var\n" +
6859       "%3 = OpIMul %int %2 %int_2\n" +
6860       "%4 = OpSDiv %int %int_4 %3\n" +
6861       "OpReturn\n" +
6862       "OpFunctionEnd\n",
6863     4, false),
6864   // Test case 9: Do not merge sdiv of imul
6865   // (4 * x) / 2
6866   InstructionFoldingCase<bool>(
6867     Header() +
6868       "%main = OpFunction %void None %void_func\n" +
6869       "%main_lab = OpLabel\n" +
6870       "%var = OpVariable %_ptr_int Function\n" +
6871       "%2 = OpLoad %int %var\n" +
6872       "%3 = OpIMul %int %int_4 %2\n" +
6873       "%4 = OpSDiv %int %3 %int_2\n" +
6874       "OpReturn\n" +
6875       "OpFunctionEnd\n",
6876     4, false),
6877   // Test case 10: Do not merge sdiv of imul
6878   // (x * 4) / 2
6879   InstructionFoldingCase<bool>(
6880     Header() +
6881       "%main = OpFunction %void None %void_func\n" +
6882       "%main_lab = OpLabel\n" +
6883       "%var = OpVariable %_ptr_int Function\n" +
6884       "%2 = OpLoad %int %var\n" +
6885       "%3 = OpIMul %int %2 %int_4\n" +
6886       "%4 = OpSDiv %int %3 %int_2\n" +
6887       "OpReturn\n" +
6888       "OpFunctionEnd\n",
6889     4, false),
6890   // Test case 11: Do not merge sdiv of snegate.  If %2 is INT_MIN, then the
6891   // sign of %3 will be the same as %2.  This cannot be accounted for in OpSDiv.
6892   // Specifically, (-INT_MIN) / 2 != INT_MIN / -2.
6893   InstructionFoldingCase<bool>(
6894     Header() +
6895       "%main = OpFunction %void None %void_func\n" +
6896       "%main_lab = OpLabel\n" +
6897       "%var = OpVariable %_ptr_int Function\n" +
6898       "%2 = OpLoad %int %var\n" +
6899       "%3 = OpSNegate %int %2\n" +
6900       "%4 = OpSDiv %int %3 %int_2\n" +
6901       "OpReturn\n" +
6902       "OpFunctionEnd\n",
6903     4, false),
6904   // Test case 12: Do not merge sdiv of snegate.  If %2 is INT_MIN, then the
6905   // sign of %3 will be the same as %2.  This cannot be accounted for in OpSDiv.
6906   // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN.
6907   InstructionFoldingCase<bool>(
6908     Header() +
6909       "%main = OpFunction %void None %void_func\n" +
6910       "%main_lab = OpLabel\n" +
6911       "%var = OpVariable %_ptr_int Function\n" +
6912       "%2 = OpLoad %int %var\n" +
6913       "%3 = OpSNegate %int %2\n" +
6914       "%4 = OpSDiv %int %int_2 %3\n" +
6915       "OpReturn\n" +
6916       "OpFunctionEnd\n",
6917     4, false),
6918   // Test case 13: Don't merge
6919   // (x / {null}) / {null}
6920   InstructionFoldingCase<bool>(
6921     Header() +
6922       "%main = OpFunction %void None %void_func\n" +
6923       "%main_lab = OpLabel\n" +
6924       "%var = OpVariable %_ptr_v2float Function\n" +
6925       "%2 = OpLoad %float %var\n" +
6926       "%3 = OpFDiv %float %2 %v2float_null\n" +
6927       "%4 = OpFDiv %float %3 %v2float_null\n" +
6928       "OpReturn\n" +
6929       "OpFunctionEnd\n",
6930     4, false),
6931   // Test case 14: merge fmul of fdiv
6932   // (y * x) / x = y
6933   InstructionFoldingCase<bool>(
6934     Header() +
6935         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6936         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6937         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6938         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6939         "%main = OpFunction %void None %void_func\n" +
6940         "%main_lab = OpLabel\n" +
6941         "%x = OpVariable %_ptr_float Function\n" +
6942         "%y = OpVariable %_ptr_float Function\n" +
6943         "%2 = OpLoad %float %x\n" +
6944         "%3 = OpLoad %float %y\n" +
6945         "%4 = OpFMul %float %3 %2\n" +
6946         "%5 = OpFDiv %float %4 %2\n" +
6947         "OpReturn\n" +
6948         "OpFunctionEnd\n",
6949     5, true),
6950   // Test case 15: merge fmul of fdiv
6951   // (x * y) / x = y
6952   InstructionFoldingCase<bool>(
6953     Header() +
6954         "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6955         "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6956         "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6957         "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6958         "%main = OpFunction %void None %void_func\n" +
6959         "%main_lab = OpLabel\n" +
6960         "%x = OpVariable %_ptr_float Function\n" +
6961         "%y = OpVariable %_ptr_float Function\n" +
6962         "%2 = OpLoad %float %x\n" +
6963         "%3 = OpLoad %float %y\n" +
6964         "%4 = OpFMul %float %2 %3\n" +
6965         "%5 = OpFDiv %float %4 %2\n" +
6966         "OpReturn\n" +
6967         "OpFunctionEnd\n",
6968     5, true),
6969   // Test case 16: Do not merge udiv of snegate
6970   // (-x) / 2u
6971   InstructionFoldingCase<bool>(
6972     Header() +
6973       "%main = OpFunction %void None %void_func\n" +
6974       "%main_lab = OpLabel\n" +
6975       "%var = OpVariable %_ptr_uint Function\n" +
6976       "%2 = OpLoad %uint %var\n" +
6977       "%3 = OpSNegate %uint %2\n" +
6978       "%4 = OpUDiv %uint %3 %uint_2\n" +
6979       "OpReturn\n" +
6980       "OpFunctionEnd\n",
6981     4, false),
6982   // Test case 17: Do not merge udiv of snegate
6983   // 2u / (-x)
6984   InstructionFoldingCase<bool>(
6985     Header() +
6986       "%main = OpFunction %void None %void_func\n" +
6987       "%main_lab = OpLabel\n" +
6988       "%var = OpVariable %_ptr_uint Function\n" +
6989       "%2 = OpLoad %uint %var\n" +
6990       "%3 = OpSNegate %uint %2\n" +
6991       "%4 = OpUDiv %uint %uint_2 %3\n" +
6992       "OpReturn\n" +
6993       "OpFunctionEnd\n",
6994     4, false)
6995 ));
6996 
6997 INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest,
6998 ::testing::Values(
6999   // Test case 0: merge add of negate
7000   // (-x) + 2 = 2 - x
7001   InstructionFoldingCase<bool>(
7002     Header() +
7003       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7004       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
7005       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7006       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
7007       "%main = OpFunction %void None %void_func\n" +
7008       "%main_lab = OpLabel\n" +
7009       "%var = OpVariable %_ptr_float Function\n" +
7010       "%2 = OpLoad %float %var\n" +
7011       "%3 = OpFNegate %float %2\n" +
7012       "%4 = OpFAdd %float %3 %float_2\n" +
7013       "OpReturn\n" +
7014       "OpFunctionEnd\n",
7015     4, true),
7016   // Test case 1: merge add of negate
7017   // 2 + (-x) = 2 - x
7018   InstructionFoldingCase<bool>(
7019     Header() +
7020       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7021       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
7022       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7023       "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
7024       "%main = OpFunction %void None %void_func\n" +
7025       "%main_lab = OpLabel\n" +
7026       "%var = OpVariable %_ptr_float Function\n" +
7027       "%2 = OpLoad %float %var\n" +
7028       "%3 = OpSNegate %float %2\n" +
7029       "%4 = OpIAdd %float %float_2 %3\n" +
7030       "OpReturn\n" +
7031       "OpFunctionEnd\n",
7032     4, true),
7033   // Test case 2: merge add of negate
7034   // (-x) + 2 = 2 - x
7035   InstructionFoldingCase<bool>(
7036     Header() +
7037       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7038       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
7039       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7040       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
7041       "%main = OpFunction %void None %void_func\n" +
7042       "%main_lab = OpLabel\n" +
7043       "%var = OpVariable %_ptr_long Function\n" +
7044       "%2 = OpLoad %long %var\n" +
7045       "%3 = OpSNegate %long %2\n" +
7046       "%4 = OpIAdd %long %3 %long_2\n" +
7047       "OpReturn\n" +
7048       "OpFunctionEnd\n",
7049     4, true),
7050   // Test case 3: merge add of negate
7051   // 2 + (-x) = 2 - x
7052   InstructionFoldingCase<bool>(
7053     Header() +
7054       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7055       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
7056       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7057       "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
7058       "%main = OpFunction %void None %void_func\n" +
7059       "%main_lab = OpLabel\n" +
7060       "%var = OpVariable %_ptr_long Function\n" +
7061       "%2 = OpLoad %long %var\n" +
7062       "%3 = OpSNegate %long %2\n" +
7063       "%4 = OpIAdd %long %long_2 %3\n" +
7064       "OpReturn\n" +
7065       "OpFunctionEnd\n",
7066     4, true),
7067   // Test case 4: merge add of subtract
7068   // (x - 1) + 2 = x + 1
7069   InstructionFoldingCase<bool>(
7070     Header() +
7071       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7072       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7073       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7074       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7075       "%main = OpFunction %void None %void_func\n" +
7076       "%main_lab = OpLabel\n" +
7077       "%var = OpVariable %_ptr_float Function\n" +
7078       "%2 = OpLoad %float %var\n" +
7079       "%3 = OpFSub %float %2 %float_1\n" +
7080       "%4 = OpFAdd %float %3 %float_2\n" +
7081       "OpReturn\n" +
7082       "OpFunctionEnd\n",
7083     4, true),
7084   // Test case 5: merge add of subtract
7085   // (1 - x) + 2 = 3 - x
7086   InstructionFoldingCase<bool>(
7087     Header() +
7088       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7089       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7090       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7091       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
7092       "%main = OpFunction %void None %void_func\n" +
7093       "%main_lab = OpLabel\n" +
7094       "%var = OpVariable %_ptr_float Function\n" +
7095       "%2 = OpLoad %float %var\n" +
7096       "%3 = OpFSub %float %float_1 %2\n" +
7097       "%4 = OpFAdd %float %3 %float_2\n" +
7098       "OpReturn\n" +
7099       "OpFunctionEnd\n",
7100     4, true),
7101   // Test case 6: merge add of subtract
7102   // 2 + (x - 1) = x + 1
7103   InstructionFoldingCase<bool>(
7104     Header() +
7105       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7106       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7107       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7108       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7109       "%main = OpFunction %void None %void_func\n" +
7110       "%main_lab = OpLabel\n" +
7111       "%var = OpVariable %_ptr_float Function\n" +
7112       "%2 = OpLoad %float %var\n" +
7113       "%3 = OpFSub %float %2 %float_1\n" +
7114       "%4 = OpFAdd %float %float_2 %3\n" +
7115       "OpReturn\n" +
7116       "OpFunctionEnd\n",
7117     4, true),
7118   // Test case 7: merge add of subtract
7119   // 2 + (1 - x) = 3 - x
7120   InstructionFoldingCase<bool>(
7121     Header() +
7122       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7123       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7124       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7125       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
7126       "%main = OpFunction %void None %void_func\n" +
7127       "%main_lab = OpLabel\n" +
7128       "%var = OpVariable %_ptr_float Function\n" +
7129       "%2 = OpLoad %float %var\n" +
7130       "%3 = OpFSub %float %float_1 %2\n" +
7131       "%4 = OpFAdd %float %float_2 %3\n" +
7132       "OpReturn\n" +
7133       "OpFunctionEnd\n",
7134     4, true),
7135   // Test case 8: merge add of add
7136   // (x + 1) + 2 = x + 3
7137   InstructionFoldingCase<bool>(
7138     Header() +
7139       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7140       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7141       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7142       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
7143       "%main = OpFunction %void None %void_func\n" +
7144       "%main_lab = OpLabel\n" +
7145       "%var = OpVariable %_ptr_float Function\n" +
7146       "%2 = OpLoad %float %var\n" +
7147       "%3 = OpFAdd %float %2 %float_1\n" +
7148       "%4 = OpFAdd %float %3 %float_2\n" +
7149       "OpReturn\n" +
7150       "OpFunctionEnd\n",
7151     4, true),
7152   // Test case 9: merge add of add
7153   // (1 + x) + 2 = 3 + x
7154   InstructionFoldingCase<bool>(
7155     Header() +
7156       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7157       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7158       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7159       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
7160       "%main = OpFunction %void None %void_func\n" +
7161       "%main_lab = OpLabel\n" +
7162       "%var = OpVariable %_ptr_float Function\n" +
7163       "%2 = OpLoad %float %var\n" +
7164       "%3 = OpFAdd %float %float_1 %2\n" +
7165       "%4 = OpFAdd %float %3 %float_2\n" +
7166       "OpReturn\n" +
7167       "OpFunctionEnd\n",
7168     4, true),
7169   // Test case 10: merge add of add
7170   // 2 + (x + 1) = x + 1
7171   InstructionFoldingCase<bool>(
7172     Header() +
7173       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7174       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7175       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7176       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
7177       "%main = OpFunction %void None %void_func\n" +
7178       "%main_lab = OpLabel\n" +
7179       "%var = OpVariable %_ptr_float Function\n" +
7180       "%2 = OpLoad %float %var\n" +
7181       "%3 = OpFAdd %float %2 %float_1\n" +
7182       "%4 = OpFAdd %float %float_2 %3\n" +
7183       "OpReturn\n" +
7184       "OpFunctionEnd\n",
7185     4, true),
7186   // Test case 11: merge add of add
7187   // 2 + (1 + x) = 3 - x
7188   InstructionFoldingCase<bool>(
7189     Header() +
7190       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7191       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7192       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7193       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
7194       "%main = OpFunction %void None %void_func\n" +
7195       "%main_lab = OpLabel\n" +
7196       "%var = OpVariable %_ptr_float Function\n" +
7197       "%2 = OpLoad %float %var\n" +
7198       "%3 = OpFAdd %float %float_1 %2\n" +
7199       "%4 = OpFAdd %float %float_2 %3\n" +
7200       "OpReturn\n" +
7201       "OpFunctionEnd\n",
7202     4, true),
7203   // Test case 12: fold overflowing signed 32 bit iadds
7204   // (x + int_max) + 1 = x + int_min
7205   InstructionFoldingCase<bool>(
7206     Header() +
7207       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
7208       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
7209       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7210       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" +
7211       "%main = OpFunction %void None %void_func\n" +
7212       "%main_lab = OpLabel\n" +
7213       "%var = OpVariable %_ptr_int Function\n" +
7214       "%2 = OpLoad %int %var\n" +
7215       "%3 = OpIAdd %int %2 %int_max\n" +
7216       "%4 = OpIAdd %int %3 %int_1\n" +
7217       "OpReturn\n" +
7218       "OpFunctionEnd\n",
7219     4, true),
7220   // Test case 13: fold overflowing signed 64 bit iadds
7221   // (x + long_max) + 1 = x + long_min
7222   InstructionFoldingCase<bool>(
7223     Header() +
7224       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
7225       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
7226       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7227       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" +
7228       "%main = OpFunction %void None %void_func\n" +
7229       "%main_lab = OpLabel\n" +
7230       "%var = OpVariable %_ptr_long Function\n" +
7231       "%2 = OpLoad %long %var\n" +
7232       "%3 = OpIAdd %long %2 %long_max\n" +
7233       "%4 = OpIAdd %long %3 %long_1\n" +
7234       "OpReturn\n" +
7235       "OpFunctionEnd\n",
7236     4, true),
7237   // Test case 14: fold overflowing 32 bit unsigned iadds
7238   // (x + uint_max) + 2 = x + 1
7239   InstructionFoldingCase<bool>(
7240     Header() +
7241       "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
7242       "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
7243       "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
7244       "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" +
7245       "%main = OpFunction %void None %void_func\n" +
7246       "%main_lab = OpLabel\n" +
7247       "%var = OpVariable %_ptr_uint Function\n" +
7248       "%2 = OpLoad %uint %var\n" +
7249       "%3 = OpIAdd %uint %2 %uint_max\n" +
7250       "%4 = OpIAdd %uint %3 %uint_2\n" +
7251       "OpReturn\n" +
7252       "OpFunctionEnd\n",
7253     4, true),
7254   // Test case 15: fold overflowing 64 bit unsigned iadds
7255   // (x + ulong_max) + 2 = x + 1
7256   InstructionFoldingCase<bool>(
7257     Header() +
7258       "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
7259       "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" +
7260       "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
7261       "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" +
7262       "%main = OpFunction %void None %void_func\n" +
7263       "%main_lab = OpLabel\n" +
7264       "%var = OpVariable %_ptr_ulong Function\n" +
7265       "%2 = OpLoad %ulong %var\n" +
7266       "%3 = OpIAdd %ulong %2 %ulong_max\n" +
7267       "%4 = OpIAdd %ulong %3 %ulong_2\n" +
7268       "OpReturn\n" +
7269       "OpFunctionEnd\n",
7270     4, true),
7271   // Test case 16: fold underflowing signed 32 bit iadds
7272   // (x + int_min) + (-1) = x + int_max
7273   InstructionFoldingCase<bool>(
7274     Header() +
7275       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
7276       "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" +
7277       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7278       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" +
7279       "%main = OpFunction %void None %void_func\n" +
7280       "%main_lab = OpLabel\n" +
7281       "%var = OpVariable %_ptr_int Function\n" +
7282       "%2 = OpLoad %int %var\n" +
7283       "%3 = OpIAdd %int %2 %int_min\n" +
7284       "%4 = OpIAdd %int %3 %int_n1\n" +
7285       "OpReturn\n" +
7286       "OpFunctionEnd\n",
7287     4, true),
7288   // Test case 17: fold underflowing signed 64 bit iadds
7289   // (x + long_min) + (-1) = x + long_max
7290   InstructionFoldingCase<bool>(
7291     Header() +
7292       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
7293       "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" +
7294       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7295       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" +
7296       "%main = OpFunction %void None %void_func\n" +
7297       "%main_lab = OpLabel\n" +
7298       "%var = OpVariable %_ptr_long Function\n" +
7299       "%2 = OpLoad %long %var\n" +
7300       "%3 = OpIAdd %long %2 %long_min\n" +
7301       "%4 = OpIAdd %long %3 %long_n1\n" +
7302       "OpReturn\n" +
7303       "OpFunctionEnd\n",
7304     4, true)
7305 ));
7306 
7307 INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
7308 ::testing::Values(
7309     // Test case 0: merge of add of sub
7310     // (a - b) + b => a
7311     InstructionFoldingCase<bool>(
7312       Header() +
7313       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7314       "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
7315       "%main = OpFunction %void None %void_func\n" +
7316       "%main_lab = OpLabel\n" +
7317       "%var0 = OpVariable %_ptr_float Function\n" +
7318       "%var1 = OpVariable %_ptr_float Function\n" +
7319       "%3 = OpLoad %float %var0\n" +
7320       "%4 = OpLoad %float %var1\n" +
7321       "%5 = OpFSub %float %3 %4\n" +
7322       "%6 = OpFAdd %float %5 %4\n" +
7323       "OpReturn\n" +
7324       "OpFunctionEnd\n",
7325       6, true),
7326   // Test case 1: merge of add of sub
7327   // b + (a - b) => a
7328   InstructionFoldingCase<bool>(
7329     Header() +
7330     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7331     "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
7332     "%main = OpFunction %void None %void_func\n" +
7333     "%main_lab = OpLabel\n" +
7334     "%var0 = OpVariable %_ptr_float Function\n" +
7335     "%var1 = OpVariable %_ptr_float Function\n" +
7336     "%3 = OpLoad %float %var0\n" +
7337     "%4 = OpLoad %float %var1\n" +
7338     "%5 = OpFSub %float %3 %4\n" +
7339     "%6 = OpFAdd %float %4 %5\n" +
7340     "OpReturn\n" +
7341     "OpFunctionEnd\n",
7342     6, true)
7343 ));
7344 
7345 INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
7346 ::testing::Values(
7347     // Test case 0: factor of add of muls
7348     // (a * b) + (a * c) => a * (b + c)
7349     InstructionFoldingCase<bool>(
7350       Header() +
7351       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7352       "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
7353       "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
7354       "%main = OpFunction %void None %void_func\n" +
7355       "%main_lab = OpLabel\n" +
7356       "%var0 = OpVariable %_ptr_float Function\n" +
7357       "%var1 = OpVariable %_ptr_float Function\n" +
7358       "%var2 = OpVariable %_ptr_float Function\n" +
7359       "%4 = OpLoad %float %var0\n" +
7360       "%5 = OpLoad %float %var1\n" +
7361       "%6 = OpLoad %float %var2\n" +
7362       "%7 = OpFMul %float %6 %4\n" +
7363       "%8 = OpFMul %float %6 %5\n" +
7364       "%9 = OpFAdd %float %7 %8\n" +
7365       "OpReturn\n" +
7366       "OpFunctionEnd\n",
7367       9, true),
7368   // Test case 1: factor of add of muls
7369   // (b * a) + (a * c) => a * (b + c)
7370   InstructionFoldingCase<bool>(
7371     Header() +
7372     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7373     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
7374     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
7375     "%main = OpFunction %void None %void_func\n" +
7376     "%main_lab = OpLabel\n" +
7377     "%var0 = OpVariable %_ptr_float Function\n" +
7378     "%var1 = OpVariable %_ptr_float Function\n" +
7379     "%var2 = OpVariable %_ptr_float Function\n" +
7380     "%4 = OpLoad %float %var0\n" +
7381     "%5 = OpLoad %float %var1\n" +
7382     "%6 = OpLoad %float %var2\n" +
7383     "%7 = OpFMul %float %4 %6\n" +
7384     "%8 = OpFMul %float %6 %5\n" +
7385     "%9 = OpFAdd %float %7 %8\n" +
7386     "OpReturn\n" +
7387     "OpFunctionEnd\n",
7388     9, true),
7389   // Test case 2: factor of add of muls
7390   // (a * b) + (c * a) => a * (b + c)
7391   InstructionFoldingCase<bool>(
7392     Header() +
7393     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7394     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
7395     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
7396     "%main = OpFunction %void None %void_func\n" +
7397     "%main_lab = OpLabel\n" +
7398     "%var0 = OpVariable %_ptr_float Function\n" +
7399     "%var1 = OpVariable %_ptr_float Function\n" +
7400     "%var2 = OpVariable %_ptr_float Function\n" +
7401     "%4 = OpLoad %float %var0\n" +
7402     "%5 = OpLoad %float %var1\n" +
7403     "%6 = OpLoad %float %var2\n" +
7404     "%7 = OpFMul %float %6 %4\n" +
7405     "%8 = OpFMul %float %5 %6\n" +
7406     "%9 = OpFAdd %float %7 %8\n" +
7407     "OpReturn\n" +
7408     "OpFunctionEnd\n",
7409     9, true),
7410   // Test case 3: factor of add of muls
7411   // (b * a) + (c * a) => a * (b + c)
7412   InstructionFoldingCase<bool>(
7413     Header() +
7414     "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7415     "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
7416     "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
7417     "%main = OpFunction %void None %void_func\n" +
7418     "%main_lab = OpLabel\n" +
7419     "%var0 = OpVariable %_ptr_float Function\n" +
7420     "%var1 = OpVariable %_ptr_float Function\n" +
7421     "%var2 = OpVariable %_ptr_float Function\n" +
7422     "%4 = OpLoad %float %var0\n" +
7423     "%5 = OpLoad %float %var1\n" +
7424     "%6 = OpLoad %float %var2\n" +
7425     "%7 = OpFMul %float %4 %6\n" +
7426     "%8 = OpFMul %float %5 %6\n" +
7427     "%9 = OpFAdd %float %7 %8\n" +
7428     "OpReturn\n" +
7429     "OpFunctionEnd\n",
7430     9, true)
7431 ));
7432 
7433 INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
7434 ::testing::Values(
7435   // Test case 0: merge sub of negate
7436   // (-x) - 2 = -2 - x
7437   InstructionFoldingCase<bool>(
7438     Header() +
7439       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7440       "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
7441       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7442       "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
7443       "%main = OpFunction %void None %void_func\n" +
7444       "%main_lab = OpLabel\n" +
7445       "%var = OpVariable %_ptr_float Function\n" +
7446       "%2 = OpLoad %float %var\n" +
7447       "%3 = OpFNegate %float %2\n" +
7448       "%4 = OpFSub %float %3 %float_2\n" +
7449       "OpReturn\n" +
7450       "OpFunctionEnd\n",
7451     4, true),
7452   // Test case 1: merge sub of negate
7453   // 2 - (-x) = x + 2
7454   InstructionFoldingCase<bool>(
7455     Header() +
7456       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7457       "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
7458       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7459       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
7460       "%main = OpFunction %void None %void_func\n" +
7461       "%main_lab = OpLabel\n" +
7462       "%var = OpVariable %_ptr_float Function\n" +
7463       "%2 = OpLoad %float %var\n" +
7464       "%3 = OpFNegate %float %2\n" +
7465       "%4 = OpFSub %float %float_2 %3\n" +
7466       "OpReturn\n" +
7467       "OpFunctionEnd\n",
7468     4, true),
7469   // Test case 2: merge sub of negate
7470   // (-x) - 2 = -2 - x
7471   InstructionFoldingCase<bool>(
7472     Header() +
7473       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7474       "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
7475       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7476       "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
7477       "%main = OpFunction %void None %void_func\n" +
7478       "%main_lab = OpLabel\n" +
7479       "%var = OpVariable %_ptr_long Function\n" +
7480       "%2 = OpLoad %long %var\n" +
7481       "%3 = OpSNegate %long %2\n" +
7482       "%4 = OpISub %long %3 %long_2\n" +
7483       "OpReturn\n" +
7484       "OpFunctionEnd\n",
7485     4, true),
7486   // Test case 3: merge sub of negate
7487   // 2 - (-x) = x + 2
7488   InstructionFoldingCase<bool>(
7489     Header() +
7490       "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7491       "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
7492       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7493       "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
7494       "%main = OpFunction %void None %void_func\n" +
7495       "%main_lab = OpLabel\n" +
7496       "%var = OpVariable %_ptr_long Function\n" +
7497       "%2 = OpLoad %long %var\n" +
7498       "%3 = OpSNegate %long %2\n" +
7499       "%4 = OpISub %long %long_2 %3\n" +
7500       "OpReturn\n" +
7501       "OpFunctionEnd\n",
7502     4, true),
7503   // Test case 4: merge add of subtract
7504   // (x + 2) - 1 = x + 1
7505   InstructionFoldingCase<bool>(
7506     Header() +
7507       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7508       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7509       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7510       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7511       "%main = OpFunction %void None %void_func\n" +
7512       "%main_lab = OpLabel\n" +
7513       "%var = OpVariable %_ptr_float Function\n" +
7514       "%2 = OpLoad %float %var\n" +
7515       "%3 = OpFAdd %float %2 %float_2\n" +
7516       "%4 = OpFSub %float %3 %float_1\n" +
7517       "OpReturn\n" +
7518       "OpFunctionEnd\n",
7519     4, true),
7520   // Test case 5: merge add of subtract
7521   // (2 + x) - 1 = x + 1
7522   InstructionFoldingCase<bool>(
7523     Header() +
7524       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7525       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7526       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7527       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7528       "%main = OpFunction %void None %void_func\n" +
7529       "%main_lab = OpLabel\n" +
7530       "%var = OpVariable %_ptr_float Function\n" +
7531       "%2 = OpLoad %float %var\n" +
7532       "%3 = OpFAdd %float %float_2 %2\n" +
7533       "%4 = OpFSub %float %3 %float_1\n" +
7534       "OpReturn\n" +
7535       "OpFunctionEnd\n",
7536     4, true),
7537   // Test case 6: merge add of subtract
7538   // 2 - (x + 1) = 1 - x
7539   InstructionFoldingCase<bool>(
7540     Header() +
7541       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7542       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7543       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7544       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7545       "%main = OpFunction %void None %void_func\n" +
7546       "%main_lab = OpLabel\n" +
7547       "%var = OpVariable %_ptr_float Function\n" +
7548       "%2 = OpLoad %float %var\n" +
7549       "%3 = OpFAdd %float %2 %float_1\n" +
7550       "%4 = OpFSub %float %float_2 %3\n" +
7551       "OpReturn\n" +
7552       "OpFunctionEnd\n",
7553     4, true),
7554   // Test case 7: merge add of subtract
7555   // 2 - (1 + x) = 1 - x
7556   InstructionFoldingCase<bool>(
7557     Header() +
7558       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7559       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7560       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7561       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7562       "%main = OpFunction %void None %void_func\n" +
7563       "%main_lab = OpLabel\n" +
7564       "%var = OpVariable %_ptr_float Function\n" +
7565       "%2 = OpLoad %float %var\n" +
7566       "%3 = OpFAdd %float %float_1 %2\n" +
7567       "%4 = OpFSub %float %float_2 %3\n" +
7568       "OpReturn\n" +
7569       "OpFunctionEnd\n",
7570     4, true),
7571   // Test case 8: merge subtract of subtract
7572   // (x - 2) - 1 = x - 3
7573   InstructionFoldingCase<bool>(
7574     Header() +
7575       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7576       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7577       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7578       "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
7579       "%main = OpFunction %void None %void_func\n" +
7580       "%main_lab = OpLabel\n" +
7581       "%var = OpVariable %_ptr_float Function\n" +
7582       "%2 = OpLoad %float %var\n" +
7583       "%3 = OpFSub %float %2 %float_2\n" +
7584       "%4 = OpFSub %float %3 %float_1\n" +
7585       "OpReturn\n" +
7586       "OpFunctionEnd\n",
7587     4, true),
7588   // Test case 9: merge subtract of subtract
7589   // (2 - x) - 1 = 1 - x
7590   InstructionFoldingCase<bool>(
7591     Header() +
7592       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7593       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7594       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7595       "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7596       "%main = OpFunction %void None %void_func\n" +
7597       "%main_lab = OpLabel\n" +
7598       "%var = OpVariable %_ptr_float Function\n" +
7599       "%2 = OpLoad %float %var\n" +
7600       "%3 = OpFSub %float %float_2 %2\n" +
7601       "%4 = OpFSub %float %3 %float_1\n" +
7602       "OpReturn\n" +
7603       "OpFunctionEnd\n",
7604     4, true),
7605   // Test case 10: merge subtract of subtract
7606   // 2 - (x - 1) = 3 - x
7607   InstructionFoldingCase<bool>(
7608     Header() +
7609       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7610       "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7611       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7612       "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
7613       "%main = OpFunction %void None %void_func\n" +
7614       "%main_lab = OpLabel\n" +
7615       "%var = OpVariable %_ptr_float Function\n" +
7616       "%2 = OpLoad %float %var\n" +
7617       "%3 = OpFSub %float %2 %float_1\n" +
7618       "%4 = OpFSub %float %float_2 %3\n" +
7619       "OpReturn\n" +
7620       "OpFunctionEnd\n",
7621     4, true),
7622   // Test case 11: merge subtract of subtract
7623   // 1 - (2 - x) = x + (-1)
7624   InstructionFoldingCase<bool>(
7625     Header() +
7626       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7627       "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
7628       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7629       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
7630       "%main = OpFunction %void None %void_func\n" +
7631       "%main_lab = OpLabel\n" +
7632       "%var = OpVariable %_ptr_float Function\n" +
7633       "%2 = OpLoad %float %var\n" +
7634       "%3 = OpFSub %float %float_2 %2\n" +
7635       "%4 = OpFSub %float %float_1 %3\n" +
7636       "OpReturn\n" +
7637       "OpFunctionEnd\n",
7638     4, true),
7639   // Test case 12: merge subtract of subtract
7640   // 2 - (1 - x) = x + 1
7641   InstructionFoldingCase<bool>(
7642     Header() +
7643       "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7644       "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7645       "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7646       "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7647       "%main = OpFunction %void None %void_func\n" +
7648       "%main_lab = OpLabel\n" +
7649       "%var = OpVariable %_ptr_float Function\n" +
7650       "%2 = OpLoad %float %var\n" +
7651       "%3 = OpFSub %float %float_1 %2\n" +
7652       "%4 = OpFSub %float %float_2 %3\n" +
7653       "OpReturn\n" +
7654       "OpFunctionEnd\n",
7655     4, true),
7656   // Test case 13: merge subtract of subtract with mixed types.
7657   // 2 - (1 - x) = x + 1
7658   InstructionFoldingCase<bool>(
7659     Header() +
7660       "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7661       "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" +
7662       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7663       "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" +
7664       "%main = OpFunction %void None %void_func\n" +
7665       "%main_lab = OpLabel\n" +
7666       "%var = OpVariable %_ptr_int Function\n" +
7667       "%2 = OpLoad %int %var\n" +
7668       "%3 = OpISub %int %uint_1 %2\n" +
7669       "%4 = OpISub %int %int_2 %3\n" +
7670       "OpReturn\n" +
7671       "OpFunctionEnd\n",
7672     4, true),
7673   // Test case 14: fold overflowing signed 32 bit isubs
7674   // (x - int_max) - 1 = x - int_min
7675   InstructionFoldingCase<bool>(
7676     Header() +
7677       "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
7678       "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
7679       "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7680       "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" +
7681       "%main = OpFunction %void None %void_func\n" +
7682       "%main_lab = OpLabel\n" +
7683       "%var = OpVariable %_ptr_int Function\n" +
7684       "%2 = OpLoad %int %var\n" +
7685       "%3 = OpISub %int %2 %int_max\n" +
7686       "%4 = OpISub %int %3 %int_1\n" +
7687       "OpReturn\n" +
7688       "OpFunctionEnd\n",
7689     4, true),
7690   // Test case 15: fold overflowing signed 64 bit isubs
7691   // (x - long_max) - 1 = x - long_min
7692   InstructionFoldingCase<bool>(
7693     Header() +
7694       "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
7695       "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
7696       "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7697       "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" +
7698       "%main = OpFunction %void None %void_func\n" +
7699       "%main_lab = OpLabel\n" +
7700       "%var = OpVariable %_ptr_long Function\n" +
7701       "%2 = OpLoad %long %var\n" +
7702       "%3 = OpISub %long %2 %long_max\n" +
7703       "%4 = OpISub %long %3 %long_1\n" +
7704       "OpReturn\n" +
7705       "OpFunctionEnd\n",
7706     4, true)
7707 ));
7708 
7709 INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
7710 ::testing::Values(
7711   // Test case 0: Fold select with the same values for both sides
7712   InstructionFoldingCase<bool>(
7713       Header() +
7714           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7715           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7716           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7717           "%main = OpFunction %void None %void_func\n" +
7718           "%main_lab = OpLabel\n" +
7719           "%n = OpVariable %_ptr_bool Function\n" +
7720           "%load = OpLoad %bool %n\n" +
7721           "%2 = OpSelect %int %load %100 %100\n" +
7722           "OpReturn\n" +
7723           "OpFunctionEnd",
7724       2, true),
7725   // Test case 1: Fold select true to left side
7726   InstructionFoldingCase<bool>(
7727       Header() +
7728           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7729           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7730           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7731           "%main = OpFunction %void None %void_func\n" +
7732           "%main_lab = OpLabel\n" +
7733           "%n = OpVariable %_ptr_int Function\n" +
7734           "%load = OpLoad %bool %n\n" +
7735           "%2 = OpSelect %int %true %100 %n\n" +
7736           "OpReturn\n" +
7737           "OpFunctionEnd",
7738       2, true),
7739   // Test case 2: Fold select false to right side
7740   InstructionFoldingCase<bool>(
7741       Header() +
7742           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7743           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7744           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7745           "%main = OpFunction %void None %void_func\n" +
7746           "%main_lab = OpLabel\n" +
7747           "%n = OpVariable %_ptr_int Function\n" +
7748           "%load = OpLoad %bool %n\n" +
7749           "%2 = OpSelect %int %false %n %100\n" +
7750           "OpReturn\n" +
7751           "OpFunctionEnd",
7752       2, true),
7753   // Test case 3: Fold select null to right side
7754   InstructionFoldingCase<bool>(
7755       Header() +
7756           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7757           "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7758           "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7759           "%main = OpFunction %void None %void_func\n" +
7760           "%main_lab = OpLabel\n" +
7761           "%n = OpVariable %_ptr_int Function\n" +
7762           "%load = OpLoad %int %n\n" +
7763           "%2 = OpSelect %int %bool_null %load %100\n" +
7764           "OpReturn\n" +
7765           "OpFunctionEnd",
7766       2, true),
7767   // Test case 4: vector null
7768   InstructionFoldingCase<bool>(
7769       Header() +
7770           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7771           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7772           "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7773           "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
7774           "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
7775           "%main = OpFunction %void None %void_func\n" +
7776           "%main_lab = OpLabel\n" +
7777           "%n = OpVariable %_ptr_v2int Function\n" +
7778           "%load = OpLoad %v2int %n\n" +
7779           "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
7780           "OpReturn\n" +
7781           "OpFunctionEnd",
7782       2, true),
7783   // Test case 5: vector select
7784   InstructionFoldingCase<bool>(
7785       Header() +
7786           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7787           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7788           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
7789           "%main = OpFunction %void None %void_func\n" +
7790           "%main_lab = OpLabel\n" +
7791           "%m = OpVariable %_ptr_v2int Function\n" +
7792           "%n = OpVariable %_ptr_v2int Function\n" +
7793           "%2 = OpLoad %v2int %n\n" +
7794           "%3 = OpLoad %v2int %n\n" +
7795           "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
7796           "OpReturn\n" +
7797           "OpFunctionEnd",
7798       4, true),
7799   // Test case 6: vector select
7800   InstructionFoldingCase<bool>(
7801       Header() +
7802           "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7803           "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7804           "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
7805           "%main = OpFunction %void None %void_func\n" +
7806           "%main_lab = OpLabel\n" +
7807           "%m = OpVariable %_ptr_v2int Function\n" +
7808           "%n = OpVariable %_ptr_v2int Function\n" +
7809           "%2 = OpLoad %v2int %n\n" +
7810           "%3 = OpLoad %v2int %n\n" +
7811           "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
7812           "OpReturn\n" +
7813           "OpFunctionEnd",
7814       4, true)
7815 ));
7816 
7817 INSTANTIATE_TEST_SUITE_P(CompositeExtractOrInsertMatchingTest, MatchingInstructionFoldingTest,
7818 ::testing::Values(
7819     // Test case 0: Extracting from result of consecutive shuffles of differing
7820     // size.
7821     InstructionFoldingCase<bool>(
7822         Header() +
7823             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7824             "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
7825             "%main = OpFunction %void None %void_func\n" +
7826             "%main_lab = OpLabel\n" +
7827             "%n = OpVariable %_ptr_v4int Function\n" +
7828             "%2 = OpLoad %v4int %n\n" +
7829             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7830             "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
7831             "%5 = OpCompositeExtract %int %4 1\n" +
7832             "OpReturn\n" +
7833             "OpFunctionEnd",
7834         5, true),
7835     // Test case 1: Extracting from result of vector shuffle of differing
7836     // input and result sizes.
7837     InstructionFoldingCase<bool>(
7838         Header() +
7839             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7840             "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
7841             "%main = OpFunction %void None %void_func\n" +
7842             "%main_lab = OpLabel\n" +
7843             "%n = OpVariable %_ptr_v4int Function\n" +
7844             "%2 = OpLoad %v4int %n\n" +
7845             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7846             "%4 = OpCompositeExtract %int %3 0\n" +
7847             "OpReturn\n" +
7848             "OpFunctionEnd",
7849         4, true),
7850     // Test case 2: Extracting from result of vector shuffle of differing
7851     // input and result sizes.
7852     InstructionFoldingCase<bool>(
7853         Header() +
7854             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7855             "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
7856             "%main = OpFunction %void None %void_func\n" +
7857             "%main_lab = OpLabel\n" +
7858             "%n = OpVariable %_ptr_v4int Function\n" +
7859             "%2 = OpLoad %v4int %n\n" +
7860             "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7861             "%4 = OpCompositeExtract %int %3 1\n" +
7862             "OpReturn\n" +
7863             "OpFunctionEnd",
7864         4, true),
7865     // Test case 3: Using fmix feeding extract with a 1 in the a position.
7866     InstructionFoldingCase<bool>(
7867         Header() +
7868             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7869             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7870             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7871             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7872             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7873             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
7874             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
7875             "%main = OpFunction %void None %void_func\n" +
7876             "%main_lab = OpLabel\n" +
7877             "%m = OpVariable %_ptr_v4double Function\n" +
7878             "%n = OpVariable %_ptr_v4double Function\n" +
7879             "%2 = OpLoad %v4double %m\n" +
7880             "%3 = OpLoad %v4double %n\n" +
7881             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7882             "%5 = OpCompositeExtract %double %4 1\n" +
7883             "OpReturn\n" +
7884             "OpFunctionEnd",
7885         5, true),
7886     // Test case 4: Using fmix feeding extract with a 0 in the a position.
7887     InstructionFoldingCase<bool>(
7888         Header() +
7889             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7890             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7891             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7892             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7893             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7894             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7895             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
7896             "%main = OpFunction %void None %void_func\n" +
7897             "%main_lab = OpLabel\n" +
7898             "%m = OpVariable %_ptr_v4double Function\n" +
7899             "%n = OpVariable %_ptr_v4double Function\n" +
7900             "%2 = OpLoad %v4double %m\n" +
7901             "%3 = OpLoad %v4double %n\n" +
7902             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7903             "%5 = OpCompositeExtract %double %4 2\n" +
7904             "OpReturn\n" +
7905             "OpFunctionEnd",
7906         5, true),
7907     // Test case 5: Using fmix feeding extract with a null for the alpha
7908     InstructionFoldingCase<bool>(
7909         Header() +
7910             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7911             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7912             "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7913             "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7914             "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7915             "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7916             "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
7917             "%main = OpFunction %void None %void_func\n" +
7918             "%main_lab = OpLabel\n" +
7919             "%m = OpVariable %_ptr_v4double Function\n" +
7920             "%n = OpVariable %_ptr_v4double Function\n" +
7921             "%2 = OpLoad %v4double %m\n" +
7922             "%3 = OpLoad %v4double %n\n" +
7923             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
7924             "%5 = OpCompositeExtract %double %4 0\n" +
7925             "OpReturn\n" +
7926             "OpFunctionEnd",
7927         5, true),
7928     // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
7929     // position.
7930     InstructionFoldingCase<bool>(
7931         Header() +
7932             "%main = OpFunction %void None %void_func\n" +
7933             "%main_lab = OpLabel\n" +
7934             "%m = OpVariable %_ptr_v4double Function\n" +
7935             "%n = OpVariable %_ptr_v4double Function\n" +
7936             "%2 = OpLoad %v4double %m\n" +
7937             "%3 = OpLoad %v4double %n\n" +
7938             "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
7939             "%5 = OpCompositeExtract %double %4 3\n" +
7940             "OpReturn\n" +
7941             "OpFunctionEnd",
7942         5, false),
7943     // Test case 7: Extracting the undefined literal value from a vector
7944     // shuffle.
7945     InstructionFoldingCase<bool>(
7946         Header() +
7947             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7948             "; CHECK: %4 = OpUndef [[int]]\n" +
7949             "%main = OpFunction %void None %void_func\n" +
7950             "%main_lab = OpLabel\n" +
7951             "%n = OpVariable %_ptr_v4int Function\n" +
7952             "%2 = OpLoad %v4int %n\n" +
7953             "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
7954             "%4 = OpCompositeExtract %int %3 1\n" +
7955             "OpReturn\n" +
7956             "OpFunctionEnd",
7957         4, true),
7958     // Test case 8: Inserting every element of a vector turns into a composite construct.
7959     InstructionFoldingCase<bool>(
7960         Header() +
7961             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7962             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7963             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7964             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7965             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7966             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7967             "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7968             "%main = OpFunction %void None %void_func\n" +
7969             "%main_lab = OpLabel\n" +
7970             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7971             "%3 = OpCompositeInsert %v4int %int_1 %2 1\n" +
7972             "%4 = OpCompositeInsert %v4int %int_2 %3 2\n" +
7973             "%5 = OpCompositeInsert %v4int %int_3 %4 3\n" +
7974             "OpReturn\n" +
7975             "OpFunctionEnd",
7976         5, true),
7977     // Test case 9: Inserting every element of a vector turns into a composite construct in a different order.
7978     InstructionFoldingCase<bool>(
7979         Header() +
7980             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7981             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7982             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7983             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7984             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7985             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7986             "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7987             "%main = OpFunction %void None %void_func\n" +
7988             "%main_lab = OpLabel\n" +
7989             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7990             "%4 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7991             "%3 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7992             "%5 = OpCompositeInsert %v4int %int_3 %3 3\n" +
7993             "OpReturn\n" +
7994             "OpFunctionEnd",
7995         5, true),
7996     // Test case 10: Check multiple inserts to the same position are handled correctly.
7997     InstructionFoldingCase<bool>(
7998         Header() +
7999             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8000             "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
8001             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
8002             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
8003             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
8004             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
8005             "; CHECK: %6 = OpCopyObject [[v4]] [[construct]]\n" +
8006             "%main = OpFunction %void None %void_func\n" +
8007             "%main_lab = OpLabel\n" +
8008             "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
8009             "%3 = OpCompositeInsert %v4int %int_2 %2 2\n" +
8010             "%4 = OpCompositeInsert %v4int %int_4 %3 1\n" +
8011             "%5 = OpCompositeInsert %v4int %int_1 %4 1\n" +
8012             "%6 = OpCompositeInsert %v4int %int_3 %5 3\n" +
8013             "OpReturn\n" +
8014             "OpFunctionEnd",
8015         6, true),
8016     // Test case 11: The last indexes are 0 and 1, but they have different first indexes.  This should not be folded.
8017     InstructionFoldingCase<bool>(
8018         Header() +
8019             "%main = OpFunction %void None %void_func\n" +
8020             "%main_lab = OpLabel\n" +
8021             "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
8022             "%3 = OpCompositeInsert %m2x2int %int_1 %2 1 1\n" +
8023             "OpReturn\n" +
8024             "OpFunctionEnd",
8025         3, false),
8026     // Test case 12: Don't fold when there is a partial insertion.
8027     InstructionFoldingCase<bool>(
8028         Header() +
8029             "%main = OpFunction %void None %void_func\n" +
8030             "%main_lab = OpLabel\n" +
8031             "%2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0\n" +
8032             "%3 = OpCompositeInsert %m2x2int %int_4 %2 0 0\n" +
8033             "%4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1\n" +
8034             "OpReturn\n" +
8035             "OpFunctionEnd",
8036         4, false),
8037     // Test case 13: Insert into a column of a matrix
8038     InstructionFoldingCase<bool>(
8039         Header() +
8040             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8041             "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
8042             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
8043             "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
8044             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
8045 // We keep this insert in the chain.  DeadInsertElimPass should remove it.
8046             "; CHECK: [[insert:%\\w+]] = OpCompositeInsert [[m2x2]] %100 [[m2x2_undef]] 0 0\n" +
8047             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
8048             "; CHECK: %3 = OpCompositeInsert [[m2x2]] [[construct]] [[insert]] 0\n" +
8049             "%main = OpFunction %void None %void_func\n" +
8050             "%main_lab = OpLabel\n" +
8051             "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
8052             "%3 = OpCompositeInsert %m2x2int %int_1 %2 0 1\n" +
8053             "OpReturn\n" +
8054             "OpFunctionEnd",
8055         3, true),
8056     // Test case 14: Insert all elements of the matrix.
8057     InstructionFoldingCase<bool>(
8058         Header() +
8059             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8060             "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
8061             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
8062             "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
8063             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
8064             "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
8065             "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
8066             "; CHECK: [[c0:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
8067             "; CHECK: [[c1:%\\w+]] = OpCompositeConstruct [[v2]] [[int2]] [[int3]]\n" +
8068             "; CHECK: [[matrix:%\\w+]] = OpCompositeConstruct [[m2x2]] [[c0]] [[c1]]\n" +
8069             "; CHECK: %5 = OpCopyObject [[m2x2]] [[matrix]]\n" +
8070             "%main = OpFunction %void None %void_func\n" +
8071             "%main_lab = OpLabel\n" +
8072             "%2 = OpCompositeConstruct %v2int %100 %int_1\n" +
8073             "%3 = OpCompositeInsert %m2x2int %2 %m2x2int_undef 0\n" +
8074             "%4 = OpCompositeInsert %m2x2int %int_2 %3 1 0\n" +
8075             "%5 = OpCompositeInsert %m2x2int %int_3 %4 1 1\n" +
8076             "OpReturn\n" +
8077             "OpFunctionEnd",
8078         5, true),
8079     // Test case 15: Replace construct with extract when reconstructing a member
8080     // of another object.
8081     InstructionFoldingCase<bool>(
8082         Header() +
8083             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8084             "; CHECK: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
8085             "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
8086             "; CHECK: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
8087             "; CHECK: %5 = OpCompositeExtract [[v2]] [[m2x2_undef]]\n" +
8088             "%main = OpFunction %void None %void_func\n" +
8089             "%main_lab = OpLabel\n" +
8090             "%3 = OpCompositeExtract %int %m2x2int_undef 1 0\n" +
8091             "%4 = OpCompositeExtract %int %m2x2int_undef 1 1\n" +
8092             "%5 = OpCompositeConstruct %v2int %3 %4\n" +
8093             "OpReturn\n" +
8094             "OpFunctionEnd",
8095         5, true),
8096     // Test case 16: Don't fold when type cannot be deduced to a constant.
8097     InstructionFoldingCase<bool>(
8098         Header() +
8099             "%main = OpFunction %void None %void_func\n" +
8100             "%main_lab = OpLabel\n" +
8101             "%4 = OpCompositeInsert %struct_v2int_int_int %int_1 %struct_v2int_int_int_null 2\n" +
8102             "OpReturn\n" +
8103             "OpFunctionEnd",
8104         4, false),
8105     // Test case 17: Don't fold when index into composite is out of bounds.
8106     InstructionFoldingCase<bool>(
8107 	Header() +
8108             "%main = OpFunction %void None %void_func\n" +
8109 	    "%main_lab = OpLabel\n" +
8110 	    "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" +
8111 	    "OpReturn\n" +
8112 	    "OpFunctionEnd",
8113 	4, false),
8114     // Test case 18: Fold when every element of an array is inserted.
8115     InstructionFoldingCase<bool>(
8116         Header() +
8117             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8118             "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
8119             "; CHECK-DAG: [[arr_type:%\\w+]] = OpTypeArray [[int]] [[int2]]\n" +
8120             "; CHECK-DAG: [[int10:%\\w+]] = OpConstant [[int]] 10\n" +
8121             "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
8122             "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[arr_type]] [[int10]] [[int1]]\n" +
8123             "; CHECK: %5 = OpCopyObject [[arr_type]] [[construct]]\n" +
8124             "%main = OpFunction %void None %void_func\n" +
8125             "%main_lab = OpLabel\n" +
8126             "%4 = OpCompositeInsert %int_arr_2 %int_10 %int_arr_2_undef 0\n" +
8127             "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" +
8128             "OpReturn\n" +
8129             "OpFunctionEnd",
8130         5, true),
8131     // Test case 19: Don't fold for isomorphic structs
8132     InstructionFoldingCase<bool>(
8133         Header() +
8134             "%structA = OpTypeStruct %ulong\n" +
8135             "%structB = OpTypeStruct %ulong\n" +
8136             "%structC = OpTypeStruct %structB\n" +
8137             "%struct_a_undef = OpUndef %structA\n" +
8138             "%main = OpFunction %void None %void_func\n" +
8139             "%main_lab = OpLabel\n" +
8140             "%3 = OpCompositeExtract %ulong %struct_a_undef 0\n" +
8141             "%4 = OpCompositeConstruct %structB %3\n" +
8142             "OpReturn\n" +
8143             "OpFunctionEnd",
8144         4, false)
8145 ));
8146 
8147 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
8148 ::testing::Values(
8149     // Test case 0: Using OpDot to extract last element.
8150     InstructionFoldingCase<bool>(
8151         Header() +
8152             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
8153             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
8154             "%main = OpFunction %void None %void_func\n" +
8155             "%main_lab = OpLabel\n" +
8156             "%n = OpVariable %_ptr_v4float Function\n" +
8157             "%2 = OpLoad %v4float %n\n" +
8158             "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
8159             "OpReturn\n" +
8160             "OpFunctionEnd",
8161         3, true),
8162     // Test case 1: Using OpDot to extract last element.
8163     InstructionFoldingCase<bool>(
8164         Header() +
8165             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
8166             "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
8167             "%main = OpFunction %void None %void_func\n" +
8168             "%main_lab = OpLabel\n" +
8169             "%n = OpVariable %_ptr_v4float Function\n" +
8170             "%2 = OpLoad %v4float %n\n" +
8171             "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
8172             "OpReturn\n" +
8173             "OpFunctionEnd",
8174         3, true),
8175     // Test case 2: Using OpDot to extract second element.
8176     InstructionFoldingCase<bool>(
8177         Header() +
8178             "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
8179             "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
8180             "%main = OpFunction %void None %void_func\n" +
8181             "%main_lab = OpLabel\n" +
8182             "%n = OpVariable %_ptr_v4float Function\n" +
8183             "%2 = OpLoad %v4float %n\n" +
8184             "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
8185             "OpReturn\n" +
8186             "OpFunctionEnd",
8187         3, true),
8188     // Test case 3: Using OpDot to extract last element.
8189     InstructionFoldingCase<bool>(
8190         Header() +
8191             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8192             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
8193             "%main = OpFunction %void None %void_func\n" +
8194             "%main_lab = OpLabel\n" +
8195             "%n = OpVariable %_ptr_v4double Function\n" +
8196             "%2 = OpLoad %v4double %n\n" +
8197             "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
8198             "OpReturn\n" +
8199             "OpFunctionEnd",
8200         3, true),
8201     // Test case 4: Using OpDot to extract last element.
8202     InstructionFoldingCase<bool>(
8203         Header() +
8204             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8205             "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
8206             "%main = OpFunction %void None %void_func\n" +
8207             "%main_lab = OpLabel\n" +
8208             "%n = OpVariable %_ptr_v4double Function\n" +
8209             "%2 = OpLoad %v4double %n\n" +
8210             "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
8211             "OpReturn\n" +
8212             "OpFunctionEnd",
8213         3, true),
8214     // Test case 5: Using OpDot to extract second element.
8215     InstructionFoldingCase<bool>(
8216         Header() +
8217             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8218             "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
8219             "%main = OpFunction %void None %void_func\n" +
8220             "%main_lab = OpLabel\n" +
8221             "%n = OpVariable %_ptr_v4double Function\n" +
8222             "%2 = OpLoad %v4double %n\n" +
8223             "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
8224             "OpReturn\n" +
8225             "OpFunctionEnd",
8226         3, true)
8227 ));
8228 
8229 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionFoldingTest,
8230 ::testing::Values(
8231     // Test case 0: Using OpDot to extract last element.
8232     InstructionFoldingCase<bool>(
8233         Header() +
8234             "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
8235             "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
8236             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v2int]]\n" +
8237             "; CHECK: OpVectorShuffle\n" +
8238             "; CHECK: %3 = OpVectorShuffle [[v2int]] [[null]] {{%\\w+}} 4294967295 2\n" +
8239             "%main = OpFunction %void None %void_func\n" +
8240             "%main_lab = OpLabel\n" +
8241             "%n = OpVariable %_ptr_int Function\n" +
8242             "%load = OpLoad %int %n\n" +
8243             "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 3 0xFFFFFFFF \n" +
8244             "%3 = OpVectorShuffle %v2int %2 %v2int_2_3 1 2 \n" +
8245             "OpReturn\n" +
8246             "OpFunctionEnd",
8247         3, true)
8248  ));
8249 
8250 // Issue #5658: The Adreno compiler does not handle 16-bit FMA instructions well.
8251 // We want to avoid this by not generating FMA. We decided to never generate
8252 // FMAs because, from a SPIR-V perspective, it is neutral. The ICD can generate
8253 // the FMA if it wants. The simplest code is no code.
8254 INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest,
8255 ::testing::Values(
8256    // Test case 0: Don't fold (x * y) + a
8257    InstructionFoldingCase<bool>(
8258        Header() +
8259            "%main = OpFunction %void None %void_func\n" +
8260            "%main_lab = OpLabel\n" +
8261            "%x = OpVariable %_ptr_float Function\n" +
8262            "%y = OpVariable %_ptr_float Function\n" +
8263            "%a = OpVariable %_ptr_float Function\n" +
8264            "%lx = OpLoad %float %x\n" +
8265            "%ly = OpLoad %float %y\n" +
8266            "%mul = OpFMul %float %lx %ly\n" +
8267            "%la = OpLoad %float %a\n" +
8268            "%3 = OpFAdd %float %mul %la\n" +
8269            "OpStore %a %3\n" +
8270            "OpReturn\n" +
8271            "OpFunctionEnd",
8272        3, false),
8273     // Test case 1: Don't fold a + (x * y)
8274    InstructionFoldingCase<bool>(
8275        Header() +
8276            "%main = OpFunction %void None %void_func\n" +
8277            "%main_lab = OpLabel\n" +
8278            "%x = OpVariable %_ptr_float Function\n" +
8279            "%y = OpVariable %_ptr_float Function\n" +
8280            "%a = OpVariable %_ptr_float Function\n" +
8281            "%lx = OpLoad %float %x\n" +
8282            "%ly = OpLoad %float %y\n" +
8283            "%mul = OpFMul %float %lx %ly\n" +
8284            "%la = OpLoad %float %a\n" +
8285            "%3 = OpFAdd %float %la %mul\n" +
8286            "OpStore %a %3\n" +
8287            "OpReturn\n" +
8288            "OpFunctionEnd",
8289        3, false),
8290    // Test case 2: Don't fold (x * y) + a with vectors
8291    InstructionFoldingCase<bool>(
8292        Header() +
8293            "%main = OpFunction %void None %void_func\n" +
8294            "%main_lab = OpLabel\n" +
8295            "%x = OpVariable %_ptr_v4float Function\n" +
8296            "%y = OpVariable %_ptr_v4float Function\n" +
8297            "%a = OpVariable %_ptr_v4float Function\n" +
8298            "%lx = OpLoad %v4float %x\n" +
8299            "%ly = OpLoad %v4float %y\n" +
8300            "%mul = OpFMul %v4float %lx %ly\n" +
8301            "%la = OpLoad %v4float %a\n" +
8302            "%3 = OpFAdd %v4float %mul %la\n" +
8303            "OpStore %a %3\n" +
8304            "OpReturn\n" +
8305            "OpFunctionEnd",
8306        3,false),
8307     // Test case 3: Don't fold a + (x * y) with vectors
8308    InstructionFoldingCase<bool>(
8309        Header() +
8310            "%main = OpFunction %void None %void_func\n" +
8311            "%main_lab = OpLabel\n" +
8312            "%x = OpVariable %_ptr_float Function\n" +
8313            "%y = OpVariable %_ptr_float Function\n" +
8314            "%a = OpVariable %_ptr_float Function\n" +
8315            "%lx = OpLoad %float %x\n" +
8316            "%ly = OpLoad %float %y\n" +
8317            "%mul = OpFMul %float %lx %ly\n" +
8318            "%la = OpLoad %float %a\n" +
8319            "%3 = OpFAdd %float %la %mul\n" +
8320            "OpStore %a %3\n" +
8321            "OpReturn\n" +
8322            "OpFunctionEnd",
8323        3, false),
8324    // Test 4: Don't fold if the multiple is marked no contract.
8325    InstructionFoldingCase<bool>(
8326        std::string() +
8327            "OpCapability Shader\n" +
8328            "OpMemoryModel Logical GLSL450\n" +
8329            "OpEntryPoint Fragment %main \"main\"\n" +
8330            "OpExecutionMode %main OriginUpperLeft\n" +
8331            "OpSource GLSL 140\n" +
8332            "OpName %main \"main\"\n" +
8333            "OpDecorate %mul NoContraction\n" +
8334            "%void = OpTypeVoid\n" +
8335            "%void_func = OpTypeFunction %void\n" +
8336            "%bool = OpTypeBool\n" +
8337            "%float = OpTypeFloat 32\n" +
8338            "%_ptr_float = OpTypePointer Function %float\n" +
8339            "%main = OpFunction %void None %void_func\n" +
8340            "%main_lab = OpLabel\n" +
8341            "%x = OpVariable %_ptr_float Function\n" +
8342            "%y = OpVariable %_ptr_float Function\n" +
8343            "%a = OpVariable %_ptr_float Function\n" +
8344            "%lx = OpLoad %float %x\n" +
8345            "%ly = OpLoad %float %y\n" +
8346            "%mul = OpFMul %float %lx %ly\n" +
8347            "%la = OpLoad %float %a\n" +
8348            "%3 = OpFAdd %float %mul %la\n" +
8349            "OpStore %a %3\n" +
8350            "OpReturn\n" +
8351            "OpFunctionEnd",
8352        3, false),
8353        // Test 5: Don't fold if the add is marked no contract.
8354        InstructionFoldingCase<bool>(
8355            std::string() +
8356                "OpCapability Shader\n" +
8357                "OpMemoryModel Logical GLSL450\n" +
8358                "OpEntryPoint Fragment %main \"main\"\n" +
8359                "OpExecutionMode %main OriginUpperLeft\n" +
8360                "OpSource GLSL 140\n" +
8361                "OpName %main \"main\"\n" +
8362                "OpDecorate %3 NoContraction\n" +
8363                "%void = OpTypeVoid\n" +
8364                "%void_func = OpTypeFunction %void\n" +
8365                "%bool = OpTypeBool\n" +
8366                "%float = OpTypeFloat 32\n" +
8367                "%_ptr_float = OpTypePointer Function %float\n" +
8368                "%main = OpFunction %void None %void_func\n" +
8369                "%main_lab = OpLabel\n" +
8370                "%x = OpVariable %_ptr_float Function\n" +
8371                "%y = OpVariable %_ptr_float Function\n" +
8372                "%a = OpVariable %_ptr_float Function\n" +
8373                "%lx = OpLoad %float %x\n" +
8374                "%ly = OpLoad %float %y\n" +
8375                "%mul = OpFMul %float %lx %ly\n" +
8376                "%la = OpLoad %float %a\n" +
8377                "%3 = OpFAdd %float %mul %la\n" +
8378                "OpStore %a %3\n" +
8379                "OpReturn\n" +
8380                "OpFunctionEnd",
8381            3, false),
8382     // Test case 6: Don't fold (x * y) - a
8383     InstructionFoldingCase<bool>(
8384        Header() +
8385            "%main = OpFunction %void None %void_func\n" +
8386            "%main_lab = OpLabel\n" +
8387            "%x = OpVariable %_ptr_float Function\n" +
8388            "%y = OpVariable %_ptr_float Function\n" +
8389            "%a = OpVariable %_ptr_float Function\n" +
8390            "%lx = OpLoad %float %x\n" +
8391            "%ly = OpLoad %float %y\n" +
8392            "%mul = OpFMul %float %lx %ly\n" +
8393            "%la = OpLoad %float %a\n" +
8394            "%3 = OpFSub %float %mul %la\n" +
8395            "OpStore %a %3\n" +
8396            "OpReturn\n" +
8397            "OpFunctionEnd",
8398        3, false),
8399    // Test case 7: Don't fold a - (x * y)
8400    InstructionFoldingCase<bool>(
8401        Header() +
8402            "%main = OpFunction %void None %void_func\n" +
8403            "%main_lab = OpLabel\n" +
8404            "%x = OpVariable %_ptr_float Function\n" +
8405            "%y = OpVariable %_ptr_float Function\n" +
8406            "%a = OpVariable %_ptr_float Function\n" +
8407            "%lx = OpLoad %float %x\n" +
8408            "%ly = OpLoad %float %y\n" +
8409            "%mul = OpFMul %float %lx %ly\n" +
8410            "%la = OpLoad %float %a\n" +
8411            "%3 = OpFSub %float %la %mul\n" +
8412            "OpStore %a %3\n" +
8413            "OpReturn\n" +
8414            "OpFunctionEnd",
8415        3, false)
8416 ));
8417 
8418 using MatchingInstructionWithNoResultFoldingTest =
8419 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8420 
8421 // Test folding instructions that do not have a result.  The instruction
8422 // that will be folded is the last instruction before the return.  If there
8423 // are multiple returns, there is not guarantee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest,Case)8424 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
8425   const auto& tc = GetParam();
8426 
8427   std::unique_ptr<IRContext> context;
8428   Instruction* inst;
8429   std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
8430 
8431   // Find the instruction to test.
8432   EXPECT_EQ(inst != nullptr, tc.expected_result);
8433   if (inst != nullptr) {
8434     Match(tc.test_body, context.get());
8435   }
8436 }
8437 
8438 INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8439 ::testing::Values(
8440     // Test case 0: Remove store of undef.
8441     InstructionFoldingCase<bool>(
8442         Header() +
8443             "; CHECK: OpLabel\n" +
8444             "; CHECK-NOT: OpStore\n" +
8445             "; CHECK: OpReturn\n" +
8446             "%main = OpFunction %void None %void_func\n" +
8447             "%main_lab = OpLabel\n" +
8448             "%n = OpVariable %_ptr_v4double Function\n" +
8449             "%undef = OpUndef %v4double\n" +
8450             "OpStore %n %undef\n" +
8451             "OpReturn\n" +
8452             "OpFunctionEnd",
8453         0 /* OpStore */, true),
8454     // Test case 1: Keep volatile store.
8455     InstructionFoldingCase<bool>(
8456         Header() +
8457             "%main = OpFunction %void None %void_func\n" +
8458             "%main_lab = OpLabel\n" +
8459             "%n = OpVariable %_ptr_v4double Function\n" +
8460             "%undef = OpUndef %v4double\n" +
8461             "OpStore %n %undef Volatile\n" +
8462             "OpReturn\n" +
8463             "OpFunctionEnd",
8464         0 /* OpStore */, false)
8465 ));
8466 
8467 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8468 ::testing::Values(
8469     // Test case 0: Basic test 1
8470     InstructionFoldingCase<bool>(
8471         Header() +
8472             "; CHECK: OpVectorShuffle\n" +
8473             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
8474             "; CHECK: OpReturn\n" +
8475             "%main = OpFunction %void None %void_func\n" +
8476             "%main_lab = OpLabel\n" +
8477             "%2 = OpVariable %_ptr_v4double Function\n" +
8478             "%3 = OpVariable %_ptr_v4double Function\n" +
8479             "%4 = OpVariable %_ptr_v4double Function\n" +
8480             "%5 = OpLoad %v4double %2\n" +
8481             "%6 = OpLoad %v4double %3\n" +
8482             "%7 = OpLoad %v4double %4\n" +
8483             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8484             "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
8485             "OpReturn\n" +
8486             "OpFunctionEnd",
8487         9, true),
8488     // Test case 1: Basic test 2
8489     InstructionFoldingCase<bool>(
8490         Header() +
8491             "; CHECK: OpVectorShuffle\n" +
8492             "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
8493             "; CHECK: OpReturn\n" +
8494             "%main = OpFunction %void None %void_func\n" +
8495             "%main_lab = OpLabel\n" +
8496             "%2 = OpVariable %_ptr_v4double Function\n" +
8497             "%3 = OpVariable %_ptr_v4double Function\n" +
8498             "%4 = OpVariable %_ptr_v4double Function\n" +
8499             "%5 = OpLoad %v4double %2\n" +
8500             "%6 = OpLoad %v4double %3\n" +
8501             "%7 = OpLoad %v4double %4\n" +
8502             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8503             "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
8504             "OpReturn\n" +
8505             "OpFunctionEnd",
8506         9, true),
8507     // Test case 2: Basic test 3
8508     InstructionFoldingCase<bool>(
8509         Header() +
8510             "; CHECK: OpVectorShuffle\n" +
8511             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
8512             "; CHECK: OpReturn\n" +
8513             "%main = OpFunction %void None %void_func\n" +
8514             "%main_lab = OpLabel\n" +
8515             "%2 = OpVariable %_ptr_v4double Function\n" +
8516             "%3 = OpVariable %_ptr_v4double Function\n" +
8517             "%4 = OpVariable %_ptr_v4double Function\n" +
8518             "%5 = OpLoad %v4double %2\n" +
8519             "%6 = OpLoad %v4double %3\n" +
8520             "%7 = OpLoad %v4double %4\n" +
8521             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8522             "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
8523             "OpReturn\n" +
8524             "OpFunctionEnd",
8525         9, true),
8526     // Test case 3: Basic test 4
8527     InstructionFoldingCase<bool>(
8528         Header() +
8529             "; CHECK: OpVectorShuffle\n" +
8530             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
8531             "; CHECK: OpReturn\n" +
8532             "%main = OpFunction %void None %void_func\n" +
8533             "%main_lab = OpLabel\n" +
8534             "%2 = OpVariable %_ptr_v4double Function\n" +
8535             "%3 = OpVariable %_ptr_v4double Function\n" +
8536             "%4 = OpVariable %_ptr_v4double Function\n" +
8537             "%5 = OpLoad %v4double %2\n" +
8538             "%6 = OpLoad %v4double %3\n" +
8539             "%7 = OpLoad %v4double %4\n" +
8540             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8541             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
8542             "OpReturn\n" +
8543             "OpFunctionEnd",
8544         9, true),
8545     // Test case 4: Don't fold, need both operands of the feeder.
8546     InstructionFoldingCase<bool>(
8547         Header() +
8548             "%main = OpFunction %void None %void_func\n" +
8549             "%main_lab = OpLabel\n" +
8550             "%2 = OpVariable %_ptr_v4double Function\n" +
8551             "%3 = OpVariable %_ptr_v4double Function\n" +
8552             "%4 = OpVariable %_ptr_v4double Function\n" +
8553             "%5 = OpLoad %v4double %2\n" +
8554             "%6 = OpLoad %v4double %3\n" +
8555             "%7 = OpLoad %v4double %4\n" +
8556             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8557             "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
8558             "OpReturn\n" +
8559             "OpFunctionEnd",
8560         9, false),
8561     // Test case 5: Don't fold, need both operands of the feeder.
8562     InstructionFoldingCase<bool>(
8563         Header() +
8564             "%main = OpFunction %void None %void_func\n" +
8565             "%main_lab = OpLabel\n" +
8566             "%2 = OpVariable %_ptr_v4double Function\n" +
8567             "%3 = OpVariable %_ptr_v4double Function\n" +
8568             "%4 = OpVariable %_ptr_v4double Function\n" +
8569             "%5 = OpLoad %v4double %2\n" +
8570             "%6 = OpLoad %v4double %3\n" +
8571             "%7 = OpLoad %v4double %4\n" +
8572             "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8573             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8574             "OpReturn\n" +
8575             "OpFunctionEnd",
8576         9, false),
8577     // Test case 6: Fold, need both operands of the feeder, but they are the same.
8578     InstructionFoldingCase<bool>(
8579         Header() +
8580             "; CHECK: OpVectorShuffle\n" +
8581             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
8582             "; CHECK: OpReturn\n" +
8583             "%main = OpFunction %void None %void_func\n" +
8584             "%main_lab = OpLabel\n" +
8585             "%2 = OpVariable %_ptr_v4double Function\n" +
8586             "%3 = OpVariable %_ptr_v4double Function\n" +
8587             "%4 = OpVariable %_ptr_v4double Function\n" +
8588             "%5 = OpLoad %v4double %2\n" +
8589             "%6 = OpLoad %v4double %3\n" +
8590             "%7 = OpLoad %v4double %4\n" +
8591             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8592             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8593             "OpReturn\n" +
8594             "OpFunctionEnd",
8595         9, true),
8596     // Test case 7: Fold, need both operands of the feeder, but they are the same.
8597     InstructionFoldingCase<bool>(
8598         Header() +
8599             "; CHECK: OpVectorShuffle\n" +
8600             "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
8601             "; CHECK: OpReturn\n" +
8602             "%main = OpFunction %void None %void_func\n" +
8603             "%main_lab = OpLabel\n" +
8604             "%2 = OpVariable %_ptr_v4double Function\n" +
8605             "%3 = OpVariable %_ptr_v4double Function\n" +
8606             "%4 = OpVariable %_ptr_v4double Function\n" +
8607             "%5 = OpLoad %v4double %2\n" +
8608             "%6 = OpLoad %v4double %3\n" +
8609             "%7 = OpLoad %v4double %4\n" +
8610             "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8611             "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
8612             "OpReturn\n" +
8613             "OpFunctionEnd",
8614         9, true),
8615     // Test case 8: Replace first operand with a smaller vector.
8616     InstructionFoldingCase<bool>(
8617         Header() +
8618             "; CHECK: OpVectorShuffle\n" +
8619             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
8620             "; CHECK: OpReturn\n" +
8621             "%main = OpFunction %void None %void_func\n" +
8622             "%main_lab = OpLabel\n" +
8623             "%2 = OpVariable %_ptr_v2double Function\n" +
8624             "%3 = OpVariable %_ptr_v4double Function\n" +
8625             "%4 = OpVariable %_ptr_v4double Function\n" +
8626             "%5 = OpLoad %v2double %2\n" +
8627             "%6 = OpLoad %v4double %3\n" +
8628             "%7 = OpLoad %v4double %4\n" +
8629             "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
8630             "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8631             "OpReturn\n" +
8632             "OpFunctionEnd",
8633         9, true),
8634     // Test case 9: Replace first operand with a larger vector.
8635     InstructionFoldingCase<bool>(
8636         Header() +
8637             "; CHECK: OpVectorShuffle\n" +
8638             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
8639             "; CHECK: OpReturn\n" +
8640             "%main = OpFunction %void None %void_func\n" +
8641             "%main_lab = OpLabel\n" +
8642             "%2 = OpVariable %_ptr_v4double Function\n" +
8643             "%3 = OpVariable %_ptr_v4double Function\n" +
8644             "%4 = OpVariable %_ptr_v4double Function\n" +
8645             "%5 = OpLoad %v4double %2\n" +
8646             "%6 = OpLoad %v4double %3\n" +
8647             "%7 = OpLoad %v4double %4\n" +
8648             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8649             "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
8650             "OpReturn\n" +
8651             "OpFunctionEnd",
8652         9, true),
8653     // Test case 10: Replace unused operand with null.
8654     InstructionFoldingCase<bool>(
8655         Header() +
8656             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8657             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8658             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8659             "; CHECK: OpVectorShuffle\n" +
8660             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
8661             "; CHECK: OpReturn\n" +
8662             "%main = OpFunction %void None %void_func\n" +
8663             "%main_lab = OpLabel\n" +
8664             "%2 = OpVariable %_ptr_v4double Function\n" +
8665             "%3 = OpVariable %_ptr_v4double Function\n" +
8666             "%4 = OpVariable %_ptr_v4double Function\n" +
8667             "%5 = OpLoad %v4double %2\n" +
8668             "%6 = OpLoad %v4double %3\n" +
8669             "%7 = OpLoad %v4double %4\n" +
8670             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8671             "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
8672             "OpReturn\n" +
8673             "OpFunctionEnd",
8674         9, true),
8675     // Test case 11: Replace unused operand with null.
8676     InstructionFoldingCase<bool>(
8677         Header() +
8678             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8679             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8680             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8681             "; CHECK: OpVectorShuffle\n" +
8682             "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
8683             "; CHECK: OpReturn\n" +
8684             "%main = OpFunction %void None %void_func\n" +
8685             "%main_lab = OpLabel\n" +
8686             "%2 = OpVariable %_ptr_v4double Function\n" +
8687             "%3 = OpVariable %_ptr_v4double Function\n" +
8688             "%5 = OpLoad %v4double %2\n" +
8689             "%6 = OpLoad %v4double %3\n" +
8690             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8691             "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
8692             "OpReturn\n" +
8693             "OpFunctionEnd",
8694         9, true),
8695     // Test case 12: Replace unused operand with null.
8696     InstructionFoldingCase<bool>(
8697         Header() +
8698             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8699             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8700             "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8701             "; CHECK: OpVectorShuffle\n" +
8702             "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
8703             "; CHECK: OpReturn\n" +
8704             "%main = OpFunction %void None %void_func\n" +
8705             "%main_lab = OpLabel\n" +
8706             "%2 = OpVariable %_ptr_v4double Function\n" +
8707             "%3 = OpVariable %_ptr_v4double Function\n" +
8708             "%4 = OpVariable %_ptr_v4double Function\n" +
8709             "%5 = OpLoad %v4double %2\n" +
8710             "%6 = OpLoad %v4double %3\n" +
8711             "%7 = OpLoad %v4double %4\n" +
8712             "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8713             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
8714             "OpReturn\n" +
8715             "OpFunctionEnd",
8716         9, true),
8717     // Test case 13: Shuffle with undef literal.
8718     InstructionFoldingCase<bool>(
8719         Header() +
8720             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8721             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8722             "; CHECK: OpVectorShuffle\n" +
8723             "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
8724             "; CHECK: OpReturn\n" +
8725             "%main = OpFunction %void None %void_func\n" +
8726             "%main_lab = OpLabel\n" +
8727             "%2 = OpVariable %_ptr_v4double Function\n" +
8728             "%3 = OpVariable %_ptr_v4double Function\n" +
8729             "%4 = OpVariable %_ptr_v4double Function\n" +
8730             "%5 = OpLoad %v4double %2\n" +
8731             "%6 = OpLoad %v4double %3\n" +
8732             "%7 = OpLoad %v4double %4\n" +
8733             "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8734             "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
8735             "OpReturn\n" +
8736             "OpFunctionEnd",
8737         9, true),
8738     // Test case 14: Shuffle with undef literal and change size of first input vector.
8739     InstructionFoldingCase<bool>(
8740         Header() +
8741             "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8742             "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8743             "; CHECK: OpVectorShuffle\n" +
8744             "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 1 4 4294967295\n" +
8745             "; CHECK: OpReturn\n" +
8746             "%main = OpFunction %void None %void_func\n" +
8747             "%main_lab = OpLabel\n" +
8748             "%2 = OpVariable %_ptr_v4double Function\n" +
8749             "%3 = OpVariable %_ptr_v4double Function\n" +
8750             "%4 = OpVariable %_ptr_v4double Function\n" +
8751             "%5 = OpLoad %v4double %2\n" +
8752             "%6 = OpLoad %v4double %3\n" +
8753             "%7 = OpLoad %v4double %4\n" +
8754             "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8755             "%9 = OpVectorShuffle %v4double %8 %7 0 1 2 4294967295\n" +
8756             "OpReturn\n" +
8757             "OpFunctionEnd",
8758         9, true)
8759 ));
8760 
8761 using EntryPointFoldingTest =
8762 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8763 
TEST_P(EntryPointFoldingTest,Case)8764 TEST_P(EntryPointFoldingTest, Case) {
8765   const auto& tc = GetParam();
8766 
8767   // Build module.
8768   std::unique_ptr<IRContext> context =
8769       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8770                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8771   ASSERT_NE(nullptr, context);
8772 
8773   // Find the first entry point. That is the instruction we want to fold.
8774   Instruction* inst = nullptr;
8775   ASSERT_FALSE(context->module()->entry_points().empty());
8776   inst = &*context->module()->entry_points().begin();
8777   assert(inst && "Invalid test.  Could not find entry point instruction to fold.");
8778   std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8779   bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8780   EXPECT_EQ(succeeded, tc.expected_result);
8781   if (succeeded) {
8782     Match(tc.test_body, context.get());
8783   }
8784 }
8785 
8786 INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest,
8787 ::testing::Values(
8788     // Test case 0: Basic test 1
8789     InstructionFoldingCase<bool>(std::string() +
8790                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" +
8791                              "OpCapability Shader\n" +
8792                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8793                              "OpMemoryModel Logical GLSL450\n" +
8794                              "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" +
8795                              "OpExecutionMode %2 OriginUpperLeft\n" +
8796                              "OpSource GLSL 430\n" +
8797                              "OpDecorate %3 Location 0\n" +
8798                      "%void = OpTypeVoid\n" +
8799                         "%5 = OpTypeFunction %void\n" +
8800                     "%float = OpTypeFloat 32\n" +
8801                   "%v4float = OpTypeVector %float 4\n" +
8802       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8803                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8804                       "%int = OpTypeInt 32 1\n" +
8805                     "%int_0 = OpConstant %int 0\n" +
8806 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8807                         "%2 = OpFunction %void None %5\n" +
8808                        "%12 = OpLabel\n" +
8809                              "OpReturn\n" +
8810                              "OpFunctionEnd\n",
8811         9, true),
8812     InstructionFoldingCase<bool>(std::string() +
8813                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" +
8814                              "OpCapability Shader\n" +
8815                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8816                              "OpMemoryModel Logical GLSL450\n" +
8817                              "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" +
8818                              "OpExecutionMode %2 OriginUpperLeft\n" +
8819                              "OpSource GLSL 430\n" +
8820                              "OpDecorate %3 Location 0\n" +
8821                      "%void = OpTypeVoid\n" +
8822                         "%5 = OpTypeFunction %void\n" +
8823                     "%float = OpTypeFloat 32\n" +
8824                   "%v4float = OpTypeVector %float 4\n" +
8825       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8826                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8827                         "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8828                       "%int = OpTypeInt 32 1\n" +
8829                     "%int_0 = OpConstant %int 0\n" +
8830 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8831                         "%2 = OpFunction %void None %5\n" +
8832                        "%12 = OpLabel\n" +
8833                              "OpReturn\n" +
8834                              "OpFunctionEnd\n",
8835         9, true),
8836     InstructionFoldingCase<bool>(std::string() +
8837                     "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" +
8838                              "OpCapability Shader\n" +
8839                         "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8840                              "OpMemoryModel Logical GLSL450\n" +
8841                              "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" +
8842                              "OpExecutionMode %2 OriginUpperLeft\n" +
8843                              "OpSource GLSL 430\n" +
8844                              "OpDecorate %3 Location 0\n" +
8845                      "%void = OpTypeVoid\n" +
8846                         "%5 = OpTypeFunction %void\n" +
8847                     "%float = OpTypeFloat 32\n" +
8848                   "%v4float = OpTypeVector %float 4\n" +
8849       "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8850                         "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8851                         "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8852                       "%int = OpTypeInt 32 1\n" +
8853                     "%int_0 = OpConstant %int 0\n" +
8854 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8855                         "%2 = OpFunction %void None %5\n" +
8856                        "%12 = OpLabel\n" +
8857                              "OpReturn\n" +
8858                              "OpFunctionEnd\n",
8859         9, true)
8860 ));
8861 
8862 using SPV14FoldingTest =
8863 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8864 
TEST_P(SPV14FoldingTest,Case)8865 TEST_P(SPV14FoldingTest, Case) {
8866   const auto& tc = GetParam();
8867 
8868   std::unique_ptr<IRContext> context;
8869   Instruction* inst;
8870   std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_4);
8871 
8872   EXPECT_EQ(inst != nullptr, tc.expected_result);
8873   if (inst !=  nullptr) {
8874     Match(tc.test_body, context.get());
8875   }
8876 }
8877 
8878 INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest,
8879 ::testing::Values(
8880     // Test case 0: select vectors with scalar condition.
8881     InstructionFoldingCase<bool>(std::string() +
8882 "; CHECK-NOT: OpSelect\n" +
8883 "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" +
8884 "OpCapability Shader\n" +
8885 "OpCapability Linkage\n" +
8886 "%void = OpTypeVoid\n" +
8887 "%bool = OpTypeBool\n" +
8888 "%true = OpConstantTrue %bool\n" +
8889 "%int = OpTypeInt 32 0\n" +
8890 "%int4 = OpTypeVector %int 4\n" +
8891 "%int_0 = OpConstant %int 0\n" +
8892 "%int_1 = OpConstant %int 1\n" +
8893 "%1 = OpUndef %int4\n" +
8894 "%2 = OpUndef %int4\n" +
8895 "%void_fn = OpTypeFunction %void\n" +
8896 "%func = OpFunction %void None %void_fn\n" +
8897 "%entry = OpLabel\n" +
8898 "%3 = OpSelect %int4 %true %1 %2\n" +
8899 "OpReturn\n" +
8900 "OpFunctionEnd\n"
8901 ,
8902                                  3, true),
8903     // Test case 1: select struct with scalar condition.
8904     InstructionFoldingCase<bool>(std::string() +
8905 "; CHECK-NOT: OpSelect\n" +
8906 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8907 "OpCapability Shader\n" +
8908 "OpCapability Linkage\n" +
8909 "%void = OpTypeVoid\n" +
8910 "%bool = OpTypeBool\n" +
8911 "%true = OpConstantFalse %bool\n" +
8912 "%int = OpTypeInt 32 0\n" +
8913 "%struct = OpTypeStruct %int %int %int %int\n" +
8914 "%int_0 = OpConstant %int 0\n" +
8915 "%int_1 = OpConstant %int 1\n" +
8916 "%1 = OpUndef %struct\n" +
8917 "%2 = OpUndef %struct\n" +
8918 "%void_fn = OpTypeFunction %void\n" +
8919 "%func = OpFunction %void None %void_fn\n" +
8920 "%entry = OpLabel\n" +
8921 "%3 = OpSelect %struct %true %1 %2\n" +
8922 "OpReturn\n" +
8923 "OpFunctionEnd\n"
8924 ,
8925                                  3, true),
8926     // Test case 1: select array with scalar condition.
8927     InstructionFoldingCase<bool>(std::string() +
8928 "; CHECK-NOT: OpSelect\n" +
8929 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8930 "OpCapability Shader\n" +
8931 "OpCapability Linkage\n" +
8932 "%void = OpTypeVoid\n" +
8933 "%bool = OpTypeBool\n" +
8934 "%true = OpConstantFalse %bool\n" +
8935 "%int = OpTypeInt 32 0\n" +
8936 "%int_0 = OpConstant %int 0\n" +
8937 "%int_1 = OpConstant %int 1\n" +
8938 "%int_4 = OpConstant %int 4\n" +
8939 "%array = OpTypeStruct %int %int %int %int\n" +
8940 "%1 = OpUndef %array\n" +
8941 "%2 = OpUndef %array\n" +
8942 "%void_fn = OpTypeFunction %void\n" +
8943 "%func = OpFunction %void None %void_fn\n" +
8944 "%entry = OpLabel\n" +
8945 "%3 = OpSelect %array %true %1 %2\n" +
8946 "OpReturn\n" +
8947 "OpFunctionEnd\n"
8948 ,
8949                                  3, true)
8950 ));
8951 
FloatControlsHeader(const std::string & capabilities)8952 std::string FloatControlsHeader(const std::string& capabilities) {
8953   std::string header = R"(
8954 OpCapability Shader
8955 )" + capabilities + R"(
8956 %void = OpTypeVoid
8957 %float = OpTypeFloat 32
8958 %float_0 = OpConstant %float 0
8959 %float_1 = OpConstant %float 1
8960 %void_fn = OpTypeFunction %void
8961 %func = OpFunction %void None %void_fn
8962 %entry = OpLabel
8963 )";
8964 
8965   return header;
8966 }
8967 
8968 using FloatControlsFoldingTest =
8969 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8970 
TEST_P(FloatControlsFoldingTest,Case)8971 TEST_P(FloatControlsFoldingTest, Case) {
8972   const auto& tc = GetParam();
8973 
8974   std::unique_ptr<IRContext> context;
8975   Instruction* inst;
8976   std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_4);
8977 
8978   EXPECT_EQ(inst != nullptr, tc.expected_result);
8979   if (inst != nullptr) {
8980     Match(tc.test_body, context.get());
8981   }
8982 }
8983 
8984 INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
8985 ::testing::Values(
8986     // Test case 0: no folding with DenormPreserve
8987     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormPreserve") +
8988                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8989                                  "OpReturn\n" +
8990                                  "OpFunctionEnd\n"
8991 ,
8992                                  1, false),
8993     // Test case 1: no folding with DenormFlushToZero
8994     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormFlushToZero") +
8995                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
8996                                  "OpReturn\n" +
8997                                  "OpFunctionEnd\n"
8998 ,
8999                                  1, false),
9000     // Test case 2: no folding with SignedZeroInfNanPreserve
9001     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") +
9002                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
9003                                  "OpReturn\n" +
9004                                  "OpFunctionEnd\n"
9005 ,
9006                                  1, false),
9007     // Test case 3: no folding with RoundingModeRTE
9008     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTE") +
9009                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
9010                                  "OpReturn\n" +
9011                                  "OpFunctionEnd\n"
9012 ,
9013                                  1, false),
9014     // Test case 4: no folding with RoundingModeRTZ
9015     InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTZ") +
9016                                  "%1 = OpFAdd %float %float_0 %float_1\n" +
9017                                  "OpReturn\n" +
9018                                  "OpFunctionEnd\n"
9019 ,
9020                                  1, false)
9021 ));
9022 
ImageOperandsTestBody(const std::string & image_instruction)9023 std::string ImageOperandsTestBody(const std::string& image_instruction) {
9024   std::string body = R"(
9025                OpCapability Shader
9026                OpCapability ImageGatherExtended
9027                OpMemoryModel Logical GLSL450
9028                OpEntryPoint Fragment %main "main"
9029                OpExecutionMode %main OriginUpperLeft
9030                OpDecorate %Texture DescriptorSet 0
9031                OpDecorate %Texture Binding 0
9032         %int = OpTypeInt 32 1
9033      %int_n1 = OpConstant %int -1
9034           %5 = OpConstant %int 0
9035       %float = OpTypeFloat 32
9036     %float_0 = OpConstant %float 0
9037 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
9038 %type_sampled_image = OpTypeSampledImage %type_2d_image
9039 %type_sampler = OpTypeSampler
9040 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
9041 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
9042    %_ptr_int = OpTypePointer Function %int
9043       %v2int = OpTypeVector %int 2
9044          %10 = OpTypeVector %float 4
9045        %void = OpTypeVoid
9046          %22 = OpTypeFunction %void
9047     %v2float = OpTypeVector %float 2
9048       %v3int = OpTypeVector %int 3
9049     %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
9050    %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
9051         %110 = OpConstantComposite %v2int %5 %5
9052         %101 = OpConstantComposite %v2int %int_n1 %int_n1
9053          %20 = OpConstantComposite %v2float %float_0 %float_0
9054        %main = OpFunction %void None %22
9055          %23 = OpLabel
9056         %var = OpVariable %_ptr_int Function
9057          %88 = OpLoad %type_2d_image %Texture
9058         %val = OpLoad %int %var
9059     %sampler = OpLoad %type_sampler %gSampler
9060          %26 = OpSampledImage %type_sampled_image %88 %sampler
9061 )" + image_instruction + R"(
9062                OpReturn
9063                OpFunctionEnd
9064 )";
9065 
9066   return body;
9067 }
9068 
9069 INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
9070 ::testing::Values(
9071     // Test case 0: OpImageFetch without Offset
9072     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9073         "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
9074         , 89, false),
9075     // Test case 1: OpImageFetch with non-const offset
9076     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9077         "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
9078         , 89, false),
9079     // Test case 2: OpImageFetch with Lod and Offset
9080     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9081       "         %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101      \n"
9082       "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
9083       , 89, true),
9084     // Test case 3: OpImageFetch with Bias and Offset
9085     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9086       "         %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101      \n"
9087       "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
9088       , 89, true),
9089     // Test case 4: OpImageFetch with Grad and Offset.
9090     // Grad adds 2 operands to the instruction.
9091     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9092       "         %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101      \n"
9093       "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
9094       , 89, true),
9095     // Test case 5: OpImageFetch with Offset and MinLod.
9096     // This is an example of a case where the bitmask bit-offset is larger than
9097     // that of the Offset.
9098     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9099       "         %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5      \n"
9100       "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
9101       , 89, true),
9102     // Test case 6: OpImageGather with constant Offset
9103     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9104       "         %89 = OpImageGather %10 %26 %20 %5 Offset %101      \n"
9105       "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
9106       , 89, true),
9107     // Test case 7: OpImageWrite with constant Offset
9108     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9109       "         OpImageWrite %88 %5 %101 Offset %101      \n"
9110       "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
9111       , 0 /* No result-id */, true),
9112     // Test case 8: OpImageFetch with zero constant Offset
9113     InstructionFoldingCase<bool>(ImageOperandsTestBody(
9114         "         %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %110      \n"
9115         "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod %5 \n")
9116         , 89, true)
9117 ));
9118 
9119 }  // namespace
9120 }  // namespace opt
9121 }  // namespace spvtools
9122