[llvm-branch-commits] [llvm] 585636d - Revert "[Inliner] Put inline history into IR as !inline_history metadata (#19…"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Apr 7 10:14:46 PDT 2026


Author: Arthur Eubanks
Date: 2026-04-07T10:14:41-07:00
New Revision: 585636d0abf3f48f3964899a921da30a88f909c0

URL: https://github.com/llvm/llvm-project/commit/585636d0abf3f48f3964899a921da30a88f909c0
DIFF: https://github.com/llvm/llvm-project/commit/585636d0abf3f48f3964899a921da30a88f909c0.diff

LOG: Revert "[Inliner] Put inline history into IR as !inline_history metadata (#19…"

This reverts commit 82505fbfc870f4a657fbaa66a7514db9f30e030a.

Added: 
    llvm/test/Transforms/Inline/inline-history-noinline.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/Analysis/InlineOrder.h
    llvm/include/llvm/IR/FixedMetadataKinds.def
    llvm/include/llvm/Transforms/Utils/Cloning.h
    llvm/lib/Analysis/InlineOrder.cpp
    llvm/lib/IR/Verifier.cpp
    llvm/lib/Transforms/IPO/AlwaysInliner.cpp
    llvm/lib/Transforms/IPO/Inliner.cpp
    llvm/lib/Transforms/IPO/ModuleInliner.cpp
    llvm/lib/Transforms/IPO/PartialInlining.cpp
    llvm/lib/Transforms/Utils/CloneFunction.cpp
    llvm/lib/Transforms/Utils/InlineFunction.cpp
    llvm/test/Transforms/Inline/debug-invoke.ll
    llvm/test/Transforms/Inline/inline-recursive-fn2.ll
    llvm/unittests/Analysis/InlineOrderPlugin/InlineOrderPlugin.cpp

Removed: 
    llvm/test/Transforms/Inline/inline-history-2.ll
    llvm/test/Transforms/Inline/inline-history.ll
    llvm/test/Verifier/inline-history-metadata.ll


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index f66cd37d9ec7e..5584e0828d3cd 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8852,25 +8852,6 @@ Example:
     !0 = !{ptr @a}
     !1 = !{ptr @b}
 
-'``inline_history``' Metadata
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The ``inline_history`` metadata may be attached to a call instruction. It
-indicates that the call instruction has been inlined from the referenced
-functions. The call itself should not be inlined if it is a call to any of the
-referenced functions since that could result in infinite inlining as we
-continually inline through mutually recursive functions.
-
-This is intended to be added by and used by inliner passes.
-
-The metadata operands must all be function pointers or ``null``. ``null`` can
-appear when the referenced function is erased from the module, e.g. an internal
-function that has had all calls to it inlined.
-
-.. code-block:: text
-
-    call void @foo(), !inline_history !0
-
-    !0 = !{ptr @bar, null, ptr @baz}
 
 Module Flags Metadata
 =====================

diff  --git a/llvm/include/llvm/Analysis/InlineOrder.h b/llvm/include/llvm/Analysis/InlineOrder.h
index 459afcde47150..bc96d546fda7a 100644
--- a/llvm/include/llvm/Analysis/InlineOrder.h
+++ b/llvm/include/llvm/Analysis/InlineOrder.h
@@ -17,26 +17,26 @@ namespace llvm {
 class CallBase;
 template <typename Fn> class function_ref;
 
-class InlineOrder {
+template <typename T> class InlineOrder {
 public:
   virtual ~InlineOrder() = default;
 
   virtual size_t size() = 0;
 
-  virtual void push(CallBase *Elt) = 0;
+  virtual void push(const T &Elt) = 0;
 
-  virtual CallBase *pop() = 0;
+  virtual T pop() = 0;
 
-  virtual void erase_if(function_ref<bool(CallBase *)> Pred) = 0;
+  virtual void erase_if(function_ref<bool(T)> Pred) = 0;
 
   bool empty() { return !size(); }
 };
 
-LLVM_ABI std::unique_ptr<InlineOrder>
+LLVM_ABI std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
 getDefaultInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
                       ModuleAnalysisManager &MAM, Module &M);
 
-LLVM_ABI std::unique_ptr<InlineOrder>
+LLVM_ABI std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
 getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
                ModuleAnalysisManager &MAM, Module &M);
 
@@ -54,9 +54,10 @@ class PluginInlineOrderAnalysis
 public:
   LLVM_ABI static AnalysisKey Key;
 
-  typedef std::unique_ptr<InlineOrder> (*InlineOrderFactory)(
-      FunctionAnalysisManager &FAM, const InlineParams &Params,
-      ModuleAnalysisManager &MAM, Module &M);
+  typedef std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>> (
+      *InlineOrderFactory)(FunctionAnalysisManager &FAM,
+                           const InlineParams &Params,
+                           ModuleAnalysisManager &MAM, Module &M);
 
   PluginInlineOrderAnalysis(InlineOrderFactory Factory) : Factory(Factory) {
     assert(Factory != nullptr &&

diff  --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 6d74aff4ae250..0d79677d7079e 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -60,4 +60,3 @@ LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45)
 LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
 LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
 LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
-LLVM_FIXED_MD_KIND(MD_inline_history, "inline_history", 49)

diff  --git a/llvm/include/llvm/Transforms/Utils/Cloning.h b/llvm/include/llvm/Transforms/Utils/Cloning.h
index ced4cfcd6d238..ff4b390eb3e6d 100644
--- a/llvm/include/llvm/Transforms/Utils/Cloning.h
+++ b/llvm/include/llvm/Transforms/Utils/Cloning.h
@@ -18,7 +18,6 @@
 #define LLVM_TRANSFORMS_UTILS_CLONING_H
 
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Analysis/AssumptionCache.h"
@@ -89,10 +88,6 @@ struct ClonedCodeInfo {
   /// check whether the main VMap mapping involves simplification or not.
   DenseMap<const Value *, const Value *> OrigVMap;
 
-  // Cloned calls that were originally an indirect call. They may be direct or
-  // indirect after cloning.
-  SmallPtrSet<const Value *, 4> OriginallyIndirectCalls;
-
   ClonedCodeInfo() = default;
 
   bool isSimplified(const Value *From, const Value *To) const {
@@ -230,12 +225,11 @@ LLVM_ABI void CloneFunctionBodyInto(
     ValueMaterializer *Materializer = nullptr,
     const MetadataPredicate *IdentityMD = nullptr);
 
-LLVM_ABI void
-CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
-                          const Instruction *StartingInst,
-                          ValueToValueMapTy &VMap, bool ModuleLevelChanges,
-                          SmallVectorImpl<ReturnInst *> &Returns,
-                          const char *NameSuffix, ClonedCodeInfo &CodeInfo);
+LLVM_ABI void CloneAndPruneIntoFromInst(
+    Function *NewFunc, const Function *OldFunc, const Instruction *StartingInst,
+    ValueToValueMapTy &VMap, bool ModuleLevelChanges,
+    SmallVectorImpl<ReturnInst *> &Returns, const char *NameSuffix = "",
+    ClonedCodeInfo *CodeInfo = nullptr);
 
 /// This works exactly like CloneFunctionInto,
 /// except that it does some simple constant prop and DCE on the fly.  The
@@ -248,11 +242,10 @@ CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
 /// If ModuleLevelChanges is false, VMap contains no non-identity GlobalValue
 /// mappings.
 ///
-LLVM_ABI void
-CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc,
-                          ValueToValueMapTy &VMap, bool ModuleLevelChanges,
-                          SmallVectorImpl<ReturnInst *> &Returns,
-                          const char *NameSuffix, ClonedCodeInfo &CodeInfo);
+LLVM_ABI void CloneAndPruneFunctionInto(
+    Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap,
+    bool ModuleLevelChanges, SmallVectorImpl<ReturnInst *> &Returns,
+    const char *NameSuffix = "", ClonedCodeInfo *CodeInfo = nullptr);
 
 /// This class captures the data input to the InlineFunction call, and records
 /// the auxiliary results produced by it.
@@ -318,7 +311,6 @@ LLVM_ABI void InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
                                  bool MergeAttributes = false,
                                  AAResults *CalleeAAR = nullptr,
                                  bool InsertLifetime = true,
-                                 bool TrackInlineHistory = false,
                                  Function *ForwardVarArgsTo = nullptr,
                                  OptimizationRemarkEmitter *ORE = nullptr);
 
