99#include " llvm/Transforms/Coroutines/CoroEarly.h"
1010#include " CoroInternal.h"
1111#include " llvm/IR/DIBuilder.h"
12+ #include " llvm/IR/Dominators.h"
1213#include " llvm/IR/Function.h"
1314#include " llvm/IR/IRBuilder.h"
1415#include " llvm/IR/InstIterator.h"
@@ -165,6 +166,7 @@ static void setCannotDuplicate(CoroIdInst *CoroId) {
165166
166167void Lowerer::lowerEarlyIntrinsics (Function &F) {
167168 CoroIdInst *CoroId = nullptr ;
169+ CoroBeginInst *CoroBegin = nullptr ;
168170 SmallVector<CoroFreeInst *, 4 > CoroFrees;
169171 bool HasCoroSuspend = false ;
170172 for (Instruction &I : llvm::make_early_inc_range (instructions (F))) {
@@ -175,6 +177,23 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
175177 switch (CB->getIntrinsicID ()) {
176178 default :
177179 continue ;
180+ case Intrinsic::coro_begin:
181+ case Intrinsic::coro_begin_custom_abi: {
182+ auto CBI = cast<CoroBeginInst>(&I);
183+
184+ // Ignore coro id's that aren't pre-split.
185+ auto Id = dyn_cast<CoroIdInst>(CBI->getId ());
186+ if (Id && !Id->getInfo ().isPreSplit ())
187+ break ;
188+
189+ if (CoroBegin)
190+ report_fatal_error (
191+ " coroutine should have exactly one defining @llvm.coro.begin" );
192+ CBI->addRetAttr (Attribute::NonNull);
193+ CBI->addRetAttr (Attribute::NoAlias);
194+ CoroBegin = CBI;
195+ break ;
196+ }
178197 case Intrinsic::coro_free:
179198 CoroFrees.push_back (cast<CoroFreeInst>(&I));
180199 break ;
@@ -218,22 +237,44 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
218237 case Intrinsic::coro_destroy:
219238 lowerResumeOrDestroy (*CB, CoroSubFnInst::DestroyIndex);
220239 break ;
221- case Intrinsic::coro_promise:
222- lowerCoroPromise (cast<CoroPromiseInst>(&I));
240+ case Intrinsic::coro_promise: {
241+ bool OutsideCoro = CoroBegin == nullptr ;
242+ if (OutsideCoro)
243+ lowerCoroPromise (cast<CoroPromiseInst>(&I));
223244 break ;
245+ }
224246 case Intrinsic::coro_done:
225247 lowerCoroDone (cast<IntrinsicInst>(&I));
226248 break ;
227249 }
228250 }
229251
230- // Make sure that all CoroFree reference the coro.id intrinsic.
231- // Token type is not exposed through coroutine C/C++ builtins to plain C, so
232- // we allow specifying none and fixing it up here.
233- if (CoroId)
252+ if (CoroId) {
253+ // Make sure that all CoroFree reference the coro.id intrinsic.
254+ // Token type is not exposed through coroutine C/C++ builtins to plain C, so
255+ // we allow specifying none and fixing it up here.
234256 for (CoroFreeInst *CF : CoroFrees)
235257 CF->setArgOperand (0 , CoroId);
236258
259+ if (auto *PA = CoroId->getPromise ()) {
260+ assert (CoroBegin && " Use Switch-Resumed ABI but missing coro.begin" );
261+
262+ Builder.SetInsertPoint (*CoroBegin->getInsertionPointAfterDef ());
263+
264+ auto *Alignment = Builder.getInt32 (PA->getAlign ().value ());
265+ auto *FromPromise = Builder.getInt1 (false );
266+ SmallVector<Value *, 3 > Arg{CoroBegin, Alignment, FromPromise};
267+ auto *PI =
268+ Builder.CreateIntrinsic (Builder.getPtrTy (), Intrinsic::coro_promise,
269+ Arg, {}, " promise.addr" );
270+ PA->replaceUsesWithIf (PI, [CoroId](Use &U) {
271+ bool IsBitcast = U == U.getUser ()->stripPointerCasts ();
272+ bool IsCoroId = U.getUser () == CoroId;
273+ return !IsBitcast && !IsCoroId;
274+ });
275+ }
276+ }
277+
237278 // Coroutine suspention could potentially lead to any argument modified
238279 // outside of the function, hence arguments should not have noalias
239280 // attributes.
0 commit comments