2424#include " llvm/IR/Instruction.h"
2525#include " llvm/IR/Module.h"
2626#include " llvm/IR/PassManager.h"
27+ #include " llvm/Support/BranchProbability.h"
28+ #include " llvm/Support/CommandLine.h"
29+ #include " llvm/Support/FileSystem.h"
2730#include " llvm/Transforms/Utils/CallGraphUpdater.h"
2831#include " llvm/Transforms/Utils/Cloning.h"
2932
@@ -33,6 +36,49 @@ using namespace llvm;
3336
3437#define DEBUG_TYPE " coro-annotation-elide"
3538
39+ static cl::opt<float > CoroElideBranchRatio (
40+ " coro-elide-branch-ratio" , cl::init(0.55 ), cl::Hidden,
41+ cl::desc(" Minimum BranchProbability to consider a elide a coroutine." ));
42+ extern cl::opt<unsigned > MinBlockCounterExecution;
43+
44+ static cl::opt<bool >
45+ PrintElidedCoroutine (" print-elided-coroutine-stats" , cl::init(false ),
46+ cl::Hidden,
47+ cl::desc(" Print stats for elided coroutine" ));
48+
49+ static cl::opt<std::string>
50+ ElideStatOutput (" coro-elide-stat-output" , cl::init(" " ), cl::Hidden,
51+ cl::desc(" Output file for -print-elided-coroutine-stats. "
52+ " Defaults to standard error output." ));
53+
54+ // The return value is used to indicate the owner of the resources. The users
55+ // should use the output parameter.
56+ static std::unique_ptr<llvm::raw_ostream>
57+ getCoroElidedStatsOStream (llvm::raw_ostream *&OS) {
58+ if (!PrintElidedCoroutine) {
59+ OS = &llvm::nulls ();
60+ return nullptr ;
61+ }
62+
63+ if (ElideStatOutput.empty ()) {
64+ OS = &llvm::errs ();
65+ return nullptr ;
66+ }
67+
68+ std::error_code EC;
69+ auto ret = std::make_unique<llvm::raw_fd_ostream>(ElideStatOutput, EC,
70+ sys::fs::OF_Append);
71+
72+ if (EC) {
73+ llvm::errs () << " llvm cannot open file: " << EC.message () << " \n " ;
74+ OS = &llvm::nulls ();
75+ return nullptr ;
76+ }
77+
78+ OS = ret.get ();
79+ return ret;
80+ }
81+
3682static Instruction *getFirstNonAllocaInTheEntryBlock (Function *F) {
3783 for (Instruction &I : F->getEntryBlock ())
3884 if (!isa<AllocaInst>(&I))
@@ -145,6 +191,37 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
145191 bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine ();
146192 bool HasAttr = CB->hasFnAttr (llvm::Attribute::CoroElideSafe);
147193 if (IsCallerPresplitCoroutine && HasAttr) {
194+
195+ llvm::raw_ostream *OS = nullptr ;
196+ auto _ = getCoroElidedStatsOStream (OS);
197+ assert (OS && " At least we should able to get access to standard error" );
198+
199+ auto &BFI = FAM.getResult <BlockFrequencyAnalysis>(*Caller);
200+ if (BFI.getBlockFreq (CB->getParent ()) <
201+ BFI.getEntryFreq ()) {
202+ static BranchProbability MinBranchProbability (
203+ static_cast <int >(CoroElideBranchRatio * MinBlockCounterExecution),
204+ MinBlockCounterExecution);
205+
206+ auto Prob = BranchProbability::getBranchProbability (
207+ BFI.getBlockFreq (CB->getParent ()).getFrequency (),
208+ BFI.getEntryFreq ().getFrequency ());
209+
210+ if (Prob < MinBranchProbability) {
211+ *OS << " Not eliding " << *CB
212+ << " with estimated probability: " << Prob << " \n " ;
213+ continue ;
214+ }
215+
216+ *OS << " BB Prob: \t " << Prob << " \n " ;
217+ } else {
218+ *OS << " BB Freq: \t "
219+ << BFI.getBlockFreq (CB->getParent ()).getFrequency () << " \n " ;
220+ *OS << " Entry Freq: \t " << BFI.getEntryFreq ().getFrequency () << " \n " ;
221+ }
222+
223+ *OS << " eliding " << *CB << " \n " ;
224+
148225 auto *CallerN = CG.lookup (*Caller);
149226 auto *CallerC = CallerN ? CG.lookupSCC (*CallerN) : nullptr ;
150227 // If CallerC is nullptr, it means LazyCallGraph hasn't visited Caller
0 commit comments