@@ -348,7 +340,6 @@ LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
                                      bool MergeAttributes = false,
                                      AAResults *CalleeAAR = nullptr,
                                      bool InsertLifetime = true,
-                                     bool TrackInlineHistory = false,
                                      Function *ForwardVarArgsTo = nullptr,
                                      OptimizationRemarkEmitter *ORE = nullptr);
 
@@ -361,7 +352,6 @@ LLVM_ABI InlineResult InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
                                      bool MergeAttributes = false,
                                      AAResults *CalleeAAR = nullptr,
                                      bool InsertLifetime = true,
-                                     bool TrackInlineHistory = false,
                                      Function *ForwardVarArgsTo = nullptr,
                                      OptimizationRemarkEmitter *ORE = nullptr);
 
@@ -443,6 +433,14 @@ LLVM_ABI void cloneAndAdaptNoAliasScopes(ArrayRef<MDNode *> NoAliasDeclScopes,
 LLVM_ABI void cloneAndAdaptNoAliasScopes(ArrayRef<MDNode *> NoAliasDeclScopes,
                                          Instruction *IStart, Instruction *IEnd,
                                          LLVMContext &Context, StringRef Ext);
+/// Check if Function F appears in the inline history chain.
+/// InlineHistory is a vector of (Function, ParentHistoryID) pairs.
+/// Returns true if F was already inlined in the chain leading to
+/// InlineHistoryID.
+LLVM_ABI bool
+inlineHistoryIncludes(Function *F, int InlineHistoryID,
+                      ArrayRef<std::pair<Function *, int>> InlineHistory);
+
 } // end namespace llvm
 
 #endif // LLVM_TRANSFORMS_UTILS_CLONING_H

diff  --git a/llvm/lib/Analysis/InlineOrder.cpp b/llvm/lib/Analysis/InlineOrder.cpp
index f54e040ff83c7..8d920153f250d 100644
--- a/llvm/lib/Analysis/InlineOrder.cpp
+++ b/llvm/lib/Analysis/InlineOrder.cpp
@@ -199,7 +199,10 @@ class MLPriority {
   int Cost = INT_MAX;
 };
 
