// 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 #include #include #include #include #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 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 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>; TEST_P(IntegerInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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::min()), // Test case 30: fold UMin 3 4 InstructionFoldingCase( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpBitcast %uint %int_n24\n" + "OpReturn\n" + "OpFunctionEnd", 2, static_cast(-24)), // Test case 48: Bit-cast float 1.0f to unsigned int InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpBitcast %uint %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, static_cast(0x3f800000)), // Test case 49: Bit-cast ushort 0xBC00 to ushort InstructionFoldingCase( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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>>; TEST_P(IntVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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 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& 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>( 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>( 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>( 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>( 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>( 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>>; TEST_P(DoubleVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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 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& 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>( 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>( 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>( 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>( 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>( 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>( 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>( 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>>; TEST_P(FloatVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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 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& 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>( 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>( 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>( 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>( 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>( 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>( 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>( 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>( 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>( 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>; TEST_P(BooleanInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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>; TEST_P(FloatInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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( 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( 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( 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( 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( 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::infinity()), // Test case 5: Fold -1.0 / 0.0 InstructionFoldingCase( 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::infinity()), // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5) InstructionFoldingCase( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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::infinity()), // Test case 16: QuantizeToF16 large negative InstructionFoldingCase( 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::infinity()), // Test case 17: QuantizeToF16 small positive InstructionFoldingCase( 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( 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( 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::quiet_NaN()), // Test case 20: FMix 1.0 4.0 0.2 InstructionFoldingCase( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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::infinity()), // Test case 44: Fold -1.0 / -0.0 InstructionFoldingCase( 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::infinity()), // Test case 45: Fold 0.0 / 0.0 InstructionFoldingCase( 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::quiet_NaN()), // Test case 46: Fold 0.0 / -0.0 InstructionFoldingCase( 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::quiet_NaN()) )); // clang-format on using DoubleInstructionFoldingTest = ::testing::TestWithParam>; TEST_P(DoubleInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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( 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( 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( 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( 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( 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::infinity()), // Test case 5: Fold -1.0 / 0.0 InstructionFoldingCase( 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::infinity()), // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5) InstructionFoldingCase( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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::infinity()), // Test case 24: Fold -1.0 / -0.0 InstructionFoldingCase( 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::infinity()), // Test case 25: Fold 0.0 / 0.0 InstructionFoldingCase( 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::quiet_NaN()), // Test case 26: Fold 0.0 / -0.0 InstructionFoldingCase( 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::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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( 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( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 12: fold 2.0 < 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 13: fold 2.0 > 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 14: fold 2.0 <= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 15: fold 2.0 >= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true) )); INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 1.0 == 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordEqual %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 1: fold 1.0 != 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 2: fold 1.0 < 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 3: fold 1.0 > 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 4: fold 1.0 <= 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 5: fold 1.0 >= 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 6: fold 1.0 == 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordEqual %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 7: fold 1.0 != 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 8: fold 1.0 < 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 9: fold 1.0 > 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 10: fold 1.0 <= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 11: fold 1.0 >= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 12: fold 2.0 < 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 13: fold 2.0 > 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 14: fold 2.0 <= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 15: fold 2.0 >= 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true) )); INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold NaN == 0 (ord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdEqual %bool %double_nan %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 1: fold NaN == NaN (unord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordEqual %bool %double_nan %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 2: fold NaN != NaN (ord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 3: fold NaN != NaN (unord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, true) )); INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold NaN == 0 (ord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdEqual %bool %float_nan %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 1: fold NaN == NaN (unord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordEqual %bool %float_nan %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 2: fold NaN != NaN (ord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, false), // Test case 3: fold NaN != NaN (unord) InstructionFoldingCase( HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, true) )); // clang-format on template struct InstructionFoldingCaseWithMap { InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id, ResultType result, std::function map) : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {} std::string test_body; uint32_t id_to_fold; ResultType expected_result; std::function id_map; }; using IntegerInstructionFoldingTestWithMap = ::testing::TestWithParam>; TEST_P(IntegerInstructionFoldingTestWithMap, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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); inst = context->get_instruction_folder().FoldInstructionToConstant(inst, tc.id_map); // Make sure the instruction folded as expected. EXPECT_NE(inst, nullptr); if (inst != nullptr) { EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); analysis::ConstantManager* const_mrg = context->get_constant_mgr(); const analysis::IntConstant* result = const_mrg->GetConstantFromInst(inst)->AsIntConstant(); EXPECT_NE(result, nullptr); if (result != nullptr) { EXPECT_EQ(result->GetU32BitValue(), tc.expected_result); } } } // clang-format off INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap, ::testing::Values( // Test case 0: fold %3 = 0; %3 * n InstructionFoldingCaseWithMap( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load = OpLoad %int %n\n" + "%3 = OpCopyObject %int %int_0\n" "%2 = OpIMul %int %3 %load\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);}) )); // clang-format on using BooleanInstructionFoldingTestWithMap = ::testing::TestWithParam>; TEST_P(BooleanInstructionFoldingTestWithMap, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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); inst = context->get_instruction_folder().FoldInstructionToConstant(inst, tc.id_map); // Make sure the instruction folded as expected. EXPECT_NE(inst, nullptr); if (inst != nullptr) { std::vector 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, BooleanInstructionFoldingTestWithMap, ::testing::Values( // Test case 0: fold %3 = true; %3 || n InstructionFoldingCaseWithMap( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_bool Function\n" + "%load = OpLoad %bool %n\n" + "%3 = OpCopyObject %bool %true\n" + "%2 = OpLogicalOr %bool %3 %load\n" + "OpReturn\n" + "OpFunctionEnd", 2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);}) )); // clang-format on using GeneralInstructionFoldingTest = ::testing::TestWithParam>; TEST_P(GeneralInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); // Make sure the instruction folded as expected. EXPECT_EQ(inst->result_id(), original_inst->result_id()); EXPECT_EQ(inst->type_id(), original_inst->type_id()); EXPECT_TRUE((!succeeded) == (tc.expected_result == 0)); if (succeeded) { EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result); } else { EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands()); for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i)); } } } // clang-format off INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n * m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpIMul %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't fold n / m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpUDiv %uint %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Don't fold n / m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpSDiv %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Don't fold n remainder m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpSRem %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 4: Don't fold n % m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpSMod %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 5: Don't fold n % m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpUMod %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 6: Don't fold n << m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpShiftRightLogical %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 7: Don't fold n >> m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpShiftLeftLogical %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 8: Don't fold n | m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpBitwiseOr %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 9: Don't fold n & m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpBitwiseAnd %int %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 10: Don't fold n < m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpULessThan %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 11: Don't fold n > m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpUGreaterThan %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 12: Don't fold n <= m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpULessThanEqual %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 13: Don't fold n >= m (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%m = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%load_m = OpLoad %uint %m\n" + "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 14: Don't fold n < m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpULessThan %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 15: Don't fold n > m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpUGreaterThan %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 16: Don't fold n <= m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpULessThanEqual %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 17: Don't fold n >= m (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%m = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%load_m = OpLoad %int %m\n" + "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 18: Don't fold n || m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_bool Function\n" + "%m = OpVariable %_ptr_bool Function\n" + "%load_n = OpLoad %bool %n\n" + "%load_m = OpLoad %bool %m\n" + "%2 = OpLogicalOr %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 19: Don't fold n && m InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_bool Function\n" + "%m = OpVariable %_ptr_bool Function\n" + "%load_n = OpLoad %bool %n\n" + "%load_m = OpLoad %bool %m\n" + "%2 = OpLogicalAnd %bool %load_n %load_m\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 20: Don't fold n * 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpIMul %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 21: Don't fold n / 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpUDiv %uint %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 22: Don't fold n / 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpSDiv %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 23: Don't fold n remainder 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpSRem %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 24: Don't fold n % 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpSMod %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 25: Don't fold n % 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpUMod %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 26: Don't fold n << 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpShiftRightLogical %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 27: Don't fold n >> 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpShiftLeftLogical %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 28: Don't fold n | 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpBitwiseOr %int %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 29: Don't fold n & 3 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 30: Don't fold n < 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpULessThan %bool %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 31: Don't fold n > 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpUGreaterThan %bool %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 32: Don't fold n <= 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpULessThanEqual %bool %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 33: Don't fold n >= 3 (unsigned) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%load_n = OpLoad %uint %n\n" + "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 34: Don't fold n < 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpULessThan %bool %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 35: Don't fold n > 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpUGreaterThan %bool %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 36: Don't fold n <= 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpULessThanEqual %bool %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 37: Don't fold n >= 3 (signed) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load_n = OpLoad %int %n\n" + "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 38: Don't fold 2 + 3 (long), bad length InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpIAdd %long %long_2 %long_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 39: Don't fold 2 + 3 (short), bad length InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpIAdd %short %short_2 %short_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 40: fold 1*n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%3 = OpLoad %int %n\n" + "%2 = OpIMul %int %int_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 41: fold n*1 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%3 = OpLoad %int %n\n" + "%2 = OpIMul %int %3 %int_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 42: Don't fold comparisons of 64-bit types // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343). InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpSLessThan %bool %long_0 %long_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0) )); INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: fold Insert feeding extract InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" + "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" + "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" + "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" + "%7 = OpCompositeExtract %int %6 0\n" + "OpReturn\n" + "OpFunctionEnd", 7, 2), // Test case 1: fold Composite construct feeding extract (position 0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" + "%4 = OpCompositeExtract %int %3 0\n" + "OpReturn\n" + "OpFunctionEnd", 4, 2), // Test case 2: fold Composite construct feeding extract (position 3) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" + "%4 = OpCompositeExtract %int %3 3\n" + "OpReturn\n" + "OpFunctionEnd", 4, INT_0_ID), // Test case 3: fold Composite construct with vectors feeding extract (scalar element) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v2int %2 %int_0\n" + "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" + "%5 = OpCompositeExtract %int %4 3\n" + "OpReturn\n" + "OpFunctionEnd", 5, INT_0_ID), // Test case 4: fold Composite construct with vectors feeding extract (start of vector element) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v2int %2 %int_0\n" + "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" + "%5 = OpCompositeExtract %int %4 0\n" + "OpReturn\n" + "OpFunctionEnd", 5, 2), // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v2int %int_0 %2\n" + "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" + "%5 = OpCompositeExtract %int %4 1\n" + "OpReturn\n" + "OpFunctionEnd", 5, 2), // Test case 6: fold Composite construct with multiple indices. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %n\n" + "%3 = OpCompositeConstruct %v2int %int_0 %2\n" + "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" + "%5 = OpCompositeExtract %int %4 0 1\n" + "OpReturn\n" + "OpFunctionEnd", 5, 2), // Test case 7: fold constant extract. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeExtract %int %102 1\n" + "OpReturn\n" + "OpFunctionEnd", 2, INT_7_ID), // Test case 8: constant struct has OpUndef InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 9: Extracting a member of element inserted via Insert InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" + "%2 = OpLoad %struct_v2int_int_int %n\n" + "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" + "%4 = OpCompositeExtract %int %3 0 1\n" + "OpReturn\n" + "OpFunctionEnd", 4, 103), // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" + "%2 = OpLoad %struct_v2int_int_int %n\n" + "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" + "%4 = OpCompositeExtract %v2int %3 0\n" + "OpReturn\n" + "OpFunctionEnd", 4, 0), // Test case 11: Extracting from result of vector shuffle (first input) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %n\n" + "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" + "%4 = OpCompositeExtract %int %3 1\n" + "OpReturn\n" + "OpFunctionEnd", 4, INT_7_ID), // Test case 12: Extracting from result of vector shuffle (second input) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %n\n" + "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" + "%4 = OpCompositeExtract %int %3 0\n" + "OpReturn\n" + "OpFunctionEnd", 4, INT_7_ID), // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608 // Out of bounds access. Do not fold. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" + "%3 = OpCompositeExtract %float %2 4\n" + "OpReturn\n" + "OpFunctionEnd", 3, 0), // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631 // Extract the component right after the vector constituent. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" + "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" + "%4 = OpCompositeExtract %int %3 2\n" + "OpReturn\n" + "OpFunctionEnd", 4, INT_0_ID), // Test case 15: // Don't fold extract fed by construct with vector result if the index is // past the last element. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" + "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" + "%4 = OpCompositeExtract %int %3 4\n" + "OpReturn\n" + "OpFunctionEnd", 4, 0) )); INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: fold Extracts feeding construct InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" + "%3 = OpCompositeExtract %int %2 0\n" + "%4 = OpCompositeExtract %int %2 1\n" + "%5 = OpCompositeExtract %int %2 2\n" + "%6 = OpCompositeExtract %int %2 3\n" + "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" + "OpReturn\n" + "OpFunctionEnd", 7, 2), // Test case 1: Don't fold Extracts feeding construct (Different source) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" + "%3 = OpCompositeExtract %int %2 0\n" + "%4 = OpCompositeExtract %int %2 1\n" + "%5 = OpCompositeExtract %int %2 2\n" + "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" + "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" + "OpReturn\n" + "OpFunctionEnd", 7, 0), // Test case 2: Don't fold Extracts feeding construct (bad indices) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" + "%3 = OpCompositeExtract %int %2 0\n" + "%4 = OpCompositeExtract %int %2 0\n" + "%5 = OpCompositeExtract %int %2 2\n" + "%6 = OpCompositeExtract %int %2 3\n" + "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" + "OpReturn\n" + "OpFunctionEnd", 7, 0), // Test case 3: Don't fold Extracts feeding construct (different type) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" + "%3 = OpCompositeExtract %v2int %2 0\n" + "%4 = OpCompositeExtract %int %2 1\n" + "%5 = OpCompositeExtract %int %2 2\n" + "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" + "OpReturn\n" + "OpFunctionEnd", 7, 0), // Test case 4: Fold construct with constants to constant. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeConstruct %v2int %103 %103\n" + "OpReturn\n" + "OpFunctionEnd", 2, VEC2_0_ID), // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct // for an empty struct, and we reached the id limit. InstructionFoldingCase( Header() + "%empty_struct = OpTypeStruct\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%4194303 = OpCompositeConstruct %empty_struct\n" + "OpReturn\n" + "OpFunctionEnd", 4194303, 0) )); INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Fold phi with the same values for all edges. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + " OpBranchConditional %true %l1 %l2\n" + "%l1 = OpLabel\n" + " OpBranch %merge_lab\n" + "%l2 = OpLabel\n" + " OpBranch %merge_lab\n" + "%merge_lab = OpLabel\n" + "%2 = OpPhi %int %100 %l1 %100 %l2\n" + "OpReturn\n" + "OpFunctionEnd", 2, INT_0_ID), // Test case 1: Fold phi in pass through loop. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + " OpBranch %l1\n" + "%l1 = OpLabel\n" + "%2 = OpPhi %int %100 %main_lab %2 %l1\n" + " OpBranchConditional %true %l1 %merge_lab\n" + "%merge_lab = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd", 2, INT_0_ID), // Test case 2: Don't Fold phi because of different values. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + " OpBranch %l1\n" + "%l1 = OpLabel\n" + "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" + " OpBranchConditional %true %l1 %merge_lab\n" + "%merge_lab = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0) )); INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't fold n - 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFSub %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Don't fold n * 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFMul %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Fold n + 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFAdd %float %3 %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 4: Fold 0.0 + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFAdd %float %float_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 5: Fold n - 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFSub %float %3 %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 6: Fold n * 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFMul %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 7: Fold 1.0 * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFMul %float %float_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 8: Fold n / 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFDiv %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 9: Fold n * 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFMul %float %3 %104\n" + "OpReturn\n" + "OpFunctionEnd", 2, FLOAT_0_ID), // Test case 10: Fold 0.0 * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFMul %float %104 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, FLOAT_0_ID), // Test case 11: Fold 0.0 / n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFDiv %float %104 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, FLOAT_0_ID), // Test case 12: Don't fold mix(a, b, 2.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_float Function\n" + "%b = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %a\n" + "%4 = OpLoad %float %b\n" + "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 13: Fold mix(a, b, 0.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_float Function\n" + "%b = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %a\n" + "%4 = OpLoad %float %b\n" + "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 14: Fold mix(a, b, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_float Function\n" + "%b = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %a\n" + "%4 = OpLoad %float %b\n" + "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 4), // Test case 15: Fold vector fadd with null InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %a\n" + "%3 = OpFAdd %v2float %2 %v2float_null\n" + "OpReturn\n" + "OpFunctionEnd", 3, 2), // Test case 16: Fold vector fadd with null InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %a\n" + "%3 = OpFAdd %v2float %v2float_null %2\n" + "OpReturn\n" + "OpFunctionEnd", 3, 2), // Test case 17: Fold vector fsub with null InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %a\n" + "%3 = OpFSub %v2float %2 %v2float_null\n" + "OpReturn\n" + "OpFunctionEnd", 3, 2), // Test case 18: Fold 0.0(half) * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_half Function\n" + "%3 = OpLoad %half %n\n" + "%2 = OpFMul %half %108 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, HALF_0_ID), // Test case 19: Don't fold 1.0(half) * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_half Function\n" + "%3 = OpLoad %half %n\n" + "%2 = OpFMul %half %half_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 20: Don't fold 1.0 * 1.0 (half) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFMul %half %half_1 %half_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpDot %half %half_0_1 %half_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0) )); INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFAdd %double %3 %double_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't fold n - 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFSub %double %3 %double_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Don't fold n * 2.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFMul %double %3 %double_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Fold n + 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFAdd %double %3 %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 4: Fold 0.0 + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFAdd %double %double_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 5: Fold n - 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFSub %double %3 %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 6: Fold n * 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFMul %double %3 %double_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 7: Fold 1.0 * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFMul %double %double_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 8: Fold n / 1.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFDiv %double %3 %double_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 9: Fold n * 0.0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFMul %double %3 %105\n" + "OpReturn\n" + "OpFunctionEnd", 2, DOUBLE_0_ID), // Test case 10: Fold 0.0 * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFMul %double %105 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, DOUBLE_0_ID), // Test case 11: Fold 0.0 / n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFDiv %double %105 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, DOUBLE_0_ID), // Test case 12: Don't fold mix(a, b, 2.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_double Function\n" + "%b = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %a\n" + "%4 = OpLoad %double %b\n" + "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 13: Fold mix(a, b, 0.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_double Function\n" + "%b = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %a\n" + "%4 = OpLoad %double %b\n" + "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 14: Fold mix(a, b, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%a = OpVariable %_ptr_double Function\n" + "%b = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %a\n" + "%4 = OpLoad %double %b\n" + "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 4) )); INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%3 = OpLoad %v4float %n\n" + "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%3 = OpLoad %v4float %n\n" + "%2 = OpFMul %v4float %3 %106\n" + "OpReturn\n" + "OpFunctionEnd", 2, VEC4_0_ID), // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%3 = OpLoad %v4float %n\n" + "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%3 = OpLoad %v4double %n\n" + "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%3 = OpLoad %v4double %n\n" + "%2 = OpFMul %v4double %3 %106\n" + "OpReturn\n" + "OpFunctionEnd", 2, DVEC4_0_ID), // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%3 = OpLoad %v4double %n\n" + "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%3 = OpLoad %uint %n\n" + "%2 = OpIAdd %uint %3 %uint_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't fold 1 + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%3 = OpLoad %uint %n\n" + "%2 = OpIAdd %uint %uint_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Fold n + 0 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%3 = OpLoad %uint %n\n" + "%2 = OpIAdd %uint %3 %uint_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 3: Fold 0 + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_uint Function\n" + "%3 = OpLoad %uint %n\n" + "%2 = OpIAdd %uint %uint_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 4: Don't fold n + (1,0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%3 = OpLoad %v2int %n\n" + "%2 = OpIAdd %v2int %3 %v2int_1_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 5: Don't fold (1,0) + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%3 = OpLoad %v2int %n\n" + "%2 = OpIAdd %v2int %v2int_1_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 6: Fold n + (0,0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%3 = OpLoad %v2int %n\n" + "%2 = OpIAdd %v2int %3 %v2int_0_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 7: Fold (0,0) + n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%3 = OpLoad %v2int %n\n" + "%2 = OpIAdd %v2int %v2int_0_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't Fold 0.0 < clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't Fold 0.0 < clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Don't Fold 0.0 <= clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Don't Fold 0.0 <= clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 4: Don't Fold 0.0 > clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 5: Don't Fold 0.0 > clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 6: Don't Fold 0.0 >= clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 7: Don't Fold 0.0 >= clamp(-1, 1) InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 8: Don't Fold 0.0 < clamp(0, 1) InstructionFoldingCase( 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 = OpFUnordLessThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 9: Don't Fold 0.0 < clamp(0, 1) InstructionFoldingCase( 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 = OpFOrdLessThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 10: Don't Fold 0.0 > clamp(-1, 0) InstructionFoldingCase( 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 = OpFUnordGreaterThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 11: Don't Fold 0.0 > clamp(-1, 0) InstructionFoldingCase( 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 = OpFOrdGreaterThan %bool %float_0 %clamp\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0) )); INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't Fold clamp(-1, 1) < 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordLessThan %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Don't Fold clamp(-1, 1) < 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdLessThan %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 2: Don't Fold clamp(-1, 1) <= 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Don't Fold clamp(-1, 1) <= 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 4: Don't Fold clamp(-1, 1) > 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 5: Don't Fold clamp(-1, 1) > 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 6: Don't Fold clamp(-1, 1) >= 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 7: Don't Fold clamp(-1, 1) >= 0.0 InstructionFoldingCase( 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_1\n" + "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 8: Don't Fold clamp(-1, 0) < 0.0 InstructionFoldingCase( 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_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 9: Don't Fold clamp(0, 1) < 1 InstructionFoldingCase( 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 = OpFOrdLessThan %bool %clamp %float_1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 10: Don't Fold clamp(-1, 0) > -1 InstructionFoldingCase( 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 = OpFUnordGreaterThan %bool %clamp %float_n1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 11: Don't Fold clamp(-1, 0) > -1 InstructionFoldingCase( 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 = OpFOrdGreaterThan %bool %clamp %float_n1\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0) )); INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest, ::testing::Values( // Test case 0: Fold int(3.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpConvertFToS %int %float_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 1: Fold uint(3.0) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpConvertFToU %int %float_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest, ::testing::Values( // Test case 0: Fold float(3) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpConvertSToF %float %int_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3.0), // Test case 1: Fold float(3u) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpConvertUToF %float %uint_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3.0) )); // clang-format on using ToNegateFoldingTest = ::testing::TestWithParam>; TEST_P(ToNegateFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); // Make sure the instruction folded as expected. EXPECT_EQ(inst->result_id(), original_inst->result_id()); EXPECT_EQ(inst->type_id(), original_inst->type_id()); EXPECT_TRUE((!succeeded) == (tc.expected_result == 0)); if (succeeded) { EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate); EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result); } else { EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands()); for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i)); } } } // clang-format off INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest, ::testing::Values( // Test case 0: Don't fold 1.0 - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFSub %float %float_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Fold 0.0 - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %n\n" + "%2 = OpFSub %float %float_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 2: Don't fold (0,0,0,1) - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%3 = OpLoad %v4float %n\n" + "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Fold (0,0,0,0) - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%3 = OpLoad %v4float %n\n" + "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest, ::testing::Values( // Test case 0: Don't fold 1.0 - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFSub %double %double_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 1: Fold 0.0 - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%3 = OpLoad %double %n\n" + "%2 = OpFSub %double %double_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3), // Test case 2: Don't fold (0,0,0,1) - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%3 = OpLoad %v4double %n\n" + "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 0), // Test case 3: Fold (0,0,0,0) - n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%3 = OpLoad %v4double %n\n" + "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", 2, 3) )); using MatchingInstructionFoldingTest = ::testing::TestWithParam>; TEST_P(MatchingInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(succeeded, tc.expected_result); if (succeeded) { Match(tc.test_body, context.get()); } } INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Fold 0 + n (change sign) InstructionFoldingCase( Header() + "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" + "; CHECK: %2 = OpBitcast [[uint]] %3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%3 = OpLoad %uint %n\n" + "%2 = OpIAdd %uint %int_0 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 2, true), // Test case 0: Fold 0 + n (change sign) InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: %2 = OpBitcast [[int]] %3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%3 = OpLoad %int %n\n" + "%2 = OpIAdd %int %uint_0 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 2, true) )); INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: fold consecutive fnegate // -(-x) = x InstructionFoldingCase( Header() + "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" + "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFNegate %float %2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 1: fold fnegate(fmul with const). // -(x * 2.0) = x * -2.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFMul %float %2 %float_2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 2: fold fnegate(fmul with const). // -(2.0 * x) = x * 2.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFMul %float %float_2 %2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 3: fold fnegate(fdiv with const). // -(x / 2.0) = x * -0.5 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %2 %float_2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 4: fold fnegate(fdiv with const). // -(2.0 / x) = -2.0 / x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %float_2 %2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 5: fold fnegate(fadd with const). // -(2.0 + x) = -2.0 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %float_2 %2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 6: fold fnegate(fadd with const). // -(x + 2.0) = -2.0 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %2 %float_2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 7: fold fnegate(fsub with const). // -(2.0 - x) = x - 2.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_2 %2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 8: fold fnegate(fsub with const). // -(x - 2.0) = 2.0 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %2 %float_2\n" + "%4 = OpFNegate %float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 9: fold consecutive snegate // -(-x) = x InstructionFoldingCase( Header() + "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" + "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSNegate %int %2\n" + "%4 = OpSNegate %int %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 10: fold consecutive vector negate // -(-x) = x InstructionFoldingCase( Header() + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" + "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %var\n" + "%3 = OpFNegate %v2float %2\n" + "%4 = OpFNegate %v2float %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 11: fold snegate(iadd with const). // -(2 + x) = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIAdd %int %int_2 %2\n" + "%4 = OpSNegate %int %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 12: fold snegate(iadd with const). // -(x + 2) = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIAdd %int %2 %int_2\n" + "%4 = OpSNegate %int %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 13: fold snegate(isub with const). // -(2 - x) = x - 2 InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpISub %int %int_2 %2\n" + "%4 = OpSNegate %int %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 14: fold snegate(isub with const). // -(x - 2) = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpISub %int %2 %int_2\n" + "%4 = OpSNegate %int %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 15: fold snegate(iadd with const). // -(x + 2) = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIAdd %long %2 %long_2\n" + "%4 = OpSNegate %long %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 16: fold snegate(isub with const). // -(2 - x) = x - 2 InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpISub %long %long_2 %2\n" + "%4 = OpSNegate %long %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 17: fold snegate(isub with const). // -(x - 2) = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpISub %long %2 %long_2\n" + "%4 = OpSNegate %long %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" + "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" + "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" + "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 19: fold vector fnegate with null InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" + "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" + "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFNegate %v2double %v2double_null\n" + "OpReturn\n" + "OpFunctionEnd", 2, true) )); INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: scalar reicprocal // x / 0.5 = x * 2.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %2 %float_0p5\n" + "OpReturn\n" + "OpFunctionEnd\n", 3, true), // Test case 1: Unfoldable InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %2 %104\n" + "OpReturn\n" + "OpFunctionEnd\n", 3, false), // Test case 2: Vector reciprocal // x / {2.0, 0.5} = x * {0.5, 2.0} InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" + "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" + "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %var\n" + "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" + "OpReturn\n" + "OpFunctionEnd\n", 3, true), // Test case 3: double reciprocal // x / 2.0 = x * 0.5 InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" + "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_double Function\n" + "%2 = OpLoad %double %var\n" + "%3 = OpFDiv %double %2 %double_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 3, true), // Test case 4: don't fold x / 0. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %var\n" + "%3 = OpFDiv %v2float %2 %v2float_null\n" + "OpReturn\n" + "OpFunctionEnd\n", 3, false) )); INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: fold consecutive fmuls // (x * 3.0) * 2.0 = x * 6.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFMul %float %2 %float_3\n" + "%4 = OpFMul %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 1: fold consecutive fmuls // 2.0 * (x * 3.0) = x * 6.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFMul %float %2 %float_3\n" + "%4 = OpFMul %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 2: fold consecutive fmuls // (3.0 * x) * 2.0 = x * 6.0 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFMul %float %float_3 %2\n" + "%4 = OpFMul %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 3: fold vector fmul InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" + "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" + "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" + "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %var\n" + "%3 = OpFMul %v2float %2 %v2float_2_3\n" + "%4 = OpFMul %v2float %3 %v2float_3_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 4: fold double fmuls // (x * 3.0) * 2.0 = x * 6.0 InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" + "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_double Function\n" + "%2 = OpLoad %double %var\n" + "%3 = OpFMul %double %2 %double_3\n" + "%4 = OpFMul %double %3 %double_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 5: fold 32 bit imuls // (x * 3) * 2 = x * 6 InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %2 %int_3\n" + "%4 = OpIMul %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 6: fold 64 bit imuls // (x * 3) * 2 = x * 6 InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIMul %long %2 %long_3\n" + "%4 = OpIMul %long %3 %long_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 7: merge vector integer mults InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" + "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %var\n" + "%3 = OpIMul %v2int %2 %v2int_2_3\n" + "%4 = OpIMul %v2int %3 %v2int_3_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 8: merge fmul of fdiv // 2.0 * (2.0 / x) = 4.0 / x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %float_2 %2\n" + "%4 = OpFMul %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 9: merge fmul of fdiv // (2.0 / x) * 2.0 = 4.0 / x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %float_2 %2\n" + "%4 = OpFMul %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 10: Do not merge imul of sdiv // 4 * (x / 2) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %2 %int_2\n" + "%4 = OpIMul %int %int_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 11: Do not merge imul of sdiv // (x / 2) * 4 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %2 %int_2\n" + "%4 = OpIMul %int %3 %int_4\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 12: Do not merge imul of udiv // 4 * (x / 2) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpUDiv %uint %2 %uint_2\n" + "%4 = OpIMul %uint %uint_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 13: Do not merge imul of udiv // (x / 2) * 4 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpUDiv %uint %2 %uint_2\n" + "%4 = OpIMul %uint %3 %uint_4\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 14: Don't fold // (x / 3) * 4 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpUDiv %uint %2 %uint_3\n" + "%4 = OpIMul %uint %3 %uint_4\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 15: merge vector fmul of fdiv // (x / {2,2}) * {4,4} = x * {2,2} InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" + "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %v2float %var\n" + "%3 = OpFDiv %v2float %2 %v2float_2_2\n" + "%4 = OpFMul %v2float %3 %v2float_4_4\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 16: merge vector imul of snegate // (-x) * {2,2} = x * {-2,-2} InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %var\n" + "%3 = OpSNegate %v2int %2\n" + "%4 = OpIMul %v2int %3 %v2int_2_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 17: merge vector imul of snegate // {2,2} * (-x) = x * {-2,-2} InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %var\n" + "%3 = OpSNegate %v2int %2\n" + "%4 = OpIMul %v2int %v2int_2_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 18: Fold OpVectorTimesScalar // {4,4} = OpVectorTimesScalar v2float {2,2} 2 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" + "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" + "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" + "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 19: Fold OpVectorTimesScalar // {0,0} = OpVectorTimesScalar v2float v2float_null -1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" + "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" + "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 20: Fold OpVectorTimesScalar // {4,4} = OpVectorTimesScalar v2double {2,2} 2 InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" + "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" + "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 21: Fold OpVectorTimesScalar // {0,0} = OpVectorTimesScalar v2double {0,0} n InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" + "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" + "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" + "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_double Function\n" + "%load = OpLoad %double %n\n" + "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 22: Fold OpVectorTimesScalar // {0,0} = OpVectorTimesScalar v2double n 0 InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" + "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2double Function\n" + "%load = OpLoad %v2double %n\n" + "%2 = OpVectorTimesScalar %v2double %load %double_0\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 23: merge fmul of fdiv // x * (y / x) = y InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" + "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %x\n" + "%3 = OpLoad %float %y\n" + "%4 = OpFDiv %float %3 %2\n" + "%5 = OpFMul %float %2 %4\n" + "OpReturn\n" + "OpFunctionEnd\n", 5, true), // Test case 24: merge fmul of fdiv // (y / x) * x = y InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" + "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %x\n" + "%3 = OpLoad %float %y\n" + "%4 = OpFDiv %float %3 %2\n" + "%5 = OpFMul %float %4 %2\n" + "OpReturn\n" + "OpFunctionEnd\n", 5, true), // Test case 25: fold overflowing signed 32 bit imuls // (x * 1073741824) * 2 = x * int_min InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %2 %int_1073741824\n" + "%4 = OpIMul %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 26: fold overflowing signed 64 bit imuls // (x * 4611686018427387904) * 2 = x * long_min InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIMul %long %2 %long_4611686018427387904\n" + "%4 = OpIMul %long %3 %long_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 27: fold overflowing 32 bit unsigned imuls // (x * 2147483649) * 2 = x * 2 InstructionFoldingCase( Header() + "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" + "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" + "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpIMul %uint %2 %uint_2147483649\n" + "%4 = OpIMul %uint %3 %uint_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 28: fold overflowing 64 bit unsigned imuls // (x * 9223372036854775809) * 2 = x * 2 InstructionFoldingCase( Header() + "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" + "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" + "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_ulong Function\n" + "%2 = OpLoad %ulong %var\n" + "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" + "%4 = OpIMul %ulong %3 %ulong_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 29: fold underflowing signed 32 bit imuls // (x * (-858993459)) * 10 = x * 2 InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %2 %int_n858993459\n" + "%4 = OpIMul %int %3 %int_10\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 30: fold underflowing signed 64 bit imuls // (x * (-3689348814741910323)) * 10 = x * 2 InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIMul %long %2 %long_n3689348814741910323\n" + "%4 = OpIMul %long %3 %long_10\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true) )); INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge consecutive fdiv // 4.0 / (2.0 / x) = 2.0 * x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %float_2 %2\n" + "%4 = OpFDiv %float %float_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 1: merge consecutive fdiv // 4.0 / (x / 2.0) = 8.0 / x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %2 %float_2\n" + "%4 = OpFDiv %float %float_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 2: merge consecutive fdiv // (4.0 / x) / 2.0 = 2.0 / x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %float_4 %2\n" + "%4 = OpFDiv %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 3: Do not merge consecutive sdiv // 4 / (2 / x) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %int_2 %2\n" + "%4 = OpSDiv %int %int_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 4: Do not merge consecutive sdiv // 4 / (x / 2) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %2 %int_2\n" + "%4 = OpSDiv %int %int_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 5: Do not merge consecutive sdiv // (4 / x) / 2 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %int_4 %2\n" + "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 6: Do not merge consecutive sdiv // (x / 4) / 2 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSDiv %int %2 %int_4\n" + "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 7: Do not merge sdiv of imul // 4 / (2 * x) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %int_2 %2\n" + "%4 = OpSDiv %int %int_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 8: Do not merge sdiv of imul // 4 / (x * 2) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %2 %int_2\n" + "%4 = OpSDiv %int %int_4 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 9: Do not merge sdiv of imul // (4 * x) / 2 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %int_4 %2\n" + "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 10: Do not merge sdiv of imul // (x * 4) / 2 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIMul %int %2 %int_4\n" + "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 11: Do not merge sdiv of snegate. If %2 is INT_MIN, then the // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv. // Specifically, (-INT_MIN) / 2 != INT_MIN / -2. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSNegate %int %2\n" + "%4 = OpSDiv %int %3 %int_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 12: Do not merge sdiv of snegate. If %2 is INT_MIN, then the // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv. // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpSNegate %int %2\n" + "%4 = OpSDiv %int %int_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 13: Don't merge // (x / {null}) / {null} InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_v2float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFDiv %float %2 %v2float_null\n" + "%4 = OpFDiv %float %3 %v2float_null\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 14: merge fmul of fdiv // (y * x) / x = y InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" + "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %x\n" + "%3 = OpLoad %float %y\n" + "%4 = OpFMul %float %3 %2\n" + "%5 = OpFDiv %float %4 %2\n" + "OpReturn\n" + "OpFunctionEnd\n", 5, true), // Test case 15: merge fmul of fdiv // (x * y) / x = y InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" + "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %x\n" + "%3 = OpLoad %float %y\n" + "%4 = OpFMul %float %2 %3\n" + "%5 = OpFDiv %float %4 %2\n" + "OpReturn\n" + "OpFunctionEnd\n", 5, true), // Test case 16: Do not merge udiv of snegate // (-x) / 2u InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpSNegate %uint %2\n" + "%4 = OpUDiv %uint %3 %uint_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false), // Test case 17: Do not merge udiv of snegate // 2u / (-x) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpSNegate %uint %2\n" + "%4 = OpUDiv %uint %uint_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, false) )); INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge add of negate // (-x) + 2 = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFNegate %float %2\n" + "%4 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 1: merge add of negate // 2 + (-x) = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpSNegate %float %2\n" + "%4 = OpIAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 2: merge add of negate // (-x) + 2 = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpSNegate %long %2\n" + "%4 = OpIAdd %long %3 %long_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 3: merge add of negate // 2 + (-x) = 2 - x InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpSNegate %long %2\n" + "%4 = OpIAdd %long %long_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 4: merge add of subtract // (x - 1) + 2 = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %2 %float_1\n" + "%4 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 5: merge add of subtract // (1 - x) + 2 = 3 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_1 %2\n" + "%4 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 6: merge add of subtract // 2 + (x - 1) = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %2 %float_1\n" + "%4 = OpFAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 7: merge add of subtract // 2 + (1 - x) = 3 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_1 %2\n" + "%4 = OpFAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 8: merge add of add // (x + 1) + 2 = x + 3 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %2 %float_1\n" + "%4 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 9: merge add of add // (1 + x) + 2 = 3 + x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %float_1 %2\n" + "%4 = OpFAdd %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 10: merge add of add // 2 + (x + 1) = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %2 %float_1\n" + "%4 = OpFAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 11: merge add of add // 2 + (1 + x) = 3 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %float_1 %2\n" + "%4 = OpFAdd %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 12: fold overflowing signed 32 bit iadds // (x + int_max) + 1 = x + int_min InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIAdd %int %2 %int_max\n" + "%4 = OpIAdd %int %3 %int_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 13: fold overflowing signed 64 bit iadds // (x + long_max) + 1 = x + long_min InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIAdd %long %2 %long_max\n" + "%4 = OpIAdd %long %3 %long_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 14: fold overflowing 32 bit unsigned iadds // (x + uint_max) + 2 = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" + "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" + "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_uint Function\n" + "%2 = OpLoad %uint %var\n" + "%3 = OpIAdd %uint %2 %uint_max\n" + "%4 = OpIAdd %uint %3 %uint_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 15: fold overflowing 64 bit unsigned iadds // (x + ulong_max) + 2 = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" + "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" + "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_ulong Function\n" + "%2 = OpLoad %ulong %var\n" + "%3 = OpIAdd %ulong %2 %ulong_max\n" + "%4 = OpIAdd %ulong %3 %ulong_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 16: fold underflowing signed 32 bit iadds // (x + int_min) + (-1) = x + int_max InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpIAdd %int %2 %int_min\n" + "%4 = OpIAdd %int %3 %int_n1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 17: fold underflowing signed 64 bit iadds // (x + long_min) + (-1) = x + long_max InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpIAdd %long %2 %long_min\n" + "%4 = OpIAdd %long %3 %long_n1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true) )); INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge of add of sub // (a - b) + b => a InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %var0\n" + "%4 = OpLoad %float %var1\n" + "%5 = OpFSub %float %3 %4\n" + "%6 = OpFAdd %float %5 %4\n" + "OpReturn\n" + "OpFunctionEnd\n", 6, true), // Test case 1: merge of add of sub // b + (a - b) => a InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%3 = OpLoad %float %var0\n" + "%4 = OpLoad %float %var1\n" + "%5 = OpFSub %float %3 %4\n" + "%6 = OpFAdd %float %4 %5\n" + "OpReturn\n" + "OpFunctionEnd\n", 6, true) )); INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: factor of add of muls // (a * b) + (a * c) => a * (b + c) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%var2 = OpVariable %_ptr_float Function\n" + "%4 = OpLoad %float %var0\n" + "%5 = OpLoad %float %var1\n" + "%6 = OpLoad %float %var2\n" + "%7 = OpFMul %float %6 %4\n" + "%8 = OpFMul %float %6 %5\n" + "%9 = OpFAdd %float %7 %8\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true), // Test case 1: factor of add of muls // (b * a) + (a * c) => a * (b + c) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%var2 = OpVariable %_ptr_float Function\n" + "%4 = OpLoad %float %var0\n" + "%5 = OpLoad %float %var1\n" + "%6 = OpLoad %float %var2\n" + "%7 = OpFMul %float %4 %6\n" + "%8 = OpFMul %float %6 %5\n" + "%9 = OpFAdd %float %7 %8\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true), // Test case 2: factor of add of muls // (a * b) + (c * a) => a * (b + c) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%var2 = OpVariable %_ptr_float Function\n" + "%4 = OpLoad %float %var0\n" + "%5 = OpLoad %float %var1\n" + "%6 = OpLoad %float %var2\n" + "%7 = OpFMul %float %6 %4\n" + "%8 = OpFMul %float %5 %6\n" + "%9 = OpFAdd %float %7 %8\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true), // Test case 3: factor of add of muls // (b * a) + (c * a) => a * (b + c) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var0 = OpVariable %_ptr_float Function\n" + "%var1 = OpVariable %_ptr_float Function\n" + "%var2 = OpVariable %_ptr_float Function\n" + "%4 = OpLoad %float %var0\n" + "%5 = OpLoad %float %var1\n" + "%6 = OpLoad %float %var2\n" + "%7 = OpFMul %float %4 %6\n" + "%8 = OpFMul %float %5 %6\n" + "%9 = OpFAdd %float %7 %8\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true) )); INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge sub of negate // (-x) - 2 = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFNegate %float %2\n" + "%4 = OpFSub %float %3 %float_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 1: merge sub of negate // 2 - (-x) = x + 2 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFNegate %float %2\n" + "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 2: merge sub of negate // (-x) - 2 = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpSNegate %long %2\n" + "%4 = OpISub %long %3 %long_2\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 3: merge sub of negate // 2 - (-x) = x + 2 InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpSNegate %long %2\n" + "%4 = OpISub %long %long_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 4: merge add of subtract // (x + 2) - 1 = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %2 %float_2\n" + "%4 = OpFSub %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 5: merge add of subtract // (2 + x) - 1 = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %float_2 %2\n" + "%4 = OpFSub %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 6: merge add of subtract // 2 - (x + 1) = 1 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %2 %float_1\n" + "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 7: merge add of subtract // 2 - (1 + x) = 1 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFAdd %float %float_1 %2\n" + "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 8: merge subtract of subtract // (x - 2) - 1 = x - 3 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %2 %float_2\n" + "%4 = OpFSub %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 9: merge subtract of subtract // (2 - x) - 1 = 1 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_2 %2\n" + "%4 = OpFSub %float %3 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 10: merge subtract of subtract // 2 - (x - 1) = 3 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %2 %float_1\n" + "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 11: merge subtract of subtract // 1 - (2 - x) = x + (-1) InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_2 %2\n" + "%4 = OpFSub %float %float_1 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 12: merge subtract of subtract // 2 - (1 - x) = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_float Function\n" + "%2 = OpLoad %float %var\n" + "%3 = OpFSub %float %float_1 %2\n" + "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 13: merge subtract of subtract with mixed types. // 2 - (1 - x) = x + 1 InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpISub %int %uint_1 %2\n" + "%4 = OpISub %int %int_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 14: fold overflowing signed 32 bit isubs // (x - int_max) - 1 = x - int_min InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" + "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_int Function\n" + "%2 = OpLoad %int %var\n" + "%3 = OpISub %int %2 %int_max\n" + "%4 = OpISub %int %3 %int_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true), // Test case 15: fold overflowing signed 64 bit isubs // (x - long_max) - 1 = x - long_min InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" + "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%var = OpVariable %_ptr_long Function\n" + "%2 = OpLoad %long %var\n" + "%3 = OpISub %long %2 %long_max\n" + "%4 = OpISub %long %3 %long_1\n" + "OpReturn\n" + "OpFunctionEnd\n", 4, true) )); INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Fold select with the same values for both sides InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" + "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_bool Function\n" + "%load = OpLoad %bool %n\n" + "%2 = OpSelect %int %load %100 %100\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 1: Fold select true to left side InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" + "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load = OpLoad %bool %n\n" + "%2 = OpSelect %int %true %100 %n\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 2: Fold select false to right side InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" + "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load = OpLoad %bool %n\n" + "%2 = OpSelect %int %false %n %100\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 3: Fold select null to right side InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" + "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_int Function\n" + "%load = OpLoad %int %n\n" + "%2 = OpSelect %int %bool_null %load %100\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 4: vector null InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" + "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%load = OpLoad %v2int %n\n" + "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" + "OpReturn\n" + "OpFunctionEnd", 2, true), // Test case 5: vector select InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v2int Function\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %n\n" + "%3 = OpLoad %v2int %n\n" + "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 6: vector select InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v2int Function\n" + "%n = OpVariable %_ptr_v2int Function\n" + "%2 = OpLoad %v2int %n\n" + "%3 = OpLoad %v2int %n\n" + "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" + "OpReturn\n" + "OpFunctionEnd", 4, true) )); INSTANTIATE_TEST_SUITE_P(CompositeExtractOrInsertMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Extracting from result of consecutive shuffles of differing // size. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4int Function\n" + "%2 = OpLoad %v4int %n\n" + "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" + "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" + "%5 = OpCompositeExtract %int %4 1\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 1: Extracting from result of vector shuffle of differing // input and result sizes. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4int Function\n" + "%2 = OpLoad %v4int %n\n" + "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" + "%4 = OpCompositeExtract %int %3 0\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 2: Extracting from result of vector shuffle of differing // input and result sizes. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4int Function\n" + "%2 = OpLoad %v4int %n\n" + "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" + "%4 = OpCompositeExtract %int %3 1\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 3: Using fmix feeding extract with a 1 in the a position. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" + "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" + "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" + "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v4double Function\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %m\n" + "%3 = OpLoad %v4double %n\n" + "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" + "%5 = OpCompositeExtract %double %4 1\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 4: Using fmix feeding extract with a 0 in the a position. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" + "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" + "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" + "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v4double Function\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %m\n" + "%3 = OpLoad %v4double %n\n" + "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" + "%5 = OpCompositeExtract %double %4 2\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 5: Using fmix feeding extract with a null for the alpha InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" + "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" + "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" + "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v4double Function\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %m\n" + "%3 = OpLoad %v4double %n\n" + "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" + "%5 = OpCompositeExtract %double %4 0\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a // position. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%m = OpVariable %_ptr_v4double Function\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %m\n" + "%3 = OpLoad %v4double %n\n" + "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" + "%5 = OpCompositeExtract %double %4 3\n" + "OpReturn\n" + "OpFunctionEnd", 5, false), // Test case 7: Extracting the undefined literal value from a vector // shuffle. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: %4 = OpUndef [[int]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4int Function\n" + "%2 = OpLoad %v4int %n\n" + "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" + "%4 = OpCompositeExtract %int %3 1\n" + "OpReturn\n" + "OpFunctionEnd", 4, true), // Test case 8: Inserting every element of a vector turns into a composite construct. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" + "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" + "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" + "%3 = OpCompositeInsert %v4int %int_1 %2 1\n" + "%4 = OpCompositeInsert %v4int %int_2 %3 2\n" + "%5 = OpCompositeInsert %v4int %int_3 %4 3\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 9: Inserting every element of a vector turns into a composite construct in a different order. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" + "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" + "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" + "%4 = OpCompositeInsert %v4int %int_2 %2 2\n" + "%3 = OpCompositeInsert %v4int %int_1 %4 1\n" + "%5 = OpCompositeInsert %v4int %int_3 %3 3\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 10: Check multiple inserts to the same position are handled correctly. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" + "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" + "; CHECK: %6 = OpCopyObject [[v4]] [[construct]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" + "%3 = OpCompositeInsert %v4int %int_2 %2 2\n" + "%4 = OpCompositeInsert %v4int %int_4 %3 1\n" + "%5 = OpCompositeInsert %v4int %int_1 %4 1\n" + "%6 = OpCompositeInsert %v4int %int_3 %5 3\n" + "OpReturn\n" + "OpFunctionEnd", 6, true), // Test case 11: The last indexes are 0 and 1, but they have different first indexes. This should not be folded. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" + "%3 = OpCompositeInsert %m2x2int %int_1 %2 1 1\n" + "OpReturn\n" + "OpFunctionEnd", 3, false), // Test case 12: Don't fold when there is a partial insertion. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0\n" + "%3 = OpCompositeInsert %m2x2int %int_4 %2 0 0\n" + "%4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1\n" + "OpReturn\n" + "OpFunctionEnd", 4, false), // Test case 13: Insert into a column of a matrix InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" + "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + // We keep this insert in the chain. DeadInsertElimPass should remove it. "; CHECK: [[insert:%\\w+]] = OpCompositeInsert [[m2x2]] %100 [[m2x2_undef]] 0 0\n" + "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" + "; CHECK: %3 = OpCompositeInsert [[m2x2]] [[construct]] [[insert]] 0\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" + "%3 = OpCompositeInsert %m2x2int %int_1 %2 0 1\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 14: Insert all elements of the matrix. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" + "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" + "; CHECK: [[c0:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" + "; CHECK: [[c1:%\\w+]] = OpCompositeConstruct [[v2]] [[int2]] [[int3]]\n" + "; CHECK: [[matrix:%\\w+]] = OpCompositeConstruct [[m2x2]] [[c0]] [[c1]]\n" + "; CHECK: %5 = OpCopyObject [[m2x2]] [[matrix]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpCompositeConstruct %v2int %100 %int_1\n" + "%3 = OpCompositeInsert %m2x2int %2 %m2x2int_undef 0\n" + "%4 = OpCompositeInsert %m2x2int %int_2 %3 1 0\n" + "%5 = OpCompositeInsert %m2x2int %int_3 %4 1 1\n" + "OpReturn\n" + "OpFunctionEnd", 5, true), // Test case 15: Replace construct with extract when reconstructing a member // of another object. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" + "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" + "; CHECK: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" + "; CHECK: %5 = OpCompositeExtract [[v2]] [[m2x2_undef]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%3 = OpCompositeExtract %int %m2x2int_undef 1 0\n" + "%4 = OpCompositeExtract %int %m2x2int_undef 1 1\n" + "%5 = OpCompositeConstruct %v2int %3 %4\n" + "OpReturn\n" + "OpFunctionEnd", 5, true) )); INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Using OpDot to extract last element. InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%2 = OpLoad %v4float %n\n" + "%3 = OpDot %float %2 %v4float_0_0_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 1: Using OpDot to extract last element. InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%2 = OpLoad %v4float %n\n" + "%3 = OpDot %float %v4float_0_0_0_1 %2\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 2: Using OpDot to extract second element. InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4float Function\n" + "%2 = OpLoad %v4float %n\n" + "%3 = OpDot %float %v4float_0_1_0_0 %2\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 3: Using OpDot to extract last element. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %n\n" + "%3 = OpDot %double %2 %v4double_0_0_0_1\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 4: Using OpDot to extract last element. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %n\n" + "%3 = OpDot %double %v4double_0_0_0_1 %2\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 5: Using OpDot to extract second element. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%2 = OpLoad %v4double %n\n" + "%3 = OpDot %double %v4double_0_1_0_0 %2\n" + "OpReturn\n" + "OpFunctionEnd", 3, true) )); INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Using OpDot to extract last element. InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + "; CHECK: [[null:%\\w+]] = OpConstantNull [[v2int]]\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: %3 = OpVectorShuffle [[v2int]] [[null]] {{%\\w+}} 4294967295 2\n" + "%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 3 0xFFFFFFFF \n" + "%3 = OpVectorShuffle %v2int %2 %v2int_2_3 1 2 \n" + "OpReturn\n" + "OpFunctionEnd", 3, true) )); INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: (x * y) + a = Fma(x, y, a) InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 1: a + (x * y) = Fma(x, y, a) InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %la %mul\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 2: (x * y) + a = Fma(x, y, a) with vectors InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_v4float Function\n" + "%y = OpVariable %_ptr_v4float Function\n" + "%a = OpVariable %_ptr_v4float Function\n" + "%lx = OpLoad %v4float %x\n" + "%ly = OpLoad %v4float %y\n" + "%mul = OpFMul %v4float %lx %ly\n" + "%la = OpLoad %v4float %a\n" + "%3 = OpFAdd %v4float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 3: a + (x * y) = Fma(x, y, a) with vectors InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %la %mul\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test 4: that the OpExtInstImport instruction is generated if it is missing. InstructionFoldingCase( std::string() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "OpCapability Shader\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %main \"main\"\n" + "OpExecutionMode %main OriginUpperLeft\n" + "OpSource GLSL 140\n" + "OpName %main \"main\"\n" + "%void = OpTypeVoid\n" + "%void_func = OpTypeFunction %void\n" + "%bool = OpTypeBool\n" + "%float = OpTypeFloat 32\n" + "%_ptr_float = OpTypePointer Function %float\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test 5: Don't fold if the multiple is marked no contract. InstructionFoldingCase( std::string() + "OpCapability Shader\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %main \"main\"\n" + "OpExecutionMode %main OriginUpperLeft\n" + "OpSource GLSL 140\n" + "OpName %main \"main\"\n" + "OpDecorate %mul NoContraction\n" + "%void = OpTypeVoid\n" + "%void_func = OpTypeFunction %void\n" + "%bool = OpTypeBool\n" + "%float = OpTypeFloat 32\n" + "%_ptr_float = OpTypePointer Function %float\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, false), // Test 6: Don't fold if the add is marked no contract. InstructionFoldingCase( std::string() + "OpCapability Shader\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %main \"main\"\n" + "OpExecutionMode %main OriginUpperLeft\n" + "OpSource GLSL 140\n" + "OpName %main \"main\"\n" + "OpDecorate %3 NoContraction\n" + "%void = OpTypeVoid\n" + "%void_func = OpTypeFunction %void\n" + "%bool = OpTypeBool\n" + "%float = OpTypeFloat 32\n" + "%_ptr_float = OpTypePointer Function %float\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFAdd %float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, false), // Test case 7: (x * y) - a = Fma(x, y, -a) InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[na:%\\w+]] = OpFNegate {{%\\w+}} [[la]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[na]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFSub %float %mul %la\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true), // Test case 8: a - (x * y) = Fma(-x, y, a) InstructionFoldingCase( Header() + "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + "; CHECK: OpFunction\n" + "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + "; CHECK: [[nx:%\\w+]] = OpFNegate {{%\\w+}} [[lx]]\n" + "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[nx]] [[ly]] [[la]]\n" + "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + "%y = OpVariable %_ptr_float Function\n" + "%a = OpVariable %_ptr_float Function\n" + "%lx = OpLoad %float %x\n" + "%ly = OpLoad %float %y\n" + "%mul = OpFMul %float %lx %ly\n" + "%la = OpLoad %float %a\n" + "%3 = OpFSub %float %la %mul\n" + "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", 3, true) )); using MatchingInstructionWithNoResultFoldingTest = ::testing::TestWithParam>; // Test folding instructions that do not have a result. The instruction // that will be folded is the last instruction before the return. If there // are multiple returns, there is not guarantee which one is used. TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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. Instruction* inst = nullptr; Function* func = &*context->module()->begin(); for (auto& bb : *func) { Instruction* terminator = bb.terminator(); if (terminator->IsReturnOrAbort()) { inst = terminator->PreviousNode(); break; } } assert(inst && "Invalid test. Could not find instruction to fold."); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(succeeded, tc.expected_result); if (succeeded) { Match(tc.test_body, context.get()); } } INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest, ::testing::Values( // Test case 0: Remove store of undef. InstructionFoldingCase( Header() + "; CHECK: OpLabel\n" + "; CHECK-NOT: OpStore\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%undef = OpUndef %v4double\n" + "OpStore %n %undef\n" + "OpReturn\n" + "OpFunctionEnd", 0 /* OpStore */, true), // Test case 1: Keep volatile store. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%n = OpVariable %_ptr_v4double Function\n" + "%undef = OpUndef %v4double\n" + "OpStore %n %undef Volatile\n" + "OpReturn\n" + "OpFunctionEnd", 0 /* OpStore */, false) )); INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest, ::testing::Values( // Test case 0: Basic test 1 InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 1: Basic test 2 InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 2: Basic test 3 InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 3: Basic test 4 InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 4: Don't fold, need both operands of the feeder. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, false), // Test case 5: Don't fold, need both operands of the feeder. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, false), // Test case 6: Fold, need both operands of the feeder, but they are the same. InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 7: Fold, need both operands of the feeder, but they are the same. InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 8: Replace first operand with a smaller vector. InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v2double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v2double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" + "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 9: Replace first operand with a larger vector. InstructionFoldingCase( Header() + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" + "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 10: Replace unused operand with null. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" + "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 11: Replace unused operand with null. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" + "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 12: Replace unused operand with null. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 13: Shuffle with undef literal. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" + "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" + "OpReturn\n" + "OpFunctionEnd", 9, true), // Test case 14: Shuffle with undef literal and change size of first input vector. InstructionFoldingCase( Header() + "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" + "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" + "; CHECK: OpVectorShuffle\n" + "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 1 4 4294967295\n" + "; CHECK: OpReturn\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpVariable %_ptr_v4double Function\n" + "%3 = OpVariable %_ptr_v4double Function\n" + "%4 = OpVariable %_ptr_v4double Function\n" + "%5 = OpLoad %v4double %2\n" + "%6 = OpLoad %v4double %3\n" + "%7 = OpLoad %v4double %4\n" + "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" + "%9 = OpVectorShuffle %v4double %8 %7 0 1 2 4294967295\n" + "OpReturn\n" + "OpFunctionEnd", 9, true) )); using EntryPointFoldingTest = ::testing::TestWithParam>; TEST_P(EntryPointFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr 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. Instruction* inst = nullptr; inst = &*context->module()->entry_points().begin(); assert(inst && "Invalid test. Could not find entry point instruction to fold."); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(succeeded, tc.expected_result); if (succeeded) { Match(tc.test_body, context.get()); } } INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest, ::testing::Values( // Test case 0: Basic test 1 InstructionFoldingCase(std::string() + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" + "OpCapability Shader\n" + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" + "OpExecutionMode %2 OriginUpperLeft\n" + "OpSource GLSL 430\n" + "OpDecorate %3 Location 0\n" + "%void = OpTypeVoid\n" + "%5 = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%v4float = OpTypeVector %float 4\n" + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + "%3 = OpVariable %_ptr_Output_v4float Output\n" + "%int = OpTypeInt 32 1\n" + "%int_0 = OpConstant %int 0\n" + "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + "%2 = OpFunction %void None %5\n" + "%12 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true), InstructionFoldingCase(std::string() + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" + "OpCapability Shader\n" + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" + "OpExecutionMode %2 OriginUpperLeft\n" + "OpSource GLSL 430\n" + "OpDecorate %3 Location 0\n" + "%void = OpTypeVoid\n" + "%5 = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%v4float = OpTypeVector %float 4\n" + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + "%3 = OpVariable %_ptr_Output_v4float Output\n" + "%4 = OpVariable %_ptr_Output_v4float Output\n" + "%int = OpTypeInt 32 1\n" + "%int_0 = OpConstant %int 0\n" + "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + "%2 = OpFunction %void None %5\n" + "%12 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true), InstructionFoldingCase(std::string() + "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" + "OpCapability Shader\n" + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" + "OpExecutionMode %2 OriginUpperLeft\n" + "OpSource GLSL 430\n" + "OpDecorate %3 Location 0\n" + "%void = OpTypeVoid\n" + "%5 = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%v4float = OpTypeVector %float 4\n" + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + "%3 = OpVariable %_ptr_Output_v4float Output\n" + "%4 = OpVariable %_ptr_Output_v4float Output\n" + "%int = OpTypeInt 32 1\n" + "%int_0 = OpConstant %int 0\n" + "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + "%2 = OpFunction %void None %5\n" + "%12 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", 9, true) )); using SPV14FoldingTest = ::testing::TestWithParam>; TEST_P(SPV14FoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr context = BuildModule(SPV_ENV_UNIVERSAL_1_4, 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); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(succeeded, tc.expected_result); if (succeeded) { Match(tc.test_body, context.get()); } } INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest, ::testing::Values( // Test case 0: select vectors with scalar condition. InstructionFoldingCase(std::string() + "; CHECK-NOT: OpSelect\n" + "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" + "OpCapability Shader\n" + "OpCapability Linkage\n" + "%void = OpTypeVoid\n" + "%bool = OpTypeBool\n" + "%true = OpConstantTrue %bool\n" + "%int = OpTypeInt 32 0\n" + "%int4 = OpTypeVector %int 4\n" + "%int_0 = OpConstant %int 0\n" + "%int_1 = OpConstant %int 1\n" + "%1 = OpUndef %int4\n" + "%2 = OpUndef %int4\n" + "%void_fn = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_fn\n" + "%entry = OpLabel\n" + "%3 = OpSelect %int4 %true %1 %2\n" + "OpReturn\n" + "OpFunctionEnd\n" , 3, true), // Test case 1: select struct with scalar condition. InstructionFoldingCase(std::string() + "; CHECK-NOT: OpSelect\n" + "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" + "OpCapability Shader\n" + "OpCapability Linkage\n" + "%void = OpTypeVoid\n" + "%bool = OpTypeBool\n" + "%true = OpConstantFalse %bool\n" + "%int = OpTypeInt 32 0\n" + "%struct = OpTypeStruct %int %int %int %int\n" + "%int_0 = OpConstant %int 0\n" + "%int_1 = OpConstant %int 1\n" + "%1 = OpUndef %struct\n" + "%2 = OpUndef %struct\n" + "%void_fn = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_fn\n" + "%entry = OpLabel\n" + "%3 = OpSelect %struct %true %1 %2\n" + "OpReturn\n" + "OpFunctionEnd\n" , 3, true), // Test case 1: select array with scalar condition. InstructionFoldingCase(std::string() + "; CHECK-NOT: OpSelect\n" + "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" + "OpCapability Shader\n" + "OpCapability Linkage\n" + "%void = OpTypeVoid\n" + "%bool = OpTypeBool\n" + "%true = OpConstantFalse %bool\n" + "%int = OpTypeInt 32 0\n" + "%int_0 = OpConstant %int 0\n" + "%int_1 = OpConstant %int 1\n" + "%int_4 = OpConstant %int 4\n" + "%array = OpTypeStruct %int %int %int %int\n" + "%1 = OpUndef %array\n" + "%2 = OpUndef %array\n" + "%void_fn = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_fn\n" + "%entry = OpLabel\n" + "%3 = OpSelect %array %true %1 %2\n" + "OpReturn\n" + "OpFunctionEnd\n" , 3, true) )); std::string FloatControlsHeader(const std::string& capabilities) { std::string header = R"( OpCapability Shader )" + capabilities + R"( %void = OpTypeVoid %float = OpTypeFloat 32 %float_0 = OpConstant %float 0 %float_1 = OpConstant %float 1 %void_fn = OpTypeFunction %void %func = OpFunction %void None %void_fn %entry = OpLabel )"; return header; } using FloatControlsFoldingTest = ::testing::TestWithParam>; TEST_P(FloatControlsFoldingTest, Case) { const auto& tc = GetParam(); // Build module. std::unique_ptr context = BuildModule(SPV_ENV_UNIVERSAL_1_4, 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); std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(succeeded, tc.expected_result); if (succeeded) { Match(tc.test_body, context.get()); } } INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest, ::testing::Values( // Test case 0: no folding with DenormPreserve InstructionFoldingCase(FloatControlsHeader("OpCapability DenormPreserve") + "%1 = OpFAdd %float %float_0 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n" , 1, false), // Test case 1: no folding with DenormFlushToZero InstructionFoldingCase(FloatControlsHeader("OpCapability DenormFlushToZero") + "%1 = OpFAdd %float %float_0 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n" , 1, false), // Test case 2: no folding with SignedZeroInfNanPreserve InstructionFoldingCase(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") + "%1 = OpFAdd %float %float_0 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n" , 1, false), // Test case 3: no folding with RoundingModeRTE InstructionFoldingCase(FloatControlsHeader("OpCapability RoundingModeRTE") + "%1 = OpFAdd %float %float_0 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n" , 1, false), // Test case 4: no folding with RoundingModeRTZ InstructionFoldingCase(FloatControlsHeader("OpCapability RoundingModeRTZ") + "%1 = OpFAdd %float %float_0 %float_1\n" + "OpReturn\n" + "OpFunctionEnd\n" , 1, false) )); std::string ImageOperandsTestBody(const std::string& image_instruction) { std::string body = R"( OpCapability Shader OpCapability ImageGatherExtended OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft OpDecorate %Texture DescriptorSet 0 OpDecorate %Texture Binding 0 %int = OpTypeInt 32 1 %int_n1 = OpConstant %int -1 %5 = OpConstant %int 0 %float = OpTypeFloat 32 %float_0 = OpConstant %float 0 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown %type_sampled_image = OpTypeSampledImage %type_2d_image %type_sampler = OpTypeSampler %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image %_ptr_int = OpTypePointer Function %int %v2int = OpTypeVector %int 2 %10 = OpTypeVector %float 4 %void = OpTypeVoid %22 = OpTypeFunction %void %v2float = OpTypeVector %float 2 %v3int = OpTypeVector %int 3 %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant %101 = OpConstantComposite %v2int %int_n1 %int_n1 %20 = OpConstantComposite %v2float %float_0 %float_0 %main = OpFunction %void None %22 %23 = OpLabel %var = OpVariable %_ptr_int Function %88 = OpLoad %type_2d_image %Texture %val = OpLoad %int %var %sampler = OpLoad %type_sampler %gSampler %26 = OpSampledImage %type_sampled_image %88 %sampler )" + image_instruction + R"( OpReturn OpFunctionEnd )"; return body; } INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest, ::testing::Values( // Test case 0: OpImageFetch without Offset InstructionFoldingCase(ImageOperandsTestBody( "%89 = OpImageFetch %10 %88 %101 Lod %5 \n") , 89, false), // Test case 1: OpImageFetch with non-const offset InstructionFoldingCase(ImageOperandsTestBody( "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n") , 89, false), // Test case 2: OpImageFetch with Lod and Offset InstructionFoldingCase(ImageOperandsTestBody( " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n" "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n") , 89, true), // Test case 3: OpImageFetch with Bias and Offset InstructionFoldingCase(ImageOperandsTestBody( " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n" "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n") , 89, true), // Test case 4: OpImageFetch with Grad and Offset. // Grad adds 2 operands to the instruction. InstructionFoldingCase(ImageOperandsTestBody( " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n" "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n") , 89, true), // Test case 5: OpImageFetch with Offset and MinLod. // This is an example of a case where the bitmask bit-offset is larger than // that of the Offset. InstructionFoldingCase(ImageOperandsTestBody( " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n" "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n") , 89, true), // Test case 6: OpImageGather with constant Offset InstructionFoldingCase(ImageOperandsTestBody( " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n" "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n") , 89, true), // Test case 7: OpImageWrite with constant Offset InstructionFoldingCase(ImageOperandsTestBody( " OpImageWrite %88 %5 %101 Offset %101 \n" "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n") , 0 /* No result-id */, true) )); } // namespace } // namespace opt } // namespace spvtools