@@ -5718,25 +5718,15 @@ void irgen::emitYieldOnceCoroutineResult(IRGenFunction &IGF, Explosion &result,
5718
5718
auto &Builder = IGF.Builder ;
5719
5719
auto &IGM = IGF.IGM ;
5720
5720
5721
- // Create coroutine exit block and branch to it.
5722
- auto coroEndBB = IGF.createBasicBlock (" coro.end.normal" );
5723
- IGF.setCoroutineExitBlock (coroEndBB);
5724
- Builder.CreateBr (coroEndBB);
5725
-
5726
- // Emit the block.
5727
- Builder.emitBlock (coroEndBB);
5728
- auto handle = IGF.getCoroutineHandle ();
5729
-
5730
- llvm::Value *resultToken = nullptr ;
5721
+ // Prepare coroutine result values
5722
+ auto &coroResults = IGF.coroutineResults ;
5723
+ assert (coroResults.empty () && " must only be single return" );
5731
5724
if (result.empty ()) {
5732
5725
assert (IGM.getTypeInfo (returnResultType)
5733
- .nativeReturnValueSchema (IGM)
5734
- .empty () &&
5726
+ .nativeReturnValueSchema (IGM)
5727
+ .empty () &&
5735
5728
" Empty explosion must match the native calling convention" );
5736
- // No results: just use none token
5737
- resultToken = llvm::ConstantTokenNone::get (Builder.getContext ());
5738
5729
} else {
5739
- // Capture results via `coro_end_results` intrinsic
5740
5730
result = IGF.coerceValueTo (returnResultType, result, funcResultType);
5741
5731
auto &nativeSchema =
5742
5732
IGM.getTypeInfo (funcResultType).nativeReturnValueSchema (IGM);
@@ -5745,19 +5735,93 @@ void irgen::emitYieldOnceCoroutineResult(IRGenFunction &IGF, Explosion &result,
5745
5735
Explosion native = nativeSchema.mapIntoNative (IGM, IGF, result,
5746
5736
funcResultType,
5747
5737
false /* isOutlined */ );
5748
- SmallVector<llvm::Value *, 1 > args;
5749
5738
for (unsigned i = 0 , e = native.size (); i != e; ++i)
5750
- args.push_back (native.claimNext ());
5739
+ coroResults.push_back (native.claimNext ());
5740
+ }
5751
5741
5752
- resultToken =
5753
- Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, args);
5742
+ auto coroEndBB = IGF.getCoroutineExitBlock ();
5743
+ auto handle = IGF.getCoroutineHandle ();
5744
+ bool newEndBlock = false ;
5745
+ if (!coroEndBB) {
5746
+ coroEndBB = IGF.createBasicBlock (" coro.end" );
5747
+ IGF.setCoroutineExitBlock (coroEndBB);
5748
+ newEndBlock = true ;
5754
5749
}
5755
5750
5756
- Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end,
5751
+ // If there are coroutine results, then we need to capture them via
5752
+ // @llvm.coro_end_results intrinsics. However, since unwind blocks would
5753
+ // jump to the same block, we wrap values into phi nodes.
5754
+ Builder.CreateBr (coroEndBB);
5755
+
5756
+ // Emit the end block.
5757
+ llvm::BasicBlock *returnBB = Builder.GetInsertBlock ();
5758
+
5759
+ if (newEndBlock) {
5760
+ Builder.emitBlock (coroEndBB);
5761
+
5762
+ llvm::Value *resultToken = nullptr ;
5763
+ if (coroResults.empty ()) {
5764
+ // No results: just use none token
5765
+ resultToken = llvm::ConstantTokenNone::get (Builder.getContext ());
5766
+ } else {
5767
+ // Otherwise, wrap result values into singleton phi nodes
5768
+ for (auto &val : coroResults) {
5769
+ auto *phi = Builder.CreatePHI (val->getType (), 0 );
5770
+ phi->addIncoming (val, returnBB);
5771
+ val = phi;
5772
+ }
5773
+
5774
+ // Capture results via result token
5775
+ resultToken =
5776
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, coroResults);
5777
+
5778
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end,
5757
5779
{handle,
5758
5780
/* is unwind*/ Builder.getFalse (),
5759
5781
resultToken});
5760
- Builder.CreateUnreachable ();
5782
+ Builder.CreateUnreachable ();
5783
+ }
5784
+ } else {
5785
+ if (coroResults.empty ()) {
5786
+ // No results, we do not need to change anything around existing coro.end
5787
+ return ;
5788
+ }
5789
+
5790
+ // Otherwise, we'd need to insert new coro.end.results intrinsics capturing
5791
+ // result values. However, we'd need to wrap results into phi nodes adding
5792
+ // undef for all values coming from incoming unwind blocks.
5793
+
5794
+ // Find coro.end intrinsic
5795
+ llvm::CallInst *coroEndCall = nullptr ;
5796
+ for (llvm::Instruction &inst : coroEndBB->instructionsWithoutDebug ()) {
5797
+ if (auto *CI = dyn_cast<llvm::CallInst>(&inst)) {
5798
+ if (CI->getIntrinsicID () == llvm::Intrinsic::coro_end) {
5799
+ coroEndCall = CI;
5800
+ break ;
5801
+ }
5802
+ }
5803
+ }
5804
+
5805
+ assert (coroEndCall && isa<llvm::ConstantTokenNone>(coroEndCall->getArgOperand (2 )) &&
5806
+ " invalid unwind coro.end call" );
5807
+
5808
+ Builder.SetInsertPoint (&*coroEndBB->getFirstInsertionPt ());
5809
+
5810
+ for (auto &val : coroResults) {
5811
+ auto *phi = Builder.CreatePHI (val->getType (), llvm::pred_size (coroEndBB));
5812
+ for (auto *predBB : llvm::predecessors (coroEndBB))
5813
+ phi->addIncoming (predBB == returnBB ? val : llvm::UndefValue::get (val->getType ()),
5814
+ predBB);
5815
+
5816
+ val = phi;
5817
+ }
5818
+
5819
+ // Capture results via result token and replace coro.end token operand
5820
+ auto *resultToken =
5821
+ Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_end_results, coroResults);
5822
+ coroEndCall->setArgOperand (2 , resultToken);
5823
+ Builder.SetInsertPoint (returnBB);
5824
+ }
5761
5825
}
5762
5826
5763
5827
FunctionPointer
0 commit comments