[FuncSpec] Invalidate analyses when deleting a fully specialised function

Deleting a fully specialised function left dangling pointers in
`FunctionAnalysisManager`, which causes an internal compiler error
when the function's storage was reused.

Fixes bug #58759.

Reviewed By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D138909

Change-Id: Ifed378c748af35e8fe7dcbdddb0f41b8777cbe87
This commit is contained in:
Momchil Velikov 2022-11-30 18:28:31 +00:00
parent c0692c08ee
commit e7ed43c753
4 changed files with 40 additions and 7 deletions

View File

@ -45,7 +45,7 @@ bool runIPSCCP(Module &M, const DataLayout &DL,
function_ref<AnalysisResultsForFn(Function &)> getAnalysis);
bool runFunctionSpecialization(
Module &M, const DataLayout &DL,
Module &M, FunctionAnalysisManager *FAM, const DataLayout &DL,
std::function<TargetLibraryInfo &(Function &)> GetTLI,
std::function<TargetTransformInfo &(Function &)> GetTTI,
std::function<AssumptionCache &(Function &)> GetAC,

View File

@ -271,6 +271,9 @@ class FunctionSpecializer {
/// The IPSCCP Solver.
SCCPSolver &Solver;
/// Analysis manager, needed to invalidate analyses.
FunctionAnalysisManager *FAM;
/// Analyses used to help determine if a function should be specialized.
std::function<AssumptionCache &(Function &)> GetAC;
std::function<TargetTransformInfo &(Function &)> GetTTI;
@ -282,11 +285,12 @@ class FunctionSpecializer {
DenseMap<Function *, CodeMetrics> FunctionMetrics;
public:
FunctionSpecializer(SCCPSolver &Solver,
FunctionSpecializer(SCCPSolver &Solver, FunctionAnalysisManager *FAM,
std::function<AssumptionCache &(Function &)> GetAC,
std::function<TargetTransformInfo &(Function &)> GetTTI,
std::function<TargetLibraryInfo &(Function &)> GetTLI)
: Solver(Solver), GetAC(GetAC), GetTTI(GetTTI), GetTLI(GetTLI) {}
: Solver(Solver), FAM(FAM), GetAC(GetAC), GetTTI(GetTTI), GetTLI(GetTLI) {
}
~FunctionSpecializer() {
// Eliminate dead code.
@ -344,6 +348,8 @@ public:
for (auto *F : FullySpecialized) {
LLVM_DEBUG(dbgs() << "FnSpecialization: Removing dead function "
<< F->getName() << "\n");
if (FAM)
FAM->clear(*F, F->getName());
F->eraseFromParent();
}
FullySpecialized.clear();
@ -819,13 +825,13 @@ private:
} // namespace
bool llvm::runFunctionSpecialization(
Module &M, const DataLayout &DL,
Module &M, FunctionAnalysisManager *FAM, const DataLayout &DL,
std::function<TargetLibraryInfo &(Function &)> GetTLI,
std::function<TargetTransformInfo &(Function &)> GetTTI,
std::function<AssumptionCache &(Function &)> GetAC,
function_ref<AnalysisResultsForFn(Function &)> GetAnalysis) {
SCCPSolver Solver(DL, GetTLI, M.getContext());
FunctionSpecializer FS(Solver, GetAC, GetTTI, GetTLI);
FunctionSpecializer FS(Solver, FAM, GetAC, GetTTI, GetTLI);
bool Changed = false;
// Loop over all functions, marking arguments to those with their addresses

View File

@ -130,7 +130,7 @@ PreservedAnalyses FunctionSpecializationPass::run(Module &M,
&FAM.getResult<LoopAnalysis>(F)};
};
if (!runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis))
if (!runFunctionSpecialization(M, &FAM, DL, GetTLI, GetTTI, GetAC, GetAnalysis))
return PreservedAnalyses::all();
PreservedAnalyses PA;
@ -179,7 +179,7 @@ struct FunctionSpecializationLegacyPass : public ModulePass {
nullptr, // manager, so set them to nullptr.
nullptr};
};
return runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis);
return runFunctionSpecialization(M, nullptr, DL, GetTLI, GetTTI, GetAC, GetAnalysis);
}
};
} // namespace

View File

@ -0,0 +1,27 @@
; RUN: opt -S --passes='default<O3>' -enable-function-specialization < %s | FileCheck %s
define dso_local i32 @g0(i32 noundef %x) local_unnamed_addr {
entry:
%call = tail call fastcc i32 @f(i32 noundef %x, ptr noundef nonnull @p0)
ret i32 %call
}
define internal fastcc i32 @f(i32 noundef %x, ptr nocapture noundef readonly %p) noinline {
entry:
%call = tail call i32 %p(i32 noundef %x)
%add = add nsw i32 %call, %x
ret i32 %add
}
define dso_local i32 @g1(i32 noundef %x) {
entry:
%call = tail call fastcc i32 @f(i32 noundef %x, ptr noundef nonnull @p1)
ret i32 %call
}
declare i32 @p0(i32 noundef)
declare i32 @p1(i32 noundef)
;; Tests that `f` has been fully specialize and it didn't cause compiler crash.
;; CHECK-DAG: f.1
;; CHECK-DAG: f.2