diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h --- a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h +++ b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h @@ -110,6 +110,7 @@ void computeCFGHash(); void computeProbeIdForBlocks(); void computeProbeIdForCallsites(); + void computeEHOnlyBlocks(DenseSet &Blocks); Function *F; diff --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp --- a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/SampleProfileProbe.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/LoopInfo.h" @@ -28,11 +29,12 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include #include #include 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"); @@ -252,9 +254,51 @@ << ", Hash = " << FunctionHash << "\n"); } +// Compute a list of blocks that are only reachable via EH paths. +void SampleProfileProber::computeEHOnlyBlocks( + DenseSet &EHBlocks) { + std::queue Worklist; + for (auto &BB : *F) { + if (BB.isEHPad() || BB.isLandingPad()) { + Worklist.push(&BB); + EHBlocks.insert(&BB); + } + } + + // Propagate EH-ness to successor blocks. + while (!Worklist.empty()) { + BasicBlock* BB = Worklist.front(); + Worklist.pop(); + for (auto *Successor : successors(BB)) { + if (EHBlocks.contains(Successor)) + continue; + + bool HasNonEHPred = false; + for (auto *Predecessor : predecessors(Successor)) { + if (Predecessor == Successor) + continue; + if (!EHBlocks.contains(Predecessor)) { + HasNonEHPred = true; + break; + } + } + if (!HasNonEHPred) { + Worklist.push(Successor); + EHBlocks.insert(Successor); + } + } + } +} + void SampleProfileProber::computeProbeIdForBlocks() { + DenseSet EHBlocks; + computeEHOnlyBlocks(EHBlocks); + // Insert pseudo probe to non-EH blocks only. This will reduce IR size as well + // as the binary size while retaining the profile quality since EH paths are + // usually cold paths. for (auto &BB : *F) { - BlockProbeIds[&BB] = ++LastProbeId; + if (!EHBlocks.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 --- /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() + +@_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 +}