diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -559,6 +559,10 @@ return CGSCCToFunctionPassAdaptor(std::move(Pass)); } +/// Checks -abort-on-max-devirt-iterations-reached to see if we should report an +/// error. +void maxDevirtIterationsReached(); + /// A helper that repeats an SCC pass each time an indirect call is refined to /// a direct call by that pass. /// @@ -711,6 +715,7 @@ // Otherwise, if we've already hit our max, we're done. if (Iteration >= MaxIterations) { + maxDevirtIterationsReached(); LLVM_DEBUG( dbgs() << "Found another devirtualization after hitting the max " "number of repetitions (" diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -21,9 +21,11 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/PassManagerImpl.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -36,6 +38,11 @@ // template typedefs. namespace llvm { +static cl::opt AbortOnMaxDevirtIterationsReached( + "abort-on-max-devirt-iterations-reached", + cl::desc("Abort when the max iterations for devirtualization CGSCC repeat " + "pass is reached")); + // Explicit instantiations for the core proxy templates. template class AllAnalysesOn; template class AnalysisManager; @@ -362,6 +369,11 @@ } } +void llvm::maxDevirtIterationsReached() { + if (AbortOnMaxDevirtIterationsReached) + report_fatal_error("Max devirtualization iterations reached"); +} + /// Helper function to update both the \c CGSCCAnalysisManager \p AM and the \c /// CGSCCPassManager's \c CGSCCUpdateResult \p UR based on a range of newly /// added SCCs. diff --git a/llvm/test/Other/cgscc-devirt-iteration.ll b/llvm/test/Other/cgscc-devirt-iteration.ll --- a/llvm/test/Other/cgscc-devirt-iteration.ll +++ b/llvm/test/Other/cgscc-devirt-iteration.ll @@ -8,6 +8,9 @@ ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<1>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER1 ; RUN: opt -aa-pipeline=basic-aa -passes='cgscc(devirt<2>(function-attrs,function(gvn,instcombine)))' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2 ; +; RUN: not --crash opt -abort-on-max-devirt-iterations-reached -aa-pipeline=basic-aa -passes='cgscc(devirt<1>(function-attrs,function(gvn,instcombine)))' -S < %s +; RUN: opt -abort-on-max-devirt-iterations-reached -aa-pipeline=basic-aa -passes='cgscc(devirt<2>(function-attrs,function(gvn,instcombine)))' -S < %s +; ; We also verify that the real O2 pipeline catches these cases. ; RUN: opt -aa-pipeline=basic-aa -passes='default' -S < %s | FileCheck %s --check-prefix=CHECK --check-prefix=AFTER --check-prefix=AFTER2