1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "CGCleanup.h" |
14 | #include "CodeGenFunction.h" |
15 | #include "llvm/ADT/ScopeExit.h" |
16 | #include "clang/AST/StmtCXX.h" |
17 | #include "clang/AST/StmtVisitor.h" |
18 | |
19 | using namespace clang; |
20 | using namespace CodeGen; |
21 | |
22 | using llvm::Value; |
23 | using llvm::BasicBlock; |
24 | |
25 | namespace { |
26 | enum class AwaitKind { Init, Normal, Yield, Final }; |
27 | static constexpr llvm::StringLiteral AwaitKindStr[] = {"init", "await", "yield", |
28 | "final"}; |
29 | } |
30 | |
31 | struct clang::CodeGen::CGCoroData { |
32 | |
33 | |
34 | |
35 | AwaitKind CurrentAwaitKind = AwaitKind::Init; |
36 | unsigned AwaitNum = 0; |
37 | unsigned YieldNum = 0; |
38 | |
39 | |
40 | |
41 | unsigned CoreturnCount = 0; |
42 | |
43 | |
44 | llvm::BasicBlock *SuspendBB = nullptr; |
45 | |
46 | |
47 | Stmt *ExceptionHandler = nullptr; |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | llvm::Value *ResumeEHVar = nullptr; |
54 | |
55 | |
56 | |
57 | |
58 | CodeGenFunction::JumpDest CleanupJD; |
59 | |
60 | |
61 | |
62 | CodeGenFunction::JumpDest FinalJD; |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | llvm::CallInst *CoroId = nullptr; |
69 | |
70 | |
71 | |
72 | |
73 | llvm::CallInst *CoroBegin = nullptr; |
74 | |
75 | |
76 | |
77 | llvm::CallInst *LastCoroFree = nullptr; |
78 | |
79 | |
80 | |
81 | |
82 | CallExpr const *CoroIdExpr = nullptr; |
83 | }; |
84 | |
85 | |
86 | clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {} |
87 | CodeGenFunction::CGCoroInfo::~CGCoroInfo() {} |
88 | |
89 | static void createCoroData(CodeGenFunction &CGF, |
90 | CodeGenFunction::CGCoroInfo &CurCoro, |
91 | llvm::CallInst *CoroId, |
92 | CallExpr const *CoroIdExpr = nullptr) { |
93 | if (CurCoro.Data) { |
94 | if (CurCoro.Data->CoroIdExpr) |
95 | CGF.CGM.Error(CoroIdExpr->getBeginLoc(), |
96 | "only one __builtin_coro_id can be used in a function"); |
97 | else if (CoroIdExpr) |
98 | CGF.CGM.Error(CoroIdExpr->getBeginLoc(), |
99 | "__builtin_coro_id shall not be used in a C++ coroutine"); |
100 | else |
101 | llvm_unreachable("EmitCoroutineBodyStatement called twice?"); |
102 | |
103 | return; |
104 | } |
105 | |
106 | CurCoro.Data = std::unique_ptr<CGCoroData>(new CGCoroData); |
107 | CurCoro.Data->CoroId = CoroId; |
108 | CurCoro.Data->CoroIdExpr = CoroIdExpr; |
109 | } |
110 | |
111 | |
112 | static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) { |
113 | unsigned No = 0; |
114 | switch (Kind) { |
115 | case AwaitKind::Init: |
116 | case AwaitKind::Final: |
117 | break; |
118 | case AwaitKind::Normal: |
119 | No = ++Coro.AwaitNum; |
120 | break; |
121 | case AwaitKind::Yield: |
122 | No = ++Coro.YieldNum; |
123 | break; |
124 | } |
125 | SmallString<32> Prefix(AwaitKindStr[static_cast<unsigned>(Kind)]); |
126 | if (No > 1) { |
127 | Twine(No).toVector(Prefix); |
128 | } |
129 | return Prefix; |
130 | } |
131 | |
132 | static bool memberCallExpressionCanThrow(const Expr *E) { |
133 | if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E)) |
134 | if (const auto *Proto = |
135 | CE->getMethodDecl()->getType()->getAs<FunctionProtoType>()) |
136 | if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) && |
137 | Proto->canThrow() == CT_Cannot) |
138 | return false; |
139 | return true; |
140 | } |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | namespace { |
170 | struct LValueOrRValue { |
171 | LValue LV; |
172 | RValue RV; |
173 | }; |
174 | } |
175 | static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, |
176 | CoroutineSuspendExpr const &S, |
177 | AwaitKind Kind, AggValueSlot aggSlot, |
178 | bool ignoreResult, bool forLValue) { |
179 | auto *E = S.getCommonExpr(); |
180 | |
181 | auto Binder = |
182 | CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E); |
183 | auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); }); |
184 | |
185 | auto Prefix = buildSuspendPrefixStr(Coro, Kind); |
186 | BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready")); |
187 | BasicBlock *SuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend")); |
188 | BasicBlock *CleanupBlock = CGF.createBasicBlock(Prefix + Twine(".cleanup")); |
189 | |
190 | |
191 | CGF.EmitBranchOnBoolExpr(S.getReadyExpr(), ReadyBlock, SuspendBlock, 0); |
192 | |
193 | |
194 | CGF.EmitBlock(SuspendBlock); |
195 | |
196 | auto &Builder = CGF.Builder; |
197 | llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save); |
198 | auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy); |
199 | auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr}); |
200 | |
201 | auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr()); |
202 | if (SuspendRet != nullptr && SuspendRet->getType()->isIntegerTy(1)) { |
203 | |
204 | BasicBlock *RealSuspendBlock = |
205 | CGF.createBasicBlock(Prefix + Twine(".suspend.bool")); |
206 | CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock); |
207 | SuspendBlock = RealSuspendBlock; |
208 | CGF.EmitBlock(RealSuspendBlock); |
209 | } |
210 | |
211 | |
212 | const bool IsFinalSuspend = (Kind == AwaitKind::Final); |
213 | llvm::Function *CoroSuspend = |
214 | CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_suspend); |
215 | auto *SuspendResult = Builder.CreateCall( |
216 | CoroSuspend, {SaveCall, Builder.getInt1(IsFinalSuspend)}); |
217 | |
218 | |
219 | auto *Switch = Builder.CreateSwitch(SuspendResult, Coro.SuspendBB, 2); |
220 | Switch->addCase(Builder.getInt8(0), ReadyBlock); |
221 | Switch->addCase(Builder.getInt8(1), CleanupBlock); |
222 | |
223 | |
224 | CGF.EmitBlock(CleanupBlock); |
225 | CGF.EmitBranchThroughCleanup(Coro.CleanupJD); |
226 | |
227 | |
228 | CGF.EmitBlock(ReadyBlock); |
229 | |
230 | |
231 | |
232 | CXXTryStmt *TryStmt = nullptr; |
233 | if (Coro.ExceptionHandler && Kind == AwaitKind::Init && |
234 | memberCallExpressionCanThrow(S.getResumeExpr())) { |
235 | Coro.ResumeEHVar = |
236 | CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh")); |
237 | Builder.CreateFlagStore(true, Coro.ResumeEHVar); |
238 | |
239 | auto Loc = S.getResumeExpr()->getExprLoc(); |
240 | auto *Catch = new (CGF.getContext()) |
241 | CXXCatchStmt(Loc, , Coro.ExceptionHandler); |
242 | auto *TryBody = |
243 | CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), Loc, Loc); |
244 | TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch); |
245 | CGF.EnterCXXTryStmt(*TryStmt); |
246 | } |
247 | |
248 | LValueOrRValue Res; |
249 | if (forLValue) |
250 | Res.LV = CGF.EmitLValue(S.getResumeExpr()); |
251 | else |
252 | Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); |
253 | |
254 | if (TryStmt) { |
255 | Builder.CreateFlagStore(false, Coro.ResumeEHVar); |
256 | CGF.ExitCXXTryStmt(*TryStmt); |
257 | } |
258 | |
259 | return Res; |
260 | } |
261 | |
262 | RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E, |
263 | AggValueSlot aggSlot, |
264 | bool ignoreResult) { |
265 | return emitSuspendExpression(*this, *CurCoro.Data, E, |
266 | CurCoro.Data->CurrentAwaitKind, aggSlot, |
267 | ignoreResult, ).RV; |
268 | } |
269 | RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E, |
270 | AggValueSlot aggSlot, |
271 | bool ignoreResult) { |
272 | return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield, |
273 | aggSlot, ignoreResult, ).RV; |
274 | } |
275 | |
276 | void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { |
277 | ++CurCoro.Data->CoreturnCount; |
278 | const Expr *RV = S.getOperand(); |
279 | if (RV && RV->getType()->isVoidType()) { |
280 | |
281 | |
282 | RunCleanupsScope cleanupScope(*this); |
283 | EmitIgnoredExpr(RV); |
284 | } |
285 | EmitStmt(S.getPromiseCall()); |
286 | EmitBranchThroughCleanup(CurCoro.Data->FinalJD); |
287 | } |
288 | |
289 | |
290 | #ifndef NDEBUG |
291 | static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx, |
292 | const CoroutineSuspendExpr *E) { |
293 | const auto *RE = E->getResumeExpr(); |
294 | |
295 | |
296 | (0) . __assert_fail ("isa(RE) && \"unexpected suspend expression type\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 296, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(isa<CallExpr>(RE) && "unexpected suspend expression type"); |
297 | return cast<CallExpr>(RE)->getCallReturnType(Ctx); |
298 | } |
299 | #endif |
300 | |
301 | LValue |
302 | CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) { |
303 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 305, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && |
304 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 305, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Can't have a scalar return unless the return type is a " |
305 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 305, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "reference type!"); |
306 | return emitSuspendExpression(*this, *CurCoro.Data, *E, |
307 | CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(), |
308 | , ).LV; |
309 | } |
310 | |
311 | LValue |
312 | CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) { |
313 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 315, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && |
314 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 315, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Can't have a scalar return unless the return type is a " |
315 | (0) . __assert_fail ("getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && \"Can't have a scalar return unless the return type is a \" \"reference type!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 315, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "reference type!"); |
316 | return emitSuspendExpression(*this, *CurCoro.Data, *E, |
317 | AwaitKind::Yield, AggValueSlot::ignored(), |
318 | , ).LV; |
319 | } |
320 | |
321 | |
322 | namespace { |
323 | struct GetParamRef : public StmtVisitor<GetParamRef> { |
324 | public: |
325 | DeclRefExpr *Expr = nullptr; |
326 | GetParamRef() {} |
327 | void VisitDeclRefExpr(DeclRefExpr *E) { |
328 | (0) . __assert_fail ("Expr == nullptr && \"multilple declref in param move\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 328, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Expr == nullptr && "multilple declref in param move"); |
329 | Expr = E; |
330 | } |
331 | void VisitStmt(Stmt *S) { |
332 | for (auto *C : S->children()) { |
333 | if (C) |
334 | Visit(C); |
335 | } |
336 | } |
337 | }; |
338 | } |
339 | |
340 | |
341 | |
342 | |
343 | |
344 | namespace { |
345 | struct ParamReferenceReplacerRAII { |
346 | CodeGenFunction::DeclMapTy SavedLocals; |
347 | CodeGenFunction::DeclMapTy& LocalDeclMap; |
348 | |
349 | ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap) |
350 | : LocalDeclMap(LocalDeclMap) {} |
351 | |
352 | void addCopy(DeclStmt const *PM) { |
353 | |
354 | |
355 | isSingleDecl()", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 355, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(PM->isSingleDecl()); |
356 | VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl()); |
357 | Expr const *InitExpr = VD->getInit(); |
358 | GetParamRef Visitor; |
359 | Visitor.Visit(const_cast<Expr*>(InitExpr)); |
360 | assert(Visitor.Expr); |
361 | DeclRefExpr *DREOrig = Visitor.Expr; |
362 | auto *PD = DREOrig->getDecl(); |
363 | |
364 | auto it = LocalDeclMap.find(PD); |
365 | (0) . __assert_fail ("it != LocalDeclMap.end() && \"parameter is not found\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 365, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(it != LocalDeclMap.end() && "parameter is not found"); |
366 | SavedLocals.insert({ PD, it->second }); |
367 | |
368 | auto copyIt = LocalDeclMap.find(VD); |
369 | (0) . __assert_fail ("copyIt != LocalDeclMap.end() && \"parameter copy is not found\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 369, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(copyIt != LocalDeclMap.end() && "parameter copy is not found"); |
370 | it->second = copyIt->getSecond(); |
371 | } |
372 | |
373 | ~ParamReferenceReplacerRAII() { |
374 | for (auto&& SavedLocal : SavedLocals) { |
375 | LocalDeclMap.insert({SavedLocal.first, SavedLocal.second}); |
376 | } |
377 | } |
378 | }; |
379 | } |
380 | |
381 | |
382 | |
383 | static SmallVector<llvm::OperandBundleDef, 1> |
384 | getBundlesForCoroEnd(CodeGenFunction &CGF) { |
385 | SmallVector<llvm::OperandBundleDef, 1> BundleList; |
386 | |
387 | if (llvm::Instruction *EHPad = CGF.CurrentFuncletPad) |
388 | BundleList.emplace_back("funclet", EHPad); |
389 | |
390 | return BundleList; |
391 | } |
392 | |
393 | namespace { |
394 | |
395 | |
396 | |
397 | struct CallCoroEnd final : public EHScopeStack::Cleanup { |
398 | void Emit(CodeGenFunction &CGF, Flags flags) override { |
399 | auto &CGM = CGF.CGM; |
400 | auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy); |
401 | llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end); |
402 | |
403 | auto Bundles = getBundlesForCoroEnd(CGF); |
404 | auto *CoroEnd = CGF.Builder.CreateCall( |
405 | CoroEndFn, {NullPtr, CGF.Builder.getTrue()}, Bundles); |
406 | if (Bundles.empty()) { |
407 | |
408 | |
409 | auto *ResumeBB = CGF.getEHResumeBlock(); |
410 | auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont"); |
411 | CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB); |
412 | CGF.EmitBlock(CleanupContBB); |
413 | } |
414 | } |
415 | }; |
416 | } |
417 | |
418 | namespace { |
419 | |
420 | struct CallCoroDelete final : public EHScopeStack::Cleanup { |
421 | Stmt *Deallocate; |
422 | |
423 | |
424 | |
425 | |
426 | |
427 | |
428 | |
429 | |
430 | void Emit(CodeGenFunction &CGF, Flags) override { |
431 | |
432 | |
433 | |
434 | BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock(); |
435 | |
436 | auto *FreeBB = CGF.createBasicBlock("coro.free"); |
437 | CGF.EmitBlock(FreeBB); |
438 | CGF.EmitStmt(Deallocate); |
439 | |
440 | auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free"); |
441 | CGF.EmitBlock(AfterFreeBB); |
442 | |
443 | |
444 | auto *CoroFree = CGF.CurCoro.Data->LastCoroFree; |
445 | if (!CoroFree) { |
446 | CGF.CGM.Error(Deallocate->getBeginLoc(), |
447 | "Deallocation expressoin does not refer to coro.free"); |
448 | return; |
449 | } |
450 | |
451 | |
452 | auto *InsertPt = SaveInsertBlock->getTerminator(); |
453 | CoroFree->moveBefore(InsertPt); |
454 | CGF.Builder.SetInsertPoint(InsertPt); |
455 | |
456 | |
457 | auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy); |
458 | auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr); |
459 | CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB); |
460 | |
461 | |
462 | InsertPt->eraseFromParent(); |
463 | CGF.Builder.SetInsertPoint(AfterFreeBB); |
464 | } |
465 | explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {} |
466 | }; |
467 | } |
468 | |
469 | namespace { |
470 | struct GetReturnObjectManager { |
471 | CodeGenFunction &CGF; |
472 | CGBuilderTy &Builder; |
473 | const CoroutineBodyStmt &S; |
474 | |
475 | Address GroActiveFlag; |
476 | CodeGenFunction::AutoVarEmission GroEmission; |
477 | |
478 | GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S) |
479 | : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()), |
480 | GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {} |
481 | |
482 | |
483 | |
484 | |
485 | |
486 | |
487 | |
488 | void EmitGroAlloca() { |
489 | auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl()); |
490 | if (!GroDeclStmt) { |
491 | |
492 | return; |
493 | } |
494 | |
495 | auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl()); |
496 | |
497 | |
498 | GroActiveFlag = |
499 | CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active"); |
500 | Builder.CreateStore(Builder.getFalse(), GroActiveFlag); |
501 | |
502 | GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl); |
503 | |
504 | |
505 | auto old_top = CGF.EHStack.stable_begin(); |
506 | CGF.EmitAutoVarCleanups(GroEmission); |
507 | auto top = CGF.EHStack.stable_begin(); |
508 | |
509 | |
510 | for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top); |
511 | b != e; b++) { |
512 | if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) { |
513 | (0) . __assert_fail ("!Cleanup->hasActiveFlag() && \"cleanup already has active flag?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGCoroutine.cpp", 513, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?"); |
514 | Cleanup->setActiveFlag(GroActiveFlag); |
515 | Cleanup->setTestFlagInEHCleanup(); |
516 | Cleanup->setTestFlagInNormalCleanup(); |
517 | } |
518 | } |
519 | } |
520 | |
521 | void EmitGroInit() { |
522 | if (!GroActiveFlag.isValid()) { |
523 | |
524 | |
525 | CGF.EmitStmt(S.getResultDecl()); |
526 | return; |
527 | } |
528 | |
529 | CGF.EmitAutoVarInit(GroEmission); |
530 | Builder.CreateStore(Builder.getTrue(), GroActiveFlag); |
531 | } |
532 | }; |
533 | } |
534 | |
535 | static void emitBodyAndFallthrough(CodeGenFunction &CGF, |
536 | const CoroutineBodyStmt &S, Stmt *Body) { |
537 | CGF.EmitStmt(Body); |
538 | const bool CanFallthrough = CGF.Builder.GetInsertBlock(); |
539 | if (CanFallthrough) |
540 | if (Stmt *OnFallthrough = S.getFallthroughHandler()) |
541 | CGF.EmitStmt(OnFallthrough); |
542 | } |
543 | |
544 | void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { |
545 | auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); |
546 | auto &TI = CGM.getContext().getTargetInfo(); |
547 | unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth(); |
548 | |
549 | auto *EntryBB = Builder.GetInsertBlock(); |
550 | auto *AllocBB = createBasicBlock("coro.alloc"); |
551 | auto *InitBB = createBasicBlock("coro.init"); |
552 | auto *FinalBB = createBasicBlock("coro.final"); |
553 | auto *RetBB = createBasicBlock("coro.ret"); |
554 | |
555 | auto *CoroId = Builder.CreateCall( |
556 | CGM.getIntrinsic(llvm::Intrinsic::coro_id), |
557 | {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr}); |
558 | createCoroData(*this, CurCoro, CoroId); |
559 | CurCoro.Data->SuspendBB = RetBB; |
560 | |
561 | |
562 | |
563 | auto *CoroAlloc = Builder.CreateCall( |
564 | CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId}); |
565 | |
566 | Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB); |
567 | |
568 | EmitBlock(AllocBB); |
569 | auto *AllocateCall = EmitScalarExpr(S.getAllocate()); |
570 | auto *AllocOrInvokeContBB = Builder.GetInsertBlock(); |
571 | |
572 | |
573 | if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) { |
574 | auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure"); |
575 | |
576 | |
577 | auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy); |
578 | auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr); |
579 | Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB); |
580 | |
581 | |
582 | EmitBlock(RetOnFailureBB); |
583 | EmitStmt(RetOnAllocFailure); |
584 | } |
585 | else { |
586 | Builder.CreateBr(InitBB); |
587 | } |
588 | |
589 | EmitBlock(InitBB); |
590 | |
591 | |
592 | auto *Phi = Builder.CreatePHI(VoidPtrTy, 2); |
593 | Phi->addIncoming(NullPtr, EntryBB); |
594 | Phi->addIncoming(AllocateCall, AllocOrInvokeContBB); |
595 | auto *CoroBegin = Builder.CreateCall( |
596 | CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi}); |
597 | CurCoro.Data->CoroBegin = CoroBegin; |
598 | |
599 | GetReturnObjectManager GroManager(*this, S); |
600 | GroManager.EmitGroAlloca(); |
601 | |
602 | CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB); |
603 | { |
604 | ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap); |
605 | CodeGenFunction::RunCleanupsScope ResumeScope(*this); |
606 | EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate()); |
607 | |
608 | |
609 | |
610 | |
611 | for (auto *PM : S.getParamMoves()) { |
612 | EmitStmt(PM); |
613 | ParamReplacer.addCopy(cast<DeclStmt>(PM)); |
614 | |
615 | |
616 | |
617 | } |
618 | |
619 | EmitStmt(S.getPromiseDeclStmt()); |
620 | |
621 | Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl()); |
622 | auto *PromiseAddrVoidPtr = |
623 | new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId); |
624 | |
625 | |
626 | CoroId->setArgOperand(1, PromiseAddrVoidPtr); |
627 | |
628 | |
629 | GroManager.EmitGroInit(); |
630 | |
631 | EHStack.pushCleanup<CallCoroEnd>(EHCleanup); |
632 | |
633 | CurCoro.Data->CurrentAwaitKind = AwaitKind::Init; |
634 | CurCoro.Data->ExceptionHandler = S.getExceptionHandler(); |
635 | EmitStmt(S.getInitSuspendStmt()); |
636 | CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB); |
637 | |
638 | CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal; |
639 | |
640 | if (CurCoro.Data->ExceptionHandler) { |
641 | |
642 | |
643 | |
644 | |
645 | |
646 | BasicBlock *ContBB = nullptr; |
647 | if (CurCoro.Data->ResumeEHVar) { |
648 | BasicBlock *BodyBB = createBasicBlock("coro.resumed.body"); |
649 | ContBB = createBasicBlock("coro.resumed.cont"); |
650 | Value *SkipBody = Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar, |
651 | "coro.resumed.eh"); |
652 | Builder.CreateCondBr(SkipBody, ContBB, BodyBB); |
653 | EmitBlock(BodyBB); |
654 | } |
655 | |
656 | auto Loc = S.getBeginLoc(); |
657 | CXXCatchStmt Catch(Loc, , |
658 | CurCoro.Data->ExceptionHandler); |
659 | auto *TryStmt = |
660 | CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch); |
661 | |
662 | EnterCXXTryStmt(*TryStmt); |
663 | emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock()); |
664 | ExitCXXTryStmt(*TryStmt); |
665 | |
666 | if (ContBB) |
667 | EmitBlock(ContBB); |
668 | } |
669 | else { |
670 | emitBodyAndFallthrough(*this, S, S.getBody()); |
671 | } |
672 | |
673 | |
674 | const bool CanFallthrough = Builder.GetInsertBlock(); |
675 | const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0; |
676 | if (CanFallthrough || HasCoreturns) { |
677 | EmitBlock(FinalBB); |
678 | CurCoro.Data->CurrentAwaitKind = AwaitKind::Final; |
679 | EmitStmt(S.getFinalSuspendStmt()); |
680 | } else { |
681 | |
682 | EmitBlock(FinalBB, ); |
683 | } |
684 | } |
685 | |
686 | EmitBlock(RetBB); |
687 | |
688 | |
689 | llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end); |
690 | Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()}); |
691 | |
692 | if (Stmt *Ret = S.getReturnStmt()) |
693 | EmitStmt(Ret); |
694 | } |
695 | |
696 | |
697 | RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E, |
698 | unsigned int IID) { |
699 | SmallVector<llvm::Value *, 8> Args; |
700 | switch (IID) { |
701 | default: |
702 | break; |
703 | |
704 | |
705 | case llvm::Intrinsic::coro_frame: { |
706 | if (CurCoro.Data && CurCoro.Data->CoroBegin) { |
707 | return RValue::get(CurCoro.Data->CoroBegin); |
708 | } |
709 | CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_begin " |
710 | "has been used earlier in this function"); |
711 | auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); |
712 | return RValue::get(NullPtr); |
713 | } |
714 | |
715 | |
716 | |
717 | case llvm::Intrinsic::coro_alloc: |
718 | case llvm::Intrinsic::coro_begin: |
719 | case llvm::Intrinsic::coro_free: { |
720 | if (CurCoro.Data && CurCoro.Data->CoroId) { |
721 | Args.push_back(CurCoro.Data->CoroId); |
722 | break; |
723 | } |
724 | CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_id has" |
725 | " been used earlier in this function"); |
726 | |
727 | LLVM_FALLTHROUGH; |
728 | } |
729 | |
730 | |
731 | case llvm::Intrinsic::coro_suspend: |
732 | Args.push_back(llvm::ConstantTokenNone::get(getLLVMContext())); |
733 | break; |
734 | } |
735 | for (const Expr *Arg : E->arguments()) |
736 | Args.push_back(EmitScalarExpr(Arg)); |
737 | |
738 | llvm::Function *F = CGM.getIntrinsic(IID); |
739 | llvm::CallInst *Call = Builder.CreateCall(F, Args); |
740 | |
741 | |
742 | |
743 | |
744 | |
745 | if (IID == llvm::Intrinsic::coro_id) { |
746 | createCoroData(*this, CurCoro, Call, E); |
747 | } |
748 | else if (IID == llvm::Intrinsic::coro_begin) { |
749 | if (CurCoro.Data) |
750 | CurCoro.Data->CoroBegin = Call; |
751 | } |
752 | else if (IID == llvm::Intrinsic::coro_free) { |
753 | |
754 | |
755 | if (CurCoro.Data) |
756 | CurCoro.Data->LastCoroFree = Call; |
757 | } |
758 | return RValue::get(Call); |
759 | } |
760 | |