From: Gor Nishanov Date: Tue, 23 May 2017 01:13:17 +0000 (+0000) Subject: [coroutines] Add support for allocation elision X-Git-Tag: llvmorg-5.0.0-rc1~4557 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aa6e9a99b46eb97fd37bd5b5f693b81bc9b13630;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index c09c63f..f6d06d0 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -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); { diff --git a/clang/test/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CodeGenCoroutines/coro-alloc.cpp index b551257..14e429e 100644 --- a/clang/test/CodeGenCoroutines/coro-alloc.cpp +++ b/clang/test/CodeGenCoroutines/coro-alloc.cpp @@ -56,8 +56,17 @@ struct std::experimental::coroutine_traits { // 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]])