Index: lib/CodeGen/CGCoroutine.cpp =================================================================== --- lib/CodeGen/CGCoroutine.cpp +++ lib/CodeGen/CGCoroutine.cpp @@ -57,6 +57,11 @@ // builtin. llvm::CallInst *CoroId = nullptr; + // Stores the llvm.coro.begin emitted in the function so that we can replace + // all coro.frame intrinsics with direct SSA value of coro.begin that returns + // the address of the coroutine frame of the current coroutine. + llvm::CallInst *CoroBegin = nullptr; + // If coro.id came from the builtin, remember the expression to give better // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by // EmitCoroutineBody. @@ -330,8 +335,9 @@ auto *Phi = Builder.CreatePHI(VoidPtrTy, 2); Phi->addIncoming(NullPtr, EntryBB); Phi->addIncoming(AllocateCall, AllocOrInvokeContBB); - Builder.CreateCall( + auto *CoroBegin = Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi}); + CurCoro.Data->CoroBegin = CoroBegin; CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB); { @@ -388,6 +394,17 @@ switch (IID) { default: break; + // The coro.frame builtin is replaced with an SSA value of the coro.begin + // intrinsic. + case llvm::Intrinsic::coro_frame: { + if (CurCoro.Data && CurCoro.Data->CoroBegin) { + return RValue::get(CurCoro.Data->CoroBegin); + } + CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_begin " + "has been used earlier in this function"); + auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); + return RValue::get(NullPtr); + } // The following three intrinsics take a token parameter referring to a token // returned by earlier call to @llvm.coro.id. Since we cannot represent it in // builtins, we patch it up here. @@ -414,10 +431,16 @@ llvm::Value *F = CGM.getIntrinsic(IID); llvm::CallInst *Call = Builder.CreateCall(F, Args); + // Note: The following code is to enable to emit coroutine intrinsics by + // hand to experiment with coroutines in C. // If we see @llvm.coro.id remember it in the CoroData. We will update // coro.alloc, coro.begin and coro.free intrinsics to refer to it. if (IID == llvm::Intrinsic::coro_id) { createCoroData(*this, CurCoro, Call, E); } + else if (IID == llvm::Intrinsic::coro_begin) { + if (CurCoro.Data) + CurCoro.Data->CoroBegin = Call; + } return RValue::get(Call); } Index: test/CodeGenCoroutines/coro-alloc.cpp =================================================================== --- test/CodeGenCoroutines/coro-alloc.cpp +++ test/CodeGenCoroutines/coro-alloc.cpp @@ -66,9 +66,8 @@ // 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.begin(token %[[ID]], i8* %[[PHI]]) - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]]) // CHECK: call void @_ZdlPv(i8* %[[MEM]]) co_return; @@ -93,7 +92,7 @@ // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]]) - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]]) // CHECK: call void @_ZdlPv(i8* %[[MEM]]) co_return; @@ -118,7 +117,7 @@ // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK: call i8* @_Znwm(i64 %[[SIZE]]) - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]]) // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]]) co_return; @@ -143,7 +142,7 @@ // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK: call i8* @_Znwm(i64 %[[SIZE]]) - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]]) // CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64() // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* %[[MEM]], i64 %[[SIZE2]]) Index: test/CodeGenCoroutines/coro-await.cpp =================================================================== --- test/CodeGenCoroutines/coro-await.cpp +++ test/CodeGenCoroutines/coro-await.cpp @@ -40,6 +40,7 @@ // CHECK-LABEL: f0( extern "C" void f0() { + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( co_await suspend_always{}; // See if we need to suspend: @@ -54,7 +55,6 @@ // --------------------------- // Build the coroutine handle and pass it to await_suspend // --------------------------- - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]]) // ... many lines of code to coerce coroutine_handle into an i8* scalar // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}} @@ -100,8 +100,9 @@ // CHECK-LABEL: f1( extern "C" void f1(int) { - co_yield 42; // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type" + // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( + co_yield 42; // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42) // See if we need to suspend: @@ -116,7 +117,6 @@ // --------------------------- // Build the coroutine handle and pass it to await_suspend // --------------------------- - // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame() // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]]) // ... many lines of code to coerce coroutine_handle into an i8* scalar // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}} Index: test/CodeGenCoroutines/coro-builtins.c =================================================================== --- test/CodeGenCoroutines/coro-builtins.c +++ test/CodeGenCoroutines/coro-builtins.c @@ -2,7 +2,7 @@ void *myAlloc(long long); -// CHECK-LABEL: f( +// CHECK-LABEL: f( void f(int n) { // CHECK: %n.addr = alloca i32 // CHECK: %n_copy = alloca i32 @@ -19,31 +19,25 @@ // CHECK-NEXT: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64() // CHECK-NEXT: %[[MEM:.+]] = call i8* @myAlloc(i64 %[[SIZE]]) - // CHECK-NEXT: %[[BEG:.+]] = call i8* @llvm.coro.begin(token %[[COROID]], i8* %[[MEM]]) + // CHECK-NEXT: %[[FRAME:.+]] = call i8* @llvm.coro.begin(token %[[COROID]], i8* %[[MEM]]) __builtin_coro_begin(myAlloc(__builtin_coro_size())); - // CHECK-NEXT: %[[FRAME1:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call void @llvm.coro.resume(i8* %[[FRAME1]]) + // CHECK-NEXT: call void @llvm.coro.resume(i8* %[[FRAME]]) __builtin_coro_resume(__builtin_coro_frame()); - // CHECK-NEXT: %[[FRAME2:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call void @llvm.coro.destroy(i8* %[[FRAME2]]) + // CHECK-NEXT: call void @llvm.coro.destroy(i8* %[[FRAME]]) __builtin_coro_destroy(__builtin_coro_frame()); - // CHECK-NEXT: %[[FRAME3:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call i1 @llvm.coro.done(i8* %[[FRAME3]]) + // CHECK-NEXT: call i1 @llvm.coro.done(i8* %[[FRAME]]) __builtin_coro_done(__builtin_coro_frame()); - // CHECK-NEXT: %[[FRAME4:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call i8* @llvm.coro.promise(i8* %[[FRAME4]], i32 48, i1 false) + // CHECK-NEXT: call i8* @llvm.coro.promise(i8* %[[FRAME]], i32 48, i1 false) __builtin_coro_promise(__builtin_coro_frame(), 48, 0); - // CHECK-NEXT: %[[FRAME5:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call i8* @llvm.coro.free(token %[[COROID]], i8* %[[FRAME5]]) + // CHECK-NEXT: call i8* @llvm.coro.free(token %[[COROID]], i8* %[[FRAME]]) __builtin_coro_free(__builtin_coro_frame()); - // CHECK-NEXT: %[[FRAME6:.+]] = call i8* @llvm.coro.frame() - // CHECK-NEXT: call i1 @llvm.coro.end(i8* %[[FRAME6]], i1 false) + // CHECK-NEXT: call i1 @llvm.coro.end(i8* %[[FRAME]], i1 false) __builtin_coro_end(__builtin_coro_frame(), 0); // CHECK-NEXT: call i8 @llvm.coro.suspend(token none, i1 true)