From: Steven Perron Date: Mon, 22 Jan 2018 19:48:43 +0000 (-0500) Subject: Use id_map in Fold*ToConstant X-Git-Tag: upstream/2018.6~545 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c4835e1bd8f179f141b116725430a3b34b002667;p=platform%2Fupstream%2FSPIRV-Tools.git 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. --- diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp index 7492f8e..fa2e73b 100644 --- a/source/opt/fold.cpp +++ b/source/opt/fold.cpp @@ -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 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 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 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) { diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 67de442..0dbd540 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -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 +struct InstructionFoldingCaseWithMap { + InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id, + ResultType result, + std::function map) + : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {} + + std::string test_body; + uint32_t id_to_fold; + ResultType expected_result; + std::function id_map; +}; + +using IntegerInstructionFoldingTestWithMap = + ::testing::TestWithParam>; + +TEST_P(IntegerInstructionFoldingTestWithMap, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + 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( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%3 = OpCopyObject %int %int_0\n" + "%2 = OpIMul %int %3 %load\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);}) + )); +// clang-format on + +using BooleanInstructionFoldingTestWithMap = + ::testing::TestWithParam>; + +TEST_P(BooleanInstructionFoldingTestWithMap, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + 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 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( + 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