spirv-opt: Implement opt::Function::HasEarlyReturn function (#3711)

This commit is contained in:
André Perez 2020-08-18 10:31:24 -03:00 committed by GitHub
parent e28436f2b8
commit ee7f0c882f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 1 deletions

View File

@ -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) {

View File

@ -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.

View File

@ -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