mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-24 16:51:06 +00:00
spirv-opt: Implement opt::Function::HasEarlyReturn function (#3711)
This commit is contained in:
parent
e28436f2b8
commit
ee7f0c882f
@ -227,6 +227,18 @@ BasicBlock* Function::InsertBasicBlockBefore(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Function::HasEarlyReturn() const {
|
||||
auto post_dominator_analysis =
|
||||
blocks_.front()->GetLabel()->context()->GetPostDominatorAnalysis(this);
|
||||
for (auto& block : blocks_) {
|
||||
if (spvOpcodeIsReturn(block->tail()->opcode()) &&
|
||||
!post_dominator_analysis->Dominates(block.get(), entry().get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Function::IsRecursive() const {
|
||||
IRContext* ctx = blocks_.front()->GetLabel()->context();
|
||||
IRContext::ProcessFunction mark_visited = [this](Function* fp) {
|
||||
|
@ -158,7 +158,10 @@ class Function {
|
||||
BasicBlock* InsertBasicBlockBefore(std::unique_ptr<BasicBlock>&& new_block,
|
||||
BasicBlock* position);
|
||||
|
||||
// Return true if the function calls itself either directly or indirectly.
|
||||
// Returns true if the function has a return block other than the exit block.
|
||||
bool HasEarlyReturn() const;
|
||||
|
||||
// Returns true if the function calls itself either directly or indirectly.
|
||||
bool IsRecursive() const;
|
||||
|
||||
// Pretty-prints all the basic blocks in this function into a std::string.
|
||||
|
@ -29,6 +29,60 @@ namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(FunctionTest, HasEarlyReturn) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %6 "main"
|
||||
|
||||
; Types
|
||||
%2 = OpTypeBool
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
|
||||
; Constants
|
||||
%5 = OpConstantTrue %2
|
||||
|
||||
; main function without early return
|
||||
%6 = OpFunction %3 None %4
|
||||
%7 = OpLabel
|
||||
OpBranch %8
|
||||
%8 = OpLabel
|
||||
OpBranch %9
|
||||
%9 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
; function with early return
|
||||
%11 = OpFunction %3 None %4
|
||||
%12 = OpLabel
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %5 %13 %14
|
||||
%13 = OpLabel
|
||||
OpReturn
|
||||
%14 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, shader,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
|
||||
// Tests |function| without early return.
|
||||
auto* function = spvtest::GetFunction(context->module(), 6);
|
||||
ASSERT_FALSE(function->HasEarlyReturn());
|
||||
|
||||
// Tests |function| with early return.
|
||||
function = spvtest::GetFunction(context->module(), 11);
|
||||
ASSERT_TRUE(function->HasEarlyReturn());
|
||||
}
|
||||
|
||||
TEST(FunctionTest, IsNotRecursive) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
|
Loading…
Reference in New Issue
Block a user