1616
1717#include " llvm/Transforms/Coroutines/CoroAnnotationElide.h"
1818
19+ #include " llvm/Analysis/CGSCCPassManager.h"
1920#include " llvm/Analysis/LazyCallGraph.h"
2021#include " llvm/Analysis/OptimizationRemarkEmitter.h"
2122#include " llvm/IR/Analysis.h"
@@ -40,10 +41,10 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
4041// Create an alloca in the caller, using FrameSize and FrameAlign as the callee
4142// coroutine's activation frame.
4243static Value *allocateFrameInCaller (Function *Caller, uint64_t FrameSize,
43- Align FrameAlign) {
44+ Align FrameAlign) {
4445 LLVMContext &C = Caller->getContext ();
4546 BasicBlock::iterator InsertPt =
46- getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
47+ getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
4748 const DataLayout &DL = Caller->getDataLayout ();
4849 auto FrameTy = ArrayType::get (Type::getInt8Ty (C), FrameSize);
4950 auto *Frame = new AllocaInst (FrameTy, DL.getAllocaAddrSpace (), " " , InsertPt);
@@ -57,7 +58,7 @@ static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
5758// - Replace the old CB with a new Call or Invoke to `NewCallee`, with the
5859// pointer to the frame as an additional argument to NewCallee.
5960static void processCall (CallBase *CB, Function *Caller, Function *NewCallee,
60- uint64_t FrameSize, Align FrameAlign) {
61+ uint64_t FrameSize, Align FrameAlign) {
6162 // TODO: generate the lifetime intrinsics for the new frame. This will require
6263 // introduction of two pesudo lifetime intrinsics in the frontend around the
6364 // `co_await` expression and convert them to real lifetime intrinsics here.
@@ -70,13 +71,13 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
7071
7172 if (auto *CI = dyn_cast<CallInst>(CB)) {
7273 auto *NewCI = CallInst::Create (NewCallee->getFunctionType (), NewCallee,
73- NewArgs, " " , NewCBInsertPt);
74+ NewArgs, " " , NewCBInsertPt);
7475 NewCI->setTailCallKind (CI->getTailCallKind ());
7576 NewCB = NewCI;
7677 } else if (auto *II = dyn_cast<InvokeInst>(CB)) {
7778 NewCB = InvokeInst::Create (NewCallee->getFunctionType (), NewCallee,
78- II->getNormalDest (), II->getUnwindDest (),
79- NewArgs, {}, " " , NewCBInsertPt);
79+ II->getNormalDest (), II->getUnwindDest (),
80+ NewArgs, {}, " " , NewCBInsertPt);
8081 } else {
8182 llvm_unreachable (" CallBase should either be Call or Invoke!" );
8283 }
@@ -86,65 +87,78 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
8687 NewCB->setAttributes (CB->getAttributes ());
8788 NewCB->setDebugLoc (CB->getDebugLoc ());
8889 std::copy (CB->bundle_op_info_begin (), CB->bundle_op_info_end (),
89- NewCB->bundle_op_info_begin ());
90+ NewCB->bundle_op_info_begin ());
9091
9192 NewCB->removeFnAttr (llvm::Attribute::CoroElideSafe);
9293 CB->replaceAllUsesWith (NewCB);
9394 CB->eraseFromParent ();
9495}
9596
96- PreservedAnalyses CoroAnnotationElidePass::run (Function &F,
97- FunctionAnalysisManager &FAM) {
97+ PreservedAnalyses CoroAnnotationElidePass::run (LazyCallGraph::SCC &C,
98+ CGSCCAnalysisManager &AM,
99+ LazyCallGraph &CG,
100+ CGSCCUpdateResult &UR) {
98101 bool Changed = false ;
102+ CallGraphUpdater CGUpdater;
103+ CGUpdater.initialize (CG, C, AM, UR);
99104
100- Function *NewCallee =
101- F. getParent ()-> getFunction ((F. getName () + " .noalloc " ). str () );
105+ auto &FAM =
106+ AM. getResult <FunctionAnalysisManagerCGSCCProxy>(C, CG). getManager ( );
102107
103- if (!NewCallee)
104- return PreservedAnalyses::all ();
105-
106- auto FramePtrArgPosition = NewCallee->arg_size () - 1 ;
107- auto FrameSize = NewCallee->getParamDereferenceableBytes (FramePtrArgPosition);
108- auto FrameAlign = NewCallee->getParamAlign (FramePtrArgPosition).valueOrOne ();
109-
110- SmallVector<CallBase *, 4 > Users;
111- for (auto *U : F.users ()) {
112- if (auto *CB = dyn_cast<CallBase>(U)) {
113- if (CB->getCalledFunction () == &F)
114- Users.push_back (CB);
115- }
116- }
117-
118- auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(F);
119-
120- for (auto *CB : Users) {
121- auto *Caller = CB->getFunction ();
122- if (!Caller)
108+ for (LazyCallGraph::Node &N : C) {
109+ Function *Callee = &N.getFunction ();
110+ Function *NewCallee = Callee->getParent ()->getFunction (
111+ (Callee->getName () + " .noalloc" ).str ());
112+ if (!NewCallee)
123113 continue ;
124114
125- bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine ();
126- bool HasAttr = CB->hasFnAttr (llvm::Attribute::CoroElideSafe);
127- if (IsCallerPresplitCoroutine && HasAttr) {
128- processCall (CB, Caller, NewCallee, FrameSize, FrameAlign);
129-
130- ORE.emit ([&]() {
131- return OptimizationRemark (DEBUG_TYPE, " CoroAnnotationElide" , Caller)
132- << " '" << ore::NV (" callee" , F.getName ()) << " ' elided in '"
133- << ore::NV (" caller" , Caller->getName ()) << " '" ;
134- });
135-
136- FAM.invalidate (*Caller, PreservedAnalyses::none ());
137- Changed = true ;
138- } else {
139- ORE.emit ([&]() {
140- return OptimizationRemarkMissed (DEBUG_TYPE, " CoroAnnotationElide" ,
141- Caller)
142- << " '" << ore::NV (" callee" , F.getName ()) << " ' not elided in '"
143- << ore::NV (" caller" , Caller->getName ()) << " ' (caller_presplit="
144- << ore::NV (" caller_presplit" , IsCallerPresplitCoroutine)
145- << " , elide_safe_attr=" << ore::NV (" elide_safe_attr" , HasAttr)
146- << " )" ;
147- });
115+ SmallVector<CallBase *, 4 > Users;
116+ for (auto *U : Callee->users ()) {
117+ if (auto *CB = dyn_cast<CallBase>(U)) {
118+ if (CB->getCalledFunction () == Callee)
119+ Users.push_back (CB);
120+ }
121+ }
122+ auto FramePtrArgPosition = NewCallee->arg_size () - 1 ;
123+ auto FrameSize = NewCallee->getParamDereferenceableBytes (FramePtrArgPosition);
124+ auto FrameAlign = NewCallee->getParamAlign (FramePtrArgPosition).valueOrOne ();
125+
126+ auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(*Callee);
127+
128+ for (auto *CB : Users) {
129+ auto *Caller = CB->getFunction ();
130+ if (!Caller)
131+ continue ;
132+
133+ bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine ();
134+ bool HasAttr = CB->hasFnAttr (llvm::Attribute::CoroElideSafe);
135+ if (IsCallerPresplitCoroutine && HasAttr) {
136+ auto *CallerN = CG.lookup (*Caller);
137+ auto *CallerC = CG.lookupSCC (*CallerN);
138+ processCall (CB, Caller, NewCallee, FrameSize, FrameAlign);
139+
140+ ORE.emit ([&]() {
141+ return OptimizationRemark (DEBUG_TYPE, " CoroAnnotationElide" , Caller)
142+ << " '" << ore::NV (" callee" , Callee->getName ()) << " ' elided in '"
143+ << ore::NV (" caller" , Caller->getName ()) << " '" ;
144+ });
145+
146+ FAM.invalidate (*Caller, PreservedAnalyses::none ());
147+ Changed = true ;
148+ updateCGAndAnalysisManagerForCGSCCPass (CG, *CallerC, *CallerN, AM, UR,
149+ FAM);
150+
151+ } else {
152+ ORE.emit ([&]() {
153+ return OptimizationRemarkMissed (DEBUG_TYPE, " CoroAnnotationElide" ,
154+ Caller)
155+ << " '" << ore::NV (" callee" , Callee->getName ()) << " ' not elided in '"
156+ << ore::NV (" caller" , Caller->getName ()) << " ' (caller_presplit="
157+ << ore::NV (" caller_presplit" , IsCallerPresplitCoroutine)
158+ << " , elide_safe_attr=" << ore::NV (" elide_safe_attr" , HasAttr)
159+ << " )" ;
160+ });
161+ }
148162 }
149163 }
150164
0 commit comments