forked from OSchip/llvm-project
[coroutines] Add support for allocation elision
Summary: We wrap allocation code so that backend can elide it if necessary. llvm.coro.alloc intrinsic returns true, when allocation is needed and false otherwise. ``` %NeedAlloc = call i1 @llvm.coro.alloc(token %2) br i1 %NeedAlloc, label %AllocBB, label %InitBB AllocBB: %5 = call i64 @llvm.coro.size.i64() %call = call i8* @_Znwm(i64 %5) ; operator new br label %InitBB InitBB: %Phi = phi i8* [ null, %0 ], [ %call, %4 ] call i8* @llvm.coro.begin(token %2, i8* %Phi) ``` Reviewers: majnemer, EricWF Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D31584 llvm-svn: 303596
This commit is contained in:
parent
fb9476ee6c
commit
aa6e9a99b4
|
@ -284,6 +284,9 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|||
auto &TI = CGM.getContext().getTargetInfo();
|
||||
unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
|
||||
|
||||
auto *EntryBB = Builder.GetInsertBlock();
|
||||
auto *AllocBB = createBasicBlock("coro.alloc");
|
||||
auto *InitBB = createBasicBlock("coro.init");
|
||||
auto *FinalBB = createBasicBlock("coro.final");
|
||||
auto *RetBB = createBasicBlock("coro.ret");
|
||||
|
||||
|
@ -293,12 +296,20 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|||
createCoroData(*this, CurCoro, CoroId);
|
||||
CurCoro.Data->SuspendBB = RetBB;
|
||||
|
||||
// Backend is allowed to elide memory allocations, to help it, emit
|
||||
// auto mem = coro.alloc() ? 0 : ... allocation code ...;
|
||||
auto *CoroAlloc = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
|
||||
|
||||
Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
|
||||
|
||||
EmitBlock(AllocBB);
|
||||
auto *AllocateCall = EmitScalarExpr(S.getAllocate());
|
||||
auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
|
||||
|
||||
// Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
|
||||
if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
|
||||
auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
|
||||
auto *InitBB = createBasicBlock("coro.init");
|
||||
|
||||
// See if allocation was successful.
|
||||
auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
|
||||
|
@ -308,9 +319,19 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
|
|||
// If not, return OnAllocFailure object.
|
||||
EmitBlock(RetOnFailureBB);
|
||||
EmitStmt(RetOnAllocFailure);
|
||||
|
||||
EmitBlock(InitBB);
|
||||
}
|
||||
else {
|
||||
Builder.CreateBr(InitBB);
|
||||
}
|
||||
|
||||
EmitBlock(InitBB);
|
||||
|
||||
// Pass the result of the allocation to coro.begin.
|
||||
auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
|
||||
Phi->addIncoming(NullPtr, EntryBB);
|
||||
Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
|
||||
Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
|
||||
|
||||
CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
|
||||
{
|
||||
|
|
|
@ -56,8 +56,17 @@ struct std::experimental::coroutine_traits<void, global_new_delete_tag> {
|
|||
// CHECK-LABEL: f0(
|
||||
extern "C" void f0(global_new_delete_tag) {
|
||||
// CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
|
||||
// CHECK: %[[NeedAlloc:.+]] = call i1 @llvm.coro.alloc(token %[[ID]])
|
||||
// CHECK: br i1 %[[NeedAlloc]], label %[[AllocBB:.+]], label %[[InitBB:.+]]
|
||||
|
||||
// CHECK: [[AllocBB]]:
|
||||
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
|
||||
// CHECK: call i8* @_Znwm(i64 %[[SIZE]])
|
||||
// CHECK: %[[MEM:.+]] = call i8* @_Znwm(i64 %[[SIZE]])
|
||||
// CHECK: br label %[[InitBB]]
|
||||
|
||||
// CHECK: [[InitBB]]:
|
||||
// CHECK: %[[PHI:.+]] = phi i8* [ null, %{{.+}} ], [ %call, %[[AllocBB]] ]
|
||||
// CHECK: call i8* @llvm.coro.begin(token %[[ID]], i8* %[[PHI]])
|
||||
|
||||
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
|
||||
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
|
||||
|
|
Loading…
Reference in New Issue