| // Copyright (c) 2016 Google Inc. |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "source/opt/fold.h" |
| |
| #include <limits> |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "effcee/effcee.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "source/opt/build_module.h" |
| #include "source/opt/def_use_manager.h" |
| #include "source/opt/ir_context.h" |
| #include "source/opt/module.h" |
| #include "spirv-tools/libspirv.hpp" |
| #include "test/opt/pass_utils.h" |
| |
| namespace spvtools { |
| namespace opt { |
| namespace { |
| |
| using ::testing::Contains; |
| |
| std::string Disassemble(const std::string& original, IRContext* context, |
| uint32_t disassemble_options = 0) { |
| std::vector<uint32_t> optimized_bin; |
| context->module()->ToBinary(&optimized_bin, true); |
| spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; |
| SpirvTools tools(target_env); |
| std::string optimized_asm; |
| EXPECT_TRUE( |
| tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options)) |
| << "Disassembling failed for shader:\n" |
| << original << std::endl; |
| return optimized_asm; |
| } |
| |
| void Match(const std::string& original, IRContext* context, |
| uint32_t disassemble_options = 0) { |
| std::string disassembly = Disassemble(original, context, disassemble_options); |
| auto match_result = effcee::Match(disassembly, original); |
| EXPECT_EQ(effcee::Result::Status::Ok, match_result.status()) |
| << match_result.message() << "\nChecking result:\n" |
| << disassembly; |
| } |
| |
| template <class ResultType> |
| struct InstructionFoldingCase { |
| InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result) |
| : test_body(tb), id_to_fold(id), expected_result(result) {} |
| |
| std::string test_body; |
| uint32_t id_to_fold; |
| ResultType expected_result; |
| }; |
| |
| using IntegerInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>; |
| |
| TEST_P(IntegerInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_TRUE(succeeded); |
| if (inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst); |
| // We expect to see either integer types or 16-bit float types here. |
| EXPECT_TRUE((constant->AsIntConstant() != nullptr) || |
| ((constant->AsFloatConstant() != nullptr) && |
| (constant->type()->AsFloat()->width() == 16))); |
| const analysis::ScalarConstant* result = |
| const_mrg->GetConstantFromInst(inst)->AsScalarConstant(); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| EXPECT_EQ(result->GetU32BitValue(), tc.expected_result); |
| } |
| } |
| } |
| |
| // Returns a common SPIR-V header for all of the test that follow. |
| #define INT_0_ID 100 |
| #define TRUE_ID 101 |
| #define VEC2_0_ID 102 |
| #define INT_7_ID 103 |
| #define FLOAT_0_ID 104 |
| #define DOUBLE_0_ID 105 |
| #define VEC4_0_ID 106 |
| #define DVEC4_0_ID 106 |
| #define HALF_0_ID 108 |
| const std::string& Header() { |
| static const std::string header = R"(OpCapability Shader |
| OpCapability Float16 |
| OpCapability Float64 |
| OpCapability Int8 |
| OpCapability Int16 |
| OpCapability Int64 |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginUpperLeft |
| OpSource GLSL 140 |
| OpName %main "main" |
| %void = OpTypeVoid |
| %void_func = OpTypeFunction %void |
| %bool = OpTypeBool |
| %float = OpTypeFloat 32 |
| %double = OpTypeFloat 64 |
| %half = OpTypeFloat 16 |
| %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps. |
| %true = OpConstantTrue %bool |
| %false = OpConstantFalse %bool |
| %bool_null = OpConstantNull %bool |
| %short = OpTypeInt 16 1 |
| %ushort = OpTypeInt 16 0 |
| %byte = OpTypeInt 8 1 |
| %ubyte = OpTypeInt 8 0 |
| %int = OpTypeInt 32 1 |
| %long = OpTypeInt 64 1 |
| %uint = OpTypeInt 32 0 |
| %ulong = OpTypeInt 64 0 |
| %v2int = OpTypeVector %int 2 |
| %v4int = OpTypeVector %int 4 |
| %v4float = OpTypeVector %float 4 |
| %v4double = OpTypeVector %double 4 |
| %v2uint = OpTypeVector %uint 2 |
| %v2float = OpTypeVector %float 2 |
| %v2double = OpTypeVector %double 2 |
| %v2half = OpTypeVector %half 2 |
| %v2bool = OpTypeVector %bool 2 |
| %m2x2int = OpTypeMatrix %v2int 2 |
| %mat4v4float = OpTypeMatrix %v4float 4 |
| %mat4v4double = OpTypeMatrix %v4double 4 |
| %struct_v2int_int_int = OpTypeStruct %v2int %int %int |
| %_ptr_int = OpTypePointer Function %int |
| %_ptr_uint = OpTypePointer Function %uint |
| %_ptr_bool = OpTypePointer Function %bool |
| %_ptr_float = OpTypePointer Function %float |
| %_ptr_double = OpTypePointer Function %double |
| %_ptr_half = OpTypePointer Function %half |
| %_ptr_long = OpTypePointer Function %long |
| %_ptr_ulong = OpTypePointer Function %ulong |
| %_ptr_v2int = OpTypePointer Function %v2int |
| %_ptr_v4int = OpTypePointer Function %v4int |
| %_ptr_v4float = OpTypePointer Function %v4float |
| %_ptr_v4double = OpTypePointer Function %v4double |
| %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int |
| %_ptr_v2float = OpTypePointer Function %v2float |
| %_ptr_v2double = OpTypePointer Function %v2double |
| %short_0 = OpConstant %short 0 |
| %short_2 = OpConstant %short 2 |
| %short_3 = OpConstant %short 3 |
| %ubyte_1 = OpConstant %ubyte 1 |
| %byte_n1 = OpConstant %byte -1 |
| %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps. |
| %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps. |
| %int_0 = OpConstant %int 0 |
| %int_1 = OpConstant %int 1 |
| %int_2 = OpConstant %int 2 |
| %int_3 = OpConstant %int 3 |
| %int_4 = OpConstant %int 4 |
| %int_10 = OpConstant %int 10 |
| %int_1073741824 = OpConstant %int 1073741824 |
| %int_n1 = OpConstant %int -1 |
| %int_n24 = OpConstant %int -24 |
| %int_n858993459 = OpConstant %int -858993459 |
| %int_min = OpConstant %int -2147483648 |
| %int_max = OpConstant %int 2147483647 |
| %long_0 = OpConstant %long 0 |
| %long_1 = OpConstant %long 1 |
| %long_2 = OpConstant %long 2 |
| %long_3 = OpConstant %long 3 |
| %long_10 = OpConstant %long 10 |
| %long_4611686018427387904 = OpConstant %long 4611686018427387904 |
| %long_n1 = OpConstant %long -1 |
| %long_n3689348814741910323 = OpConstant %long -3689348814741910323 |
| %long_min = OpConstant %long -9223372036854775808 |
| %long_max = OpConstant %long 9223372036854775807 |
| %uint_0 = OpConstant %uint 0 |
| %uint_1 = OpConstant %uint 1 |
| %uint_2 = OpConstant %uint 2 |
| %uint_3 = OpConstant %uint 3 |
| %uint_4 = OpConstant %uint 4 |
| %uint_32 = OpConstant %uint 32 |
| %uint_42 = OpConstant %uint 42 |
| %uint_2147483649 = OpConstant %uint 2147483649 |
| %uint_max = OpConstant %uint 4294967295 |
| %ulong_0 = OpConstant %ulong 0 |
| %ulong_1 = OpConstant %ulong 1 |
| %ulong_2 = OpConstant %ulong 2 |
| %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809 |
| %ulong_max = OpConstant %ulong 18446744073709551615 |
| %v2int_undef = OpUndef %v2int |
| %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0 |
| %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0 |
| %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2 |
| %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3 |
| %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2 |
| %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4 |
| %v2int_min_max = OpConstantComposite %v2int %int_min %int_max |
| %v2bool_null = OpConstantNull %v2bool |
| %v2bool_true_false = OpConstantComposite %v2bool %true %false |
| %v2bool_false_true = OpConstantComposite %v2bool %false %true |
| %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int |
| %v2int_null = OpConstantNull %v2int |
| %102 = OpConstantComposite %v2int %103 %103 |
| %v4int_undef = OpUndef %v4int |
| %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0 |
| %m2x2int_undef = OpUndef %m2x2int |
| %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0 |
| %float_n1 = OpConstant %float -1 |
| %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps. |
| %float_null = OpConstantNull %float |
| %float_0 = OpConstant %float 0 |
| %float_n0 = OpConstant %float -0.0 |
| %float_1 = OpConstant %float 1 |
| %float_2 = OpConstant %float 2 |
| %float_3 = OpConstant %float 3 |
| %float_4 = OpConstant %float 4 |
| %float_2049 = OpConstant %float 2049 |
| %float_n2049 = OpConstant %float -2049 |
| %float_0p5 = OpConstant %float 0.5 |
| %float_0p2 = OpConstant %float 0.2 |
| %float_pi = OpConstant %float 1.5555 |
| %float_1e16 = OpConstant %float 1e16 |
| %float_n1e16 = OpConstant %float -1e16 |
| %float_1en16 = OpConstant %float 1e-16 |
| %float_n1en16 = OpConstant %float -1e-16 |
| %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0 |
| %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2 |
| %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3 |
| %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2 |
| %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4 |
| %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5 |
| %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5 |
| %v2float_null = OpConstantNull %v2float |
| %double_n1 = OpConstant %double -1 |
| %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps. |
| %double_null = OpConstantNull %double |
| %double_0 = OpConstant %double 0 |
| %double_n0 = OpConstant %double -0.0 |
| %double_1 = OpConstant %double 1 |
| %double_2 = OpConstant %double 2 |
| %double_3 = OpConstant %double 3 |
| %double_4 = OpConstant %double 4 |
| %double_5 = OpConstant %double 5 |
| %double_0p5 = OpConstant %double 0.5 |
| %double_0p2 = OpConstant %double 0.2 |
| %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0 |
| %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2 |
| %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3 |
| %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2 |
| %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4 |
| %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5 |
| %v2double_null = OpConstantNull %v2double |
| %108 = OpConstant %half 0 |
| %half_1 = OpConstant %half 1 |
| %half_0_1 = OpConstantComposite %v2half %108 %half_1 |
| %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 |
| %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 |
| %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1 |
| %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0 |
| %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 |
| %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4 |
| %v4float_null = OpConstantNull %v4float |
| %mat4v4float_null = OpConstantComposite %mat4v4float %v4float_null %v4float_null %v4float_null %v4float_null |
| %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 |
| %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0 |
| %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0 |
| %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1 |
| %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0 |
| %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1 |
| %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4 |
| %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5 |
| %v4double_null = OpConstantNull %v4double |
| %mat4v4double_null = OpConstantComposite %mat4v4double %v4double_null %v4double_null %v4double_null %v4double_null |
| %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 |
| %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3 |
| %uint_0x3f800000 = OpConstant %uint 0x3f800000 |
| %uint_0xbf800000 = OpConstant %uint 0xbf800000 |
| %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000 |
| %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000 |
| %int_0x3FF00000 = OpConstant %int 0x3FF00000 |
| %int_0x00000000 = OpConstant %int 0x00000000 |
| %int_0xC05FD666 = OpConstant %int 0xC05FD666 |
| %int_0x66666666 = OpConstant %int 0x66666666 |
| %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666 |
| %ushort_0xBC00 = OpConstant %ushort 0xBC00 |
| %short_0xBC00 = OpConstant %short 0xBC00 |
| )"; |
| |
| return header; |
| } |
| |
| // Returns the header with definitions of float NaN and double NaN. Since FC |
| // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds |
| // %double_nan = OpConstant %double -0x1.8p+1024 instead of |
| // %double_n0 = OpConstant %double -0, |
| // we separates those definitions from Header(). |
| const std::string& HeaderWithNaN() { |
| static const std::string headerWithNaN = |
| Header() + |
| R"(%float_nan = OpConstant %float -0x1.8p+128 |
| %double_nan = OpConstant %double -0x1.8p+1024 |
| )"; |
| |
| return headerWithNaN; |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 0*n |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpIMul %int %int_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 1: fold n*0 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpIMul %int %load %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 2: fold 0/n (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSDiv %int %int_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 3: fold n/0 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSDiv %int %load %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 4: fold 0/n (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUDiv %uint %uint_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 5: fold n/0 (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSDiv %int %load %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 6: fold 0 remainder n |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSRem %int %int_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 7: fold n remainder 0 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSRem %int %load %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 8: fold 0%n (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSMod %int %int_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 9: fold n%0 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSMod %int %load %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 10: fold 0%n (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUMod %uint %uint_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 11: fold n%0 (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUMod %uint %load %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 12: fold n << 32 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpShiftLeftLogical %uint %load %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 13: fold n >> 32 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpShiftRightLogical %uint %load %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 14: fold n | 0xFFFFFFFF |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpBitwiseOr %uint %load %uint_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFFFFF), |
| // Test case 15: fold 0xFFFFFFFF | n |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpBitwiseOr %uint %uint_max %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFFFFF), |
| // Test case 16: fold n & 0 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpBitwiseAnd %uint %load %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 17: fold 1/0 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpSDiv %int %int_1 %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 18: fold 1/0 (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpUDiv %uint %uint_1 %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 19: fold OpSRem 1 0 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpSRem %int %int_1 %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 20: fold 1%0 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpSMod %int %int_1 %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 21: fold 1%0 (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpUMod %uint %uint_1 %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 22: fold unsigned n >> 42 (undefined, so set to zero). |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpShiftRightLogical %uint %load %uint_42\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 23: fold signed n >> 42 (undefined, so set to zero). |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpShiftRightLogical %int %load %uint_42\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 24: fold n << 42 (undefined, so set to zero). |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpShiftLeftLogical %int %load %uint_42\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 25: fold -24 >> 32 (defined as -1) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -1), |
| // Test case 26: fold 2 >> 32 (signed) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 27: fold 2 >> 32 (unsigned) |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 28: fold 2 << 32 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 29: fold -INT_MIN |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpSNegate %int %int_min\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<int32_t>::min()), |
| // Test case 30: fold UMin 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 31: fold UMin 4 2 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 32: fold SMin 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 33: fold SMin 4 2 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 34: fold UMax 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4), |
| // Test case 35: fold UMax 3 2 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 36: fold SMax 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4), |
| // Test case 37: fold SMax 3 2 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 38: fold UClamp 2 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 39: fold UClamp 2 0 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 40: fold UClamp 2 0 1 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1), |
| // Test case 41: fold SClamp 2 3 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3), |
| // Test case 42: fold SClamp 2 0 4 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 43: fold SClamp 2 0 1 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1), |
| // Test case 44: SClamp 1 2 x |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %int\n" + |
| "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 45: SClamp 2 x 1 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %int\n" + |
| "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1), |
| // Test case 44: UClamp 1 2 x |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %uint\n" + |
| "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2), |
| // Test case 45: UClamp 2 x 1 |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %uint\n" + |
| "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1), |
| // Test case 46: Bit-cast int 0 to unsigned int |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %uint %int_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0), |
| // Test case 47: Bit-cast int -24 to unsigned int |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %uint %int_n24\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, static_cast<uint32_t>(-24)), |
| // Test case 48: Bit-cast float 1.0f to unsigned int |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %uint %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, static_cast<uint32_t>(0x3f800000)), |
| // Test case 49: Bit-cast ushort 0xBC00 to ushort |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %ushort %ushort_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xBC00), |
| // Test case 50: Bit-cast short 0xBC00 to ushort |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %ushort %short_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFBC00), |
| // Test case 51: Bit-cast half 1 to ushort |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %ushort %half_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0x3C00), |
| // Test case 52: Bit-cast ushort 0xBC00 to short |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %short %ushort_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xBC00), |
| // Test case 53: Bit-cast short 0xBC00 to short |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %short %short_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFBC00), |
| // Test case 54: Bit-cast half 1 to short |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %short %half_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0x3C00), |
| // Test case 55: Bit-cast ushort 0xBC00 to half |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %half %ushort_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xBC00), |
| // Test case 56: Bit-cast short 0xBC00 to half |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %half %short_0xBC00\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFBC00), |
| // Test case 57: Bit-cast half 1 to half |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %half %half_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0x3C00), |
| // Test case 58: Bit-cast ubyte 1 to byte |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %byte %ubyte_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1), |
| // Test case 59: Bit-cast byte -1 to ubyte |
| InstructionFoldingCase<uint32_t>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %ubyte %byte_n1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0xFFFFFFFF) |
| )); |
| // clang-format on |
| |
| using IntVectorInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>; |
| |
| TEST_P(IntVectorInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| spv::Op original_opcode = inst->opcode(); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode); |
| if (succeeded && inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite}; |
| EXPECT_THAT(opcodes, Contains(inst->opcode())); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| const std::vector<const analysis::Constant*>& componenets = |
| result->AsVectorConstant()->GetComponents(); |
| EXPECT_EQ(componenets.size(), tc.expected_result.size()); |
| for (size_t i = 0; i < componenets.size(); i++) { |
| EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32()); |
| } |
| } |
| } |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 0*n |
| InstructionFoldingCase<std::vector<uint32_t>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {2,3}), |
| InstructionFoldingCase<std::vector<uint32_t>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0,3}), |
| InstructionFoldingCase<std::vector<uint32_t>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0,0}), |
| InstructionFoldingCase<std::vector<uint32_t>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0,0}), |
| // Test case 4: fold bit-cast int -24 to unsigned int |
| InstructionFoldingCase<std::vector<uint32_t>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpBitcast %v2uint %v2int_min_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {2147483648, 2147483647}) |
| )); |
| // clang-format on |
| |
| using DoubleVectorInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>; |
| |
| TEST_P(DoubleVectorInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_TRUE(succeeded); |
| if (succeeded && inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite}; |
| EXPECT_THAT(opcodes, Contains(inst->opcode())); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| const std::vector<const analysis::Constant*>& componenets = |
| result->AsVectorConstant()->GetComponents(); |
| EXPECT_EQ(componenets.size(), tc.expected_result.size()); |
| for (size_t i = 0; i < componenets.size(); i++) { |
| EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble()); |
| } |
| } |
| } |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666} |
| // to double vector |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {1.0,-127.35}), |
| // 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0,0.0,0.0,0.0}), |
| // 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0,0.0,0.0,0.0}), |
| // 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {30.0,30.0,30.0,30.0}), |
| // Test case 4: 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0,0.0,0.0,0.0}), |
| // Test case 5: 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0,0.0,0.0,0.0}), |
| // Test case 6: 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} |
| InstructionFoldingCase<std::vector<double>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {10.0,20.0,30.0,40.0}) |
| )); |
| |
| using FloatVectorInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>; |
| |
| TEST_P(FloatVectorInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| spv::Op original_opcode = inst->opcode(); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode); |
| if (succeeded && inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite}; |
| EXPECT_THAT(opcodes, Contains(inst->opcode())); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| const std::vector<const analysis::Constant*>& componenets = |
| result->AsVectorConstant()->GetComponents(); |
| EXPECT_EQ(componenets.size(), tc.expected_result.size()); |
| for (size_t i = 0; i < componenets.size(); i++) { |
| EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat()); |
| } |
| } |
| } |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {1.6f,1.5f}), |
| // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to |
| // float vector |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {1.0f,-1.0f}), |
| // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {1.0f,-1.0f}), |
| // 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0f,0.0f,0.0f,0.0f}), |
| // Test case 4: 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0f,0.0f,0.0f,0.0f}), |
| // Test case 5: 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {30.0f,30.0f,30.0f,30.0f}), |
| // Test case 6: 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0f,0.0f,0.0f,0.0f}), |
| // Test case 7: 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {0.0f,0.0f,0.0f,0.0f}), |
| // Test case 8: 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} |
| InstructionFoldingCase<std::vector<float>>( |
| Header() + |
| "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, {10.0f,20.0f,30.0f,40.0f}) |
| )); |
| // clang-format on |
| using BooleanInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<bool>>; |
| |
| TEST_P(BooleanInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_TRUE(succeeded); |
| if (inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue, |
| spv::Op::OpConstantFalse}; |
| EXPECT_THAT(bool_opcodes, Contains(inst->opcode())); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::BoolConstant* result = |
| const_mrg->GetConstantFromInst(inst)->AsBoolConstant(); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| EXPECT_EQ(result->value(), tc.expected_result); |
| } |
| } |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold true || n |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_bool Function\n" + |
| "%load = OpLoad %bool %n\n" + |
| "%2 = OpLogicalOr %bool %true %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 1: fold n || true |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_bool Function\n" + |
| "%load = OpLoad %bool %n\n" + |
| "%2 = OpLogicalOr %bool %load %true\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold false && n |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_bool Function\n" + |
| "%load = OpLoad %bool %n\n" + |
| "%2 = OpLogicalAnd %bool %false %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 3: fold n && false |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_bool Function\n" + |
| "%load = OpLoad %bool %n\n" + |
| "%2 = OpLogicalAnd %bool %load %false\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 4: fold n < 0 (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpULessThan %bool %load %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 5: fold UINT_MAX < n (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpULessThan %bool %uint_max %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold INT_MAX < n (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSLessThan %bool %int_max %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 7: fold n < INT_MIN (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSLessThan %bool %load %int_min\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold 0 > n (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUGreaterThan %bool %uint_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold n > UINT_MAX (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUGreaterThan %bool %load %uint_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 10: fold n > INT_MAX (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSGreaterThan %bool %load %int_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 11: fold INT_MIN > n (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpSGreaterThan %bool %int_min %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 12: fold 0 <= n (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpULessThanEqual %bool %uint_0 %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 13: fold n <= UINT_MAX (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpULessThanEqual %bool %load %uint_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 14: fold INT_MIN <= n (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSLessThanEqual %bool %int_min %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 15: fold n <= INT_MAX (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSLessThanEqual %bool %load %int_max\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 16: fold n >= 0 (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 17: fold UINT_MAX >= n (unsigned) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_uint Function\n" + |
| "%load = OpLoad %uint %n\n" + |
| "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 18: fold n >= INT_MIN (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSGreaterThanEqual %bool %load %int_min\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 19: fold INT_MAX >= n (signed) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_int Function\n" + |
| "%load = OpLoad %int %n\n" + |
| "%2 = OpSGreaterThanEqual %bool %int_max %load\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true) |
| )); |
| |
| INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" + |
| "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold 0.0 >= clamp(n, 1, 2) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" + |
| "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold 0.0 < clamp(n, 1, 2) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" + |
| "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 10: fold 0.0 >= clamp(n, 1, 2) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" + |
| "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 14: fold 0.0 < clamp(n, 1, 2) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false) |
| )); |
| |
| INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" + |
| "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold clamp(n, 1, 2) >= 0.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold clamp(n, 1, 2) < 3 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFOrdLessThan %bool %clamp %float_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 10: fold clamp(n, 1, 2) >= 3.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" + |
| "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" + |
| "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 14: fold clamp(n, 1, 2) < 3 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" + |
| "%2 = OpFUnordLessThan %bool %clamp %float_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_float Function\n" + |
| "%ld = OpLoad %float %n\n" + |
| "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" + |
| "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double) |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%n = OpVariable %_ptr_double Function\n" + |
| "%ld = OpLoad %double %n\n" + |
| "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" + |
| "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false) |
| )); |
| // clang-format on |
| |
| using FloatInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<float>>; |
| |
| TEST_P(FloatInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_TRUE(succeeded); |
| if (inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::FloatConstant* result = |
| const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| if (!std::isnan(tc.expected_result)) { |
| EXPECT_EQ(result->GetFloatValue(), tc.expected_result); |
| } else { |
| EXPECT_TRUE(std::isnan(result->GetFloatValue())); |
| } |
| } |
| } |
| } |
| |
| // Not testing NaNs because there are no expectations concerning NaNs according |
| // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan |
| // specification. |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: Fold 2.0 - 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFSub %float %float_2 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 1: Fold 2.0 + 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFAdd %float %float_2 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3.0), |
| // Test case 2: Fold 3.0 * 2.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFMul %float %float_3 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 6.0), |
| // Test case 3: Fold 1.0 / 2.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.5), |
| // Test case 4: Fold 1.0 / 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_1 %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::infinity()), |
| // Test case 5: Fold -1.0 / 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_n1 %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -std::numeric_limits<float>::infinity()), |
| // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5) |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 5.5f), |
| // Test case 7: Fold (0.0, 0.0) dot v |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2float Function\n" + |
| "%2 = OpLoad %v2float %v\n" + |
| "%3 = OpDot %float %v2float_0_0 %2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 8: Fold v dot (0.0, 0.0) |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2float Function\n" + |
| "%2 = OpLoad %v2float %v\n" + |
| "%3 = OpDot %float %2 %v2float_0_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 9: Fold Null dot v |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2float Function\n" + |
| "%2 = OpLoad %v2float %v\n" + |
| "%3 = OpDot %float %v2float_null %2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 10: Fold v dot Null |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2float Function\n" + |
| "%2 = OpLoad %v2float %v\n" + |
| "%3 = OpDot %float %2 %v2float_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 11: Fold -2.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFNegate %float %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -2), |
| // Test case 12: QuantizeToF16 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 13: QuantizeToF16 positive non exact |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_2049\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2048), |
| // Test case 14: QuantizeToF16 negative non exact |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_n2049\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -2048), |
| // Test case 15: QuantizeToF16 large positive |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_1e16\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::infinity()), |
| // Test case 16: QuantizeToF16 large negative |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_n1e16\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -std::numeric_limits<float>::infinity()), |
| // Test case 17: QuantizeToF16 small positive |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_1en16\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 18: QuantizeToF16 small negative |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_n1en16\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 19: QuantizeToF16 nan |
| InstructionFoldingCase<float>( |
| HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpQuantizeToF16 %float %float_nan\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::quiet_NaN()), |
| // Test case 20: FMix 1.0 4.0 0.2 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.6f), |
| // Test case 21: FMin 1.0 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0f), |
| // Test case 22: FMin 4.0 0.2 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.2f), |
| // Test case 23: FMax 1.0 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4.0f), |
| // Test case 24: FMax 1.0 0.2 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0f), |
| // Test case 25: FClamp 1.0 0.2 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0f), |
| // Test case 26: FClamp 0.2 2.0 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0f), |
| // Test case 27: FClamp 2049.0 2.0 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4.0f), |
| // Test case 28: FClamp 1.0 2.0 x |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %float\n" + |
| "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 29: FClamp 1.0 x 0.5 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %float\n" + |
| "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.5), |
| // Test case 30: Sin 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Sin %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 31: Cos 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Cos %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 32: Tan 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Tan %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 33: Asin 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Asin %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 34: Acos 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Acos %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 35: Atan 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Atan %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 36: Exp 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Exp %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 37: Log 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Log %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 38: Exp2 2.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Exp2 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4.0), |
| // Test case 39: Log2 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Log2 %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 40: Sqrt 4.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Sqrt %float_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 41: Atan2 0.0 1.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.0), |
| // Test case 42: Pow 2.0 3.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 8.0), |
| // Test case 43: Fold 1.0 / -0.0. |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_1 %float_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -std::numeric_limits<float>::infinity()), |
| // Test case 44: Fold -1.0 / -0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_n1 %float_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::infinity()), |
| // Test case 45: Fold 0.0 / 0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_0 %float_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::quiet_NaN()), |
| // Test case 46: Fold 0.0 / -0.0 |
| InstructionFoldingCase<float>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %float %float_0 %float_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<float>::quiet_NaN()) |
| )); |
| // clang-format on |
| |
| using DoubleInstructionFoldingTest = |
| ::testing::TestWithParam<InstructionFoldingCase<double>>; |
| |
| TEST_P(DoubleInstructionFoldingTest, Case) { |
| const auto& tc = GetParam(); |
| |
| // Build module. |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| ASSERT_NE(nullptr, context); |
| |
| // Fold the instruction to test. |
| analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); |
| Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); |
| bool succeeded = context->get_instruction_folder().FoldInstruction(inst); |
| |
| // Make sure the instruction folded as expected. |
| EXPECT_TRUE(succeeded); |
| if (inst != nullptr) { |
| EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); |
| inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); |
| EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); |
| analysis::ConstantManager* const_mrg = context->get_constant_mgr(); |
| const analysis::FloatConstant* result = |
| const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); |
| EXPECT_NE(result, nullptr); |
| if (result != nullptr) { |
| if (!std::isnan(tc.expected_result)) { |
| EXPECT_EQ(result->GetDoubleValue(), tc.expected_result); |
| } else { |
| EXPECT_TRUE(std::isnan(result->GetDoubleValue())); |
| } |
| } |
| } |
| } |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: Fold 2.0 - 1.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFSub %double %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 1: Fold 2.0 + 1.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFAdd %double %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 3.0), |
| // Test case 2: Fold 3.0 * 2.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFMul %double %double_3 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 6.0), |
| // Test case 3: Fold 1.0 / 2.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.5), |
| // Test case 4: Fold 1.0 / 0.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_1 %double_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<double>::infinity()), |
| // Test case 5: Fold -1.0 / 0.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_n1 %double_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -std::numeric_limits<double>::infinity()), |
| // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5) |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 5.5f), |
| // Test case 7: Fold (0.0, 0.0) dot v |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2double Function\n" + |
| "%2 = OpLoad %v2double %v\n" + |
| "%3 = OpDot %double %v2double_0_0 %2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 8: Fold v dot (0.0, 0.0) |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2double Function\n" + |
| "%2 = OpLoad %v2double %v\n" + |
| "%3 = OpDot %double %2 %v2double_0_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 9: Fold Null dot v |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2double Function\n" + |
| "%2 = OpLoad %v2double %v\n" + |
| "%3 = OpDot %double %v2double_null %2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 10: Fold v dot Null |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%v = OpVariable %_ptr_v2double Function\n" + |
| "%2 = OpLoad %v2double %v\n" + |
| "%3 = OpDot %double %2 %v2double_null\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 3, 0.0f), |
| // Test case 11: Fold -2.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFNegate %double %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -2), |
| // Test case 12: FMin 1.0 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 13: FMin 4.0 0.2 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.2), |
| // Test case 14: FMax 1.0 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4.0), |
| // Test case 15: FMax 1.0 0.2 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 16: FClamp 1.0 0.2 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 1.0), |
| // Test case 17: FClamp 0.2 2.0 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 18: FClamp 5.0 2.0 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 4.0), |
| // Test case 19: FClamp 1.0 2.0 x |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %double\n" + |
| "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 20: FClamp 1.0 x 0.5 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %double\n" + |
| "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 0.5), |
| // Test case 21: Sqrt 4.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %double\n" + |
| "%2 = OpExtInst %double %1 Sqrt %double_4\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 2.0), |
| // Test case 22: Pow 2.0 3.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%undef = OpUndef %double\n" + |
| "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, 8.0), |
| // Test case 23: Fold 1.0 / -0.0. |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_1 %double_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, -std::numeric_limits<double>::infinity()), |
| // Test case 24: Fold -1.0 / -0.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_n1 %double_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<double>::infinity()), |
| // Test case 25: Fold 0.0 / 0.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_0 %double_0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<double>::quiet_NaN()), |
| // Test case 26: Fold 0.0 / -0.0 |
| InstructionFoldingCase<double>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFDiv %double %double_0 %double_n0\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, std::numeric_limits<double>::quiet_NaN()) |
| )); |
| // clang-format on |
| |
| // clang-format off |
| INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 1.0 == 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 1: fold 1.0 != 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold 1.0 < 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 3: fold 1.0 > 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 4: fold 1.0 <= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 5: fold 1.0 >= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold 1.0 == 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 7: fold 1.0 != 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold 1.0 < 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold 1.0 > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 10: fold 1.0 <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 11: fold 1.0 >= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 12: fold 2.0 < 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 13: fold 2.0 > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 14: fold 2.0 <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 15: fold 2.0 >= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true) |
| )); |
| |
| INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 1.0 == 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 1: fold 1.0 != 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold 1.0 < 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 3: fold 1.0 > 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 4: fold 1.0 <= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 5: fold 1.0 >= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold 1.0 == 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 7: fold 1.0 != 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold 1.0 < 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold 1.0 > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 10: fold 1.0 <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 11: fold 1.0 >= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 12: fold 2.0 < 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 13: fold 2.0 > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 14: fold 2.0 <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 15: fold 2.0 >= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true) |
| )); |
| |
| INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, |
| ::testing::Values( |
| // Test case 0: fold 1.0 == 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdEqual %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 1: fold 1.0 != 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 2: fold 1.0 < 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 3: fold 1.0 > 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 4: fold 1.0 <= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 5: fold 1.0 >= 2.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 6: fold 1.0 == 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdEqual %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 7: fold 1.0 != 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 8: fold 1.0 < 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 9: fold 1.0 > 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, false), |
| // Test case 10: fold 1.0 <= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |
| 2, true), |
| // Test case 11: fold 1.0 >= 1.0 |
| InstructionFoldingCase<bool>( |
| Header() + "%main = OpFunction %void None %void_func\n" + |
| "%main_lab = OpLabel\n" + |
| "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" + |
| "OpReturn\n" + |
| "OpFunctionEnd", |