Update passes to handle function declarations (#4599)

Spirv-opt has not had to handle module with function declarations.  This
lead many passes to assume that every function has a body.  This is not
always true.  This commit will modify a number of passes to handle
function declarations.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4443
This commit is contained in:
Steven Perron 2021-10-28 11:54:37 -04:00 committed by GitHub
parent b2ba019bf6
commit 7c5b17d379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 276 additions and 1 deletions

View File

@ -291,6 +291,10 @@ bool CCPPass::ReplaceValues() {
}
bool CCPPass::PropagateConstants(Function* fp) {
if (fp->IsDeclaration()) {
return false;
}
// Mark function parameters as varying.
fp->ForEachParam([this](const Instruction* inst) {
values_[inst->result_id()] = kVaryingSSAId;

View File

@ -34,6 +34,10 @@ Pass::Status CombineAccessChains::Process() {
}
bool CombineAccessChains::ProcessFunction(Function& function) {
if (function.IsDeclaration()) {
return false;
}
bool modified = false;
cfg()->ForEachBlockInReversePostOrder(

View File

@ -40,6 +40,10 @@ bool IsDebugDeclareOrValue(Instruction* di) {
Pass::Status CopyPropagateArrays::Process() {
bool modified = false;
for (Function& function : *get_module()) {
if (function.IsDeclaration()) {
continue;
}
BasicBlock* entry_bb = &*function.begin();
for (auto var_inst = entry_bb->begin(); var_inst->opcode() == SpvOpVariable;

View File

@ -420,6 +420,10 @@ bool DeadBranchElimPass::EraseDeadBlocks(
}
bool DeadBranchElimPass::EliminateDeadBranches(Function* func) {
if (func->IsDeclaration()) {
return false;
}
bool modified = false;
std::unordered_set<BasicBlock*> live_blocks;
modified |= MarkLiveBlocks(func, &live_blocks);

View File

@ -177,6 +177,9 @@ class Function {
// debuggers.
void Dump() const;
// Returns true is a function declaration and not a function definition.
bool IsDeclaration() { return begin() == end(); }
private:
// The OpFunction instruction that begins the definition of this function.
std::unique_ptr<Instruction> def_inst_;

View File

@ -1102,6 +1102,10 @@ void LoopUtils::Finalize() {
Pass::Status LoopUnroller::Process() {
bool changed = false;
for (Function& f : *context()->module()) {
if (f.IsDeclaration()) {
continue;
}
LoopDescriptor* LD = context()->GetLoopDescriptor(&f);
for (Loop& loop : *LD) {
LoopUtils loop_utils{context(), &loop};

View File

@ -24,6 +24,10 @@ Pass::Status RedundancyEliminationPass::Process() {
ValueNumberTable vnTable(context());
for (auto& func : *get_module()) {
if (func.IsDeclaration()) {
continue;
}
// Build the dominator tree for this function. It is how the code is
// traversed.
DominatorTree& dom_tree =

View File

@ -35,6 +35,10 @@ namespace opt {
Pass::Status ScalarReplacementPass::Process() {
Status status = Status::SuccessWithoutChange;
for (auto& f : *get_module()) {
if (f.IsDeclaration()) {
continue;
}
Status functionStatus = ProcessFunction(&f);
if (functionStatus == Status::Failure)
return functionStatus;

View File

@ -45,6 +45,10 @@ void SimplificationPass::AddNewOperands(
}
bool SimplificationPass::SimplifyFunction(Function* function) {
if (function->IsDeclaration()) {
return false;
}
bool modified = false;
// Phase 1: Traverse all instructions in dominance order.
// The second phase will only be on the instructions whose inputs have changed

View File

@ -753,6 +753,9 @@ Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
Pass::Status SSARewritePass::Process() {
Status status = Status::SuccessWithoutChange;
for (auto& fn : *get_module()) {
if (fn.IsDeclaration()) {
continue;
}
status =
CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn));
// Kill DebugDeclares for target variables.

View File

@ -1208,6 +1208,32 @@ TEST_F(CCPTest, CCPNoChangeFailureWithUnfoldableInstr) {
auto result = SinglePassRunAndMatch<CCPPass>(text, true);
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
}
TEST_F(CCPTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CCPPass>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -768,6 +768,32 @@ OpFunctionEnd
SinglePassRunAndMatch<CombineAccessChains>(text, true);
}
TEST_F(CombineAccessChainsTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CombineAccessChains>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -1814,6 +1814,31 @@ OpFunctionEnd
SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
}
TEST_F(CopyPropArrayPassTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -3442,6 +3442,32 @@ TEST_F(DeadBranchElimTest, DontTransferDecorations) {
SinglePassRunAndMatch<DeadBranchElimPass>(text, true);
}
TEST_F(DeadBranchElimTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<DeadBranchElimPass>(text, text, false);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// More complex control flow

View File

@ -4225,6 +4225,32 @@ TEST_F(LocalSSAElimTest, PointerVariables) {
SinglePassRunAndMatch<SSARewritePass>(text, true);
}
TEST_F(LocalSSAElimTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<SSARewritePass>(text, text, false);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// No optimization in the presence of

View File

@ -42,6 +42,10 @@ class PartialUnrollerTestPass : public Pass {
Status Process() override {
bool changed = false;
for (Function& f : *context()->module()) {
if (f.IsDeclaration()) {
continue;
}
LoopDescriptor& loop_descriptor = *context()->GetLoopDescriptor(&f);
for (auto& loop : loop_descriptor) {
LoopUtils loop_utils{context(), &loop};
@ -1510,6 +1514,33 @@ OpFunctionEnd
SinglePassRunAndCheck<PartialUnrollerTestPass<2>>(text, text, false);
}
TEST_F(PassClassTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LoopUnroller>(text, text, false);
SinglePassRunAndCheck<PartialUnrollerTestPass<1>>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -335,6 +335,32 @@ TEST_F(RedundancyEliminationTest, OpenCLDebugInfo100) {
SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
}
TEST_F(RedundancyEliminationTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<RedundancyEliminationPass>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools
} // namespace spvtools

View File

@ -2237,6 +2237,32 @@ OpFunctionEnd
SinglePassRunAndMatch<ScalarReplacementPass>(text, false);
}
TEST_F(ScalarReplacementTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<ScalarReplacementPass>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -360,6 +360,31 @@ OpFunctionEnd
SinglePassRunAndMatch<SimplificationPass>(spirv, true);
}
TEST_F(SimplificationTest, FunctionDeclaration) {
// Make sure the pass works with a function declaration that is called.
const std::string text = R"(OpCapability Addresses
OpCapability Linkage
OpCapability Kernel
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
OpExecutionMode %2 ContractionOff
OpSource Unknown 0
OpDecorate %3 LinkageAttributes "julia_error_7712" Import
%void = OpTypeVoid
%5 = OpTypeFunction %void
%3 = OpFunction %void None %5
OpFunctionEnd
%2 = OpFunction %void None %5
%6 = OpLabel
%7 = OpFunctionCall %void %3
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<SimplificationPass>(text, text, false);
}
} // namespace
} // namespace opt
} // namespace spvtools