[llvm] 950487b - [Pseudo Probe] Do not instrument EH blocks.

Hongtao Yu via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 30 13:27:05 PST 2023


Author: Hongtao Yu
Date: 2023-01-30T13:26:56-08:00
New Revision: 950487bddf1922c87559339a24cf5a77ad59c363

URL: https://github.com/llvm/llvm-project/commit/950487bddf1922c87559339a24cf5a77ad59c363
DIFF: https://github.com/llvm/llvm-project/commit/950487bddf1922c87559339a24cf5a77ad59c363.diff

LOG: [Pseudo Probe] Do not instrument EH blocks.

This change avoids inserting probes to EH blocks. Pseudo probe can prevent block merging when probes in the blocks look different. This has a chained effect to passes incurring exponential IR growth (such as jump threading) and as a consequence the compilation may time out.  Not inserting probes to EH blocks could mitigate the issue. Another benefit is that both IR size and binary size are smaller. Since EH blocks are usually cold, the change should have minimal impact to profile quality.

Testing:

Out of two internal large benchmarks, no perf impact seen. 1% size savings to both the `text` and the `pseudo_probe` section.

Reviewed By: wenlei

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

Added: 
    llvm/include/llvm/Analysis/EHUtils.h
    llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll

Modified: 
    llvm/include/llvm/CodeGen/MachineBasicBlock.h
    llvm/include/llvm/CodeGen/MachineSSAContext.h
    llvm/lib/CodeGen/MachineFunctionSplitter.cpp
    llvm/lib/Transforms/IPO/SampleProfileProbe.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/EHUtils.h b/llvm/include/llvm/Analysis/EHUtils.h
new file mode 100644
index 0000000000000..728ab53c89bcf
--- /dev/null
+++ b/llvm/include/llvm/Analysis/EHUtils.h
@@ -0,0 +1,90 @@
+//===-- Analysis/EHUtils.h - Exception handling related utils --*-//C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+
+#ifndef LLVM_ANALYSIS_EHUTILS_H
+#define LLVM_ANALYSIS_EHUTILS_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace llvm {
+
+/// Compute a list of blocks that are only reachable via EH paths.
+template <typename FunctionT, typename BlockT>
+static void computeEHOnlyBlocks(FunctionT &F, DenseSet<BlockT *> &EHBlocks) {
+  // A block can be unknown if its not reachable from anywhere
+  // EH if its only reachable from start blocks via some path through EH pads
+  // NonEH if it's reachable from Non EH blocks as well.
+  enum Status { Unknown = 0, EH = 1, NonEH = 2 };
+  DenseSet<BlockT *> WorkList;
+  DenseMap<BlockT *, Status> Statuses;
+
+  auto GetStatus = [&](BlockT *BB) {
+    if (Statuses.find(BB) != Statuses.end())
+      return Statuses[BB];
+    else
+      return Unknown;
+  };
+
+  auto CheckPredecessors = [&](BlockT *BB, Status Stat) {
+    for (auto *PredBB : predecessors(BB)) {
+      Status PredStatus = GetStatus(PredBB);
+      // If status of predecessor block has gone above current block
+      // we update current blocks status.
+      if (PredStatus > Stat)
+        Stat = PredStatus;
+    }
+    return Stat;
+  };
+
+  auto AddSuccesors = [&](BlockT *BB) {
+    for (auto *SuccBB : successors(BB)) {
+      if (!SuccBB->isEHPad())
+        WorkList.insert(SuccBB);
+    }
+  };
+
+  // Insert the successors of start block and landing pads successor.
+  BlockT *StartBlock = &F.front();
+  Statuses[StartBlock] = NonEH;
+  AddSuccesors(StartBlock);
+
+  for (auto &BB : F) {
+    if (BB.isEHPad()) {
+      AddSuccesors(&BB);
+      Statuses[&BB] = EH;
+    }
+  }
+
+  // Worklist iterative algorithm.
+  while (!WorkList.empty()) {
+    auto *BB = *WorkList.begin();
+    WorkList.erase(BB);
+
+    Status OldStatus = GetStatus(BB);
+
+    // Check on predecessors and check for
+    // Status update.
+    Status NewStatus = CheckPredecessors(BB, OldStatus);
+
+    // Did the block status change?
+    bool Changed = OldStatus != NewStatus;
+    if (Changed) {
+      AddSuccesors(BB);
+      Statuses[BB] = NewStatus;
+    }
+  }
+
+  EHBlocks.clear();
+  for (auto Entry : Statuses) {
+    if (Entry.second == EH)
+      EHBlocks.insert(Entry.first);
+  }
+}
+} // namespace llvm
+
+#endif

