[llvm] 3f8e416 - [FunctionPropertiesAnalysis] Generalize support for unreachable

Mircea Trofin via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 21 08:18:29 PDT 2022


Author: Mircea Trofin
Date: 2022-06-21T08:18:01-07:00
New Revision: 3f8e4169c1c390fd086658c1e51983ee61bff9bc

URL: https://github.com/llvm/llvm-project/commit/3f8e4169c1c390fd086658c1e51983ee61bff9bc
DIFF: https://github.com/llvm/llvm-project/commit/3f8e4169c1c390fd086658c1e51983ee61bff9bc.diff

LOG: [FunctionPropertiesAnalysis] Generalize support for unreachable

Generalized support for subgraphs that get rendered unreachable, for
both `call` and `invoke` cases.

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

Added: 
    

Modified: 
    llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
    llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
index 77a9ca0844466..782c11937507e 100644
--- a/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
+++ b/llvm/lib/Analysis/FunctionPropertiesAnalysis.cpp
@@ -129,7 +129,7 @@ FunctionPropertiesPrinterPass::run(Function &F, FunctionAnalysisManager &AM) {
 FunctionPropertiesUpdater::FunctionPropertiesUpdater(
     FunctionPropertiesInfo &FPI, const CallBase &CB)
     : FPI(FPI), CallSiteBB(*CB.getParent()), Caller(*CallSiteBB.getParent()) {
-
+  assert(isa<CallInst>(CB) || isa<InvokeInst>(CB));
   // For BBs that are likely to change, we subtract from feature totals their
   // contribution. Some features, like max loop counts or depths, are left
   // invalid, as they will be updated post-inlining.
@@ -146,6 +146,18 @@ FunctionPropertiesUpdater::FunctionPropertiesUpdater(
   // with the CB BB ('Entry') between which the inlined callee will be pasted.
   Successors.insert(succ_begin(&CallSiteBB), succ_end(&CallSiteBB));
 
+  // Inlining only handles invoke and calls. If this is an invoke, and inlining
+  // it pulls another invoke, the original landing pad may get split, so as to
+  // share its content with other potential users. So the edge up to which we
+  // need to invalidate and then re-account BB data is the successors of the
+  // current landing pad. We can leave the current lp, too - if it doesn't get
+  // split, then it will be the place traversal stops. Either way, the
+  // discounted BBs will be checked if reachable and re-added.
+  if (const auto *II = dyn_cast<InvokeInst>(&CB)) {
+    const auto *UnwindDest = II->getUnwindDest();
+    Successors.insert(succ_begin(UnwindDest), succ_end(UnwindDest));
+  }
+
   // Exclude the CallSiteBB, if it happens to be its own successor (1-BB loop).
   // We are only interested in BBs the graph moves past the callsite BB to
   // define the frontier past which we don't want to re-process BBs. Including
@@ -165,46 +177,72 @@ FunctionPropertiesUpdater::FunctionPropertiesUpdater(
 }
 
 void FunctionPropertiesUpdater::finish(FunctionAnalysisManager &FAM) const {
-  SetVector<const BasicBlock *> Worklist;
-
-  if (&CallSiteBB != &*Caller.begin()) {
-    FPI.reIncludeBB(*Caller.begin());
-    Worklist.insert(&*Caller.begin());
-  }
-
   // Update feature values from the BBs that were copied from the callee, or
   // might have been modified because of inlining. The latter have been
   // subtracted in the FunctionPropertiesUpdater ctor.
   // There could be successors that were reached before but now are only
   // reachable from elsewhere in the CFG.
-  // Suppose the following diamond CFG (lines are arrows pointing down):
+  // One example is the following diamond CFG (lines are arrows pointing down):
   //    A
   //  /   \
   // B     C
+  // |     |
+  // |     D
+  // |     |
+  // |     E
   //  \   /
-  //    D
+  //    F
   // There's a call site in C that is inlined. Upon doing that, it turns out
   // it expands to
   //   call void @llvm.trap()
   //   unreachable
-  // D isn't reachable from C anymore, but we did discount it when we set up
+  // F isn't reachable from C anymore, but we did discount it when we set up
   // FunctionPropertiesUpdater, so we need to re-include it here.
-
+  // At the same time, D and E were reachable before, but now are not anymore,
+  // so we need to leave D out (we discounted it at setup), and explicitly
+  // remove E.
+  SetVector<const BasicBlock *> Reinclude;
+  SetVector<const BasicBlock *> Unreachable;
   const auto &DT =
       FAM.getResult<DominatorTreeAnalysis>(const_cast<Function &>(Caller));
-  for (const auto *Succ : Successors)
-    if (DT.isReachableFromEntry(Succ) && Worklist.insert(Succ))
-      FPI.reIncludeBB(*Succ);
 
-  auto I = Worklist.size();
-  bool CSInsertion = Worklist.insert(&CallSiteBB);
+  if (&CallSiteBB != &*Caller.begin())
+    Reinclude.insert(&*Caller.begin());
+
+  // Distribute the successors to the 2 buckets.
+  for (const auto *Succ : Successors)
+    if (DT.isReachableFromEntry(Succ))
+      Reinclude.insert(Succ);
+    else
+      Unreachable.insert(Succ);
+
+  // For reinclusion, we want to stop at the reachable successors, who are at
+  // the beginning of the worklist; but, starting from the callsite bb and
+  // ending at those successors, we also want to perform a traversal.
+  // IncludeSuccessorsMark is the index after which we include successors.
+  const auto IncludeSuccessorsMark = Reinclude.size();
+  bool CSInsertion = Reinclude.insert(&CallSiteBB);
   (void)CSInsertion;
   assert(CSInsertion);
-  for (; I < Worklist.size(); ++I) {
-    const auto *BB = Worklist[I];
+  for (size_t I = 0; I < Reinclude.size(); ++I) {
+    const auto *BB = Reinclude[I];
     FPI.reIncludeBB(*BB);
-    for (const auto *Succ : successors(BB))
-      Worklist.insert(Succ);
+    if (I >= IncludeSuccessorsMark)
+      Reinclude.insert(succ_begin(BB), succ_end(BB));
+  }
+
+  // For exclusion, we don't need to exclude the set of BBs that were successors
+  // before and are now unreachable, because we already did that at setup. For
+  // the rest, as long as a successor is unreachable, we want to explicitly
+  // exclude it.
+  const auto AlreadyExcludedMark = Unreachable.size();
+  for (size_t I = 0; I < Unreachable.size(); ++I) {
+    const auto *U = Unreachable[I];
+    if (I >= AlreadyExcludedMark)
+      FPI.updateForBB(*U, -1);
+    for (const auto *Succ : successors(U))
+      if (!DT.isReachableFromEntry(Succ))
+        Unreachable.insert(Succ);
   }
 
   const auto &LI = FAM.getResult<LoopAnalysis>(const_cast<Function &>(Caller));

diff  --git a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
index cb51e8fbd64cd..acf61ca30e469 100644
--- a/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
+++ b/llvm/unittests/Analysis/FunctionPropertiesAnalysisTest.cpp
@@ -636,10 +636,16 @@ cond.true:                                        ; preds = %entry
 
 cond.false:                                       ; preds = %entry
   %call3 = call noundef i64 @f2()
+  br label %extra
+
+extra:
+  br label %extra2
+
+extra2:
   br label %cond.end
 
 cond.end:                                         ; preds = %cond.false, %cond.true
-  %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %cond.false ]
+  %cond = phi i64 [ %conv2, %cond.true ], [ %call3, %extra ]
   ret i64 %cond
 }
 
@@ -657,8 +663,8 @@ declare void @llvm.trap()
   EXPECT_NE(CB, nullptr);
 
   FunctionPropertiesInfo ExpectedInitial;
-  ExpectedInitial.BasicBlockCount = 4;
-  ExpectedInitial.TotalInstructionCount = 7;
+  ExpectedInitial.BasicBlockCount = 6;
+  ExpectedInitial.TotalInstructionCount = 9;
   ExpectedInitial.BlocksReachedFromConditionalInstruction = 2;
   ExpectedInitial.Uses = 1;
   ExpectedInitial.DirectCallsToDefinedFunctions = 1;
@@ -680,4 +686,63 @@ declare void @llvm.trap()
   EXPECT_EQ(FPI, ExpectedFinal);
 }
 
+TEST_F(FunctionPropertiesAnalysisTest, InvokeSkipLP) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = makeLLVMModule(C,
+                                             R"IR(
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+define i64 @f1(i32 noundef %value) {
+entry:
+  invoke fastcc void @f2() to label %cont unwind label %lpad
+cont:
+  ret i64 1
+lpad:
+  %lp = landingpad i32 cleanup
+  br label %ehcleanup
+ehcleanup:
+  resume i32 0
+}
+define void @f2() {
+  invoke noundef void @f3() to label %exit unwind label %lpad
+exit:
+  ret void
+lpad:
+  %lp = landingpad i32 cleanup
+  resume i32 %lp
+}
+declare void @f3()
+)IR");
+
+  // The outcome of inlining will be that lpad becomes unreachable. The landing
+  // pad of the invoke inherited from f2 will land on a new bb which will branch
+  // to a bb containing the body of lpad.
+  Function *F1 = M->getFunction("f1");
+  CallBase *CB = findCall(*F1);
+  EXPECT_NE(CB, nullptr);
+
+  FunctionPropertiesInfo ExpectedInitial;
+  ExpectedInitial.BasicBlockCount = 4;
+  ExpectedInitial.TotalInstructionCount = 5;
+  ExpectedInitial.BlocksReachedFromConditionalInstruction = 0;
+  ExpectedInitial.Uses = 1;
+  ExpectedInitial.DirectCallsToDefinedFunctions = 1;
+
+  FunctionPropertiesInfo ExpectedFinal = ExpectedInitial;
+  ExpectedFinal.BasicBlockCount = 6;
+  ExpectedFinal.DirectCallsToDefinedFunctions = 0;
+  ExpectedFinal.TotalInstructionCount = 8;
+
+  auto FPI = buildFPI(*F1);
+  EXPECT_EQ(FPI, ExpectedInitial);
+
+  FunctionPropertiesUpdater FPU(FPI, *CB);
+  InlineFunctionInfo IFI;
+  auto IR = llvm::InlineFunction(*CB, IFI);
+  EXPECT_TRUE(IR.isSuccess());
+  invalidate(*F1);
+  FPU.finish(FAM);
+  EXPECT_EQ(FPI, ExpectedFinal);
+}
 } // end anonymous namespace


        


More information about the llvm-commits mailing list