16
16
17
17
#include " llvm/Transforms/Coroutines/CoroAnnotationElide.h"
18
18
19
+ #include " llvm/Analysis/CGSCCPassManager.h"
19
20
#include " llvm/Analysis/LazyCallGraph.h"
20
21
#include " llvm/Analysis/OptimizationRemarkEmitter.h"
21
22
#include " llvm/IR/Analysis.h"
@@ -40,10 +41,10 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
40
41
// Create an alloca in the caller, using FrameSize and FrameAlign as the callee
41
42
// coroutine's activation frame.
42
43
static Value *allocateFrameInCaller (Function *Caller, uint64_t FrameSize,
43
- Align FrameAlign) {
44
+ Align FrameAlign) {
44
45
LLVMContext &C = Caller->getContext ();
45
46
BasicBlock::iterator InsertPt =
46
- getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
47
+ getFirstNonAllocaInTheEntryBlock (Caller)->getIterator ();
47
48
const DataLayout &DL = Caller->getDataLayout ();
48
49
auto FrameTy = ArrayType::get (Type::getInt8Ty (C), FrameSize);
49
50
auto *Frame = new AllocaInst (FrameTy, DL.getAllocaAddrSpace (), " " , InsertPt);
@@ -57,7 +58,7 @@ static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
57
58
// - Replace the old CB with a new Call or Invoke to `NewCallee`, with the
58
59
// pointer to the frame as an additional argument to NewCallee.
59
60
static void processCall (CallBase *CB, Function *Caller, Function *NewCallee,
60
- uint64_t FrameSize, Align FrameAlign) {
61
+ uint64_t FrameSize, Align FrameAlign) {
61
62
// TODO: generate the lifetime intrinsics for the new frame. This will require
62
63
// introduction of two pesudo lifetime intrinsics in the frontend around the
63
64
// `co_await` expression and convert them to real lifetime intrinsics here.
@@ -70,13 +71,13 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
70
71
71
72
if (auto *CI = dyn_cast<CallInst>(CB)) {
72
73
auto *NewCI = CallInst::Create (NewCallee->getFunctionType (), NewCallee,
73
- NewArgs, " " , NewCBInsertPt);
74
+ NewArgs, " " , NewCBInsertPt);
74
75
NewCI->setTailCallKind (CI->getTailCallKind ());
75
76
NewCB = NewCI;
76
77
} else if (auto *II = dyn_cast<InvokeInst>(CB)) {
77
78
NewCB = InvokeInst::Create (NewCallee->getFunctionType (), NewCallee,
78
- II->getNormalDest (), II->getUnwindDest (),
79
- NewArgs, {}, " " , NewCBInsertPt);
79
+ II->getNormalDest (), II->getUnwindDest (),
80
+ NewArgs, {}, " " , NewCBInsertPt);
80
81
} else {
81
82
llvm_unreachable (" CallBase should either be Call or Invoke!" );
82
83
}
@@ -86,65 +87,78 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
86
87
NewCB->setAttributes (CB->getAttributes ());
87
88
NewCB->setDebugLoc (CB->getDebugLoc ());
88
89
std::copy (CB->bundle_op_info_begin (), CB->bundle_op_info_end (),
89
- NewCB->bundle_op_info_begin ());
90
+ NewCB->bundle_op_info_begin ());
90
91
91
92
NewCB->removeFnAttr (llvm::Attribute::CoroElideSafe);
92
93
CB->replaceAllUsesWith (NewCB);
93
94
CB->eraseFromParent ();
94
95
}
95
96
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) {
98
101
bool Changed = false ;
102
+ CallGraphUpdater CGUpdater;
103
+ CGUpdater.initialize (CG, C, AM, UR);
99
104
100
- Function *NewCallee =
101
- F. getParent ()-> getFunction ((F. getName () + " .noalloc " ). str () );
105
+ auto &FAM =
106
+ AM. getResult <FunctionAnalysisManagerCGSCCProxy>(C, CG). getManager ( );
102
107
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)
123
113
continue ;
124
114
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
+ }
148
162
}
149
163
}
150
164
0 commit comments