diff  --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 1ab24b554f5b5..127793c4bcc5d 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -1261,6 +1261,12 @@ template <> struct GraphTraits<Inverse<const MachineBasicBlock*>> {
   static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
 };
 
+// These accessors are handy for sharing templated code between IR and MIR.
+inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
+inline auto predecessors(const MachineBasicBlock *BB) {
+  return BB->predecessors();
+}
+
 /// MachineInstrSpan provides an interface to get an iteration range
 /// containing the instruction it was initialized with, along with all
 /// those instructions inserted prior to or following that instruction

diff  --git a/llvm/include/llvm/CodeGen/MachineSSAContext.h b/llvm/include/llvm/CodeGen/MachineSSAContext.h
index e3b2dc4598810..31a192cd8d290 100644
--- a/llvm/include/llvm/CodeGen/MachineSSAContext.h
+++ b/llvm/include/llvm/CodeGen/MachineSSAContext.h
@@ -26,10 +26,6 @@ class Register;
 template <typename _FunctionT> class GenericSSAContext;
 template <typename, bool> class DominatorTreeBase;
 
-inline auto successors(const MachineBasicBlock *BB) { return BB->successors(); }
-inline auto predecessors(const MachineBasicBlock *BB) {
-  return BB->predecessors();
-}
 inline unsigned succ_size(const MachineBasicBlock *BB) {
   return BB->succ_size();
 }

diff  --git a/llvm/lib/CodeGen/MachineFunctionSplitter.cpp b/llvm/lib/CodeGen/MachineFunctionSplitter.cpp
index 613c52900331e..1b939a518f168 100644
--- a/llvm/lib/CodeGen/MachineFunctionSplitter.cpp
+++ b/llvm/lib/CodeGen/MachineFunctionSplitter.cpp
@@ -24,6 +24,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/EHUtils.h"
 #include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/CodeGen/BasicBlockSectionUtils.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
@@ -83,75 +84,13 @@ class MachineFunctionSplitter : public MachineFunctionPass {
 } // end anonymous namespace
 
 /// setDescendantEHBlocksCold - This splits all EH pads and blocks reachable
