@@ -614,49 +614,135 @@ void IRGenFunction::emitTaskDeallocThrough(Address address) {
614614 call->setCallingConv (IGM.SwiftCC );
615615}
616616
617+ namespace {
618+ struct Allocator {
619+ struct Field {
620+ enum Kind : uint8_t {
621+ Flags = 0 ,
622+ Allocate = 1 ,
623+ Deallocate = 2 ,
624+ };
625+ Kind kind;
626+ Field (Kind kind) : kind(kind) {}
627+ operator Kind () { return kind; }
628+
629+ llvm::Type *getType (IRGenModule &IGM) {
630+ switch (kind) {
631+ case Flags:
632+ return IGM.Int32Ty ;
633+ case Field::Allocate:
634+ case Field::Deallocate:
635+ return IGM.PtrTy ;
636+ }
637+ }
638+
639+ Alignment getAlignment (IRGenModule &IGM) {
640+ switch (kind) {
641+ case Flags:
642+ return Alignment (4 );
643+ case Field::Allocate:
644+ case Field::Deallocate:
645+ return IGM.getPointerAlignment ();
646+ }
647+ }
648+
649+ StringRef getName () {
650+ switch (kind) {
651+ case Flags:
652+ return " flags" ;
653+ case Field::Allocate:
654+ return " allocate_fn" ;
655+ case Field::Deallocate:
656+ return " deallocate_fn" ;
657+ }
658+ }
659+
660+ llvm::FunctionType *getFunctionType (IRGenModule &IGM) {
661+ switch (kind) {
662+ case Flags:
663+ llvm_unreachable (" not a function" );
664+ case Field::Allocate:
665+ return IGM.CoroAllocateFnTy ;
666+ case Field::Deallocate:
667+ return IGM.CoroDeallocateFnTy ;
668+ }
669+ }
670+ };
671+
672+ llvm::Value *address;
673+ IRGenFunction &IGF;
674+
675+ Allocator (llvm::Value *address, IRGenFunction &IGF)
676+ : address(address), IGF(IGF) {}
677+
678+ llvm::Value *getField (Field field) {
679+ auto *fieldAddress = IGF.Builder .CreateInBoundsGEP (
680+ IGF.IGM .CoroAllocatorTy , address,
681+ {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
682+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , field.kind )});
683+ return IGF.Builder .CreateLoad (Address (fieldAddress, field.getType (IGF.IGM ),
684+ field.getAlignment (IGF.IGM )),
685+ field.getName ());
686+ }
687+
688+ llvm::Value *getFlags () { return getField (Field::Flags); }
689+
690+ FunctionPointer getAllocate () { return getFunctionPointer (Field::Allocate); }
691+
692+ FunctionPointer getDeallocate () {
693+ return getFunctionPointer (Field::Deallocate);
694+ }
695+
696+ void emitOnNullAllocator (StringRef nullBlockName, StringRef nonnullBlockName,
697+ llvm::function_ref<void (IRGenFunction &)> body) {
698+ auto *nullAllocator =
699+ IGF.Builder .CreateCmp (llvm::CmpInst::Predicate::ICMP_EQ, address,
700+ llvm::ConstantPointerNull::get (
701+ cast<llvm::PointerType>(address->getType ())));
702+ auto *poplessReturn = IGF.createBasicBlock (nullBlockName);
703+ auto *normalReturn = IGF.createBasicBlock (nonnullBlockName);
704+ IGF.Builder .CreateCondBr (nullAllocator, poplessReturn, normalReturn);
705+ IGF.Builder .emitBlock (poplessReturn);
706+ body (IGF);
707+ // Start emitting the "normal" block.
708+ IGF.Builder .emitBlock (normalReturn);
709+ }
710+
711+ private:
712+ FunctionPointer getFunctionPointer (Field field) {
713+ llvm::Value *callee = getField (field);
714+ return FunctionPointer::createUnsigned (
715+ FunctionPointer::Kind::Function, callee,
716+ Signature (field.getFunctionType (IGF.IGM ), {}, IGF.IGM .SwiftCC ));
717+ }
718+ };
719+ } // end anonymous namespace
720+
617721llvm::Constant *swift::irgen::getCoroAllocFn (IRGenModule &IGM) {
618722 auto isSwiftCoroCCAvailable = IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro;
619723 return IGM.getOrCreateHelperFunction (
620724 " _swift_coro_alloc" , IGM.Int8PtrTy , {IGM.CoroAllocatorPtrTy , IGM.SizeTy },
621725 [isSwiftCoroCCAvailable](IRGenFunction &IGF) {
622726 auto parameters = IGF.collectParameters ();
623- auto * allocator = parameters.claimNext ();
727+ auto allocator = Allocator ( parameters.claimNext (), IGF );
624728 auto *size = parameters.claimNext ();
625729 if (isSwiftCoroCCAvailable) {
626730 // swiftcorocc is available, so if there's no allocator pointer,
627731 // allocate storage on the stack and return a pointer to it without
628732 // popping the stack.
629- auto *nullAllocator = IGF.Builder .CreateCmp (
630- llvm::CmpInst::Predicate::ICMP_EQ, allocator,
631- llvm::ConstantPointerNull::get (
632- cast<llvm::PointerType>(allocator->getType ())));
633- auto *poplessReturn = IGF.createBasicBlock (" popless" );
634- auto *normalReturn = IGF.createBasicBlock (" normal" );
635- IGF.Builder .CreateCondBr (nullAllocator, poplessReturn, normalReturn);
636- IGF.Builder .emitBlock (poplessReturn);
637- // Emit the dynamic alloca.
638- auto *alloca =
639- IGF.Builder .IRBuilderBase ::CreateAlloca (IGF.IGM .Int8Ty , size);
640- alloca->setAlignment (llvm::Align (MaximumAlignment));
641- auto *retPopless = IGF.Builder .CreateIntrinsic (
642- IGF.IGM .VoidTy , llvm::Intrinsic::ret_popless, {});
643- retPopless->setTailCallKind (
644- llvm::CallInst::TailCallKind::TCK_MustTail);
645- IGF.Builder .CreateRet (alloca);
646- // Start emitting the "normal" block.
647- IGF.Builder .emitBlock (normalReturn);
733+ allocator.emitOnNullAllocator (" popless" , " normal" , [size](auto &IGF) {
734+ // Emit the dynamic alloca.
735+ auto *alloca =
736+ IGF.Builder .IRBuilderBase ::CreateAlloca (IGF.IGM .Int8Ty , size);
737+ alloca->setAlignment (llvm::Align (MaximumAlignment));
738+ auto *retPopless = IGF.Builder .CreateIntrinsic (
739+ IGF.IGM .VoidTy , llvm::Intrinsic::ret_popless, {});
740+ retPopless->setTailCallKind (
741+ llvm::CallInst::TailCallKind::TCK_MustTail);
742+ IGF.Builder .CreateRet (alloca);
743+ });
648744 }
649- auto *calleePtr = IGF.Builder .CreateInBoundsGEP (
650- IGF.IGM .CoroAllocatorTy , allocator,
651- {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
652- llvm::ConstantInt::get (IGF.IGM .Int32Ty , 1 )});
653- auto *callee = IGF.Builder .CreateLoad (
654- Address (calleePtr, IGF.IGM .PtrTy , IGF.IGM .getPointerAlignment ()),
655- " allocate_fn" );
656- auto fnPtr = FunctionPointer::createUnsigned (
657- FunctionPointer::Kind::Function, callee,
658- Signature (cast<llvm::FunctionType>(IGF.IGM .CoroAllocateFnTy ), {},
659- IGF.IGM .SwiftCC ));
745+ auto fnPtr = allocator.getAllocate ();
660746 auto *call = IGF.Builder .CreateCall (fnPtr, {size});
661747 call->setDoesNotThrow ();
662748 call->setCallingConv (IGF.IGM .SwiftCC );
@@ -679,39 +765,26 @@ llvm::Constant *swift::irgen::getCoroDeallocFn(IRGenModule &IGM) {
679765 {IGM.CoroAllocatorPtrTy , IGM.Int8PtrTy },
680766 [isSwiftCoroCCAvailable](IRGenFunction &IGF) {
681767 auto parameters = IGF.collectParameters ();
682- auto * allocator = parameters.claimNext ();
768+ auto allocator = :: Allocator ( parameters.claimNext (), IGF );
683769 auto *ptr = parameters.claimNext ();
684770 if (isSwiftCoroCCAvailable) {
685771 // swiftcorocc is available, so if there's no allocator pointer,
686772 // storage was allocated on the stack which will be naturally cleaned
687773 // up when the coroutine's frame is "freed".
688- auto *nullAllocator = IGF.Builder .CreateCmp (
689- llvm::CmpInst::Predicate::ICMP_EQ, allocator,
690- llvm::ConstantPointerNull::get (
691- cast<llvm::PointerType>(allocator->getType ())));
692- auto *bailBlock = IGF.createBasicBlock (" null_allocator" );
693- auto *normalBlock = IGF.createBasicBlock (" nonnull_allocator" );
694- IGF.Builder .CreateCondBr (nullAllocator, bailBlock, normalBlock);
695- IGF.Builder .emitBlock (bailBlock);
696- // Nothing to do here.
697- IGF.Builder .CreateRetVoid ();
698- // Start emitting the "normal" block.
699- IGF.Builder .emitBlock (normalBlock);
774+ allocator.emitOnNullAllocator (" null_allocator" , " nonnull_allocator" ,
775+ [&](auto &IGF) {
776+ // Nothing to do here.
777+ IGF.Builder .CreateRetVoid ();
778+ });
700779 }
701780 auto shouldDeallocateImmediatelyFlag = CoroAllocatorFlags (0 );
702781 shouldDeallocateImmediatelyFlag.setShouldDeallocateImmediately (true );
703- auto *flagsPtr = IGF.Builder .CreateInBoundsGEP (
704- IGF.IGM .CoroAllocatorTy , allocator,
705- {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
706- llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 )});
707- auto *flags = IGF.Builder .CreateLoad (
708- Address (flagsPtr, IGF.IGM .Int32Ty , Alignment (4 )), " " );
709- auto *deallocDeferringAllocator = IGF.Builder .CreateAnd (
710- flags,
711- llvm::APInt (IGF.IGM .Int32Ty ->getBitWidth (),
712- shouldDeallocateImmediatelyFlag.getOpaqueValue ()));
782+ auto *flags = allocator.getFlags ();
713783 auto *isDeallocDeferringAllocator = IGF.Builder .CreateICmpNE (
714- deallocDeferringAllocator,
784+ IGF.Builder .CreateAnd (
785+ flags,
786+ llvm::APInt (IGF.IGM .Int32Ty ->getBitWidth (),
787+ shouldDeallocateImmediatelyFlag.getOpaqueValue ())),
715788 llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ));
716789 auto *deferringAllocatorBlock =
717790 IGF.createBasicBlock (" deferring_allocator" );
@@ -723,17 +796,7 @@ llvm::Constant *swift::irgen::getCoroDeallocFn(IRGenModule &IGM) {
723796 IGF.Builder .CreateRetVoid ();
724797 // Start emitting the "normal" block.
725798 IGF.Builder .emitBlock (normalBlock);
726- auto *calleePtr = IGF.Builder .CreateInBoundsGEP (
727- IGF.IGM .CoroAllocatorTy , allocator,
728- {llvm::ConstantInt::get (IGF.IGM .Int32Ty , 0 ),
729- llvm::ConstantInt::get (IGF.IGM .Int32Ty , 2 )});
730- auto *callee = IGF.Builder .CreateLoad (
731- Address (calleePtr, IGF.IGM .PtrTy , IGF.IGM .getPointerAlignment ()),
732- " deallocate_fn" );
733- auto fnPtr = FunctionPointer::createUnsigned (
734- FunctionPointer::Kind::Function, callee,
735- Signature (cast<llvm::FunctionType>(IGF.IGM .CoroDeallocateFnTy ), {},
736- IGF.IGM .SwiftCC ));
799+ auto fnPtr = allocator.getDeallocate ();
737800 auto *call = IGF.Builder .CreateCall (fnPtr, {ptr});
738801 call->setDoesNotThrow ();
739802 call->setCallingConv (IGF.IGM .SwiftCC );
0 commit comments