Skip to content

Commit d00b73c

Browse files
committed
[NFC] IRGen: Refactor and deduplicate this code.
1 parent cd8144a commit d00b73c

File tree

1 file changed

+129
-66
lines changed

1 file changed

+129
-66
lines changed

lib/IRGen/GenCoro.cpp

Lines changed: 129 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
617721
llvm::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

Comments
 (0)