-/// only by EH pad as cold. This will help mark EH pads statically cold instead
-/// of relying on profile data.
-static void
-setDescendantEHBlocksCold(SmallVectorImpl<MachineBasicBlock *> &EHBlocks,
-                          MachineFunction &MF) {
-  MachineBasicBlock *StartBlock = &MF.front();
-  // A block can be unknown if its not reachable from anywhere
-  // EH if its only reachable from start blocks via some path through EH pads
-  // NonEH if it's reachable from Non EH blocks as well.
-  enum Status { Unknown = 0, EH = 1, NonEH = 2 };
-  DenseSet<MachineBasicBlock *> WorkList;
-  DenseMap<MachineBasicBlock *, Status> Statuses;
-
-  auto getStatus = [&](MachineBasicBlock *MBB) {
-    if (Statuses.find(MBB) != Statuses.end())
-      return Statuses[MBB];
-    else
-      return Unknown;
-  };
-
-  auto checkPredecessors = [&](MachineBasicBlock *MBB, Status Stat) {
-    for (auto *PredMBB : MBB->predecessors()) {
-      Status PredStatus = getStatus(PredMBB);
-      // If status of predecessor block has gone above current block
-      // we update current blocks status.
-      if (PredStatus > Stat)
-        Stat = PredStatus;
-    }
-    return Stat;
-  };
-
-  auto addSuccesors = [&](MachineBasicBlock *MBB) {
-    for (auto *SuccMBB : MBB->successors()) {
-      if (!SuccMBB->isEHPad())
-        WorkList.insert(SuccMBB);
-    }
-  };
-
-  // Insert the successors of start block
-  // and landing pads successor.
-  Statuses[StartBlock] = NonEH;
-  addSuccesors(StartBlock);
-  for (auto *LP : EHBlocks) {
-    addSuccesors(LP);
-    Statuses[LP] = EH;
-  }
-
-  // Worklist iterative algorithm.
-  while (!WorkList.empty()) {
-    auto *MBB = *WorkList.begin();
-    WorkList.erase(MBB);
-
-    Status OldStatus = getStatus(MBB);
-
-    // Check on predecessors and check for
-    // Status update.
-    Status NewStatus = checkPredecessors(MBB, OldStatus);
-
-    // Did the block status change?
-    bool changed = OldStatus != NewStatus;
-    if (changed) {
-      addSuccesors(MBB);
-      Statuses[MBB] = NewStatus;
-    }
-  }
-
-  for (auto Entry : Statuses) {
-    if (Entry.second == EH)
-      Entry.first->setSectionID(MBBSectionID::ColdSectionID);
+/// only by EH pad as cold. This will help mark EH pads statically cold
+/// instead of relying on profile data.
+static void setDescendantEHBlocksCold(MachineFunction &MF) {
+  DenseSet<MachineBasicBlock *> EHBlocks;
+  computeEHOnlyBlocks(MF, EHBlocks);
+  for (auto Block : EHBlocks) {
+    Block->setSectionID(MBBSectionID::ColdSectionID);
   }
 }
 
@@ -219,7 +158,7 @@ bool MachineFunctionSplitter::runOnMachineFunction(MachineFunction &MF) {
 
   // Split all EH code and it's descendant statically by default.
   if (SplitAllEHCode)
-    setDescendantEHBlocksCold(LandingPads, MF);
+    setDescendantEHBlocksCold(MF);
   // We only split out eh pads if all of them are cold.
   else {
     bool HasHotLandingPads = false;

diff  --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
index c4844dbe7f3c9..a819bd9fb6e03 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Transforms/IPO/SampleProfileProbe.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/Analysis/EHUtils.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constants.h"
@@ -32,7 +33,7 @@
 #include <vector>
 
 using namespace llvm;
-#define DEBUG_TYPE "sample-profile-probe"
+#define DEBUG_TYPE "pseudo-probe"
 
 STATISTIC(ArtificialDbgLine,
           "Number of probes that have an artificial debug line");
@@ -253,8 +254,14 @@ void SampleProfileProber::computeCFGHash() {
 }
 
 void SampleProfileProber::computeProbeIdForBlocks() {
+  DenseSet<BasicBlock *> KnownColdBlocks;
+  computeEHOnlyBlocks(*F, KnownColdBlocks);
+  // Insert pseudo probe to non-cold blocks only. This will reduce IR size as
+  // well as the binary size while retaining the profile quality.
   for (auto &BB : *F) {
-    BlockProbeIds[&BB] = ++LastProbeId;
+    ++LastProbeId;
+    if (!KnownColdBlocks.contains(&BB))
+      BlockProbeIds[&BB] = LastProbeId;
   }
 }
 

diff  --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll
new file mode 100644
index 0000000000000..697ef44fb7ed7
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll
@@ -0,0 +1,43 @@
+; REQUIRES: x86_64-linux
+; RUN: opt < %s -passes=pseudo-probe -function-sections -S -o - | FileCheck %s
+
+;; Check the generation of pseudoprobe intrinsic call for non-EH blocks only.
+
+declare i32 @__gxx_personality_v0(...)
+declare i32 @llvm.eh.typeid.for(ptr) nounwind
+declare ptr @__cxa_begin_catch(ptr)
+declare void @__cxa_end_catch()
+declare void @bar()
+
+ at _ZTIi = external constant ptr
+
+define void @foo() uwtable ssp personality ptr @__gxx_personality_v0 {
+entry:
+; CHECK: call void @llvm.pseudoprobe
+  invoke void @bar()
+          to label %ret unwind label %lpad
+
+ret:
+; CHECK: call void @llvm.pseudoprobe
+  ret void
+
+lpad:                                             ; preds = %entry
+; CHECK-NOT: call void @llvm.pseudoprobe
+  %exn = landingpad {ptr, i32}
+            catch ptr @_ZTIi
+  %eh.exc = extractvalue { ptr, i32 } %exn, 0
+  %eh.selector = extractvalue { ptr, i32 } %exn, 1
+  %0 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) nounwind
+  %1 = icmp eq i32 %eh.selector, %0
+  br i1 %1, label %catch, label %eh.resume
+
+catch:
+; CHECK-NOT: call void @llvm.pseudoprobe
+  %ignored = call ptr @__cxa_begin_catch(ptr %eh.exc) nounwind
+  call void @__cxa_end_catch() nounwind
+  br label %ret
+
+eh.resume:
+; CHECK-NOT: call void @llvm.pseudoprobe
+  resume { ptr, i32 } %exn
+}


        


More information about the llvm-commits mailing list