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"
@@ -42,10 +43,10 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
4243// Create an alloca in the caller, using FrameSize and FrameAlign as the callee
4344// coroutine's activation frame.
4445static Value *allocateFrameInCaller (Function *Caller, uint64_t FrameSize,
45- Align FrameAlign) {
46+ Align FrameAlign) {
4647 LLVMContext &C = Caller->getContext ();
4748 BasicBlock::iterator InsertPt =
48- getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
49+ getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
4950 const DataLayout &DL = Caller->getDataLayout ();
5051 auto FrameTy = ArrayType::get (Type::getInt8Ty (C), FrameSize);
5152 auto *Frame = new AllocaInst (FrameTy, DL.getAllocaAddrSpace (), " " , InsertPt);
@@ -59,7 +60,7 @@ static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
5960// - Replace the old CB with a new Call or Invoke to `NewCallee`, with the
6061// pointer to the frame as an additional argument to NewCallee.
6162static void processCall (CallBase *CB, Function *Caller, Function *NewCallee,
62- uint64_t FrameSize, Align FrameAlign) {
63+ uint64_t FrameSize, Align FrameAlign) {
6364 // TODO: generate the lifetime intrinsics for the new frame. This will require
6465 // introduction of two pesudo lifetime intrinsics in the frontend around the
6566 // `co_await` expression and convert them to real lifetime intrinsics here.
@@ -72,13 +73,13 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
7273
7374 if (auto *CI = dyn_cast<CallInst>(CB)) {
7475 auto *NewCI = CallInst::Create (NewCallee->getFunctionType (), NewCallee,
75- NewArgs, " " , NewCBInsertPt);
76+ NewArgs, " " , NewCBInsertPt);
7677 NewCI->setTailCallKind (CI->getTailCallKind ());
7778 NewCB = NewCI;
7879 } else if (auto *II = dyn_cast<InvokeInst>(CB)) {
7980 NewCB = InvokeInst::Create (NewCallee->getFunctionType (), NewCallee,
80- II->getNormalDest (), II->getUnwindDest (),
81- NewArgs, {}, " " , NewCBInsertPt);
81+ II->getNormalDest (), II->getUnwindDest (),
82+ NewArgs, {}, " " , NewCBInsertPt);
8283 } else {
8384 llvm_unreachable (" CallBase should either be Call or Invoke!" );
8485 }
@@ -88,65 +89,78 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
8889 NewCB->setAttributes (CB->getAttributes ());
8990 NewCB->setDebugLoc (CB->getDebugLoc ());
9091 std::copy (CB->bundle_op_info_begin (), CB->bundle_op_info_end (),
91- NewCB->bundle_op_info_begin ());
92+ NewCB->bundle_op_info_begin ());
9293
9394 NewCB->removeFnAttr (llvm::Attribute::CoroElideSafe);
9495 CB->replaceAllUsesWith (NewCB);
9596 CB->eraseFromParent ();
9697}
9798
98- PreservedAnalyses CoroAnnotationElidePass::run (Function &F,
99- FunctionAnalysisManager &FAM) {
99+ PreservedAnalyses CoroAnnotationElidePass::run (LazyCallGraph::SCC &C,
100+ CGSCCAnalysisManager &AM,
101+ LazyCallGraph &CG,
102+ CGSCCUpdateResult &UR) {
100103 bool Changed = false ;
104+ CallGraphUpdater CGUpdater;
105+ CGUpdater.initialize (CG, C, AM, UR);
101106
102- Function *NewCallee =
103- F. getParent ()-> getFunction ((F. getName () + " .noalloc " ). str () );
107+ auto &FAM =
108+ AM. getResult <FunctionAnalysisManagerCGSCCProxy>(C, CG). getManager ( );
104109
105- if (!NewCallee)
106- return PreservedAnalyses::all ();
107-
108- auto FramePtrArgPosition = NewCallee->arg_size () - 1 ;
109- auto FrameSize = NewCallee->getParamDereferenceableBytes (FramePtrArgPosition);
110- auto FrameAlign = NewCallee->getParamAlign (FramePtrArgPosition).valueOrOne ();
111-
112- SmallVector<CallBase *, 4 > Users;
113- for (auto *U : F.users ()) {
114- if (auto *CB = dyn_cast<CallBase>(U)) {
115- if (CB->getCalledFunction () == &F)
116- Users.push_back (CB);
117- }
118- }
119-
120- auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(F);
121-
122- for (auto *CB : Users) {
123- auto *Caller = CB->getFunction ();
124- if (!Caller)
110+ for (LazyCallGraph::Node &N : C) {
111+ Function *Callee = &N.getFunction ();
112+ Function *NewCallee = Callee->getParent ()->getFunction (
113+ (Callee->getName () + " .noalloc" ).str ());
114+ if (!NewCallee)
125115 continue ;
126116
127- bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine ();
128- bool HasAttr = CB->hasFnAttr (llvm::Attribute::CoroElideSafe);
129- if (IsCallerPresplitCoroutine && HasAttr) {
130- processCall (CB, Caller, NewCallee, FrameSize, FrameAlign);
131-
132- ORE.emit ([&]() {
133- return OptimizationRemark (DEBUG_TYPE, " CoroAnnotationElide" , Caller)
134- << " '" << ore::NV (" callee" , F.getName ()) << " ' elided in '"
135- << ore::NV (" caller" , Caller->getName ()) << " '" ;
136- });
137-
138- FAM.invalidate (*Caller, PreservedAnalyses::none ());
139- Changed = true ;
140- } else {
141- ORE.emit ([&]() {
142- return OptimizationRemarkMissed (DEBUG_TYPE, " CoroAnnotationElide" ,
143- Caller)
144- << " '" << ore::NV (" callee" , F.getName ()) << " ' not elided in '"
145- << ore::NV (" caller" , Caller->getName ()) << " ' (caller_presplit="
146- << ore::NV (" caller_presplit" , IsCallerPresplitCoroutine)
147- << " , elide_safe_attr=" << ore::NV (" elide_safe_attr" , HasAttr)
148- << " )" ;
149- });
117+ SmallVector<CallBase *, 4 > Users;
118+ for (auto *U : Callee->users ()) {
119+ if (auto *CB = dyn_cast<CallBase>(U)) {
120+ if (CB->getCalledFunction () == Callee)
121+ Users.push_back (CB);
122+ }
123+ }
124+ auto FramePtrArgPosition = NewCallee->arg_size () - 1 ;
125+ auto FrameSize = NewCallee->getParamDereferenceableBytes (FramePtrArgPosition);
126+ auto FrameAlign = NewCallee->getParamAlign (FramePtrArgPosition).valueOrOne ();
127+
128+ auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(*Callee);
129+
130+ for (auto *CB : Users) {
131+ auto *Caller = CB->getFunction ();
132+ if (!Caller)
133+ continue ;
134+
135+ bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine ();
136+ bool HasAttr = CB->hasFnAttr (llvm::Attribute::CoroElideSafe);
137+ if (IsCallerPresplitCoroutine && HasAttr) {
138+ auto *CallerN = CG.lookup (*Caller);
139+ auto *CallerC = CG.lookupSCC (*CallerN);
140+ processCall (CB, Caller, NewCallee, FrameSize, FrameAlign);
141+
142+ ORE.emit ([&]() {
143+ return OptimizationRemark (DEBUG_TYPE, " CoroAnnotationElide" , Caller)
144+ << " '" << ore::NV (" callee" , Callee->getName ()) << " ' elided in '"
145+ << ore::NV (" caller" , Caller->getName ()) << " '" ;
146+ });
147+
148+ FAM.invalidate (*Caller, PreservedAnalyses::none ());
149+ Changed = true ;
150+ updateCGAndAnalysisManagerForCGSCCPass (CG, *CallerC, *CallerN, AM, UR,
151+ FAM);
152+
153+ } else {
154+ ORE.emit ([&]() {
155+ return OptimizationRemarkMissed (DEBUG_TYPE, " CoroAnnotationElide" ,
156+ Caller)
157+ << " '" << ore::NV (" callee" , Callee->getName ()) << " ' not elided in '"
158+ << ore::NV (" caller" , Caller->getName ()) << " ' (caller_presplit="
159+ << ore::NV (" caller_presplit" , IsCallerPresplitCoroutine)
160+ << " , elide_safe_attr=" << ore::NV (" elide_safe_attr" , HasAttr)
161+ << " )" ;
162+ });
163+ }
150164 }
151165 }
152166
0 commit comments