@@ -5829,25 +5829,15 @@ void irgen::emitYieldOnceCoroutineResult(IRGenFunction &IGF, Explosion &result,
5829
5829
auto &Builder = IGF.Builder ;
5830
5830
auto &IGM = IGF.IGM ;
5831
5831
5832
- // Create coroutine exit block and branch to it.
5833
- auto coroEndBB = IGF.createBasicBlock (" coro.end.normal" );
5834
- IGF.setCoroutineExitBlock (coroEndBB);
5835
- Builder.CreateBr (coroEndBB);
5836
-
5837
- // Emit the block.
5838
- Builder.emitBlock (coroEndBB);
5839
- auto handle = IGF.getCoroutineHandle ();
5840
-
5841
- llvm::Value *resultToken = nullptr ;
5832
+ // Prepare coroutine result values
5833
+ auto &coroResults = IGF.coroutineResults ;
5834
+ assert (coroResults.empty () && " must only be single return" );
5842
5835
if (result.empty ()) {
5843
5836
assert (IGM.getTypeInfo (returnResultType)
5844
- .nativeReturnValueSchema (IGM)
5845
- .empty () &&
5837
+ .nativeReturnValueSchema (IGM)
5838
+ .empty () &&
5846
5839
" Empty explosion must match the native calling convention" );
5847
- // No results: just use none token
5848
- resultToken = llvm::ConstantTokenNone::get (Builder.getContext ());
5849
5840
} else {
5850
- // Capture results via `coro_end_results` intrinsic
5851
5841
result = IGF.coerceValueTo (returnResultType, result, funcResultType);
5852
5842
auto &nativeSchema =
5853
5843
IGM.getTypeInfo (funcResultType).nativeReturnValueSchema (IGM);
@@ -5856,19 +5846,93 @@ void irgen::emitYieldOnceCoroutineResult(IRGenFunction &IGF, Explosion &result,
5856
5846
Explosion native = nativeSchema.mapIntoNative (IGM, IGF, result,
5857
5847
funcResultType,
5858
5848
false /* isOutlined */ );
5859
- SmallVector<llvm::Value *, 1 > args;
5860
5849
for (unsigned i = 0 , e = native.size (); i != e; ++i)
5861
- args.push_back (native.claimNext ());
5850
+ coroResults.push_back (native.claimNext ());
5851
+ }
5862
5852
5863
- resultToken =
5864
- Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, args);
5853
+ auto coroEndBB = IGF.getCoroutineExitBlock ();
5854
+ auto handle = IGF.getCoroutineHandle ();
5855
+ bool newEndBlock = false ;
5856
+ if (!coroEndBB) {
5857
+ coroEndBB = IGF.createBasicBlock (" coro.end" );
5858
+ IGF.setCoroutineExitBlock (coroEndBB);
5859
+ newEndBlock = true ;
5865
5860
}
5866
5861
5867
- Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end,
5862
+ // If there are coroutine results, then we need to capture them via
5863
+ // @llvm.coro_end_results intrinsics. However, since unwind blocks would
5864
+ // jump to the same block, we wrap values into phi nodes.
5865
+ Builder.CreateBr (coroEndBB);
5866
+
5867
+ // Emit the end block.
5868
+ llvm::BasicBlock *returnBB = Builder.GetInsertBlock ();
5869
+
5870
+ if (newEndBlock) {
5871
+ Builder.emitBlock (coroEndBB);
5872
+
5873
+ llvm::Value *resultToken = nullptr ;
5874
+ if (coroResults.empty ()) {
5875
+ // No results: just use none token
5876
+ resultToken = llvm::ConstantTokenNone::get (Builder.getContext ());
5877
+ } else {
5878
+ // Otherwise, wrap result values into singleton phi nodes
5879
+ for (auto &val : coroResults) {
5880
+ auto *phi = Builder.CreatePHI (val->getType (), 0 );
5881
+ phi->addIncoming (val, returnBB);
5882
+ val = phi;
5883
+ }
5884
+
5885
+ // Capture results via result token
5886
+ resultToken =
5887
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, coroResults);
5888
+
5889
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end,
5868
5890
{handle,
5869
5891
/* is unwind*/ Builder.getFalse (),
5870
5892
resultToken});
5871
- Builder.CreateUnreachable ();
5893
+ Builder.CreateUnreachable ();
5894
+ }
5895
+ } else {
5896
+ if (coroResults.empty ()) {
5897
+ // No results, we do not need to change anything around existing coro.end
5898
+ return ;
5899
+ }
5900
+
5901
+ // Otherwise, we'd need to insert new coro.end.results intrinsics capturing
5902
+ // result values. However, we'd need to wrap results into phi nodes adding
5903
+ // undef for all values coming from incoming unwind blocks.
5904
+
5905
+ // Find coro.end intrinsic
5906
+ llvm::CallInst *coroEndCall = nullptr ;
5907
+ for (llvm::Instruction &inst : coroEndBB->instructionsWithoutDebug ()) {
5908
+ if (auto *CI = dyn_cast<llvm::CallInst>(&inst)) {
5909
+ if (CI->getIntrinsicID () == llvm::Intrinsic::coro_end) {
5910
+ coroEndCall = CI;
5911
+ break ;
5912
+ }
5913
+ }
5914
+ }
5915
+
5916
+ assert (coroEndCall && isa<llvm::ConstantTokenNone>(coroEndCall->getArgOperand (2 )) &&
5917
+ " invalid unwind coro.end call" );
5918
+
5919
+ Builder.SetInsertPoint (&*coroEndBB->getFirstInsertionPt ());
5920
+
5921
+ for (auto &val : coroResults) {
5922
+ auto *phi = Builder.CreatePHI (val->getType (), llvm::pred_size (coroEndBB));
5923
+ for (auto *predBB : llvm::predecessors (coroEndBB))
5924
+ phi->addIncoming (predBB == returnBB ? val : llvm::UndefValue::get (val->getType ()),
5925
+ predBB);
5926
+
5927
+ val = phi;
5928
+ }
5929
+
5930
+ // Capture results via result token and replace coro.end token operand
5931
+ auto *resultToken =
5932
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, coroResults);
5933
+ coroEndCall->setArgOperand (2 , resultToken);
5934
+ Builder.SetInsertPoint (returnBB);
5935
+ }
5872
5936
}
5873
5937
5874
5938
FunctionPointer
0 commit comments