mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
Use id_map in Fold*ToConstant
The folding routines are suppose to use the id_map provided to map the ids in the instruction. The ones I just added are missing it.
This commit is contained in:
parent
6c409e30a2
commit
c4835e1bd8
@ -211,10 +211,13 @@ uint32_t FoldScalars(SpvOp opcode,
|
||||
|
||||
// Returns true if |inst| is a binary operation that takes two integers as
|
||||
// parameters and folds to a constant that can be represented as an unsigned
|
||||
// 32-bit value. If |inst| can be folded, the resulting value is returned
|
||||
// in |*result|. Valid result types for the instruction are any integer (signed
|
||||
// or unsigned) with 32-bits or less, or a boolean value.
|
||||
bool FoldBinaryIntegerOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
// 32-bit value when the ids have been replaced by |id_map|. If |inst| can be
|
||||
// folded, the resulting value is returned in |*result|. Valid result types for
|
||||
// the instruction are any integer (signed or unsigned) with 32-bits or less, or
|
||||
// a boolean value.
|
||||
bool FoldBinaryIntegerOpToConstant(ir::Instruction* inst,
|
||||
std::function<uint32_t(uint32_t)> id_map,
|
||||
uint32_t* result) {
|
||||
SpvOp opcode = inst->opcode();
|
||||
ir::IRContext* context = inst->context();
|
||||
analysis::ConstantManager* const_manger = context->get_constant_mgr();
|
||||
@ -226,7 +229,7 @@ bool FoldBinaryIntegerOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
if (operand->type != SPV_OPERAND_TYPE_ID) {
|
||||
return false;
|
||||
}
|
||||
ids[i] = operand->words[0];
|
||||
ids[i] = id_map(operand->words[0]);
|
||||
const analysis::Constant* constant =
|
||||
const_manger->FindDeclaredConstant(ids[i]);
|
||||
constants[i] = (constant != nullptr ? constant->AsIntConstant() : nullptr);
|
||||
@ -397,9 +400,11 @@ bool FoldBinaryIntegerOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
}
|
||||
|
||||
// Returns true if |inst| is a binary operation on two boolean values, and folds
|
||||
// to a constant boolean value. If |inst| can be folded, the result value is
|
||||
// returned in |*result|.
|
||||
bool FoldBinaryBooleanOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
// to a constant boolean value when the ids have been replaced using |id_map|.
|
||||
// If |inst| can be folded, the result value is returned in |*result|.
|
||||
bool FoldBinaryBooleanOpToConstant(ir::Instruction* inst,
|
||||
std::function<uint32_t(uint32_t)> id_map,
|
||||
uint32_t* result) {
|
||||
SpvOp opcode = inst->opcode();
|
||||
ir::IRContext* context = inst->context();
|
||||
analysis::ConstantManager* const_manger = context->get_constant_mgr();
|
||||
@ -411,7 +416,7 @@ bool FoldBinaryBooleanOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
if (operand->type != SPV_OPERAND_TYPE_ID) {
|
||||
return false;
|
||||
}
|
||||
ids[i] = operand->words[0];
|
||||
ids[i] = id_map(operand->words[0]);
|
||||
const analysis::Constant* constant =
|
||||
const_manger->FindDeclaredConstant(ids[i]);
|
||||
constants[i] = (constant != nullptr ? constant->AsBoolConstant() : nullptr);
|
||||
@ -446,16 +451,19 @@ bool FoldBinaryBooleanOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if |inst| can be folded to an constant. If it can, the value
|
||||
// is returned in |result|. If not, |result| is unchanged. It is assumed that
|
||||
// not all operands are constant. Those cases are handled by |FoldScalar|.
|
||||
bool FoldIntegerOpToConstant(ir::Instruction* inst, uint32_t* result) {
|
||||
// Returns true if |inst| can be folded to an constant when the ids have been
|
||||
// substituted using id_map. If it can, the value is returned in |result|. If
|
||||
// not, |result| is unchanged. It is assumed that not all operands are
|
||||
// constant. Those cases are handled by |FoldScalar|.
|
||||
bool FoldIntegerOpToConstant(ir::Instruction* inst,
|
||||
std::function<uint32_t(uint32_t)> id_map,
|
||||
uint32_t* result) {
|
||||
assert(IsFoldableOpcode(inst->opcode()) &&
|
||||
"Unhandled instruction opcode in FoldScalars");
|
||||
switch (inst->NumInOperands()) {
|
||||
case 2:
|
||||
return FoldBinaryIntegerOpToConstant(inst, result) ||
|
||||
FoldBinaryBooleanOpToConstant(inst, result);
|
||||
return FoldBinaryIntegerOpToConstant(inst, id_map, result) ||
|
||||
FoldBinaryBooleanOpToConstant(inst, id_map, result);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -589,7 +597,7 @@ ir::Instruction* FoldInstructionToConstant(
|
||||
}
|
||||
|
||||
if (!successful) {
|
||||
successful = FoldIntegerOpToConstant(inst, &result_val);
|
||||
successful = FoldIntegerOpToConstant(inst, id_map, &result_val);
|
||||
}
|
||||
|
||||
if (successful) {
|
||||
|
@ -75,6 +75,8 @@ TEST_P(IntegerInstructionFoldingTest, Case) {
|
||||
}
|
||||
|
||||
// Returns a common SPIR-V header for all of the test that follow.
|
||||
#define INT_0_ID 100
|
||||
#define TRUE_ID 101
|
||||
const std::string& Header() {
|
||||
static const std::string header = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
@ -87,6 +89,7 @@ OpName %main "main"
|
||||
%void_func = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
|
||||
%false = OpConstantFalse %bool
|
||||
%short = OpTypeInt 16 1
|
||||
%int = OpTypeInt 32 1
|
||||
@ -98,6 +101,7 @@ OpName %main "main"
|
||||
%short_0 = OpConstant %short 0
|
||||
%short_3 = OpConstant %short 3
|
||||
%int_0 = OpConstant %int 0
|
||||
%100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_min = OpConstant %int -2147483648
|
||||
%int_max = OpConstant %int 2147483647
|
||||
@ -988,4 +992,113 @@ INSTANTIATE_TEST_CASE_P(TestCase, InstructionNotFoldedTest,
|
||||
2, nullptr)
|
||||
));
|
||||
// clang-format on
|
||||
|
||||
template <class ResultType>
|
||||
struct InstructionFoldingCaseWithMap {
|
||||
InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
|
||||
ResultType result,
|
||||
std::function<uint32_t(uint32_t)> map)
|
||||
: test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
|
||||
|
||||
std::string test_body;
|
||||
uint32_t id_to_fold;
|
||||
ResultType expected_result;
|
||||
std::function<uint32_t(uint32_t)> id_map;
|
||||
};
|
||||
|
||||
using IntegerInstructionFoldingTestWithMap =
|
||||
::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
|
||||
|
||||
TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
|
||||
const auto& tc = GetParam();
|
||||
|
||||
// Build module.
|
||||
std::unique_ptr<ir::IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
// Fold the instruction to test.
|
||||
opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
|
||||
ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
|
||||
inst = opt::FoldInstruction(inst, tc.id_map);
|
||||
|
||||
// Make sure the instruction folded as expected.
|
||||
EXPECT_NE(inst, nullptr);
|
||||
if (inst != nullptr) {
|
||||
EXPECT_EQ(inst->opcode(), SpvOpConstant);
|
||||
opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
|
||||
const opt::analysis::IntConstant* result =
|
||||
const_mrg->GetConstantFromInst(inst)->AsIntConstant();
|
||||
EXPECT_NE(result, nullptr);
|
||||
if (result != nullptr) {
|
||||
EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap,
|
||||
::testing::Values(
|
||||
// Test case 0: fold %3 = 0; %3 * n
|
||||
InstructionFoldingCaseWithMap<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%n = OpVariable %_ptr_int Function\n" +
|
||||
"%load = OpLoad %int %n\n" +
|
||||
"%3 = OpCopyObject %int %int_0\n"
|
||||
"%2 = OpIMul %int %3 %load\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
|
||||
));
|
||||
// clang-format on
|
||||
|
||||
using BooleanInstructionFoldingTestWithMap =
|
||||
::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
|
||||
|
||||
TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
|
||||
const auto& tc = GetParam();
|
||||
|
||||
// Build module.
|
||||
std::unique_ptr<ir::IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
// Fold the instruction to test.
|
||||
opt::analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
|
||||
ir::Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
|
||||
inst = opt::FoldInstruction(inst, tc.id_map);
|
||||
|
||||
// Make sure the instruction folded as expected.
|
||||
EXPECT_NE(inst, nullptr);
|
||||
if (inst != nullptr) {
|
||||
std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
|
||||
EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
|
||||
opt::analysis::ConstantManager* const_mrg = context->get_constant_mgr();
|
||||
const opt::analysis::BoolConstant* result =
|
||||
const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
|
||||
EXPECT_NE(result, nullptr);
|
||||
if (result != nullptr) {
|
||||
EXPECT_EQ(result->value(), tc.expected_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap,
|
||||
::testing::Values(
|
||||
// Test case 0: fold %3 = true; %3 || n
|
||||
InstructionFoldingCaseWithMap<bool>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%n = OpVariable %_ptr_bool Function\n" +
|
||||
"%load = OpLoad %bool %n\n" +
|
||||
"%3 = OpCopyObject %bool %true\n" +
|
||||
"%2 = OpLogicalOr %bool %3 %load\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
|
||||
));
|
||||
// clang-format on
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user