diff --git a/llvm/include/llvm/Transforms/Scalar/SCCP.h b/llvm/include/llvm/Transforms/Scalar/SCCP.h --- a/llvm/include/llvm/Transforms/Scalar/SCCP.h +++ b/llvm/include/llvm/Transforms/Scalar/SCCP.h @@ -45,7 +45,7 @@ function_ref getAnalysis); bool runFunctionSpecialization( - Module &M, const DataLayout &DL, + Module &M, FunctionAnalysisManager *FAM, const DataLayout &DL, std::function GetTLI, std::function GetTTI, std::function GetAC, diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -271,6 +271,9 @@ /// 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 GetAC; std::function GetTTI; @@ -282,11 +285,12 @@ DenseMap FunctionMetrics; public: - FunctionSpecializer(SCCPSolver &Solver, + FunctionSpecializer(SCCPSolver &Solver, FunctionAnalysisManager *FAM, std::function GetAC, std::function GetTTI, std::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 @@ 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 @@ } // namespace bool llvm::runFunctionSpecialization( - Module &M, const DataLayout &DL, + Module &M, FunctionAnalysisManager *FAM, const DataLayout &DL, std::function GetTLI, std::function GetTTI, std::function GetAC, function_ref 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 diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp --- a/llvm/lib/Transforms/IPO/SCCP.cpp +++ b/llvm/lib/Transforms/IPO/SCCP.cpp @@ -130,7 +130,7 @@ &FAM.getResult(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 @@ 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 diff --git a/llvm/test/Transforms/FunctionSpecialization/compiler-crash-58759.ll b/llvm/test/Transforms/FunctionSpecialization/compiler-crash-58759.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/FunctionSpecialization/compiler-crash-58759.ll @@ -0,0 +1,27 @@ +; RUN: opt -S --passes='default' -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