blob: 3ea32046368aca65dcdaa7e7f4db9a8ea62904fd [file] [log] [blame]
// 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 <limits>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
#include "effcee/effcee.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "source/opt/build_module.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/fold.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "spirv-tools/libspirv.hpp"
#include "test/opt/pass_utils.h"
namespace spvtools {
namespace opt {
namespace {
using ::testing::Contains;
std::string Disassemble(const std::string& original, IRContext* context,
uint32_t disassemble_options = 0) {
std::vector<uint32_t> optimized_bin;
context->module()->ToBinary(&optimized_bin, true);
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
SpirvTools tools(target_env);
std::string optimized_asm;
EXPECT_TRUE(
tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
<< "Disassembling failed for shader:\n"
<< original << std::endl;
return optimized_asm;
}
void Match(const std::string& original, IRContext* context,
uint32_t disassemble_options = 0) {
std::string disassembly = Disassemble(original, context, disassemble_options);
auto match_result = effcee::Match(disassembly, original);
EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
<< match_result.message() << "\nChecking result:\n"
<< disassembly;
}
template <class ResultType>
struct InstructionFoldingCase {
InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
: test_body(tb), id_to_fold(id), expected_result(result) {}
std::string test_body;
uint32_t id_to_fold;
ResultType expected_result;
};
using IntegerInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
TEST_P(IntegerInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
// Make sure the instruction folded as expected.
EXPECT_TRUE(succeeded);
if (inst != nullptr) {
EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
EXPECT_EQ(inst->opcode(), SpvOpConstant);
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);
}
}
}
// 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 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
%int = OpTypeInt 32 1
%long = OpTypeInt 64 1
%uint = OpTypeInt 32 0
%v2int = OpTypeVector %int 2
%v4int = OpTypeVector %int 4
%v4float = OpTypeVector %float 4
%v4double = OpTypeVector %double 4
%v2float = OpTypeVector %float 2
%v2double = OpTypeVector %double 2
%v2half = OpTypeVector %half 2
%v2bool = OpTypeVector %bool 2
%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_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
%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_n24 = OpConstant %int -24
%int_min = OpConstant %int -2147483648
%int_max = OpConstant %int 2147483647
%long_0 = OpConstant %long 0
%long_2 = OpConstant %long 2
%long_3 = OpConstant %long 3
%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_max = OpConstant %uint 4294967295
%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
%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_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
%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_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_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_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_1 = OpConstant %double 1
%double_2 = OpConstant %double 2
%double_3 = OpConstant %double 3
%double_4 = OpConstant %double 4
%double_0p5 = OpConstant %double 0.5
%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
%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_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
%v4double_null = OpConstantNull %v4double
%v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
)";
return header;
}
// Returns the header with definitions of float NaN and double NaN. Since FC
// "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
// %double_nan = OpConstant %double -0x1.8p+1024 instead of
// %double_n0 = OpConstant %double -0,
// we separates those definitions from Header().
const std::string& HeaderWithNaN() {
static const std::string headerWithNaN =
Header() +
R"(%float_nan = OpConstant %float -0x1.8p+128
%double_nan = OpConstant %double -0x1.8p+1024
)";
return headerWithNaN;
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 0*n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpIMul %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 1: fold n*0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpIMul %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 2: fold 0/n (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 3: fold n/0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 4: fold 0/n (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUDiv %uint %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 5: fold n/0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 6: fold 0 remainder n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSRem %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 7: fold n remainder 0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSRem %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 8: fold 0%n (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSMod %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 9: fold n%0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSMod %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 10: fold 0%n (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUMod %uint %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 11: fold n%0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUMod %uint %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 12: fold n << 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 13: fold n >> 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftRightLogical %uint %load %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 14: fold n | 0xFFFFFFFF
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseOr %uint %load %uint_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFFFFF),
// Test case 15: fold 0xFFFFFFFF | n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseOr %uint %uint_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFFFFF),
// Test case 16: fold n & 0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseAnd %uint %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 17: fold 1/0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSDiv %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 18: fold 1/0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUDiv %uint %uint_1 %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 19: fold OpSRem 1 0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSRem %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 20: fold 1%0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSMod %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 21: fold 1%0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUMod %uint %uint_1 %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftRightLogical %uint %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 23: fold signed n >> 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpShiftRightLogical %int %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 24: fold n << 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpShiftLeftLogical %int %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 25: fold -24 >> 32 (defined as -1)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -1),
// Test case 26: fold 2 >> 32 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 27: fold 2 >> 32 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 28: fold 2 << 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 29: fold -INT_MIN
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %int %int_min\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<int32_t>::min())
));
// clang-format on
using IntVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
TEST_P(IntVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
SpvOp 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(), SpvOpCopyObject);
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
EXPECT_THAT(opcodes, Contains(inst->opcode()));
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
EXPECT_NE(result, nullptr);
if (result != nullptr) {
const std::vector<const analysis::Constant*>& componenets =
result->AsVectorConstant()->GetComponents();
EXPECT_EQ(componenets.size(), tc.expected_result.size());
for (size_t i = 0; i < componenets.size(); i++) {
EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
}
}
}
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 0*n
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {2,3}),
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0,3}),
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0,0}),
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0,0})
));
// clang-format on
using BooleanInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<bool>>;
TEST_P(BooleanInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
// Make sure the instruction folded as expected.
EXPECT_TRUE(succeeded);
if (inst != nullptr) {
EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::BoolConstant* result =
const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
EXPECT_NE(result, nullptr);
if (result != nullptr) {
EXPECT_EQ(result->value(), tc.expected_result);
}
}
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold true || n
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_bool Function\n" +
"%load = OpLoad %bool %n\n" +
"%2 = OpLogicalOr %bool %true %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 1: fold n || true
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_bool Function\n" +
"%load = OpLoad %bool %n\n" +
"%2 = OpLogicalOr %bool %load %true\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold false && n
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_bool Function\n" +
"%load = OpLoad %bool %n\n" +
"%2 = OpLogicalAnd %bool %false %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 3: fold n && false
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_bool Function\n" +
"%load = OpLoad %bool %n\n" +
"%2 = OpLogicalAnd %bool %load %false\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 4: fold n < 0 (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpULessThan %bool %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 5: fold UINT_MAX < n (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpULessThan %bool %uint_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold INT_MAX < n (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSLessThan %bool %int_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 7: fold n < INT_MIN (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSLessThan %bool %load %int_min\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold 0 > n (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUGreaterThan %bool %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold n > UINT_MAX (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUGreaterThan %bool %load %uint_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 10: fold n > INT_MAX (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSGreaterThan %bool %load %int_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 11: fold INT_MIN > n (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpSGreaterThan %bool %int_min %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 12: fold 0 <= n (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpULessThanEqual %bool %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 13: fold n <= UINT_MAX (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpULessThanEqual %bool %load %uint_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 14: fold INT_MIN <= n (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSLessThanEqual %bool %int_min %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 15: fold n <= INT_MAX (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSLessThanEqual %bool %load %int_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 16: fold n >= 0 (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 17: fold UINT_MAX >= n (unsigned)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 18: fold n >= INT_MIN (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 19: fold INT_MAX >= n (signed)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true)
));
INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
"%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold 0.0 >= clamp(n, 1, 2)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
"%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold 0.0 < clamp(n, 1, 2)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
"%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 10: fold 0.0 >= clamp(n, 1, 2)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
"%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 14: fold 0.0 < clamp(n, 1, 2)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false)
));
INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
"%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold clamp(n, 1, 2) >= 0.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold clamp(n, 1, 2) < 3
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 10: fold clamp(n, 1, 2) >= 3.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
"%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
"%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 14: fold clamp(n, 1, 2) < 3
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
"%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_float Function\n" +
"%ld = OpLoad %float %n\n" +
"%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
"%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_double Function\n" +
"%ld = OpLoad %double %n\n" +
"%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
"%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false)
));
// clang-format on
using FloatInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<float>>;
TEST_P(FloatInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
// Make sure the instruction folded as expected.
EXPECT_TRUE(succeeded);
if (inst != nullptr) {
EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
EXPECT_EQ(inst->opcode(), SpvOpConstant);
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::FloatConstant* result =
const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
EXPECT_NE(result, nullptr);
if (result != nullptr) {
if (!std::isnan(tc.expected_result)) {
EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
} else {
EXPECT_TRUE(std::isnan(result->GetFloatValue()));
}
}
}
}
// Not testing NaNs because there are no expectations concerning NaNs according
// to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
// specification.
// clang-format off
INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
::testing::Values(
// Test case 0: Fold 2.0 - 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFSub %float %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 1: Fold 2.0 + 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFAdd %float %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3.0),
// Test case 2: Fold 3.0 * 2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFMul %float %float_3 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 6.0),
// Test case 3: Fold 1.0 / 2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.5),
// Test case 4: Fold 1.0 / 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 5: Fold -1.0 / 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_n1 %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity()),
// Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 5.5f),
// Test case 7: Fold (0.0, 0.0) dot v
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %v2float_0_0 %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 8: Fold v dot (0.0, 0.0)
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %2 %v2float_0_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 9: Fold Null dot v
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %v2float_null %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 10: Fold v dot Null
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %2 %v2float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 11: Fold -2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFNegate %float %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2),
// Test case 12: QuantizeToF16 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 13: QuantizeToF16 positive non exact
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_2049\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2048),
// Test case 14: QuantizeToF16 negative non exact
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n2049\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2048),
// Test case 15: QuantizeToF16 large positive
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1e16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 16: QuantizeToF16 large negative
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n1e16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity()),
// Test case 17: QuantizeToF16 small positive
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1en16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 18: QuantizeToF16 small negative
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n1en16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 19: QuantizeToF16 nan
InstructionFoldingCase<float>(
HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_nan\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::quiet_NaN()),
// Test case 20: QuantizeToF16 inf
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_0\n" +
"%3 = OpQuantizeToF16 %float %3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 21: QuantizeToF16 -inf
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_n1 %float_0\n" +
"%3 = OpQuantizeToF16 %float %3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity())
));
// clang-format on
using DoubleInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<double>>;
TEST_P(DoubleInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
// Make sure the instruction folded as expected.
EXPECT_TRUE(succeeded);
if (inst != nullptr) {
EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
EXPECT_EQ(inst->opcode(), SpvOpConstant);
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::FloatConstant* result =
const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
EXPECT_NE(result, nullptr);
if (result != nullptr) {
EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
}
}
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
::testing::Values(
// Test case 0: Fold 2.0 - 1.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFSub %double %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 1: Fold 2.0 + 1.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFAdd %double %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3.0),
// Test case 2: Fold 3.0 * 2.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFMul %double %double_3 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 6.0),
// Test case 3: Fold 1.0 / 2.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.5),
// Test case 4: Fold 1.0 / 0.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_1 %double_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<double>::infinity()),
// Test case 5: Fold -1.0 / 0.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_n1 %double_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<double>::infinity()),
// Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 5.5f),
// Test case 7: Fold (0.0, 0.0) dot v
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %v2double_0_0 %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 8: Fold v dot (0.0, 0.0)
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %2 %v2double_0_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 9: Fold Null dot v
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %v2double_null %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 10: Fold v dot Null
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %2 %v2double_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 11: Fold -2.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFNegate %double %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2)
));
// clang-format on
// clang-format off
INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 1.0 == 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 1: fold 1.0 != 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold 1.0 < 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 3: fold 1.0 > 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 4: fold 1.0 <= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 5: fold 1.0 >= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold 1.0 == 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 7: fold 1.0 != 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold 1.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold 1.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 10: fold 1.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 11: fold 1.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 12: fold 2.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 13: fold 2.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 14: fold 2.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 15: fold 2.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true)
));
INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 1.0 == 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 1: fold 1.0 != 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold 1.0 < 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 3: fold 1.0 > 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 4: fold 1.0 <= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 5: fold 1.0 >= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold 1.0 == 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 7: fold 1.0 != 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold 1.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold 1.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 10: fold 1.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 11: fold 1.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 12: fold 2.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 13: fold 2.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 14: fold 2.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 15: fold 2.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true)
));
INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 1.0 == 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 1: fold 1.0 != 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 2: fold 1.0 < 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 3: fold 1.0 > 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 4: fold 1.0 <= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 5: fold 1.0 >= 2.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 6: fold 1.0 == 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 7: fold 1.0 != 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 8: fold 1.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 9: fold 1.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 10: fold 1.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 11: fold 1.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 12: fold 2.0 < 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 13: fold 2.0 > 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, true),
// Test case 14: fold 2.0 <= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, false),
// Test case 15: fold 2.0 >= 1.0
InstructionFoldingCase<bool>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFOrdGreaterThanEqual %bool %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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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<bool>(
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 <class ResultType>
struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
ResultType result,
std::function<uint32_t(uint32_t)> 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<uint32_t(uint32_t)> id_map;
};
using IntegerInstructionFoldingTestWithMap =
::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
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(), SpvOpConstant);
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<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%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<InstructionFoldingCaseWithMap<bool>>;
TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
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<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
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<bool>(
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<InstructionFoldingCase<uint32_t>>;
TEST_P(GeneralInstructionFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
// Fold the instruction to test.
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
std::unique_ptr<Instruction> 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(), SpvOpCopyObject);
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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<uint32_t>(
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),