-template <typename PriorityT> class PriorityInlineOrder : public InlineOrder {
+template <typename PriorityT>
+class PriorityInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
+  using T = std::pair<CallBase *, int>;
+
   bool hasLowerPriority(const CallBase *L, const CallBase *R) const {
     const auto I1 = Priorities.find(L);
     const auto I2 = Priorities.find(R);
@@ -240,21 +243,31 @@ template <typename PriorityT> class PriorityInlineOrder : public InlineOrder {
 
   size_t size() override { return Heap.size(); }
 
-  void push(CallBase *CB) override {
+  void push(const T &Elt) override {
+    CallBase *CB = Elt.first;
+    const int InlineHistoryID = Elt.second;
+
     Heap.push_back(CB);
     Priorities[CB] = PriorityT(CB, FAM, Params);
     std::push_heap(Heap.begin(), Heap.end(), isLess);
+    InlineHistoryMap[CB] = InlineHistoryID;
   }
 
-  CallBase *pop() override {
+  T pop() override {
     assert(size() > 0);
     pop_heap_adjust();
 
-    return Heap.pop_back_val();
+    CallBase *CB = Heap.pop_back_val();
+    T Result = std::make_pair(CB, InlineHistoryMap[CB]);
+    InlineHistoryMap.erase(CB);
+    return Result;
   }
 
-  void erase_if(function_ref<bool(CallBase *)> Pred) override {
-    llvm::erase_if(Heap, Pred);
+  void erase_if(function_ref<bool(T)> Pred) override {
+    auto PredWrapper = [=](CallBase *CB) -> bool {
+      return Pred(std::make_pair(CB, InlineHistoryMap[CB]));
+    };
+    llvm::erase_if(Heap, PredWrapper);
     std::make_heap(Heap.begin(), Heap.end(), isLess);
   }
 
@@ -271,7 +284,7 @@ template <typename PriorityT> class PriorityInlineOrder : public InlineOrder {
 
 AnalysisKey llvm::PluginInlineOrderAnalysis::Key;
 
-std::unique_ptr<InlineOrder>
+std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
 llvm::getDefaultInlineOrder(FunctionAnalysisManager &FAM,
                             const InlineParams &Params,
                             ModuleAnalysisManager &MAM, Module &M) {
@@ -296,10 +309,9 @@ llvm::getDefaultInlineOrder(FunctionAnalysisManager &FAM,
   return nullptr;
 }
 
-std::unique_ptr<InlineOrder> llvm::getInlineOrder(FunctionAnalysisManager &FAM,
-                                                  const InlineParams &Params,
-                                                  ModuleAnalysisManager &MAM,
-                                                  Module &M) {
+std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
+llvm::getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
+                     ModuleAnalysisManager &MAM, Module &M) {
   if (MAM.isPassRegistered<PluginInlineOrderAnalysis>()) {
     LLVM_DEBUG(dbgs() << "    Current used priority: plugin ---- \n");
     return MAM.getResult<PluginInlineOrderAnalysis>(M).Factory(FAM, Params, MAM,

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 4e760a02477b9..cf9131c66d6c3 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -549,7 +549,6 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   void visitAccessGroupMetadata(const MDNode *MD);
   void visitCapturesMetadata(Instruction &I, const MDNode *Captures);
   void visitAllocTokenMetadata(Instruction &I, MDNode *MD);
-  void visitInlineHistoryMetadata(Instruction &I, MDNode *MD);
 
   template <class Ty> bool isValidMetadataArray(const MDTuple &N);
 #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
@@ -5620,20 +5619,6 @@ void Verifier::visitAllocTokenMetadata(Instruction &I, MDNode *MD) {
         "expected integer constant", MD);
 }
 
-void Verifier::visitInlineHistoryMetadata(Instruction &I, MDNode *MD) {
-  Check(isa<CallBase>(I), "!inline_history should only exist on calls", &I);
-  for (Metadata *Op : MD->operands()) {
-    // Can be null when a function is erased.
-    if (!Op)
-      continue;
-    Check(isa<ValueAsMetadata>(Op) &&
-              isa<Function>(cast<ValueAsMetadata>(Op)
-                                ->getValue()
-                                ->stripPointerCastsAndAliases()),
-          "!inline_history operands must be functions or null", MD);
-  }
-}
-
 /// verifyInstruction - Verify that an instruction is well formed.
 ///
 void Verifier::visitInstruction(Instruction &I) {
@@ -5866,9 +5851,6 @@ void Verifier::visitInstruction(Instruction &I) {
   if (MDNode *MD = I.getMetadata(LLVMContext::MD_alloc_token))
     visitAllocTokenMetadata(I, MD);
 
-  if (MDNode *MD = I.getMetadata(LLVMContext::MD_inline_history))
-    visitInlineHistoryMetadata(I, MD);
-
   if (MDNode *N = I.getDebugLoc().getAsMDNode()) {
     CheckDI(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
     visitMDNode(*N, AreDebugLocsAllowed::Yes);

diff  --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index 080cb8ddb33fd..d0e309427d32e 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -53,9 +53,8 @@ bool AlwaysInlineImpl(
     BasicBlock *Block = CB.getParent();
 
     InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
-    InlineResult Res = InlineFunction(
-        CB, IFI, /*MergeAttributes=*/true, &GetAAR(Callee), InsertLifetime,
-        /*TrackInlineHistory=*/NewCallSites != nullptr);
+    InlineResult Res = InlineFunction(CB, IFI, /*MergeAttributes=*/true,
+                                      &GetAAR(Callee), InsertLifetime);
     if (!Res.isSuccess()) {
       ORE.emit([&]() {
         return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block)
@@ -141,7 +140,8 @@ bool AlwaysInlineImpl(
         continue;
 
       // Detect recursion.
-      if (Callee == F) {
+      if (Callee == F ||
+          inlineHistoryIncludes(Callee, InlineHistoryID, InlineHistory)) {
         ORE.emit([&]() {
           return OptimizationRemarkMissed("inline", "NotInlined",
                                           CB->getDebugLoc(), CB->getParent())

diff  --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp
index 2c56df9a3e245..d795fbbbe4120 100644
--- a/llvm/lib/Transforms/IPO/Inliner.cpp
+++ b/llvm/lib/Transforms/IPO/Inliner.cpp
@@ -231,7 +231,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
   // this model, but it is uniformly spread across all the functions in the SCC
   // and eventually they all become too large to inline, rather than
   // incrementally maknig a single function grow in a super linear fashion.
-  SmallVector<CallBase *, 16> Calls;
+  SmallVector<std::pair<CallBase *, int>, 16> Calls;
 
   // Populate the initial list of calls in this SCC.
   for (auto &N : InitialC) {
@@ -246,7 +246,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
       if (auto *CB = dyn_cast<CallBase>(&I))
         if (Function *Callee = CB->getCalledFunction()) {
           if (!Callee->isDeclaration())
-            Calls.push_back(CB);
+            Calls.push_back({CB, -1});
           else if (!isa<IntrinsicInst>(I)) {
             using namespace ore;
             setInlineRemark(*CB, "unavailable definition");
@@ -269,6 +269,12 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
   if (Calls.empty())
     return PreservedAnalyses::all();
 
+  // When inlining a callee produces new call sites, we want to keep track of
+  // the fact that they were inlined from the callee.  This allows us to avoid
+  // infinite inlining in some obscure cases.  To represent this, we use an
+  // index into the InlineHistory vector.
+  SmallVector<std::pair<Function *, int>, 16> InlineHistory;
+
   // Track a set vector of inlined callees so that we can augment the caller
   // with all of their edges in the call graph before pruning out the ones that
   // got simplified away.
@@ -289,7 +295,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
     // have the same caller, so we first set up some shared infrastructure for
     // this caller. We also do any pruning we can at this layer on the caller
     // alone.
-    Function &F = *Calls[I]->getCaller();
+    Function &F = *Calls[I].first->getCaller();
     LazyCallGraph::Node &N = *CG.lookup(F);
     if (CG.lookupSCC(N) != C)
       continue;
@@ -306,17 +312,29 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
     // We bail out as soon as the caller has to change so we can update the
     // call graph and prepare the context of that new caller.
     bool DidInline = false;
-    for (; I < (int)Calls.size() && Calls[I]->getCaller() == &F; ++I) {
-      CallBase *CB = Calls[I];
+    for (; I < (int)Calls.size() && Calls[I].first->getCaller() == &F; ++I) {
+      auto &P = Calls[I];
+      CallBase *CB = P.first;
+      const int InlineHistoryID = P.second;
       Function &Callee = *CB->getCalledFunction();
 
+      if (InlineHistoryID != -1 &&
+          inlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) {
+        LLVM_DEBUG(dbgs() << "Skipping inlining due to history: " << F.getName()
+                          << " -> " << Callee.getName() << "\n");
+        setInlineRemark(*CB, "recursive");
+        // Set noinline so that we don't forget this decision across CGSCC
+        // iterations.
+        CB->setIsNoInline();
+        continue;
+      }
+
       // Check if this inlining may repeat breaking an SCC apart that has
       // already been split once before. In that case, inlining here may
       // trigger infinite inlining, much like is prevented within the inliner
       // itself by the InlineHistory above, but spread across CGSCC iterations
       // and thus hidden from the full inline history.
-      LazyCallGraph::Node &CalleeN = *CG.lookup(Callee);
-      LazyCallGraph::SCC *CalleeSCC = CG.lookupSCC(CalleeN);
+      LazyCallGraph::SCC *CalleeSCC = CG.lookupSCC(*CG.lookup(Callee));
       if (CalleeSCC == C && UR.InlinedInternalEdges.count({&N, C})) {
         LLVM_DEBUG(dbgs() << "Skipping inlining internal SCC edge from a node "
                              "previously split out of this SCC by inlining: "
@@ -349,20 +367,9 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
           &FAM.getResult<BlockFrequencyAnalysis>(*(CB->getCaller())),
           &FAM.getResult<BlockFrequencyAnalysis>(Callee));
 
-      // For compile time reasons we try to only track inline history for the
-      // calls where it may actually prevent inlining, which is inlining through
-      // an SCC. This can happen if the callee is in a non-trivial SCC/RefSCC,
-      // or if an inlined call site was an indirect call, which can be
-      // devirtualized to call any target by replacing the indirectly called
-      // function with a function pointer referenced by the caller. The indirect
-      // call case is handled within InlineFunction.
-      bool TrackInlineHistory =
-          CalleeSCC->size() != 1 || CalleeSCC->getOuterRefSCC().size() != 1;
-
       InlineResult IR = InlineFunction(
           *CB, IFI, /*MergeAttributes=*/true,
-          &FAM.getResult<AAManager>(*CB->getCaller()), /*InsertLifetime=*/true,
-          TrackInlineHistory, nullptr,
+          &FAM.getResult<AAManager>(*CB->getCaller()), true, nullptr,
           &FAM.getResult<OptimizationRemarkEmitterAnalysis>(*CB->getCaller()));
       if (!IR.isSuccess()) {
         Advice->recordUnsuccessfulInlining(IR);
@@ -381,6 +388,9 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
 
       // Add any new callsites to defined functions to the worklist.
       if (!IFI.InlinedCallSites.empty()) {
+        int NewHistoryID = InlineHistory.size();
+        InlineHistory.push_back({&Callee, InlineHistoryID});
+
         for (CallBase *ICB : reverse(IFI.InlinedCallSites)) {
           Function *NewCallee = ICB->getCalledFunction();
           assert(!(NewCallee && NewCallee->isIntrinsic()) &&
@@ -395,7 +405,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
           }
           if (NewCallee) {
             if (!NewCallee->isDeclaration()) {
-              Calls.push_back(ICB);
+              Calls.push_back({ICB, NewHistoryID});
               // Continually inlining through an SCC can result in huge compile
               // times and bloated code since we arbitrarily stop at some point
               // when the inliner decides it's not profitable to inline anymore.
@@ -427,11 +437,12 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
       if (Callee.isDiscardableIfUnused() && Callee.hasZeroLiveUses() &&
           !CG.isLibFunction(Callee)) {
         if (Callee.hasLocalLinkage() || !Callee.hasComdat()) {
-          Calls.erase(std::remove_if(Calls.begin() + I + 1, Calls.end(),
-                                     [&](const CallBase *CB) {
-                                       return CB->getCaller() == &Callee;
-                                     }),
-                      Calls.end());
+          Calls.erase(
+              std::remove_if(Calls.begin() + I + 1, Calls.end(),
+                             [&](const std::pair<CallBase *, int> &Call) {
+                               return Call.first->getCaller() == &Callee;
+                             }),
+              Calls.end());
 
           // Report inlining decision BEFORE deleting function contents, so we
           // can still access e.g. the DebugLoc

diff  --git a/llvm/lib/Transforms/IPO/ModuleInliner.cpp b/llvm/lib/Transforms/IPO/ModuleInliner.cpp
index 79f545a9b3283..31c26c9fb8c06 100644
--- a/llvm/lib/Transforms/IPO/ModuleInliner.cpp
+++ b/llvm/lib/Transforms/IPO/ModuleInliner.cpp
@@ -144,7 +144,7 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
       if (auto *CB = dyn_cast<CallBase>(&I)) {
         if (Function *Callee = CB->getCalledFunction()) {
           if (!Callee->isDeclaration())
-            Calls->push(CB);
+            Calls->push({CB, -1});
           else if (!isa<IntrinsicInst>(I)) {
             using namespace ore;
             setInlineRemark(*CB, "unavailable definition");
@@ -166,18 +166,26 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
   }
   for (auto &[CB, Target] : ICPCandidates) {
     if (auto *DirectCB = promoteCallWithIfThenElse(*CB, *Target, CtxProf))
-      Calls->push(DirectCB);
+      Calls->push({DirectCB, -1});
   }
   if (Calls->empty())
     return PreservedAnalyses::all();
 
+  // When inlining a callee produces new call sites, we want to keep track of
+  // the fact that they were inlined from the callee.  This allows us to avoid
+  // infinite inlining in some obscure cases.  To represent this, we use an
+  // index into the InlineHistory vector.
+  SmallVector<std::pair<Function *, int>, 16> InlineHistory;
+
   // Track the dead functions to delete once finished with inlining calls. We
   // defer deleting these to make it easier to handle the call graph updates.
   SmallVector<Function *, 4> DeadFunctions;
 
   // Loop forward over all of the calls.
   while (!Calls->empty()) {
-    CallBase *CB = Calls->pop();
+    auto P = Calls->pop();
+    CallBase *CB = P.first;
+    const int InlineHistoryID = P.second;
     Function &F = *CB->getCaller();
     Function &Callee = *CB->getCalledFunction();
 
@@ -190,6 +198,12 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
       return FAM.getResult<AssumptionAnalysis>(F);
     };
 
+    if (InlineHistoryID != -1 &&
+        inlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) {
+      setInlineRemark(*CB, "recursive");
+      continue;
+    }
+
     auto Advice = Advisor.getAdvice(*CB, /*OnlyMandatory*/ false);
     // Check whether we want to inline this callsite.
     if (!Advice->isInliningRecommended()) {
@@ -220,6 +234,9 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
 
     // Add any new callsites to defined functions to the worklist.
     if (!IFI.InlinedCallSites.empty()) {
+      int NewHistoryID = InlineHistory.size();
+      InlineHistory.push_back({&Callee, InlineHistoryID});
+
       for (CallBase *ICB : reverse(IFI.InlinedCallSites)) {
         Function *NewCallee = ICB->getCalledFunction();
         if (!NewCallee) {
@@ -234,7 +251,7 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
         }
         if (NewCallee)
           if (!NewCallee->isDeclaration())
-            Calls->push(ICB);
+            Calls->push({ICB, NewHistoryID});
       }
     }
 
@@ -249,8 +266,9 @@ PreservedAnalyses ModuleInlinerPass::run(Module &M,
       Callee.removeDeadConstantUsers();
       // if (Callee.use_empty() && !CG.isLibFunction(Callee)) {
       if (Callee.use_empty() && !isKnownLibFunction(Callee, GetTLI(Callee))) {
-        Calls->erase_if(
-            [&](const CallBase *CB) { return CB->getCaller() == &Callee; });
+        Calls->erase_if([&](const std::pair<CallBase *, int> &Call) {
+          return Call.first->getCaller() == &Callee;
+        });
 
         // Report inlining decision BEFORE deleting function contents, so we
         // can still access e.g. the DebugLoc

diff  --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp
index 0b5c5d17abf81..c00402f8ef102 100644
--- a/llvm/lib/Transforms/IPO/PartialInlining.cpp
+++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp
@@ -1372,8 +1372,7 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) {
     InlineFunctionInfo IFI(GetAssumptionCache, &PSI);
     // We can only forward varargs when we outlined a single region, else we
     // bail on vararg functions.
-    if (!InlineFunction(*CB, IFI, /*MergeAttributes=*/false, nullptr,
-                        /*InsertLifetime=*/true, /*TrackInlineHistory=*/true,
+    if (!InlineFunction(*CB, IFI, /*MergeAttributes=*/false, nullptr, true,
                         (Cloner.ClonedOI ? Cloner.OutlinedFunctions.back().first
                                          : nullptr))
              .isSuccess())

diff  --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp
index 8bf941cf19cd9..ac78e8251df9a 100644
--- a/llvm/lib/Transforms/Utils/CloneFunction.cpp
+++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp
@@ -433,7 +433,7 @@ struct PruningFunctionCloner {
   ValueToValueMapTy &VMap;
   bool ModuleLevelChanges;
   const char *NameSuffix;
-  ClonedCodeInfo &CodeInfo;
+  ClonedCodeInfo *CodeInfo;
   bool HostFuncIsStrictFP;
 
   Instruction *cloneInstruction(BasicBlock::const_iterator II);
@@ -441,7 +441,7 @@ struct PruningFunctionCloner {
 public:
   PruningFunctionCloner(Function *newFunc, const Function *oldFunc,
                         ValueToValueMapTy &valueMap, bool moduleLevelChanges,
-                        const char *nameSuffix, ClonedCodeInfo &codeInfo)
+                        const char *nameSuffix, ClonedCodeInfo *codeInfo)
       : NewFunc(newFunc), OldFunc(oldFunc), VMap(valueMap),
         ModuleLevelChanges(moduleLevelChanges), NameSuffix(nameSuffix),
         CodeInfo(codeInfo) {
@@ -615,9 +615,6 @@ void PruningFunctionCloner::CloneBlock(
       }
     }
 
-    if (auto *CB = dyn_cast<CallBase>(II); CB && CB->isIndirectCall())
-      CodeInfo.OriginallyIndirectCalls.insert(NewInst);
-
     if (II->hasName())
       NewInst->setName(II->getName() + NameSuffix);
     VMap[&*II] = NewInst; // Add instruction map to value.
@@ -629,10 +626,12 @@ void PruningFunctionCloner::CloneBlock(
 
     CloneDbgRecordsToHere(NewInst, II);
 
-    CodeInfo.OrigVMap[&*II] = NewInst;
-    if (auto *CB = dyn_cast<CallBase>(&*II))
-      if (CB->hasOperandBundles())
-        CodeInfo.OperandBundleCallSites.push_back(NewInst);
+    if (CodeInfo) {
+      CodeInfo->OrigVMap[&*II] = NewInst;
+      if (auto *CB = dyn_cast<CallBase>(&*II))
+        if (CB->hasOperandBundles())
+          CodeInfo->OperandBundleCallSites.push_back(NewInst);
+    }
 
     if (const AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
       if (isa<ConstantInt>(AI->getArraySize()))
@@ -691,10 +690,12 @@ void PruningFunctionCloner::CloneBlock(
 
     VMap[OldTI] = NewInst; // Add instruction map to value.
 
-    CodeInfo.OrigVMap[OldTI] = NewInst;
-    if (auto *CB = dyn_cast<CallBase>(OldTI))
-      if (CB->hasOperandBundles())
-        CodeInfo.OperandBundleCallSites.push_back(NewInst);
+    if (CodeInfo) {
+      CodeInfo->OrigVMap[OldTI] = NewInst;
+      if (auto *CB = dyn_cast<CallBase>(OldTI))
+        if (CB->hasOperandBundles())
+          CodeInfo->OperandBundleCallSites.push_back(NewInst);
+    }
 
     // Recursively clone any reachable successor blocks.
     append_range(ToClone, successors(BB->getTerminator()));
@@ -707,11 +708,13 @@ void PruningFunctionCloner::CloneBlock(
     CloneDbgRecordsToHere(NewInst, OldTI->getIterator());
   }
 
-  CodeInfo.ContainsCalls |= hasCalls;
-  CodeInfo.ContainsMemProfMetadata |= hasMemProfMetadata;
-  CodeInfo.ContainsDynamicAllocas |= hasDynamicAllocas;
-  CodeInfo.ContainsDynamicAllocas |=
-      hasStaticAllocas && BB != &BB->getParent()->front();
+  if (CodeInfo) {
+    CodeInfo->ContainsCalls |= hasCalls;
+    CodeInfo->ContainsMemProfMetadata |= hasMemProfMetadata;
+    CodeInfo->ContainsDynamicAllocas |= hasDynamicAllocas;
+    CodeInfo->ContainsDynamicAllocas |=
+        hasStaticAllocas && BB != &BB->getParent()->front();
+  }
 }
 
 /// This works like CloneAndPruneFunctionInto, except that it does not clone the
@@ -723,7 +726,7 @@ void llvm::CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
                                      bool ModuleLevelChanges,
                                      SmallVectorImpl<ReturnInst *> &Returns,
                                      const char *NameSuffix,
-                                     ClonedCodeInfo &CodeInfo) {
+                                     ClonedCodeInfo *CodeInfo) {
   assert(NameSuffix && "NameSuffix cannot be null!");
 
   ValueMapTypeRemapper *TypeMapper = nullptr;
@@ -1003,12 +1006,10 @@ void llvm::CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
 /// constant arguments cause a significant amount of code in the callee to be
 /// dead.  Since this doesn't produce an exact copy of the input, it can't be
 /// used for things like CloneFunction or CloneModule.
-void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc,
-                                     ValueToValueMapTy &VMap,
-                                     bool ModuleLevelChanges,
-                                     SmallVectorImpl<ReturnInst *> &Returns,
-                                     const char *NameSuffix,
-                                     ClonedCodeInfo &CodeInfo) {
+void llvm::CloneAndPruneFunctionInto(
+    Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap,
+    bool ModuleLevelChanges, SmallVectorImpl<ReturnInst *> &Returns,
+    const char *NameSuffix, ClonedCodeInfo *CodeInfo) {
   CloneAndPruneIntoFromInst(NewFunc, OldFunc, &OldFunc->front().front(), VMap,
                             ModuleLevelChanges, Returns, NameSuffix, CodeInfo);
 }

diff  --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index 7eef188bbc57a..1c4df54b60f46 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -2412,15 +2412,13 @@ remapIndices(Function &Caller, BasicBlock *StartBB,
 // Updating the contextual profile after an inlining means, at a high level,
 // copying over the data of the callee, **intentionally without any value
 // scaling**, and copying over the callees of the inlined callee.
-llvm::InlineResult
-llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
-                     PGOContextualProfile &CtxProf, bool MergeAttributes,
-                     AAResults *CalleeAAR, bool InsertLifetime,
-                     bool TrackInlineHistory, Function *ForwardVarArgsTo,
-                     OptimizationRemarkEmitter *ORE) {
+llvm::InlineResult llvm::InlineFunction(
+    CallBase &CB, InlineFunctionInfo &IFI, PGOContextualProfile &CtxProf,
+    bool MergeAttributes, AAResults *CalleeAAR, bool InsertLifetime,
+    Function *ForwardVarArgsTo, OptimizationRemarkEmitter *ORE) {
   if (!CtxProf.isInSpecializedModule())
     return InlineFunction(CB, IFI, MergeAttributes, CalleeAAR, InsertLifetime,
-                          TrackInlineHistory, ForwardVarArgsTo, ORE);
+                          ForwardVarArgsTo, ORE);
 
   auto &Caller = *CB.getCaller();
   auto &Callee = *CB.getCalledFunction();
@@ -2438,7 +2436,7 @@ llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
   const auto NumCalleeCallsites = CtxProf.getNumCallsites(Callee);
 
   auto Ret = InlineFunction(CB, IFI, MergeAttributes, CalleeAAR, InsertLifetime,
-                            TrackInlineHistory, ForwardVarArgsTo, ORE);
+                            ForwardVarArgsTo, ORE);
   if (!Ret.isSuccess())
     return Ret;
 
@@ -2524,18 +2522,6 @@ llvm::InlineResult llvm::CanInlineCallSite(const CallBase &CB,
       CalledFunc->isDeclaration()) // call!
     return InlineResult::failure("external or indirect");
 
-  // Don't inline if we've already inlined this callee through this call site
-  // before to prevent infinite inlining through mutually recursive functions.
-  if (MDNode *InlineHistory = CB.getMetadata(LLVMContext::MD_inline_history)) {
-    for (const auto &Op : InlineHistory->operands()) {
-      if (auto *MD = dyn_cast_or_null<ValueAsMetadata>(Op)) {
-        if (MD->getValue() == CalledFunc) {
-          return InlineResult::failure("inline history");
-        }
-      }
-    }
-  }
-
   // The inliner does not know how to inline through calls with operand bundles
   // in general ...
   if (CB.hasOperandBundles()) {
@@ -2661,8 +2647,7 @@ llvm::InlineResult llvm::CanInlineCallSite(const CallBase &CB,
 /// function by one level.
 void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
                               bool MergeAttributes, AAResults *CalleeAAR,
-                              bool InsertLifetime, bool TrackInlineHistory,
-                              Function *ForwardVarArgsTo,
+                              bool InsertLifetime, Function *ForwardVarArgsTo,
                               OptimizationRemarkEmitter *ORE) {
   BasicBlock *OrigBB = CB.getParent();
   Function *Caller = OrigBB->getParent();
@@ -2783,7 +2768,7 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
     // happy with whatever the cloner can do.
     CloneAndPruneFunctionInto(Caller, CalledFunc, VMap,
                               /*ModuleLevelChanges=*/false, Returns, ".i",
-                              InlinedFunctionInfo);
+                              &InlinedFunctionInfo);
     // Remember the first block that is newly cloned over.
     FirstNewBlock = LastBlock; ++FirstNewBlock;
 
@@ -3284,35 +3269,6 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
             IFI.InlinedCallSites.push_back(CB);
   }
 
-  for (CallBase *ICB : IFI.InlinedCallSites) {
-    // We only track inline history if requested, or if the inlined call site
-    // was originally an indirect call (it may have become a direct call
-    // during inlining).
-    if (TrackInlineHistory ||
-        InlinedFunctionInfo.OriginallyIndirectCalls.contains(ICB)) {
-      // !inline_history is {Callee, CB.inline_history, ICB.inline_history}.
-      // Metadata nodes may be null if the referenced function was erased from
-      // the module.
-      SmallVector<Metadata *, 4> History;
-      History.push_back(ValueAsMetadata::get(CalledFunc));
-      if (MDNode *CBHistory = CB.getMetadata(LLVMContext::MD_inline_history)) {
-        for (const auto &Op : CBHistory->operands()) {
-          if (Op)
-            History.push_back(Op.get());
-        }
-      }
-      if (MDNode *CBHistory =
-              ICB->getMetadata(LLVMContext::MD_inline_history)) {
-        for (const auto &Op : CBHistory->operands()) {
-          if (Op)
-            History.push_back(Op.get());
-        }
-      }
-      MDNode *NewHistory = MDNode::get(Caller->getContext(), History);
-      ICB->setMetadata(LLVMContext::MD_inline_history, NewHistory);
-    }
-  }
-
   // If we cloned in _exactly one_ basic block, and if that block ends in a
   // return instruction, we splice the body of the inlined callee directly into
   // the calling basic block.
@@ -3518,15 +3474,30 @@ void llvm::InlineFunctionImpl(CallBase &CB, InlineFunctionInfo &IFI,
     AttributeFuncs::mergeAttributesForInlining(*Caller, *CalledFunc);
 }
 
-llvm::InlineResult llvm::InlineFunction(
-    CallBase &CB, InlineFunctionInfo &IFI, bool MergeAttributes,
-    AAResults *CalleeAAR, bool InsertLifetime, bool TrackInlineHistory,
-    Function *ForwardVarArgsTo, OptimizationRemarkEmitter *ORE) {
+llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
+                                        bool MergeAttributes,
+                                        AAResults *CalleeAAR,
+                                        bool InsertLifetime,
+                                        Function *ForwardVarArgsTo,
+                                        OptimizationRemarkEmitter *ORE) {
   llvm::InlineResult Result = CanInlineCallSite(CB, IFI);
   if (Result.isSuccess()) {
     InlineFunctionImpl(CB, IFI, MergeAttributes, CalleeAAR, InsertLifetime,
-                       TrackInlineHistory, ForwardVarArgsTo, ORE);
+                       ForwardVarArgsTo, ORE);
   }
 
   return Result;
 }
+
+bool llvm::inlineHistoryIncludes(
+    Function *F, int InlineHistoryID,
+    ArrayRef<std::pair<Function *, int>> InlineHistory) {
+  while (InlineHistoryID != -1) {
+    assert(unsigned(InlineHistoryID) < InlineHistory.size() &&
+           "Invalid inline history ID");
+    if (InlineHistory[InlineHistoryID].first == F)
+      return true;
+    InlineHistoryID = InlineHistory[InlineHistoryID].second;
+  }
+  return false;
+}

diff  --git a/llvm/test/Transforms/Inline/debug-invoke.ll b/llvm/test/Transforms/Inline/debug-invoke.ll
index 444363667fa2b..3cf1ca36e774a 100644
--- a/llvm/test/Transforms/Inline/debug-invoke.ll
+++ b/llvm/test/Transforms/Inline/debug-invoke.ll
@@ -3,7 +3,7 @@
 ; Test that the debug location is preserved when rewriting an inlined call as an invoke
 
 ; CHECK: invoke void @test()
-; CHECK-NEXT: to label {{.*}} unwind label {{.*}}, !dbg [[INL_LOC:![0-9]+]]
+; CHECK-NEXT: to label {{.*}} unwind label {{.*}}, !dbg [[INL_LOC:!.*]]
 ; CHECK: [[SP:.*]] = distinct !DISubprogram(
 ; CHECK: [[INL_LOC]] = !DILocation(line: 1, scope: [[SP]], inlinedAt: [[INL_AT:.*]])
 ; CHECK: [[INL_AT]] = distinct !DILocation(line: 2, scope: [[SP]])

diff  --git a/llvm/test/Transforms/Inline/inline-history-2.ll b/llvm/test/Transforms/Inline/inline-history-2.ll
deleted file mode 100644
index 9cb12a352bbc7..0000000000000
--- a/llvm/test/Transforms/Inline/inline-history-2.ll
+++ /dev/null
@@ -1,25 +0,0 @@
-; RUN: opt -passes='cgscc(inline,function(instcombine))' -S < %s | FileCheck %s
-
-; Check that devirtualization of an indirect call to itself doesn't cause
-; infinite inlining. Note that we need the devirtualization to happen in
-; simplification between inlining runs or else InlineCost will substitute %p
-; with @p and see that the call is a recursive call and bail.
-
-define void @p(ptr %p, i64 %x) {
-  %a = alloca ptr
-  store ptr %p, ptr %a
-  %g = getelementptr i8, ptr %a, i64 %x
-  %b = load ptr, ptr %g
-  call void %b(ptr %p, i64 %x)
-  ret void
-}
-
-define void @q() {
-; CHECK-LABEL: define void @q() {
-; CHECK-NEXT:    call void @p({{.*}}), !inline_history [[HISTORY:![0-9]+]]
-; CHECK-NEXT:    ret void
-  call void @p(ptr @p, i64 0)
-  ret void
-}
-
-; CHECK: [[HISTORY]] = !{ptr @p}

diff  --git a/llvm/test/Transforms/Inline/inline-history-noinline.ll b/llvm/test/Transforms/Inline/inline-history-noinline.ll
new file mode 100644
index 0000000000000..742bd25ecd9bb
--- /dev/null
+++ b/llvm/test/Transforms/Inline/inline-history-noinline.ll
@@ -0,0 +1,32 @@
+; RUN: opt -passes=inline -S < %s | FileCheck %s
+
+; This will inline @f1 into @a, causing two new calls to @f2, which will get inlined for two calls to @f1.
+; The inline history should stop recursive inlining here, and make sure to mark the inlined calls as noinline so we don't repeat the inlining later on when @a gets inlined into @b.
+
+define internal void @f1(ptr %p) {
+  call void %p(ptr @f1)
+  ret void
+}
+
+define internal void @f2(ptr %p) {
+  call void %p(ptr @f2)
+  call void %p(ptr @f2)
+  ret void
+}
+
+define void @b() {
+; CHECK-LABEL: define void @b() {
+; CHECK-NEXT:    call void @f1(ptr @f2) #[[NOINLINE:[0-9]+]]
+; CHECK-NEXT:    call void @f1(ptr @f2) #[[NOINLINE]]
+; CHECK-NEXT:    ret void
+;
+  call void @a()
+  ret void
+}
+
+define internal void @a() {
+  call void @f1(ptr @f2)
+  ret void
+}
+
+; CHECK: [[NOINLINE]] = { noinline }

diff  --git a/llvm/test/Transforms/Inline/inline-history.ll b/llvm/test/Transforms/Inline/inline-history.ll
deleted file mode 100644
index 5f2d67bba1d6c..0000000000000
--- a/llvm/test/Transforms/Inline/inline-history.ll
+++ /dev/null
@@ -1,102 +0,0 @@
-; RUN: opt -passes=inline -S < %s | FileCheck %s
-
-declare ptr @get()
-declare ptr @foo1()
-declare ptr @foo2()
-
-; Don't need to track inline history for non-mutually recursive calls.
-
-define internal void @x() noinline {
-  ret void
-}
-
-define internal void @y() {
-  call void @x()
-  ret void
-}
-
-define void @z() {
-; CHECK-LABEL: define void @z() {
-; CHECK-NEXT:    call void @x(){{$}}
-; CHECK-NEXT:    ret void
-  call void @y()
-  ret void
-}
-
-; Indirect calls may be devirtualized, they need inline history tracking. In
-; this case, @s is the history, but it gets deleted so the inline history
-; metadata becomes null. This is fine since we cannot infinitely inline through
-; @s anymore as it doesn't exist.
-
-define internal void @s() {
-  %p = call ptr @get()
-  call void %p()
-  ret void
-}
-
-define void @t() {
-; CHECK-LABEL: define void @t() {
-; CHECK-NEXT:    %p.i = call ptr @get()
-; CHECK-NEXT:    call void %p.i(), !inline_history [[HISTORY_T:![0-9]+]]
-; CHECK-NEXT:    ret void
-  call void @s()
-  ret void
-}
-
-; This will inline @f1 into @a, causing two new calls to @f2, which will get inlined for two calls to @f1.
-; The inline history should stop recursive inlining here.
-
-define internal void @f1(ptr %p) {
-  call void %p(ptr @f1)
-  ret void
-}
-
-define internal void @f2(ptr %p) {
-  call void %p(ptr @f2)
-  call void %p(ptr @f2)
-  ret void
-}
-
-define void @b() {
-; CHECK-LABEL: define void @b() {
-; CHECK-NEXT:    call void @f1(ptr @f2), !inline_history [[HISTORY_B:![0-9]+]]
-; CHECK-NEXT:    call void @f1(ptr @f2), !inline_history [[HISTORY_B:![0-9]+]]
-; CHECK-NEXT:    ret void
-;
-  call void @a()
-  ret void
-}
-
-define internal void @a() {
-  call void @f1(ptr @f2)
-  ret void
-}
-
-; Check that the inline history is
-; {callee, processed call's inline_history, just-inlined call's inline_history}
-
-define void @m(ptr %p) noinline {
-  ret void
-}
-
-define void @n() {
-  call void @m(ptr @n2), !inline_history !{ptr @foo1}
-  ret void
-}
-
-define void @n2() {
-  call void @m(ptr @n)
-  ret void
-}
-
-define void @o() {
-; CHECK-LABEL: define void @o() {
-; CHECK-NEXT:    call void @m(ptr @n2), !inline_history [[HISTORY_O:![0-9]+]]
-; CHECK-NEXT:    ret void
-  call void @n(), !inline_history !{ptr @foo2}
-  ret void
-}
-
-; CHECK-DAG: [[HISTORY_T]] = distinct !{null}
-; CHECK-DAG: [[HISTORY_B]] = !{ptr @f2, ptr @f1}
-; CHECK-DAG: [[HISTORY_O]] = !{ptr @n, ptr @foo2, ptr @foo1}

diff  --git a/llvm/test/Transforms/Inline/inline-recursive-fn2.ll b/llvm/test/Transforms/Inline/inline-recursive-fn2.ll
index 27987fc845d5e..52d7b21902e8e 100644
--- a/llvm/test/Transforms/Inline/inline-recursive-fn2.ll
+++ b/llvm/test/Transforms/Inline/inline-recursive-fn2.ll
@@ -14,7 +14,7 @@
 ; CHECK:      Size after inlining: 17
 ; CHECK:      NOT Inlining (cost=never): noinline function attribute, Call:   %call_test = tail call float @test(float %fneg, float %common.ret18.op.i)
 ; CHECK:      NOT Inlining (cost=never): noinline function attribute, Call:   %call_test.i = tail call float @test(float %x, float %call.i)
-; CHECK:      NOT Inlining (cost=never): recursive, Call: %call.i = tail call float @inline_rec_true_successor(float %x, float %scale)
+; CHECK:  Skipping inlining due to history: inline_rec_true_successor -> inline_rec_true_successor
 ; CHECK:  Updated inlining SCC: (test, inline_rec_true_successor)
 
 ; CHECK:  Inlining calls in: test

diff  --git a/llvm/test/Verifier/inline-history-metadata.ll b/llvm/test/Verifier/inline-history-metadata.ll
deleted file mode 100644
index 30ffa2aa3f43d..0000000000000
--- a/llvm/test/Verifier/inline-history-metadata.ll
+++ /dev/null
@@ -1,61 +0,0 @@
-; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
-
- at x = global i32 0
- at alias = alias void (), ptr @f
-
-define void @f() {
-  ret void
-}
-
-; CHECK: !inline_history should only exist on calls
-define void @wrong_instr(ptr %x) {
-  load ptr, ptr %x, !inline_history !{ptr @wrong_instr}
-  ret void
-}
-
-; CHECK: !inline_history operands must be functions or null
-define void @global_value_operand() {
-  call void @f(), !inline_history !{ptr @x}
-  ret void
-}
-
-; CHECK: !inline_history operands must be functions or null
-define void @metadata_operand() {
-  call void @f(), !inline_history !{!0}
-  ret void
-}
-
-; CHECK: !inline_history operands must be functions or null
-define void @nullptr_operand() {
-  call void @f(), !inline_history !{ptr null}
-  ret void
-}
-
-; CHECK-NOT: !inline_history operands must be functions or null
-
-define void @empty_metadata() {
-  call void @f(), !inline_history !{}
-  ret void
-}
-
-define void @null_metadata() {
-  call void @f(), !inline_history !{null}
-  ret void
-}
-
-define void @function_metadata() {
-  call void @f(), !inline_history !{ptr @f}
-  ret void
-}
-
-define void @alias_metadata() {
-  call void @f(), !inline_history !{ptr @alias}
-  ret void
-}
-
-define void @mixed_metadata() {
-  call void @f(), !inline_history !{null, ptr @f, null, ptr @mixed_metadata}
-  ret void
-}
-
-!0 = !{}

diff  --git a/llvm/unittests/Analysis/InlineOrderPlugin/InlineOrderPlugin.cpp b/llvm/unittests/Analysis/InlineOrderPlugin/InlineOrderPlugin.cpp
index a263edc3f6f41..6fe54c24d70c1 100644
--- a/llvm/unittests/Analysis/InlineOrderPlugin/InlineOrderPlugin.cpp
+++ b/llvm/unittests/Analysis/InlineOrderPlugin/InlineOrderPlugin.cpp
@@ -12,29 +12,31 @@ using namespace llvm;
 
 namespace {
 
-class NoFooInlineOrder : public InlineOrder {
+class NoFooInlineOrder : public InlineOrder<std::pair<CallBase *, int>> {
 public:
   NoFooInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params,
                    ModuleAnalysisManager &MAM, Module &M) {
     DefaultInlineOrder = getDefaultInlineOrder(FAM, Params, MAM, M);
   }
   size_t size() override { return DefaultInlineOrder->size(); }
-  void push(CallBase *Elt) override {
-    // We ignore callees named "foo"
-    if (Elt->getCalledFunction()->getName() == "foo") {
+  void push(const std::pair<CallBase *, int> &Elt) override {
+    // We ignore calles named "foo"
+    if (Elt.first->getCalledFunction()->getName() == "foo") {
       DefaultInlineOrder->push(Elt);
     }
   }
-  CallBase *pop() override { return DefaultInlineOrder->pop(); }
-  void erase_if(function_ref<bool(CallBase *)> Pred) override {
+  std::pair<CallBase *, int> pop() override {
+    return DefaultInlineOrder->pop();
+  }
+  void erase_if(function_ref<bool(std::pair<CallBase *, int>)> Pred) override {
     DefaultInlineOrder->erase_if(Pred);
   }
 
 private:
-  std::unique_ptr<InlineOrder> DefaultInlineOrder;
+  std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>> DefaultInlineOrder;
 };
 
-std::unique_ptr<InlineOrder>
+std::unique_ptr<InlineOrder<std::pair<CallBase *, int>>>
 NoFooInlineOrderFactory(FunctionAnalysisManager &FAM,
                         const InlineParams &Params, ModuleAnalysisManager &MAM,
                         Module &M) {


        


More information about the llvm-branch-commits mailing list