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