[CoroutineAccessors] Open code alloc fn.

Replace the runtime function with an open-coded version.
This commit is contained in:
Nate Chandler
2025-03-27 13:38:02 -07:00
parent b878155a5a
commit dd238343bb
6 changed files with 72 additions and 54 deletions

View File

@@ -22,9 +22,6 @@
#include <cstddef> #include <cstddef>
namespace swift { namespace swift {
SWIFT_RUNTIME_EXPORT
SWIFT_CC(swift) void *swift_coro_alloc(CoroAllocator *allocator, size_t size);
SWIFT_RUNTIME_EXPORT SWIFT_RUNTIME_EXPORT
SWIFT_CC(swift) void swift_coro_dealloc(CoroAllocator *allocator, void *ptr); SWIFT_CC(swift) void swift_coro_dealloc(CoroAllocator *allocator, void *ptr);
} // end namespace swift } // end namespace swift

View File

@@ -3008,16 +3008,6 @@ FUNCTION(MemsetS, c, memset_s, C_CC, AlwaysAvailable,
EFFECT(RuntimeEffect::NoEffect), EFFECT(RuntimeEffect::NoEffect),
UNKNOWN_MEMEFFECTS) UNKNOWN_MEMEFFECTS)
// void *swift_coro_alloc(CoroAllocator *, size_t size);
FUNCTION(CoroAlloc,
Swift, swift_coro_alloc, SwiftCC,
CoroutineAccessorsAvailability,
RETURNS(Int8PtrTy),
ARGS(CoroAllocatorPtrTy, SizeTy),
NO_ATTRS,
EFFECT(RuntimeEffect::Allocating, RuntimeEffect::Concurrency),
UNKNOWN_MEMEFFECTS)
// void swift_coro_dealloc(CoroAllocator *, void *ptr); // void swift_coro_dealloc(CoroAllocator *, void *ptr);
FUNCTION(CoroDealloc, FUNCTION(CoroDealloc,
Swift, swift_coro_dealloc, SwiftCC, Swift, swift_coro_dealloc, SwiftCC,

View File

@@ -5118,39 +5118,59 @@ void irgen::emitYieldManyCoroutineEntry(
allocFn, deallocFn, {}); allocFn, deallocFn, {});
} }
static llvm::Constant *getCoroAllocWrapperFn(IRGenModule &IGM) { static llvm::Constant *getCoroAllocFn(IRGenModule &IGM) {
auto isSwiftCoroCCAvailable = IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro;
return IGM.getOrCreateHelperFunction( return IGM.getOrCreateHelperFunction(
"__swift_coro_alloc_", IGM.Int8PtrTy, "_swift_coro_alloc", IGM.Int8PtrTy, {IGM.CoroAllocatorPtrTy, IGM.SizeTy},
{IGM.CoroAllocatorPtrTy, IGM.SizeTy}, [isSwiftCoroCCAvailable](IRGenFunction &IGF) {
[](IRGenFunction &IGF) {
auto parameters = IGF.collectParameters(); auto parameters = IGF.collectParameters();
auto *allocator = parameters.claimNext(); auto *allocator = parameters.claimNext();
auto *size = parameters.claimNext(); auto *size = parameters.claimNext();
auto *nullAllocator = IGF.Builder.CreateCmp( if (isSwiftCoroCCAvailable) {
llvm::CmpInst::Predicate::ICMP_EQ, allocator, // swiftcorocc is available, so if there's no allocator pointer,
llvm::ConstantPointerNull::get( // allocate storage on the stack and return a pointer to it without
cast<llvm::PointerType>(allocator->getType()))); // popping the stack.
auto *poplessReturn = IGF.createBasicBlock("coro.return.popless"); auto *nullAllocator = IGF.Builder.CreateCmp(
auto *normalReturn = IGF.createBasicBlock("coro.return.normal"); llvm::CmpInst::Predicate::ICMP_EQ, allocator,
IGF.Builder.CreateCondBr(nullAllocator, poplessReturn, normalReturn); llvm::ConstantPointerNull::get(
IGF.Builder.emitBlock(poplessReturn); cast<llvm::PointerType>(allocator->getType())));
// Emit the dynamic alloca. auto *poplessReturn = IGF.createBasicBlock("popless");
auto *alloca = auto *normalReturn = IGF.createBasicBlock("normal");
IGF.Builder.IRBuilderBase::CreateAlloca(IGF.IGM.Int8Ty, size); IGF.Builder.CreateCondBr(nullAllocator, poplessReturn, normalReturn);
alloca->setAlignment(llvm::Align(MaximumAlignment)); IGF.Builder.emitBlock(poplessReturn);
auto *retPopless = IGF.Builder.CreateIntrinsic( // Emit the dynamic alloca.
IGF.IGM.VoidTy, llvm::Intrinsic::ret_popless, {}); auto *alloca =
retPopless->setTailCallKind(llvm::CallInst::TailCallKind::TCK_MustTail); IGF.Builder.IRBuilderBase::CreateAlloca(IGF.IGM.Int8Ty, size);
IGF.Builder.CreateRet(alloca); alloca->setAlignment(llvm::Align(MaximumAlignment));
IGF.Builder.emitBlock(normalReturn); auto *retPopless = IGF.Builder.CreateIntrinsic(
auto *call = IGF.Builder.CreateCall( IGF.IGM.VoidTy, llvm::Intrinsic::ret_popless, {});
IGF.IGM.getCoroAllocFunctionPointer(), {allocator, size}); retPopless->setTailCallKind(
llvm::CallInst::TailCallKind::TCK_MustTail);
IGF.Builder.CreateRet(alloca);
// Start emitting the "normal" block.
IGF.Builder.emitBlock(normalReturn);
}
auto *calleePtr = IGF.Builder.CreateInBoundsGEP(
IGF.IGM.CoroAllocatorTy, allocator,
{llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0),
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1)});
auto *callee = IGF.Builder.CreateLoad(
Address(calleePtr, IGF.IGM.CoroAllocateFnTy->getPointerTo(),
IGF.IGM.getPointerAlignment()),
"allocate_fn");
auto fnPtr = FunctionPointer::createUnsigned(
FunctionPointer::Kind::Function, callee,
Signature(cast<llvm::FunctionType>(IGF.IGM.CoroAllocateFnTy), {},
IGF.IGM.SwiftCC));
auto *call = IGF.Builder.CreateCall(fnPtr, {size});
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.SwiftCC);
IGF.Builder.CreateRet(call); IGF.Builder.CreateRet(call);
}, },
/*setIsNoInline=*/false, /*setIsNoInline=*/true,
/*forPrologue=*/false, /*forPrologue=*/false,
/*isPerformanceConstraint=*/false, /*isPerformanceConstraint=*/false,
/*optionalLinkageOverride=*/nullptr, llvm::CallingConv::SwiftCoro); /*optionalLinkageOverride=*/nullptr, IGM.SwiftCoroCC);
} }
static llvm::Constant *getCoroDeallocWrapperFn(IRGenModule &IGM) { static llvm::Constant *getCoroDeallocWrapperFn(IRGenModule &IGM) {
@@ -5190,9 +5210,7 @@ void irgen::emitYieldOnce2CoroutineEntry(IRGenFunction &IGF,
IGF.setCoroutineAllocator(allocator); IGF.setCoroutineAllocator(allocator);
auto isSwiftCoroCCAvailable = auto isSwiftCoroCCAvailable =
IGF.IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro; IGF.IGM.SwiftCoroCC == llvm::CallingConv::SwiftCoro;
auto allocFn = IGF.IGM.getOpaquePtr(isSwiftCoroCCAvailable auto allocFn = IGF.IGM.getOpaquePtr(getCoroAllocFn(IGF.IGM));
? getCoroAllocWrapperFn(IGF.IGM)
: IGF.IGM.getCoroAllocFn());
auto deallocFn = IGF.IGM.getOpaquePtr(isSwiftCoroCCAvailable auto deallocFn = IGF.IGM.getOpaquePtr(isSwiftCoroCCAvailable
? getCoroDeallocWrapperFn(IGF.IGM) ? getCoroDeallocWrapperFn(IGF.IGM)
: IGF.IGM.getCoroDeallocFn()); : IGF.IGM.getCoroDeallocFn());

View File

@@ -16,10 +16,6 @@
using namespace swift; using namespace swift;
void *swift::swift_coro_alloc(CoroAllocator *allocator, size_t size) {
return allocator->allocate(size);
}
void swift::swift_coro_dealloc(CoroAllocator *allocator, void *ptr) { void swift::swift_coro_dealloc(CoroAllocator *allocator, void *ptr) {
assert(allocator); assert(allocator);
// Calls to swift_coro_dealloc are emitted in resume funclets for every // Calls to swift_coro_dealloc are emitted in resume funclets for every

View File

@@ -24,6 +24,21 @@
// CHECK-SAME: swift_task_dealloc // CHECK-SAME: swift_task_dealloc
// CHECK-SAME: } // CHECK-SAME: }
// CHECK-LABEL: @_swift_coro_alloc(
// CHECK-SAME: ptr [[ALLOCATOR:%[^,]+]]
// CHECK-SAME: [[INT]] [[SIZE:%[^)]+]]
// CHECK-SAME: )
// CHECK-SAME: {
// CHECK: entry:
// CHECK: [[ALLOCATE_FN_PTR:%[^,]+]] = getelementptr inbounds %swift.coro_allocator
// CHECK-SAME: ptr [[ALLOCATOR]]
// CHECK-SAME: i32 0
// CHECK-SAME: i32 1
// CHECK: [[ALLOCATE_FN:%[^,]+]] = load ptr, ptr [[ALLOCATE_FN_PTR]]
// CHECK: [[ALLOCATION:%[^,]+]] = call swiftcc ptr [[ALLOCATE_FN]]([[INT]] [[SIZE]])
// CHECK: ret ptr [[ALLOCATION]]
// CHECK: }
@frozen @frozen
public struct S { public struct S {
public var o: any AnyObject public var o: any AnyObject

View File

@@ -28,7 +28,7 @@
// CHECK-SAME: free // CHECK-SAME: free
// CHECK-SAME: } // CHECK-SAME: }
// CHECK-LABEL: @__swift_coro_alloc_( // CHECK-LABEL: @_swift_coro_alloc(
// CHECK-SAME: ptr [[ALLOCATOR:%[^,]+]] // CHECK-SAME: ptr [[ALLOCATOR:%[^,]+]]
// CHECK-SAME: i64 [[SIZE:%[^)]+]] // CHECK-SAME: i64 [[SIZE:%[^)]+]]
// CHECK-SAME: ) // CHECK-SAME: )
@@ -36,18 +36,20 @@
// CHECK: entry: // CHECK: entry:
// CHECK: [[USE_POPLESS:%[^,]+]] = icmp eq ptr [[ALLOCATOR]], null // CHECK: [[USE_POPLESS:%[^,]+]] = icmp eq ptr [[ALLOCATOR]], null
// CHECK: br i1 [[USE_POPLESS]], // CHECK: br i1 [[USE_POPLESS]],
// CHECK-SAME: label %coro.return.popless // CHECK-SAME: label %popless
// CHECK-SAME: label %coro.return.normal // CHECK-SAME: label %normal
// CHECK: coro.return.popless: // CHECK: popless:
// CHECK: [[STACK_ALLOCATION:%[^,]+]] = alloca i8, i64 [[SIZE]] // CHECK: [[STACK_ALLOCATION:%[^,]+]] = alloca i8, i64 [[SIZE]]
// CHECK: musttail call void @llvm.ret.popless() // CHECK: musttail call void @llvm.ret.popless()
// CHECK: ret ptr [[STACK_ALLOCATION]] // CHECK: ret ptr [[STACK_ALLOCATION]]
// CHECK: coro.return.normal: // CHECK: normal:
// CHECK: [[OTHER_ALLOCATION:%[^,]+]] = call swiftcc ptr @swift_coro_alloc( // CHECK: [[ALLOCATE_FN_PTR:%[^,]+]] = getelementptr inbounds %swift.coro_allocator
// CHECK-SAME: ptr [[ALLOCATOR]] // CHECK-SAME: ptr [[ALLOCATOR]]
// CHECK-SAME: i64 [[SIZE]] // CHECK-SAME: i32 0
// CHECK-SAME: ) // CHECK-SAME: i32 1
// CHECK: ret ptr [[OTHER_ALLOCATION]] // CHECK: [[ALLOCATE_FN:%[^,]+]] = load ptr, ptr [[ALLOCATE_FN_PTR]]
// CHECK: [[ALLOCATION:%[^,]+]] = call swiftcc ptr [[ALLOCATE_FN]](i64 [[SIZE]])
// CHECK: ret ptr [[ALLOCATION]]
// CHECK: } // CHECK: }
// CHECK-LABEL: @__swift_coro_dealloc_( // CHECK-LABEL: @__swift_coro_dealloc_(