blob: a4e0447c104217b86f37839485c98c10ccb831e2 [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 "source/opt/fold.h"
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include "effcee/effcee.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "source/opt/build_module.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "spirv-tools/libspirv.hpp"
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;
};
std::tuple<std::unique_ptr<IRContext>, Instruction*> GetInstructionToFold(
const std::string test_body, const uint32_t id_to_fold,
spv_target_env spv_env) {
// Build module.
std::unique_ptr<IRContext> context =
BuildModule(spv_env, nullptr, test_body,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
if (context == nullptr) {
return {nullptr, nullptr};
}
// Fold the instruction to test.
if (id_to_fold != 0) {
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
Instruction* inst = def_use_mgr->GetDef(id_to_fold);
return {std::move(context), inst};
}
// If there is not ID, we get the instruction just before a terminator
// instruction. That could be a return or abort. This is used for cases where
// the instruction we want to fold does not have a result id.
Function* func = &*context->module()->begin();
for (auto& bb : *func) {
Instruction* terminator = bb.terminator();
if (terminator->IsReturnOrAbort()) {
return {std::move(context), terminator->PreviousNode()};
}
}
return {nullptr, nullptr};
}
std::tuple<std::unique_ptr<IRContext>, Instruction*> FoldInstruction(
const std::string test_body, const uint32_t id_to_fold,
spv_target_env spv_env) {
// Build module.
std::unique_ptr<IRContext> context;
Instruction* inst = nullptr;
std::tie(context, inst) =
GetInstructionToFold(test_body, id_to_fold, spv_env);
if (context == nullptr) {
return {nullptr, nullptr};
}
std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
EXPECT_EQ(inst->result_id(), original_inst->result_id());
EXPECT_EQ(inst->type_id(), original_inst->type_id());
if (!succeeded && inst != nullptr) {
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));
}
}
return {std::move(context), succeeded ? inst : nullptr};
}
template <class ElementType, class Function>
void CheckForExpectedScalarConstant(Instruction* inst,
ElementType expected_result,
Function GetValue) {
ASSERT_TRUE(inst);
IRContext* context = inst->context();
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
while (inst->opcode() == spv::Op::OpCopyObject) {
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
}
// Make sure we have a constant.
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
ASSERT_TRUE(constant);
// Make sure the constant is a scalar.
const analysis::ScalarConstant* result = constant->AsScalarConstant();
ASSERT_TRUE(result);
// Check if the result matches the expected value.
// If ExpectedType is not a float type, it should cast the value to a double
// and never get a nan.
if (!std::isnan(static_cast<double>(expected_result))) {
EXPECT_EQ(expected_result, GetValue(result));
} else {
EXPECT_TRUE(std::isnan(static_cast<double>(GetValue(result))));
}
}
template <class ElementType, class Function>
void CheckForExpectedVectorConstant(Instruction* inst,
std::vector<ElementType> expected_result,
Function GetValue) {
ASSERT_TRUE(inst);
IRContext* context = inst->context();
EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
EXPECT_THAT(opcodes, Contains(inst->opcode()));
analysis::ConstantManager* const_mrg = context->get_constant_mgr();
const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
EXPECT_NE(result, nullptr);
if (result != nullptr) {
const std::vector<const analysis::Constant*>& componenets =
result->AsVectorConstant()->GetComponents();
EXPECT_EQ(componenets.size(), expected_result.size());
for (size_t i = 0; i < componenets.size(); i++) {
EXPECT_EQ(expected_result[i], GetValue(componenets[i]));
}
}
}
using IntegerInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
TEST_P(IntegerInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedScalarConstant(
inst, tc.expected_result, [](const analysis::Constant* c) {
return c->AsScalarConstant()->GetU32BitValue();
});
}
// 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
%v2short = OpTypeVector %short 2
%v2long = OpTypeVector %long 2
%v4long = OpTypeVector %long 4
%v4float = OpTypeVector %float 4
%v4double = OpTypeVector %double 4
%v2uint = OpTypeVector %uint 2
%v2ulong = OpTypeVector %ulong 2
%v2float = OpTypeVector %float 2
%v2double = OpTypeVector %double 2
%v2half = OpTypeVector %half 2
%v2bool = OpTypeVector %bool 2
%m2x2int = OpTypeMatrix %v2int 2
%mat4v2float = OpTypeMatrix %v2float 4
%mat2v4float = OpTypeMatrix %v4float 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
%int_2 = OpConstant %int 2
%int_arr_2 = OpTypeArray %int %int_2
%short_0 = OpConstant %short 0
%short_2 = OpConstant %short 2
%short_3 = OpConstant %short 3
%short_n5 = OpConstant %short -5
%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_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_n3 = OpConstant %long -3
%long_7 = OpConstant %long 7
%long_n7 = OpConstant %long -7
%long_10 = OpConstant %long 10
%long_32768 = OpConstant %long 32768
%long_n57344 = OpConstant %long -57344
%long_n4611686018427387904 = OpConstant %long -4611686018427387904
%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
%ulong_7 = OpConstant %ulong 7
%ulong_4611686018427387904 = OpConstant %ulong 4611686018427387904
%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_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24
%v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
%v2int_min_max = OpConstantComposite %v2int %int_min %int_max
%v2short_2_n5 = OpConstantComposite %v2short %short_2 %short_n5
%v2long_2_2 = OpConstantComposite %v2long %long_2 %long_2
%v2long_2_3 = OpConstantComposite %v2long %long_2 %long_3
%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_2 = OpConstant %half 2
%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
%mat2v4float_null = OpConstantNull %mat2v4float
%mat4v4float_null = OpConstantNull %mat4v4float
%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
%mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null
%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 = OpConstantNull %mat4v4double
%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
%mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null
%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_0x4400 = OpConstant %ushort 0x4400
%short_0x4400 = OpConstant %short 0x4400
%ushort_0xBC00 = OpConstant %ushort 0xBC00
%short_0xBC00 = OpConstant %short 0xBC00
%int_arr_2_undef = OpUndef %int_arr_2
)";
return header;
}
// Returns the header with definitions of float NaN and double NaN. Since FC
// "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
// %double_nan = OpConstant %double -0x1.8p+1024 instead of
// %double_n0 = OpConstant %double -0,
// we separates those definitions from Header().
const std::string& HeaderWithNaN() {
static const std::string headerWithNaN =
Header() +
R"(%float_nan = OpConstant %float -0x1.8p+128
%double_nan = OpConstant %double -0x1.8p+1024
)";
return headerWithNaN;
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 0*n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpIMul %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 1: fold n*0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpIMul %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 2: fold 0/n (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 3: fold n/0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 4: fold 0/n (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUDiv %uint %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 5: fold n/0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSDiv %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 6: fold 0 remainder n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSRem %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 7: fold n remainder 0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSRem %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 8: fold 0%n (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSMod %int %int_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 9: fold n%0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpSMod %int %load %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 10: fold 0%n (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUMod %uint %uint_0 %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 11: fold n%0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpUMod %uint %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 12: fold n << 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 13: fold n >> 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftRightLogical %uint %load %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 14: fold n | 0xFFFFFFFF
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseOr %uint %load %uint_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFFFFF),
// Test case 15: fold 0xFFFFFFFF | n
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseOr %uint %uint_max %load\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFFFFF),
// Test case 16: fold n & 0
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpBitwiseAnd %uint %load %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 17: fold 1/0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSDiv %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 18: fold 1/0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUDiv %uint %uint_1 %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 19: fold OpSRem 1 0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSRem %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 20: fold 1%0 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSMod %int %int_1 %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 21: fold 1%0 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUMod %uint %uint_1 %uint_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_uint Function\n" +
"%load = OpLoad %uint %n\n" +
"%2 = OpShiftRightLogical %uint %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 23: fold signed n >> 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpShiftRightLogical %int %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 24: fold n << 42 (undefined, so set to zero).
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpShiftLeftLogical %int %load %uint_42\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 25: fold -24 >> 32 (defined as -1)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -1),
// Test case 26: fold 2 >> 32 (signed)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 27: fold 2 >> 32 (unsigned)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 28: fold 2 << 32
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 29: fold -INT_MIN
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %int %int_min\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<int32_t>::min()),
// Test case 30: fold UMin 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 31: fold UMin 4 2
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 32: fold SMin 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 33: fold SMin 4 2
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 34: fold UMax 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 4),
// Test case 35: fold UMax 3 2
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 36: fold SMax 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 4),
// Test case 37: fold SMax 3 2
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 38: fold UClamp 2 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 39: fold UClamp 2 0 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 40: fold UClamp 2 0 1
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1),
// Test case 41: fold SClamp 2 3 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 42: fold SClamp 2 0 4
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 43: fold SClamp 2 0 1
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1),
// Test case 44: SClamp 1 2 x
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %int\n" +
"%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 45: SClamp 2 x 1
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %int\n" +
"%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1),
// Test case 46: UClamp 1 2 x
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %uint\n" +
"%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2),
// Test case 47: UClamp 2 x 1
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %uint\n" +
"%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1),
// Test case 48: Bit-cast int 0 to unsigned int
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %uint %int_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0),
// Test case 49: Bit-cast int -24 to unsigned int
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %uint %int_n24\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, static_cast<uint32_t>(-24)),
// Test case 50: Bit-cast float 1.0f to unsigned int
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %uint %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, static_cast<uint32_t>(0x3f800000)),
// Test case 51: Bit-cast ushort 0xBC00 to ushort
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %ushort %ushort_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xBC00),
// Test case 52: Bit-cast short 0xBC00 to ushort
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %ushort %short_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFBC00),
// Test case 53: Bit-cast half 1 to ushort
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %ushort %half_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0x3C00),
// Test case 54: Bit-cast ushort 0xBC00 to short
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %short %ushort_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xBC00),
// Test case 55: Bit-cast short 0xBC00 to short
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %short %short_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFBC00),
// Test case 56: Bit-cast half 1 to short
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %short %half_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0x3C00),
// Test case 57: Bit-cast ushort 0xBC00 to half
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %half %ushort_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xBC00),
// Test case 58: Bit-cast short 0xBC00 to half
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %half %short_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFBC00),
// Test case 59: Bit-cast half 1 to half
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %half %half_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0x3C00),
// Test case 60: Bit-cast ubyte 1 to byte
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %byte %ubyte_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1),
// Test case 61: Bit-cast byte -1 to ubyte
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %ubyte %byte_n1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFFFFF),
// Test case 62: Negate 2.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %int %int_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2),
// Test case 63: Negate negative short.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %short %short_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0x4400 /* expected to be sign extended. */),
// Test case 64: Negate positive short.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %short %short_0x4400\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xFFFFBC00 /* expected to be sign extended. */),
// Test case 65: Negate a negative short.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %ushort %ushort_0xBC00\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0x4400 /* expected to be zero extended. */),
// Test case 66: Negate positive short.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %ushort %ushort_0x4400\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0xBC00 /* expected to be zero extended. */),
// Test case 67: Fold 2 + 3 (short)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpIAdd %short %short_2 %short_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 5),
// Test case 68: Fold 2 + -5 (short)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpIAdd %short %short_2 %short_n5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -3),
// Test case 69: Fold int(3ll)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSConvert %int %long_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3),
// Test case 70: Fold short(-3ll)
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSConvert %short %long_n3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -3),
// Test case 71: Fold short(32768ll) - This should do a sign extend when
// converting to short.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSConvert %short %long_32768\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -32768),
// Test case 72: Fold short(-57344) - This should do a sign extend when
// converting to short making the upper bits 0.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSConvert %short %long_n57344\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 8192),
// Test case 73: Fold int(-5(short)). The -5 should be interpreted as an unsigned value, and be zero extended to 32-bits.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUConvert %uint %short_n5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 65531),
// Test case 74: Fold short(-24(int)). The upper bits should be cleared. So 0xFFFFFFE8 should become 0x0000FFE8.
InstructionFoldingCase<uint32_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUConvert %ushort %int_n24\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 65512)
));
// clang-format on
using LongIntegerInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<uint64_t>>;
TEST_P(LongIntegerInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedScalarConstant(
inst, tc.expected_result, [](const analysis::Constant* c) {
return c->AsScalarConstant()->GetU64BitValue();
});
}
INSTANTIATE_TEST_SUITE_P(
TestCase, LongIntegerInstructionFoldingTest,
::testing::Values(
// Test case 0: fold 1+4611686018427387904
InstructionFoldingCase<uint64_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 = OpIAdd %long %long_1 %long_4611686018427387904\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 1 + 4611686018427387904),
// Test case 1: fold 1-4611686018427387904
InstructionFoldingCase<uint64_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 = OpISub %long %long_1 %long_4611686018427387904\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 1 - 4611686018427387904),
// Test case 2: fold 2*4611686018427387904
InstructionFoldingCase<uint64_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 %long %long_2 %long_4611686018427387904\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 9223372036854775808ull),
// Test case 3: fold 4611686018427387904/2 (unsigned)
InstructionFoldingCase<uint64_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 = OpUDiv %ulong %ulong_4611686018427387904 %ulong_2\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 4611686018427387904 / 2),
// Test case 4: fold 4611686018427387904/2 (signed)
InstructionFoldingCase<uint64_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 %long %long_4611686018427387904 %long_2\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 4611686018427387904 / 2),
// Test case 5: fold -4611686018427387904/2 (signed)
InstructionFoldingCase<uint64_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 %long %long_n4611686018427387904 %long_2\n" +
"OpReturn\n" + "OpFunctionEnd",
2, -4611686018427387904 / 2),
// Test case 6: fold 4611686018427387904 mod 7 (unsigned)
InstructionFoldingCase<uint64_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 = OpUMod %ulong %ulong_4611686018427387904 %ulong_7\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 4611686018427387904ull % 7ull),
// Test case 7: fold 7 mod 3 (signed)
InstructionFoldingCase<uint64_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 %long %long_7 %long_3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, 1ull),
// Test case 8: fold 7 rem 3 (signed)
InstructionFoldingCase<uint64_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 %long %long_7 %long_3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, 1ull),
// Test case 9: fold 7 mod -3 (signed)
InstructionFoldingCase<uint64_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 %long %long_7 %long_n3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, -2ll),
// Test case 10: fold 7 rem 3 (signed)
InstructionFoldingCase<uint64_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 %long %long_7 %long_n3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, 1ll),
// Test case 11: fold -7 mod 3 (signed)
InstructionFoldingCase<uint64_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 %long %long_n7 %long_3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, 2ll),
// Test case 12: fold -7 rem 3 (signed)
InstructionFoldingCase<uint64_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 %long %long_n7 %long_3\n" + "OpReturn\n" +
"OpFunctionEnd",
2, -1ll),
// Test case 13: fold long(-24)
InstructionFoldingCase<uint64_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 = OpSConvert %long %int_n24\n" + "OpReturn\n" +
"OpFunctionEnd",
2, -24ll),
// Test case 14: fold long(-24)
InstructionFoldingCase<uint64_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 = OpSConvert %long %int_10\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 10ll),
// Test case 15: fold long(-24(short)).
// The upper bits should be cleared. So 0xFFFFFFE8 should become
// 0x000000000000FFE8.
InstructionFoldingCase<uint64_t>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" + "%2 = OpUConvert %ulong %short_n5\n" +
"OpReturn\n" + "OpFunctionEnd",
2, 65531ull)));
using UIntVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
TEST_P(UIntVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedVectorConstant(
inst, tc.expected_result,
[](const analysis::Constant* c) { return c->GetU32(); });
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest,
::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}),
// Test case 4: fold bit-cast int -24 to unsigned int
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%n = OpVariable %_ptr_int Function\n" +
"%load = OpLoad %int %n\n" +
"%2 = OpBitcast %v2uint %v2int_min_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {2147483648, 2147483647}),
// Test case 5: fold SNegate vector of uint
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 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {static_cast<uint32_t>(-0x3f800000), static_cast<uint32_t>(-0xbf800000)}),
// Test case 6: fold vector components of uint (including integer overflow)
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0x7f000000u, 0x7f000000u}),
// Test case 6: fold vector components of uint
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSConvert %v2int %v2short_2_n5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {2,static_cast<uint32_t>(-5)}),
// Test case 6: fold vector components of uint (incuding integer overflow)
InstructionFoldingCase<std::vector<uint32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpUConvert %v2uint %v2short_2_n5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {2,65531})
));
// clang-format on
using IntVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<int32_t>>>;
TEST_P(IntVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedVectorConstant(
inst, tc.expected_result,
[](const analysis::Constant* c) { return c->GetS32(); });
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
::testing::Values(
// Test case 0: fold negate of a vector
InstructionFoldingCase<std::vector<int32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %v2int %v2int_2_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {-2, -3}),
// Test case 1: fold negate of a vector containing negative values.
InstructionFoldingCase<std::vector<int32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %v2int %v2int_n1_n24\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1, 24}),
// Test case 2: fold negate of a vector at the limits
InstructionFoldingCase<std::vector<int32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpSNegate %v2int %v2int_min_max\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {INT_MIN, -INT_MAX}),
// Test case 3: fold vector components of int
InstructionFoldingCase<std::vector<int32_t>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {4,9})
));
// clang-format on
using LongIntVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<uint64_t>>>;
TEST_P(LongIntVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedVectorConstant(
inst, tc.expected_result,
[](const analysis::Constant* c) { return c->GetU64(); });
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, LongIntVectorInstructionFoldingTest,
::testing::Values(
// Test case 0: fold {2,2} + {2,3} (Testing that the vector logic works
// correctly. Scalar tests will check that the 64-bit values are correctly
// folded.)
InstructionFoldingCase<std::vector<uint64_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 = OpIAdd %v2long %v2long_2_2 %v2long_2_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {4,5}),
// Test case 0: fold {2,2} / {2,3} (Testing that the vector logic works
// correctly. Scalar tests will check that the 64-bit values are correctly
// folded.)
InstructionFoldingCase<std::vector<uint64_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 %v2long %v2long_2_2 %v2long_2_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1,0})
));
// clang-format on
using DoubleVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
TEST_P(DoubleVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedVectorConstant(
inst, tc.expected_result,
[](const analysis::Constant* c) { return c->GetDouble(); });
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
::testing::Values(
// Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
// to double vector
InstructionFoldingCase<std::vector<double>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1.0,-127.35}),
// Test case 1: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0,0.0,0.0,0.0}),
// Test case 2: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0,0.0,0.0,0.0}),
// Test case 3: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {30.0,30.0,30.0,30.0}),
// Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {30.0,0.0,30.0,0.0}),
// Test case 5: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0,0.0,0.0,0.0}),
// Test case 6: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0,0.0,0.0,0.0}),
// Test case 7: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {10.0,20.0,30.0,40.0}),
// Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
InstructionFoldingCase<std::vector<double>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4_null %v4double_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {4.0,8.0,12.0,16.0})
));
using FloatVectorInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
TEST_P(FloatVectorInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedVectorConstant(inst, tc.expected_result, [](const analysis::Constant* c){ return c->GetFloat();});
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
::testing::Values(
// Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
InstructionFoldingCase<std::vector<float>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1.6f,1.5f}),
// Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
// float vector
InstructionFoldingCase<std::vector<float>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1.0f,-1.0f}),
// Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
InstructionFoldingCase<std::vector<float>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {1.0f,-1.0f}),
// Test case 3: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0f,0.0f,0.0f,0.0f}),
// Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {30.0,0.0,30.0,0.0}),
// Test case 5: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0f,0.0f,0.0f,0.0f}),
// Test case 6: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {30.0f,30.0f,30.0f,30.0f}),
// Test case 7: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0f,0.0f,0.0f,0.0f}),
// Test case 8: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {0.0f,0.0f,0.0f,0.0f}),
// Test case 9: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {10.0f,20.0f,30.0f,40.0f}),
// Test case 10: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
InstructionFoldingCase<std::vector<float>>(
Header() +
"%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4_null %v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {4.0,8.0,12.0,16.0})
));
// clang-format on
using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam<
InstructionFoldingCase<std::vector<std::vector<float>>>>;
TEST_P(FloatMatrixInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
if (inst->opcode() == spv::Op::OpCopyObject) {
analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
analysis::ConstantManager* const_mgr = context->get_constant_mgr();
const analysis::Constant* result = const_mgr->GetConstantFromInst(inst);
EXPECT_NE(result, nullptr);
if (result != nullptr) {
std::vector<const analysis::Constant*> matrix =
result->AsMatrixConstant()->GetComponents();
EXPECT_EQ(matrix.size(), tc.expected_result.size());
for (size_t c = 0; c < matrix.size(); c++) {
if (matrix[c]->AsNullConstant() != nullptr) {
matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type());
}
const analysis::VectorConstant* column_const =
matrix[c]->AsVectorConstant();
ASSERT_NE(column_const, nullptr);
const std::vector<const analysis::Constant*>& column =
column_const->GetComponents();
EXPECT_EQ(column.size(), tc.expected_result[c].size());
for (size_t r = 0; r < column.size(); r++) {
EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat());
}
}
}
}
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest,
::testing::Values(
// Test case 0: OpTranspose square null matrix
InstructionFoldingCase<std::vector<std::vector<float>>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpTranspose %mat4v4float %mat4v4float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f}}),
// Test case 1: OpTranspose rectangular null matrix
InstructionFoldingCase<std::vector<std::vector<float>>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpTranspose %mat4v2float %mat2v4float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}),
InstructionFoldingCase<std::vector<std::vector<float>>>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, {{1.0f, 1.0f, 1.0f, 1.0f},{2.0f, 2.0f, 2.0f, 2.0f},{3.0f, 3.0f, 3.0f, 3.0f},{4.0f, 4.0f, 4.0f, 4.0f}})
));
// clang-format on
using BooleanInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<bool>>;
TEST_P(BooleanInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedScalarConstant(
inst, tc.expected_result,
[](const analysis::Constant* c) { return c->AsBoolConstant()->value(); });
}
// 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();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedScalarConstant(inst, tc.expected_result,
[](const analysis::Constant* c) {
return c->AsFloatConstant()->GetFloatValue();
});
}
// Not testing NaNs because there are no expectations concerning NaNs according
// to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
// specification.
// clang-format off
INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
::testing::Values(
// Test case 0: Fold 2.0 - 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFSub %float %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 1: Fold 2.0 + 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFAdd %float %float_2 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3.0),
// Test case 2: Fold 3.0 * 2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFMul %float %float_3 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 6.0),
// Test case 3: Fold 1.0 / 2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.5),
// Test case 4: Fold 1.0 / 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 5: Fold -1.0 / 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_n1 %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity()),
// Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 5.5f),
// Test case 7: Fold (0.0, 0.0) dot v
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %v2float_0_0 %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 8: Fold v dot (0.0, 0.0)
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %2 %v2float_0_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 9: Fold Null dot v
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %v2float_null %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 10: Fold v dot Null
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2float Function\n" +
"%2 = OpLoad %v2float %v\n" +
"%3 = OpDot %float %2 %v2float_null\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 11: Fold -2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFNegate %float %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2),
// Test case 12: QuantizeToF16 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 13: QuantizeToF16 positive non exact
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_2049\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2048),
// Test case 14: QuantizeToF16 negative non exact
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n2049\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -2048),
// Test case 15: QuantizeToF16 large positive
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1e16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 16: QuantizeToF16 large negative
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n1e16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity()),
// Test case 17: QuantizeToF16 small positive
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_1en16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 18: QuantizeToF16 small negative
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_n1en16\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 19: QuantizeToF16 nan
InstructionFoldingCase<float>(
HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpQuantizeToF16 %float %float_nan\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::quiet_NaN()),
// Test case 20: FMix 1.0 4.0 0.2
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.6f),
// Test case 21: FMin 1.0 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0f),
// Test case 22: FMin 4.0 0.2
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.2f),
// Test case 23: FMax 1.0 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 4.0f),
// Test case 24: FMax 1.0 0.2
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0f),
// Test case 25: FClamp 1.0 0.2 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0f),
// Test case 26: FClamp 0.2 2.0 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2.0f),
// Test case 27: FClamp 2049.0 2.0 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 4.0f),
// Test case 28: FClamp 1.0 2.0 x
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %float\n" +
"%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2.0),
// Test case 29: FClamp 1.0 x 0.5
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%undef = OpUndef %float\n" +
"%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.5),
// Test case 30: Sin 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Sin %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 31: Cos 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Cos %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 32: Tan 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Tan %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 33: Asin 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Asin %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 34: Acos 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Acos %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 35: Atan 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Atan %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 36: Exp 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Exp %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 37: Log 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Log %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 38: Exp2 2.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Exp2 %float_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 4.0),
// Test case 39: Log2 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Log2 %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2.0),
// Test case 40: Sqrt 4.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Sqrt %float_4\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 2.0),
// Test case 41: Atan2 0.0 1.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.0),
// Test case 42: Pow 2.0 3.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 8.0),
// Test case 43: Fold 1.0 / -0.0.
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_1 %float_n0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<float>::infinity()),
// Test case 44: Fold -1.0 / -0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_n1 %float_n0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::infinity()),
// Test case 45: Fold 0.0 / 0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_0 %float_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::quiet_NaN()),
// Test case 46: Fold 0.0 / -0.0
InstructionFoldingCase<float>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %float %float_0 %float_n0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<float>::quiet_NaN())
));
// clang-format on
using DoubleInstructionFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<double>>;
TEST_P(DoubleInstructionFoldingTest, Case) {
const auto& tc = GetParam();
std::unique_ptr<IRContext> context;
Instruction* inst;
std::tie(context, inst) =
FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1);
CheckForExpectedScalarConstant(
inst, tc.expected_result, [](const analysis::Constant* c) {
return c->AsFloatConstant()->GetDoubleValue();
});
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
::testing::Values(
// Test case 0: Fold 2.0 - 1.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFSub %double %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 1.0),
// Test case 1: Fold 2.0 + 1.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFAdd %double %double_2 %double_1\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 3.0),
// Test case 2: Fold 3.0 * 2.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFMul %double %double_3 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 6.0),
// Test case 3: Fold 1.0 / 2.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_1 %double_2\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 0.5),
// Test case 4: Fold 1.0 / 0.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_1 %double_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, std::numeric_limits<double>::infinity()),
// Test case 5: Fold -1.0 / 0.0
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpFDiv %double %double_n1 %double_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, -std::numeric_limits<double>::infinity()),
// Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
"OpReturn\n" +
"OpFunctionEnd",
2, 5.5f),
// Test case 7: Fold (0.0, 0.0) dot v
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %v2double_0_0 %2\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 8: Fold v dot (0.0, 0.0)
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +
"%v = OpVariable %_ptr_v2double Function\n" +
"%2 = OpLoad %v2double %v\n" +
"%3 = OpDot %double %2 %v2double_0_0\n" +
"OpReturn\n" +
"OpFunctionEnd",
3, 0.0f),
// Test case 9: Fold Null dot v
InstructionFoldingCase<double>(
Header() + "%main = OpFunction %void None %void_func\n" +
"%main_lab = OpLabel\n" +