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
6 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <unordered_set>
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
21 #include "opt/build_module.h"
22 #include "opt/def_use_manager.h"
23 #include "opt/ir_context.h"
24 #include "opt/module.h"
25 #include "pass_utils.h"
26 #include "spirv-tools/libspirv.hpp"
30 using ::testing::Contains;
32 using namespace spvtools;
33 using spvtools::opt::analysis::DefUseManager;
35 template <class ResultType>
36 struct InstructionFoldingCase {
37 InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
38 : test_body(tb), id_to_fold(id), expected_result(result) {}
40 std::string test_body;
42 ResultType expected_result;
45 using IntegerInstructionFoldingTest =
46 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
48 TEST_P(IntegerInstructionFoldingTest, Case) {
49 const auto& tc = GetParam();
52 std::unique_ptr<ir::IRContext> context =
53 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
54 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
55 ASSERT_NE(nullptr, context);
57 // Fold the instruction to test.
58 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
59 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
60 bool succeeded = opt::FoldInstruction(inst);
62 // Make sure the instruction folded as expected.
63 EXPECT_TRUE(succeeded);
64 if (inst != nullptr) {
65 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
66 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
67 EXPECT_EQ(inst->opcode(), SpvOpConstant);
68 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
69 const opt::analysis::IntConstant* result =
70 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
71 EXPECT_NE(result, nullptr);
72 if (result != nullptr) {
73 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
78 // Returns a common SPIR-V header for all of the test that follow.
83 const std::string& Header() {
84 static const std::string header = R"(OpCapability Shader
85 %1 = OpExtInstImport "GLSL.std.450"
86 OpMemoryModel Logical GLSL450
87 OpEntryPoint Fragment %main "main"
88 OpExecutionMode %main OriginUpperLeft
92 %void_func = OpTypeFunction %void
94 %float16 = OpTypeFloat 16
95 %float = OpTypeFloat 32
96 %double = OpTypeFloat 64
97 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
98 %true = OpConstantTrue %bool
99 %false = OpConstantFalse %bool
100 %short = OpTypeInt 16 1
101 %int = OpTypeInt 32 1
102 %long = OpTypeInt 64 1
103 %uint = OpTypeInt 32 1
104 %v2int = OpTypeVector %int 2
105 %v4int = OpTypeVector %int 4
106 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
107 %_ptr_int = OpTypePointer Function %int
108 %_ptr_uint = OpTypePointer Function %uint
109 %_ptr_bool = OpTypePointer Function %bool
110 %short_0 = OpConstant %short 0
111 %short_3 = OpConstant %short 3
112 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
113 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
114 %int_0 = OpConstant %int 0
115 %int_1 = OpConstant %int 1
116 %int_3 = OpConstant %int 3
117 %int_min = OpConstant %int -2147483648
118 %int_max = OpConstant %int 2147483647
119 %long_0 = OpConstant %long 0
120 %long_3 = OpConstant %long 3
121 %uint_0 = OpConstant %uint 0
122 %uint_3 = OpConstant %uint 3
123 %uint_32 = OpConstant %uint 32
124 %uint_max = OpConstant %uint -1
125 %v2int_undef = OpUndef %v2int
126 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
127 %102 = OpConstantComposite %v2int %103 %103
128 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
129 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
130 %float16_0 = OpConstant %float16 0
131 %float16_1 = OpConstant %float16 1
132 %float16_2 = OpConstant %float16 2
133 %float_n1 = OpConstant %float -1
134 %float_0 = OpConstant %float 0
135 %float_1 = OpConstant %float 1
136 %float_2 = OpConstant %float 2
137 %float_3 = OpConstant %float 3
138 %double_n1 = OpConstant %double -1
139 %double_0 = OpConstant %double 0
140 %double_1 = OpConstant %double 1
141 %double_2 = OpConstant %double 2
142 %double_3 = OpConstant %double 3
149 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
151 // Test case 0: fold 0*n
152 InstructionFoldingCase<uint32_t>(
153 Header() + "%main = OpFunction %void None %void_func\n" +
154 "%main_lab = OpLabel\n" +
155 "%n = OpVariable %_ptr_int Function\n" +
156 "%load = OpLoad %int %n\n" +
157 "%2 = OpIMul %int %int_0 %load\n" +
161 // Test case 1: fold n*0
162 InstructionFoldingCase<uint32_t>(
163 Header() + "%main = OpFunction %void None %void_func\n" +
164 "%main_lab = OpLabel\n" +
165 "%n = OpVariable %_ptr_int Function\n" +
166 "%load = OpLoad %int %n\n" +
167 "%2 = OpIMul %int %load %int_0\n" +
171 // Test case 2: fold 0/n (signed)
172 InstructionFoldingCase<uint32_t>(
173 Header() + "%main = OpFunction %void None %void_func\n" +
174 "%main_lab = OpLabel\n" +
175 "%n = OpVariable %_ptr_int Function\n" +
176 "%load = OpLoad %int %n\n" +
177 "%2 = OpSDiv %int %int_0 %load\n" +
181 // Test case 3: fold n/0 (signed)
182 InstructionFoldingCase<uint32_t>(
183 Header() + "%main = OpFunction %void None %void_func\n" +
184 "%main_lab = OpLabel\n" +
185 "%n = OpVariable %_ptr_int Function\n" +
186 "%load = OpLoad %int %n\n" +
187 "%2 = OpSDiv %int %load %int_0\n" +
191 // Test case 4: fold 0/n (unsigned)
192 InstructionFoldingCase<uint32_t>(
193 Header() + "%main = OpFunction %void None %void_func\n" +
194 "%main_lab = OpLabel\n" +
195 "%n = OpVariable %_ptr_uint Function\n" +
196 "%load = OpLoad %uint %n\n" +
197 "%2 = OpUDiv %uint %uint_0 %load\n" +
201 // Test case 5: fold n/0 (unsigned)
202 InstructionFoldingCase<uint32_t>(
203 Header() + "%main = OpFunction %void None %void_func\n" +
204 "%main_lab = OpLabel\n" +
205 "%n = OpVariable %_ptr_int Function\n" +
206 "%load = OpLoad %int %n\n" +
207 "%2 = OpSDiv %int %load %int_0\n" +
211 // Test case 6: fold 0 remainder n
212 InstructionFoldingCase<uint32_t>(
213 Header() + "%main = OpFunction %void None %void_func\n" +
214 "%main_lab = OpLabel\n" +
215 "%n = OpVariable %_ptr_int Function\n" +
216 "%load = OpLoad %int %n\n" +
217 "%2 = OpSRem %int %int_0 %load\n" +
221 // Test case 7: fold n remainder 0
222 InstructionFoldingCase<uint32_t>(
223 Header() + "%main = OpFunction %void None %void_func\n" +
224 "%main_lab = OpLabel\n" +
225 "%n = OpVariable %_ptr_int Function\n" +
226 "%load = OpLoad %int %n\n" +
227 "%2 = OpSRem %int %load %int_0\n" +
231 // Test case 8: fold 0%n (signed)
232 InstructionFoldingCase<uint32_t>(
233 Header() + "%main = OpFunction %void None %void_func\n" +
234 "%main_lab = OpLabel\n" +
235 "%n = OpVariable %_ptr_int Function\n" +
236 "%load = OpLoad %int %n\n" +
237 "%2 = OpSMod %int %int_0 %load\n" +
241 // Test case 9: fold n%0 (signed)
242 InstructionFoldingCase<uint32_t>(
243 Header() + "%main = OpFunction %void None %void_func\n" +
244 "%main_lab = OpLabel\n" +
245 "%n = OpVariable %_ptr_int Function\n" +
246 "%load = OpLoad %int %n\n" +
247 "%2 = OpSMod %int %load %int_0\n" +
251 // Test case 10: fold 0%n (unsigned)
252 InstructionFoldingCase<uint32_t>(
253 Header() + "%main = OpFunction %void None %void_func\n" +
254 "%main_lab = OpLabel\n" +
255 "%n = OpVariable %_ptr_uint Function\n" +
256 "%load = OpLoad %uint %n\n" +
257 "%2 = OpUMod %uint %uint_0 %load\n" +
261 // Test case 11: fold n%0 (unsigned)
262 InstructionFoldingCase<uint32_t>(
263 Header() + "%main = OpFunction %void None %void_func\n" +
264 "%main_lab = OpLabel\n" +
265 "%n = OpVariable %_ptr_uint Function\n" +
266 "%load = OpLoad %uint %n\n" +
267 "%2 = OpUMod %uint %load %uint_0\n" +
271 // Test case 12: fold n << 32
272 InstructionFoldingCase<uint32_t>(
273 Header() + "%main = OpFunction %void None %void_func\n" +
274 "%main_lab = OpLabel\n" +
275 "%n = OpVariable %_ptr_uint Function\n" +
276 "%load = OpLoad %uint %n\n" +
277 "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
281 // Test case 13: fold n >> 32
282 InstructionFoldingCase<uint32_t>(
283 Header() + "%main = OpFunction %void None %void_func\n" +
284 "%main_lab = OpLabel\n" +
285 "%n = OpVariable %_ptr_uint Function\n" +
286 "%load = OpLoad %uint %n\n" +
287 "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
291 // Test case 14: fold n | 0xFFFFFFFF
292 InstructionFoldingCase<uint32_t>(
293 Header() + "%main = OpFunction %void None %void_func\n" +
294 "%main_lab = OpLabel\n" +
295 "%n = OpVariable %_ptr_uint Function\n" +
296 "%load = OpLoad %uint %n\n" +
297 "%2 = OpBitwiseOr %uint %load %uint_max\n" +
301 // Test case 15: fold 0xFFFFFFFF | n
302 InstructionFoldingCase<uint32_t>(
303 Header() + "%main = OpFunction %void None %void_func\n" +
304 "%main_lab = OpLabel\n" +
305 "%n = OpVariable %_ptr_uint Function\n" +
306 "%load = OpLoad %uint %n\n" +
307 "%2 = OpBitwiseOr %uint %uint_max %load\n" +
311 // Test case 16: fold n & 0
312 InstructionFoldingCase<uint32_t>(
313 Header() + "%main = OpFunction %void None %void_func\n" +
314 "%main_lab = OpLabel\n" +
315 "%n = OpVariable %_ptr_uint Function\n" +
316 "%load = OpLoad %uint %n\n" +
317 "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
324 using BooleanInstructionFoldingTest =
325 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
327 TEST_P(BooleanInstructionFoldingTest, Case) {
328 const auto& tc = GetParam();
331 std::unique_ptr<ir::IRContext> context =
332 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
333 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
334 ASSERT_NE(nullptr, context);
336 // Fold the instruction to test.
337 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
338 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
339 bool succeeded = opt::FoldInstruction(inst);
341 // Make sure the instruction folded as expected.
342 EXPECT_TRUE(succeeded);
343 if (inst != nullptr) {
344 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
345 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
346 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
347 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
348 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
349 const opt::analysis::BoolConstant* result =
350 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
351 EXPECT_NE(result, nullptr);
352 if (result != nullptr) {
353 EXPECT_EQ(result->value(), tc.expected_result);
359 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest,
361 // Test case 0: fold true || n
362 InstructionFoldingCase<bool>(
363 Header() + "%main = OpFunction %void None %void_func\n" +
364 "%main_lab = OpLabel\n" +
365 "%n = OpVariable %_ptr_bool Function\n" +
366 "%load = OpLoad %bool %n\n" +
367 "%2 = OpLogicalOr %bool %true %load\n" +
371 // Test case 1: fold n || true
372 InstructionFoldingCase<bool>(
373 Header() + "%main = OpFunction %void None %void_func\n" +
374 "%main_lab = OpLabel\n" +
375 "%n = OpVariable %_ptr_bool Function\n" +
376 "%load = OpLoad %bool %n\n" +
377 "%2 = OpLogicalOr %bool %load %true\n" +
381 // Test case 2: fold false && n
382 InstructionFoldingCase<bool>(
383 Header() + "%main = OpFunction %void None %void_func\n" +
384 "%main_lab = OpLabel\n" +
385 "%n = OpVariable %_ptr_bool Function\n" +
386 "%load = OpLoad %bool %n\n" +
387 "%2 = OpLogicalAnd %bool %false %load\n" +
391 // Test case 3: fold n && false
392 InstructionFoldingCase<bool>(
393 Header() + "%main = OpFunction %void None %void_func\n" +
394 "%main_lab = OpLabel\n" +
395 "%n = OpVariable %_ptr_bool Function\n" +
396 "%load = OpLoad %bool %n\n" +
397 "%2 = OpLogicalAnd %bool %load %false\n" +
401 // Test case 4: fold n < 0 (unsigned)
402 InstructionFoldingCase<bool>(
403 Header() + "%main = OpFunction %void None %void_func\n" +
404 "%main_lab = OpLabel\n" +
405 "%n = OpVariable %_ptr_uint Function\n" +
406 "%load = OpLoad %uint %n\n" +
407 "%2 = OpULessThan %bool %load %uint_0\n" +
411 // Test case 5: fold UINT_MAX < n (unsigned)
412 InstructionFoldingCase<bool>(
413 Header() + "%main = OpFunction %void None %void_func\n" +
414 "%main_lab = OpLabel\n" +
415 "%n = OpVariable %_ptr_uint Function\n" +
416 "%load = OpLoad %uint %n\n" +
417 "%2 = OpULessThan %bool %uint_max %load\n" +
421 // Test case 6: fold INT_MAX < n (signed)
422 InstructionFoldingCase<bool>(
423 Header() + "%main = OpFunction %void None %void_func\n" +
424 "%main_lab = OpLabel\n" +
425 "%n = OpVariable %_ptr_int Function\n" +
426 "%load = OpLoad %int %n\n" +
427 "%2 = OpSLessThan %bool %int_max %load\n" +
431 // Test case 7: fold n < INT_MIN (signed)
432 InstructionFoldingCase<bool>(
433 Header() + "%main = OpFunction %void None %void_func\n" +
434 "%main_lab = OpLabel\n" +
435 "%n = OpVariable %_ptr_int Function\n" +
436 "%load = OpLoad %int %n\n" +
437 "%2 = OpSLessThan %bool %load %int_min\n" +
441 // Test case 8: fold 0 > n (unsigned)
442 InstructionFoldingCase<bool>(
443 Header() + "%main = OpFunction %void None %void_func\n" +
444 "%main_lab = OpLabel\n" +
445 "%n = OpVariable %_ptr_uint Function\n" +
446 "%load = OpLoad %uint %n\n" +
447 "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
451 // Test case 9: fold n > UINT_MAX (unsigned)
452 InstructionFoldingCase<bool>(
453 Header() + "%main = OpFunction %void None %void_func\n" +
454 "%main_lab = OpLabel\n" +
455 "%n = OpVariable %_ptr_uint Function\n" +
456 "%load = OpLoad %uint %n\n" +
457 "%2 = OpUGreaterThan %bool %load %uint_max\n" +
461 // Test case 10: fold n > INT_MAX (signed)
462 InstructionFoldingCase<bool>(
463 Header() + "%main = OpFunction %void None %void_func\n" +
464 "%main_lab = OpLabel\n" +
465 "%n = OpVariable %_ptr_int Function\n" +
466 "%load = OpLoad %int %n\n" +
467 "%2 = OpSGreaterThan %bool %load %int_max\n" +
471 // Test case 11: fold INT_MIN > n (signed)
472 InstructionFoldingCase<bool>(
473 Header() + "%main = OpFunction %void None %void_func\n" +
474 "%main_lab = OpLabel\n" +
475 "%n = OpVariable %_ptr_uint Function\n" +
476 "%load = OpLoad %uint %n\n" +
477 "%2 = OpSGreaterThan %bool %int_min %load\n" +
481 // Test case 12: fold 0 <= n (unsigned)
482 InstructionFoldingCase<bool>(
483 Header() + "%main = OpFunction %void None %void_func\n" +
484 "%main_lab = OpLabel\n" +
485 "%n = OpVariable %_ptr_uint Function\n" +
486 "%load = OpLoad %uint %n\n" +
487 "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
491 // Test case 13: fold n <= UINT_MAX (unsigned)
492 InstructionFoldingCase<bool>(
493 Header() + "%main = OpFunction %void None %void_func\n" +
494 "%main_lab = OpLabel\n" +
495 "%n = OpVariable %_ptr_uint Function\n" +
496 "%load = OpLoad %uint %n\n" +
497 "%2 = OpULessThanEqual %bool %load %uint_max\n" +
501 // Test case 14: fold INT_MIN <= n (signed)
502 InstructionFoldingCase<bool>(
503 Header() + "%main = OpFunction %void None %void_func\n" +
504 "%main_lab = OpLabel\n" +
505 "%n = OpVariable %_ptr_int Function\n" +
506 "%load = OpLoad %int %n\n" +
507 "%2 = OpSLessThanEqual %bool %int_min %load\n" +
511 // Test case 15: fold n <= INT_MAX (signed)
512 InstructionFoldingCase<bool>(
513 Header() + "%main = OpFunction %void None %void_func\n" +
514 "%main_lab = OpLabel\n" +
515 "%n = OpVariable %_ptr_int Function\n" +
516 "%load = OpLoad %int %n\n" +
517 "%2 = OpSLessThanEqual %bool %load %int_max\n" +
521 // Test case 16: fold n >= 0 (unsigned)
522 InstructionFoldingCase<bool>(
523 Header() + "%main = OpFunction %void None %void_func\n" +
524 "%main_lab = OpLabel\n" +
525 "%n = OpVariable %_ptr_uint Function\n" +
526 "%load = OpLoad %uint %n\n" +
527 "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
531 // Test case 17: fold UINT_MAX >= n (unsigned)
532 InstructionFoldingCase<bool>(
533 Header() + "%main = OpFunction %void None %void_func\n" +
534 "%main_lab = OpLabel\n" +
535 "%n = OpVariable %_ptr_uint Function\n" +
536 "%load = OpLoad %uint %n\n" +
537 "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
541 // Test case 18: fold n >= INT_MIN (signed)
542 InstructionFoldingCase<bool>(
543 Header() + "%main = OpFunction %void None %void_func\n" +
544 "%main_lab = OpLabel\n" +
545 "%n = OpVariable %_ptr_int Function\n" +
546 "%load = OpLoad %int %n\n" +
547 "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
551 // Test case 19: fold INT_MAX >= n (signed)
552 InstructionFoldingCase<bool>(
553 Header() + "%main = OpFunction %void None %void_func\n" +
554 "%main_lab = OpLabel\n" +
555 "%n = OpVariable %_ptr_int Function\n" +
556 "%load = OpLoad %int %n\n" +
557 "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
564 using FloatInstructionFoldingTest =
565 ::testing::TestWithParam<InstructionFoldingCase<float>>;
567 TEST_P(FloatInstructionFoldingTest, Case) {
568 const auto& tc = GetParam();
571 std::unique_ptr<ir::IRContext> context =
572 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
573 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
574 ASSERT_NE(nullptr, context);
576 // Fold the instruction to test.
577 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
578 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
579 bool succeeded = opt::FoldInstruction(inst);
581 // Make sure the instruction folded as expected.
582 EXPECT_TRUE(succeeded);
583 if (inst != nullptr) {
584 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
585 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
586 EXPECT_EQ(inst->opcode(), SpvOpConstant);
587 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
588 const opt::analysis::FloatConstant* result =
589 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
590 EXPECT_NE(result, nullptr);
591 if (result != nullptr) {
592 EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
597 // Not testing NaNs because there are no expectations concerning NaNs according
598 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
602 INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
604 // Test case 0: Fold 2.0 - 1.0
605 InstructionFoldingCase<float>(
606 Header() + "%main = OpFunction %void None %void_func\n" +
607 "%main_lab = OpLabel\n" +
608 "%2 = OpFSub %float %float_2 %float_1\n" +
612 // Test case 1: Fold 2.0 + 1.0
613 InstructionFoldingCase<float>(
614 Header() + "%main = OpFunction %void None %void_func\n" +
615 "%main_lab = OpLabel\n" +
616 "%2 = OpFAdd %float %float_2 %float_1\n" +
620 // Test case 2: Fold 3.0 * 2.0
621 InstructionFoldingCase<float>(
622 Header() + "%main = OpFunction %void None %void_func\n" +
623 "%main_lab = OpLabel\n" +
624 "%2 = OpFMul %float %float_3 %float_2\n" +
628 // Test case 3: Fold 1.0 / 2.0
629 InstructionFoldingCase<float>(
630 Header() + "%main = OpFunction %void None %void_func\n" +
631 "%main_lab = OpLabel\n" +
632 "%2 = OpFDiv %float %float_1 %float_2\n" +
636 // Test case 4: Fold 1.0 / 0.0
637 InstructionFoldingCase<float>(
638 Header() + "%main = OpFunction %void None %void_func\n" +
639 "%main_lab = OpLabel\n" +
640 "%2 = OpFDiv %float %float_1 %float_0\n" +
643 2, std::numeric_limits<float>::infinity()),
644 // Test case 4: Fold -1.0 / 0.0
645 InstructionFoldingCase<float>(
646 Header() + "%main = OpFunction %void None %void_func\n" +
647 "%main_lab = OpLabel\n" +
648 "%2 = OpFDiv %float %float_n1 %float_0\n" +
651 2, -std::numeric_limits<float>::infinity())
655 using DoubleInstructionFoldingTest =
656 ::testing::TestWithParam<InstructionFoldingCase<double>>;
658 TEST_P(DoubleInstructionFoldingTest, Case) {
659 const auto& tc = GetParam();
662 std::unique_ptr<ir::IRContext> context =
663 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
664 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
665 ASSERT_NE(nullptr, context);
667 // Fold the instruction to test.
668 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
669 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
670 bool succeeded = opt::FoldInstruction(inst);
672 // Make sure the instruction folded as expected.
673 EXPECT_TRUE(succeeded);
674 if (inst != nullptr) {
675 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
676 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
677 EXPECT_EQ(inst->opcode(), SpvOpConstant);
678 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
679 const opt::analysis::FloatConstant* result =
680 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
681 EXPECT_NE(result, nullptr);
682 if (result != nullptr) {
683 EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
689 INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
691 // Test case 0: Fold 2.0 - 1.0
692 InstructionFoldingCase<double>(
693 Header() + "%main = OpFunction %void None %void_func\n" +
694 "%main_lab = OpLabel\n" +
695 "%2 = OpFSub %double %double_2 %double_1\n" +
699 // Test case 1: Fold 2.0 + 1.0
700 InstructionFoldingCase<double>(
701 Header() + "%main = OpFunction %void None %void_func\n" +
702 "%main_lab = OpLabel\n" +
703 "%2 = OpFAdd %double %double_2 %double_1\n" +
707 // Test case 2: Fold 3.0 * 2.0
708 InstructionFoldingCase<double>(
709 Header() + "%main = OpFunction %void None %void_func\n" +
710 "%main_lab = OpLabel\n" +
711 "%2 = OpFMul %double %double_3 %double_2\n" +
715 // Test case 3: Fold 1.0 / 2.0
716 InstructionFoldingCase<double>(
717 Header() + "%main = OpFunction %void None %void_func\n" +
718 "%main_lab = OpLabel\n" +
719 "%2 = OpFDiv %double %double_1 %double_2\n" +
723 // Test case 4: Fold 1.0 / 0.0
724 InstructionFoldingCase<double>(
725 Header() + "%main = OpFunction %void None %void_func\n" +
726 "%main_lab = OpLabel\n" +
727 "%2 = OpFDiv %double %double_1 %double_0\n" +
730 2, std::numeric_limits<double>::infinity()),
731 // Test case 4: Fold -1.0 / 0.0
732 InstructionFoldingCase<double>(
733 Header() + "%main = OpFunction %void None %void_func\n" +
734 "%main_lab = OpLabel\n" +
735 "%2 = OpFDiv %double %double_n1 %double_0\n" +
738 2, -std::numeric_limits<double>::infinity())
741 template <class ResultType>
742 struct InstructionFoldingCaseWithMap {
743 InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
745 std::function<uint32_t(uint32_t)> map)
746 : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
748 std::string test_body;
750 ResultType expected_result;
751 std::function<uint32_t(uint32_t)> id_map;
754 using IntegerInstructionFoldingTestWithMap =
755 ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
757 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
758 const auto& tc = GetParam();
761 std::unique_ptr<ir::IRContext> context =
762 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
763 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
764 ASSERT_NE(nullptr, context);
766 // Fold the instruction to test.
767 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
768 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
769 inst = opt::FoldInstructionToConstant(inst, tc.id_map);
771 // Make sure the instruction folded as expected.
772 EXPECT_NE(inst, nullptr);
773 if (inst != nullptr) {
774 EXPECT_EQ(inst->opcode(), SpvOpConstant);
775 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
776 const opt::analysis::IntConstant* result =
777 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
778 EXPECT_NE(result, nullptr);
779 if (result != nullptr) {
780 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
785 INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap,
787 // Test case 0: fold %3 = 0; %3 * n
788 InstructionFoldingCaseWithMap<uint32_t>(
789 Header() + "%main = OpFunction %void None %void_func\n" +
790 "%main_lab = OpLabel\n" +
791 "%n = OpVariable %_ptr_int Function\n" +
792 "%load = OpLoad %int %n\n" +
793 "%3 = OpCopyObject %int %int_0\n"
794 "%2 = OpIMul %int %3 %load\n" +
797 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
801 using BooleanInstructionFoldingTestWithMap =
802 ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
804 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
805 const auto& tc = GetParam();
808 std::unique_ptr<ir::IRContext> context =
809 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
810 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
811 ASSERT_NE(nullptr, context);
813 // Fold the instruction to test.
814 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
815 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
816 inst = opt::FoldInstructionToConstant(inst, tc.id_map);
818 // Make sure the instruction folded as expected.
819 EXPECT_NE(inst, nullptr);
820 if (inst != nullptr) {
821 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
822 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
823 opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
824 const opt::analysis::BoolConstant* result =
825 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
826 EXPECT_NE(result, nullptr);
827 if (result != nullptr) {
828 EXPECT_EQ(result->value(), tc.expected_result);
834 INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap,
836 // Test case 0: fold %3 = true; %3 || n
837 InstructionFoldingCaseWithMap<bool>(
838 Header() + "%main = OpFunction %void None %void_func\n" +
839 "%main_lab = OpLabel\n" +
840 "%n = OpVariable %_ptr_bool Function\n" +
841 "%load = OpLoad %bool %n\n" +
842 "%3 = OpCopyObject %bool %true\n" +
843 "%2 = OpLogicalOr %bool %3 %load\n" +
846 2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
850 using GeneralInstructionFoldingTest =
851 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
853 TEST_P(GeneralInstructionFoldingTest, Case) {
854 const auto& tc = GetParam();
857 std::unique_ptr<ir::IRContext> context =
858 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
859 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
860 ASSERT_NE(nullptr, context);
862 // Fold the instruction to test.
863 opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
864 ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
865 std::unique_ptr<ir::Instruction> original_inst(inst->Clone(context.get()));
866 bool succeeded = opt::FoldInstruction(inst);
868 // Make sure the instruction folded as expected.
869 EXPECT_EQ(inst->result_id(), original_inst->result_id());
870 EXPECT_EQ(inst->type_id(), original_inst->type_id());
871 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
873 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
874 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
876 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
877 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
878 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
884 INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
886 // Test case 0: Don't fold n * m
887 InstructionFoldingCase<uint32_t>(
888 Header() + "%main = OpFunction %void None %void_func\n" +
889 "%main_lab = OpLabel\n" +
890 "%n = OpVariable %_ptr_int Function\n" +
891 "%m = OpVariable %_ptr_int Function\n" +
892 "%load_n = OpLoad %int %n\n" +
893 "%load_m = OpLoad %int %m\n" +
894 "%2 = OpIMul %int %load_n %load_m\n" +
898 // Test case 1: Don't fold n / m (unsigned)
899 InstructionFoldingCase<uint32_t>(
900 Header() + "%main = OpFunction %void None %void_func\n" +
901 "%main_lab = OpLabel\n" +
902 "%n = OpVariable %_ptr_uint Function\n" +
903 "%m = OpVariable %_ptr_uint Function\n" +
904 "%load_n = OpLoad %uint %n\n" +
905 "%load_m = OpLoad %uint %m\n" +
906 "%2 = OpUDiv %uint %load_n %load_m\n" +
910 // Test case 2: Don't fold n / m (signed)
911 InstructionFoldingCase<uint32_t>(
912 Header() + "%main = OpFunction %void None %void_func\n" +
913 "%main_lab = OpLabel\n" +
914 "%n = OpVariable %_ptr_int Function\n" +
915 "%m = OpVariable %_ptr_int Function\n" +
916 "%load_n = OpLoad %int %n\n" +
917 "%load_m = OpLoad %int %m\n" +
918 "%2 = OpSDiv %int %load_n %load_m\n" +
922 // Test case 3: Don't fold n remainder m
923 InstructionFoldingCase<uint32_t>(
924 Header() + "%main = OpFunction %void None %void_func\n" +
925 "%main_lab = OpLabel\n" +
926 "%n = OpVariable %_ptr_int Function\n" +
927 "%m = OpVariable %_ptr_int Function\n" +
928 "%load_n = OpLoad %int %n\n" +
929 "%load_m = OpLoad %int %m\n" +
930 "%2 = OpSRem %int %load_n %load_m\n" +
934 // Test case 4: Don't fold n % m (signed)
935 InstructionFoldingCase<uint32_t>(
936 Header() + "%main = OpFunction %void None %void_func\n" +
937 "%main_lab = OpLabel\n" +
938 "%n = OpVariable %_ptr_int Function\n" +
939 "%m = OpVariable %_ptr_int Function\n" +
940 "%load_n = OpLoad %int %n\n" +
941 "%load_m = OpLoad %int %m\n" +
942 "%2 = OpSMod %int %load_n %load_m\n" +
946 // Test case 5: Don't fold n % m (unsigned)
947 InstructionFoldingCase<uint32_t>(
948 Header() + "%main = OpFunction %void None %void_func\n" +
949 "%main_lab = OpLabel\n" +
950 "%n = OpVariable %_ptr_uint Function\n" +
951 "%m = OpVariable %_ptr_uint Function\n" +
952 "%load_n = OpLoad %uint %n\n" +
953 "%load_m = OpLoad %uint %m\n" +
954 "%2 = OpUMod %int %load_n %load_m\n" +
958 // Test case 6: Don't fold n << m
959 InstructionFoldingCase<uint32_t>(
960 Header() + "%main = OpFunction %void None %void_func\n" +
961 "%main_lab = OpLabel\n" +
962 "%n = OpVariable %_ptr_uint Function\n" +
963 "%m = OpVariable %_ptr_uint Function\n" +
964 "%load_n = OpLoad %uint %n\n" +
965 "%load_m = OpLoad %uint %m\n" +
966 "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
970 // Test case 7: Don't fold n >> m
971 InstructionFoldingCase<uint32_t>(
972 Header() + "%main = OpFunction %void None %void_func\n" +
973 "%main_lab = OpLabel\n" +
974 "%n = OpVariable %_ptr_uint Function\n" +
975 "%m = OpVariable %_ptr_uint Function\n" +
976 "%load_n = OpLoad %uint %n\n" +
977 "%load_m = OpLoad %uint %m\n" +
978 "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
982 // Test case 8: Don't fold n | m
983 InstructionFoldingCase<uint32_t>(
984 Header() + "%main = OpFunction %void None %void_func\n" +
985 "%main_lab = OpLabel\n" +
986 "%n = OpVariable %_ptr_uint Function\n" +
987 "%m = OpVariable %_ptr_uint Function\n" +
988 "%load_n = OpLoad %uint %n\n" +
989 "%load_m = OpLoad %uint %m\n" +
990 "%2 = OpBitwiseOr %int %load_n %load_m\n" +
994 // Test case 9: Don't fold n & m
995 InstructionFoldingCase<uint32_t>(
996 Header() + "%main = OpFunction %void None %void_func\n" +
997 "%main_lab = OpLabel\n" +
998 "%n = OpVariable %_ptr_uint Function\n" +
999 "%m = OpVariable %_ptr_uint Function\n" +
1000 "%load_n = OpLoad %uint %n\n" +
1001 "%load_m = OpLoad %uint %m\n" +
1002 "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
1006 // Test case 10: Don't fold n < m (unsigned)
1007 InstructionFoldingCase<uint32_t>(
1008 Header() + "%main = OpFunction %void None %void_func\n" +
1009 "%main_lab = OpLabel\n" +
1010 "%n = OpVariable %_ptr_uint Function\n" +
1011 "%m = OpVariable %_ptr_uint Function\n" +
1012 "%load_n = OpLoad %uint %n\n" +
1013 "%load_m = OpLoad %uint %m\n" +
1014 "%2 = OpULessThan %bool %load_n %load_m\n" +
1018 // Test case 11: Don't fold n > m (unsigned)
1019 InstructionFoldingCase<uint32_t>(
1020 Header() + "%main = OpFunction %void None %void_func\n" +
1021 "%main_lab = OpLabel\n" +
1022 "%n = OpVariable %_ptr_uint Function\n" +
1023 "%m = OpVariable %_ptr_uint Function\n" +
1024 "%load_n = OpLoad %uint %n\n" +
1025 "%load_m = OpLoad %uint %m\n" +
1026 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1030 // Test case 12: Don't fold n <= m (unsigned)
1031 InstructionFoldingCase<uint32_t>(
1032 Header() + "%main = OpFunction %void None %void_func\n" +
1033 "%main_lab = OpLabel\n" +
1034 "%n = OpVariable %_ptr_uint Function\n" +
1035 "%m = OpVariable %_ptr_uint Function\n" +
1036 "%load_n = OpLoad %uint %n\n" +
1037 "%load_m = OpLoad %uint %m\n" +
1038 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1042 // Test case 13: Don't fold n >= m (unsigned)
1043 InstructionFoldingCase<uint32_t>(
1044 Header() + "%main = OpFunction %void None %void_func\n" +
1045 "%main_lab = OpLabel\n" +
1046 "%n = OpVariable %_ptr_uint Function\n" +
1047 "%m = OpVariable %_ptr_uint Function\n" +
1048 "%load_n = OpLoad %uint %n\n" +
1049 "%load_m = OpLoad %uint %m\n" +
1050 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1054 // Test case 14: Don't fold n < m (signed)
1055 InstructionFoldingCase<uint32_t>(
1056 Header() + "%main = OpFunction %void None %void_func\n" +
1057 "%main_lab = OpLabel\n" +
1058 "%n = OpVariable %_ptr_int Function\n" +
1059 "%m = OpVariable %_ptr_int Function\n" +
1060 "%load_n = OpLoad %int %n\n" +
1061 "%load_m = OpLoad %int %m\n" +
1062 "%2 = OpULessThan %bool %load_n %load_m\n" +
1066 // Test case 15: Don't fold n > m (signed)
1067 InstructionFoldingCase<uint32_t>(
1068 Header() + "%main = OpFunction %void None %void_func\n" +
1069 "%main_lab = OpLabel\n" +
1070 "%n = OpVariable %_ptr_int Function\n" +
1071 "%m = OpVariable %_ptr_int Function\n" +
1072 "%load_n = OpLoad %int %n\n" +
1073 "%load_m = OpLoad %int %m\n" +
1074 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
1078 // Test case 16: Don't fold n <= m (signed)
1079 InstructionFoldingCase<uint32_t>(
1080 Header() + "%main = OpFunction %void None %void_func\n" +
1081 "%main_lab = OpLabel\n" +
1082 "%n = OpVariable %_ptr_int Function\n" +
1083 "%m = OpVariable %_ptr_int Function\n" +
1084 "%load_n = OpLoad %int %n\n" +
1085 "%load_m = OpLoad %int %m\n" +
1086 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
1090 // Test case 17: Don't fold n >= m (signed)
1091 InstructionFoldingCase<uint32_t>(
1092 Header() + "%main = OpFunction %void None %void_func\n" +
1093 "%main_lab = OpLabel\n" +
1094 "%n = OpVariable %_ptr_int Function\n" +
1095 "%m = OpVariable %_ptr_int Function\n" +
1096 "%load_n = OpLoad %int %n\n" +
1097 "%load_m = OpLoad %int %m\n" +
1098 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
1102 // Test case 18: Don't fold n || m
1103 InstructionFoldingCase<uint32_t>(
1104 Header() + "%main = OpFunction %void None %void_func\n" +
1105 "%main_lab = OpLabel\n" +
1106 "%n = OpVariable %_ptr_bool Function\n" +
1107 "%m = OpVariable %_ptr_bool Function\n" +
1108 "%load_n = OpLoad %bool %n\n" +
1109 "%load_m = OpLoad %bool %m\n" +
1110 "%2 = OpLogicalOr %bool %load_n %load_m\n" +
1114 // Test case 19: Don't fold n && m
1115 InstructionFoldingCase<uint32_t>(
1116 Header() + "%main = OpFunction %void None %void_func\n" +
1117 "%main_lab = OpLabel\n" +
1118 "%n = OpVariable %_ptr_bool Function\n" +
1119 "%m = OpVariable %_ptr_bool Function\n" +
1120 "%load_n = OpLoad %bool %n\n" +
1121 "%load_m = OpLoad %bool %m\n" +
1122 "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
1126 // Test case 20: Don't fold n * 3
1127 InstructionFoldingCase<uint32_t>(
1128 Header() + "%main = OpFunction %void None %void_func\n" +
1129 "%main_lab = OpLabel\n" +
1130 "%n = OpVariable %_ptr_int Function\n" +
1131 "%load_n = OpLoad %int %n\n" +
1132 "%2 = OpIMul %int %load_n %int_3\n" +
1136 // Test case 21: Don't fold n / 3 (unsigned)
1137 InstructionFoldingCase<uint32_t>(
1138 Header() + "%main = OpFunction %void None %void_func\n" +
1139 "%main_lab = OpLabel\n" +
1140 "%n = OpVariable %_ptr_uint Function\n" +
1141 "%load_n = OpLoad %uint %n\n" +
1142 "%2 = OpUDiv %uint %load_n %uint_3\n" +
1146 // Test case 22: Don't fold n / 3 (signed)
1147 InstructionFoldingCase<uint32_t>(
1148 Header() + "%main = OpFunction %void None %void_func\n" +
1149 "%main_lab = OpLabel\n" +
1150 "%n = OpVariable %_ptr_int Function\n" +
1151 "%load_n = OpLoad %int %n\n" +
1152 "%2 = OpSDiv %int %load_n %int_3\n" +
1156 // Test case 23: Don't fold n remainder 3
1157 InstructionFoldingCase<uint32_t>(
1158 Header() + "%main = OpFunction %void None %void_func\n" +
1159 "%main_lab = OpLabel\n" +
1160 "%n = OpVariable %_ptr_int Function\n" +
1161 "%load_n = OpLoad %int %n\n" +
1162 "%2 = OpSRem %int %load_n %int_3\n" +
1166 // Test case 24: Don't fold n % 3 (signed)
1167 InstructionFoldingCase<uint32_t>(
1168 Header() + "%main = OpFunction %void None %void_func\n" +
1169 "%main_lab = OpLabel\n" +
1170 "%n = OpVariable %_ptr_int Function\n" +
1171 "%load_n = OpLoad %int %n\n" +
1172 "%2 = OpSMod %int %load_n %int_3\n" +
1176 // Test case 25: Don't fold n % 3 (unsigned)
1177 InstructionFoldingCase<uint32_t>(
1178 Header() + "%main = OpFunction %void None %void_func\n" +
1179 "%main_lab = OpLabel\n" +
1180 "%n = OpVariable %_ptr_uint Function\n" +
1181 "%load_n = OpLoad %uint %n\n" +
1182 "%2 = OpUMod %int %load_n %int_3\n" +
1186 // Test case 26: Don't fold n << 3
1187 InstructionFoldingCase<uint32_t>(
1188 Header() + "%main = OpFunction %void None %void_func\n" +
1189 "%main_lab = OpLabel\n" +
1190 "%n = OpVariable %_ptr_uint Function\n" +
1191 "%load_n = OpLoad %uint %n\n" +
1192 "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
1196 // Test case 27: Don't fold n >> 3
1197 InstructionFoldingCase<uint32_t>(
1198 Header() + "%main = OpFunction %void None %void_func\n" +
1199 "%main_lab = OpLabel\n" +
1200 "%n = OpVariable %_ptr_uint Function\n" +
1201 "%load_n = OpLoad %uint %n\n" +
1202 "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
1206 // Test case 28: Don't fold n | 3
1207 InstructionFoldingCase<uint32_t>(
1208 Header() + "%main = OpFunction %void None %void_func\n" +
1209 "%main_lab = OpLabel\n" +
1210 "%n = OpVariable %_ptr_uint Function\n" +
1211 "%load_n = OpLoad %uint %n\n" +
1212 "%2 = OpBitwiseOr %int %load_n %int_3\n" +
1216 // Test case 29: Don't fold n & 3
1217 InstructionFoldingCase<uint32_t>(
1218 Header() + "%main = OpFunction %void None %void_func\n" +
1219 "%main_lab = OpLabel\n" +
1220 "%n = OpVariable %_ptr_uint Function\n" +
1221 "%load_n = OpLoad %uint %n\n" +
1222 "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
1226 // Test case 30: Don't fold n < 3 (unsigned)
1227 InstructionFoldingCase<uint32_t>(
1228 Header() + "%main = OpFunction %void None %void_func\n" +
1229 "%main_lab = OpLabel\n" +
1230 "%n = OpVariable %_ptr_uint Function\n" +
1231 "%load_n = OpLoad %uint %n\n" +
1232 "%2 = OpULessThan %bool %load_n %uint_3\n" +
1236 // Test case 31: Don't fold n > 3 (unsigned)
1237 InstructionFoldingCase<uint32_t>(
1238 Header() + "%main = OpFunction %void None %void_func\n" +
1239 "%main_lab = OpLabel\n" +
1240 "%n = OpVariable %_ptr_uint Function\n" +
1241 "%load_n = OpLoad %uint %n\n" +
1242 "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
1246 // Test case 32: Don't fold n <= 3 (unsigned)
1247 InstructionFoldingCase<uint32_t>(
1248 Header() + "%main = OpFunction %void None %void_func\n" +
1249 "%main_lab = OpLabel\n" +
1250 "%n = OpVariable %_ptr_uint Function\n" +
1251 "%load_n = OpLoad %uint %n\n" +
1252 "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
1256 // Test case 33: Don't fold n >= 3 (unsigned)
1257 InstructionFoldingCase<uint32_t>(
1258 Header() + "%main = OpFunction %void None %void_func\n" +
1259 "%main_lab = OpLabel\n" +
1260 "%n = OpVariable %_ptr_uint Function\n" +
1261 "%load_n = OpLoad %uint %n\n" +
1262 "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
1266 // Test case 34: Don't fold n < 3 (signed)
1267 InstructionFoldingCase<uint32_t>(
1268 Header() + "%main = OpFunction %void None %void_func\n" +
1269 "%main_lab = OpLabel\n" +
1270 "%n = OpVariable %_ptr_int Function\n" +
1271 "%load_n = OpLoad %int %n\n" +
1272 "%2 = OpULessThan %bool %load_n %int_3\n" +
1276 // Test case 35: Don't fold n > 3 (signed)
1277 InstructionFoldingCase<uint32_t>(
1278 Header() + "%main = OpFunction %void None %void_func\n" +
1279 "%main_lab = OpLabel\n" +
1280 "%n = OpVariable %_ptr_int Function\n" +
1281 "%load_n = OpLoad %int %n\n" +
1282 "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
1286 // Test case 36: Don't fold n <= 3 (signed)
1287 InstructionFoldingCase<uint32_t>(
1288 Header() + "%main = OpFunction %void None %void_func\n" +
1289 "%main_lab = OpLabel\n" +
1290 "%n = OpVariable %_ptr_int Function\n" +
1291 "%load_n = OpLoad %int %n\n" +
1292 "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
1296 // Test case 37: Don't fold n >= 3 (signed)
1297 InstructionFoldingCase<uint32_t>(
1298 Header() + "%main = OpFunction %void None %void_func\n" +
1299 "%main_lab = OpLabel\n" +
1300 "%n = OpVariable %_ptr_int Function\n" +
1301 "%load_n = OpLoad %int %n\n" +
1302 "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
1306 // Test case 38: Don't fold 0 + 3 (long), bad length
1307 InstructionFoldingCase<uint32_t>(
1308 Header() + "%main = OpFunction %void None %void_func\n" +
1309 "%main_lab = OpLabel\n" +
1310 "%2 = OpIAdd %long %long_0 %long_3\n" +
1314 // Test case 39: Don't fold 0 + 3 (short), bad length
1315 InstructionFoldingCase<uint32_t>(
1316 Header() + "%main = OpFunction %void None %void_func\n" +
1317 "%main_lab = OpLabel\n" +
1318 "%2 = OpIAdd %short %short_0 %short_3\n" +
1322 // Test case 40: fold 1*n
1323 InstructionFoldingCase<uint32_t>(
1324 Header() + "%main = OpFunction %void None %void_func\n" +
1325 "%main_lab = OpLabel\n" +
1326 "%n = OpVariable %_ptr_int Function\n" +
1327 "%3 = OpLoad %int %n\n" +
1328 "%2 = OpIMul %int %int_1 %3\n" +
1332 // Test case 41: fold n*1
1333 InstructionFoldingCase<uint32_t>(
1334 Header() + "%main = OpFunction %void None %void_func\n" +
1335 "%main_lab = OpLabel\n" +
1336 "%n = OpVariable %_ptr_int Function\n" +
1337 "%3 = OpLoad %int %n\n" +
1338 "%2 = OpIMul %int %3 %int_1\n" +
1344 INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
1346 // Test case 0: fold Insert feeding extract
1347 InstructionFoldingCase<uint32_t>(
1348 Header() + "%main = OpFunction %void None %void_func\n" +
1349 "%main_lab = OpLabel\n" +
1350 "%n = OpVariable %_ptr_int Function\n" +
1351 "%2 = OpLoad %int %n\n" +
1352 "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
1353 "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
1354 "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
1355 "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
1356 "%7 = OpCompositeExtract %int %6 0\n" +
1360 // Test case 1: fold Composite construct feeding extract (position 0)
1361 InstructionFoldingCase<uint32_t>(
1362 Header() + "%main = OpFunction %void None %void_func\n" +
1363 "%main_lab = OpLabel\n" +
1364 "%n = OpVariable %_ptr_int Function\n" +
1365 "%2 = OpLoad %int %n\n" +
1366 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
1367 "%4 = OpCompositeExtract %int %3 0\n" +
1371 // Test case 2: fold Composite construct feeding extract (position 3)
1372 InstructionFoldingCase<uint32_t>(
1373 Header() + "%main = OpFunction %void None %void_func\n" +
1374 "%main_lab = OpLabel\n" +
1375 "%n = OpVariable %_ptr_int Function\n" +
1376 "%2 = OpLoad %int %n\n" +
1377 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
1378 "%4 = OpCompositeExtract %int %3 3\n" +
1382 // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
1383 InstructionFoldingCase<uint32_t>(
1384 Header() + "%main = OpFunction %void None %void_func\n" +
1385 "%main_lab = OpLabel\n" +
1386 "%n = OpVariable %_ptr_int Function\n" +
1387 "%2 = OpLoad %int %n\n" +
1388 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
1389 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1390 "%5 = OpCompositeExtract %int %4 3\n" +
1394 // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
1395 InstructionFoldingCase<uint32_t>(
1396 Header() + "%main = OpFunction %void None %void_func\n" +
1397 "%main_lab = OpLabel\n" +
1398 "%n = OpVariable %_ptr_int Function\n" +
1399 "%2 = OpLoad %int %n\n" +
1400 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
1401 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1402 "%5 = OpCompositeExtract %int %4 0\n" +
1406 // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
1407 InstructionFoldingCase<uint32_t>(
1408 Header() + "%main = OpFunction %void None %void_func\n" +
1409 "%main_lab = OpLabel\n" +
1410 "%n = OpVariable %_ptr_int Function\n" +
1411 "%2 = OpLoad %int %n\n" +
1412 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
1413 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
1414 "%5 = OpCompositeExtract %int %4 1\n" +
1418 // Test case 6: fold Composite construct with multiple indices.
1419 InstructionFoldingCase<uint32_t>(
1420 Header() + "%main = OpFunction %void None %void_func\n" +
1421 "%main_lab = OpLabel\n" +
1422 "%n = OpVariable %_ptr_int Function\n" +
1423 "%2 = OpLoad %int %n\n" +
1424 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
1425 "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
1426 "%5 = OpCompositeExtract %int %4 0 1\n" +
1430 // Test case 7: fold constant extract.
1431 InstructionFoldingCase<uint32_t>(
1432 Header() + "%main = OpFunction %void None %void_func\n" +
1433 "%main_lab = OpLabel\n" +
1434 "%2 = OpCompositeExtract %int %102 1\n" +
1438 // Test case 8: constant struct has OpUndef
1439 InstructionFoldingCase<uint32_t>(
1440 Header() + "%main = OpFunction %void None %void_func\n" +
1441 "%main_lab = OpLabel\n" +
1442 "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
1448 INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
1450 // Test case 0: fold Extracts feeding construct
1451 InstructionFoldingCase<uint32_t>(
1452 Header() + "%main = OpFunction %void None %void_func\n" +
1453 "%main_lab = OpLabel\n" +
1454 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1455 "%3 = OpCompositeExtract %int %2 0\n" +
1456 "%4 = OpCompositeExtract %int %2 1\n" +
1457 "%5 = OpCompositeExtract %int %2 2\n" +
1458 "%6 = OpCompositeExtract %int %2 3\n" +
1459 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1463 // Test case 1: Don't fold Extracts feeding construct (Different source)
1464 InstructionFoldingCase<uint32_t>(
1465 Header() + "%main = OpFunction %void None %void_func\n" +
1466 "%main_lab = OpLabel\n" +
1467 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1468 "%3 = OpCompositeExtract %int %2 0\n" +
1469 "%4 = OpCompositeExtract %int %2 1\n" +
1470 "%5 = OpCompositeExtract %int %2 2\n" +
1471 "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
1472 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1476 // Test case 2: Don't fold Extracts feeding construct (bad indices)
1477 InstructionFoldingCase<uint32_t>(
1478 Header() + "%main = OpFunction %void None %void_func\n" +
1479 "%main_lab = OpLabel\n" +
1480 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
1481 "%3 = OpCompositeExtract %int %2 0\n" +
1482 "%4 = OpCompositeExtract %int %2 0\n" +
1483 "%5 = OpCompositeExtract %int %2 2\n" +
1484 "%6 = OpCompositeExtract %int %2 3\n" +
1485 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
1489 // Test case 3: Don't fold Extracts feeding construct (different type)
1490 InstructionFoldingCase<uint32_t>(
1491 Header() + "%main = OpFunction %void None %void_func\n" +
1492 "%main_lab = OpLabel\n" +
1493 "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
1494 "%3 = OpCompositeExtract %v2int %2 0\n" +
1495 "%4 = OpCompositeExtract %int %2 1\n" +
1496 "%5 = OpCompositeExtract %int %2 2\n" +
1497 "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
1501 // Test case 4: Fold construct with constants to constant.
1502 InstructionFoldingCase<uint32_t>(
1503 Header() + "%main = OpFunction %void None %void_func\n" +
1504 "%main_lab = OpLabel\n" +
1505 "%2 = OpCompositeConstruct %v2int %103 %103\n" +
1511 INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
1513 // Test case 0: Fold phi with the same values for all edges.
1514 InstructionFoldingCase<uint32_t>(
1515 Header() + "%main = OpFunction %void None %void_func\n" +
1516 "%main_lab = OpLabel\n" +
1517 " OpBranchConditional %true %l1 %l2\n" +
1519 " OpBranch %merge_lab\n" +
1521 " OpBranch %merge_lab\n" +
1522 "%merge_lab = OpLabel\n" +
1523 "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
1527 // Test case 1: Fold phi in pass through loop.
1528 InstructionFoldingCase<uint32_t>(
1529 Header() + "%main = OpFunction %void None %void_func\n" +
1530 "%main_lab = OpLabel\n" +
1533 "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
1534 " OpBranchConditional %true %l1 %merge_lab\n" +
1535 "%merge_lab = OpLabel\n" +
1539 // Test case 2: Don't Fold phi because of different values.
1540 InstructionFoldingCase<uint32_t>(
1541 Header() + "%main = OpFunction %void None %void_func\n" +
1542 "%main_lab = OpLabel\n" +
1545 "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
1546 " OpBranchConditional %true %l1 %merge_lab\n" +
1547 "%merge_lab = OpLabel\n" +
1553 INSTANTIATE_TEST_CASE_P(SelectFoldingTest, GeneralInstructionFoldingTest,
1555 // Test case 0: Fold select with the same values for both sides
1556 InstructionFoldingCase<uint32_t>(
1557 Header() + "%main = OpFunction %void None %void_func\n" +
1558 "%main_lab = OpLabel\n" +
1559 "%n = OpVariable %_ptr_bool Function\n" +
1560 "%load = OpLoad %bool %n\n" +
1561 "%2 = OpSelect %int %load %100 %100\n" +
1565 // Test case 1: Fold select true to left side
1566 InstructionFoldingCase<uint32_t>(
1567 Header() + "%main = OpFunction %void None %void_func\n" +
1568 "%main_lab = OpLabel\n" +
1569 "%n = OpVariable %_ptr_int Function\n" +
1570 "%load = OpLoad %bool %n\n" +
1571 "%2 = OpSelect %int %true %100 %n\n" +
1575 // Test case 2: Fold select false to right side
1576 InstructionFoldingCase<uint32_t>(
1577 Header() + "%main = OpFunction %void None %void_func\n" +
1578 "%main_lab = OpLabel\n" +
1579 "%n = OpVariable %_ptr_int Function\n" +
1580 "%load = OpLoad %bool %n\n" +
1581 "%2 = OpSelect %int %false %n %100\n" +
1587 } // anonymous namespace