@@ -5173,33 +5173,78 @@ static llvm::Constant *getCoroAllocFn(IRGenModule &IGM) {
51735173 /* optionalLinkageOverride=*/ nullptr , IGM.SwiftCoroCC );
51745174}
51755175
5176- static llvm::Constant *getCoroDeallocWrapperFn (IRGenModule &IGM) {
5176+ static llvm::Constant *getCoroDeallocFn (IRGenModule &IGM) {
5177+ auto isSwiftCoroCCAvailable = IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro;
51775178 return IGM.getOrCreateHelperFunction (
5178- " __swift_coro_dealloc_ " , IGM.VoidTy ,
5179+ " _swift_coro_dealloc " , IGM.VoidTy ,
51795180 {IGM.CoroAllocatorPtrTy , IGM.Int8PtrTy },
5180- [](IRGenFunction &IGF) {
5181+ [isSwiftCoroCCAvailable ](IRGenFunction &IGF) {
51815182 auto parameters = IGF.collectParameters ();
51825183 auto *allocator = parameters.claimNext ();
51835184 auto *ptr = parameters.claimNext ();
5184- auto *nullAllocator = IGF.Builder .CreateCmp (
5185- llvm::CmpInst::Predicate::ICMP_EQ, allocator,
5186- llvm::ConstantPointerNull::get (
5187- cast<llvm::PointerType>(allocator->getType ())));
5188- auto *bailBlock = IGF.createBasicBlock (" bail" );
5189- auto *forwardBlock = IGF.createBasicBlock (" forward" );
5190- IGF.Builder .CreateCondBr (nullAllocator, bailBlock, forwardBlock);
5191- IGF.Builder .emitBlock (bailBlock);
5192- // Emit the dynamic alloca.
5185+ if (isSwiftCoroCCAvailable) {
5186+ // swiftcorocc is available, so if there's no allocator pointer,
5187+ // storage was allocated on the stack which will be naturally cleaned
5188+ // up when the coroutine's frame is "freed".
5189+ auto *nullAllocator = IGF.Builder .CreateCmp (
5190+ llvm::CmpInst::Predicate::ICMP_EQ, allocator,
5191+ llvm::ConstantPointerNull::get (
5192+ cast<llvm::PointerType>(allocator->getType ())));
5193+ auto *bailBlock = IGF.createBasicBlock (" null_allocator" );
5194+ auto *normalBlock = IGF.createBasicBlock (" nonnull_allocator" );
5195+ IGF.Builder .CreateCondBr (nullAllocator, bailBlock, normalBlock);
5196+ IGF.Builder .emitBlock (bailBlock);
5197+ // Nothing to do here.
5198+ IGF.Builder .CreateRetVoid ();
5199+ // Start emitting the "normal" block.
5200+ IGF.Builder .emitBlock (normalBlock);
5201+ }
5202+ auto shouldDeallocateImmediatelyFlag = CoroAllocatorFlags (0 );
5203+ shouldDeallocateImmediatelyFlag.setShouldDeallocateImmediately (true );
5204+ auto *flagsPtr = IGF.Builder .CreateInBoundsGEP (
5205+ IGF.IGM .CoroAllocatorTy , allocator,
5206+ {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
5207+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 )});
5208+ auto *flags = IGF.Builder .CreateLoad (
5209+ Address (flagsPtr, IGF.IGM .Int32Ty , Alignment (4 )), " " );
5210+ auto *deallocDeferringAllocator = IGF.Builder .CreateAnd (
5211+ flags,
5212+ llvm::APInt (IGF.IGM .Int32Ty ->getBitWidth (),
5213+ shouldDeallocateImmediatelyFlag.getOpaqueValue ()));
5214+ auto *isDeallocDeferringAllocator = IGF.Builder .CreateICmpNE (
5215+ deallocDeferringAllocator,
5216+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ));
5217+ auto *deferringAllocatorBlock =
5218+ IGF.createBasicBlock (" deferring_allocator" );
5219+ auto *normalBlock = IGF.createBasicBlock (" normal" );
5220+ IGF.Builder .CreateCondBr (isDeallocDeferringAllocator,
5221+ deferringAllocatorBlock, normalBlock);
5222+ IGF.Builder .emitBlock (deferringAllocatorBlock);
5223+ // Nothing to do here.
51935224 IGF.Builder .CreateRetVoid ();
5194- IGF.Builder .emitBlock (forwardBlock);
5195- IGF.Builder .CreateCall (
5196- IGF.IGM .getCoroDeallocFunctionPointer (), {allocator, ptr});
5225+ // Start emitting the "normal" block.
5226+ IGF.Builder .emitBlock (normalBlock);
5227+ auto *calleePtr = IGF.Builder .CreateInBoundsGEP (
5228+ IGF.IGM .CoroAllocatorTy , allocator,
5229+ {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
5230+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , 2 )});
5231+ auto *callee = IGF.Builder .CreateLoad (
5232+ Address (calleePtr, IGF.IGM .CoroDeallocateFnTy ->getPointerTo (),
5233+ IGF.IGM .getPointerAlignment ()),
5234+ " deallocate_fn" );
5235+ auto fnPtr = FunctionPointer::createUnsigned (
5236+ FunctionPointer::Kind::Function, callee,
5237+ Signature (cast<llvm::FunctionType>(IGF.IGM .CoroDeallocateFnTy ), {},
5238+ IGF.IGM .SwiftCC ));
5239+ auto *call = IGF.Builder .CreateCall (fnPtr, {ptr});
5240+ call->setDoesNotThrow ();
5241+ call->setCallingConv (IGF.IGM .SwiftCC );
51975242 IGF.Builder .CreateRetVoid ();
51985243 },
5199- /* setIsNoInline=*/ false ,
5244+ /* setIsNoInline=*/ true ,
52005245 /* forPrologue=*/ false ,
52015246 /* isPerformanceConstraint=*/ false ,
5202- /* optionalLinkageOverride=*/ nullptr , llvm::CallingConv::SwiftCoro );
5247+ /* optionalLinkageOverride=*/ nullptr , IGM. SwiftCoroCC );
52035248}
52045249
52055250void irgen::emitYieldOnce2CoroutineEntry (IRGenFunction &IGF,
@@ -5208,12 +5253,8 @@ void irgen::emitYieldOnce2CoroutineEntry(IRGenFunction &IGF,
52085253 llvm::Value *allocator,
52095254 llvm::GlobalVariable *cfp) {
52105255 IGF.setCoroutineAllocator (allocator);
5211- auto isSwiftCoroCCAvailable =
5212- IGF.IGM .SwiftCoroCC == llvm::CallingConv::SwiftCoro;
52135256 auto allocFn = IGF.IGM .getOpaquePtr (getCoroAllocFn (IGF.IGM ));
5214- auto deallocFn = IGF.IGM .getOpaquePtr (isSwiftCoroCCAvailable
5215- ? getCoroDeallocWrapperFn (IGF.IGM )
5216- : IGF.IGM .getCoroDeallocFn ());
5257+ auto deallocFn = IGF.IGM .getOpaquePtr (getCoroDeallocFn (IGF.IGM ));
52175258 emitRetconCoroutineEntry (
52185259 IGF, fnType, buffer, llvm::Intrinsic::coro_id_retcon_once_dynamic,
52195260 Size (-1 ) /* dynamic-to-IRGen size*/ , IGF.IGM .getCoroStaticFrameAlignment (),
0 commit comments