Skip to content

[6.2][SUA][IRGen] Add stub for swift_coroFrameAlloc that weakly links against the runtime function #80769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ class IRGenOptions {
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false),
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(true),
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false),
UseCoroCCX8664(false), UseCoroCCArm64(false),
MergeableTraps(false),
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,12 @@ FUNCTION(CoroFrameAlloc, Swift, swift_coroFrameAlloc, C_CC, AlwaysAvailable,
NO_ATTRS,
EFFECT(RuntimeEffect::Allocating),
UNKNOWN_MEMEFFECTS)
FUNCTION(coroFrameAllocStub, Swift, swift_coroFrameAllocStub, C_CC,
AlwaysAvailable, RETURNS(Int8PtrTy),
ARGS(SizeTy, Int64Ty),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::Allocating),
UNKNOWN_MEMEFFECTS)

// void *_Block_copy(void *block);
FUNCTION(BlockCopy, BlocksRuntime, _Block_copy, C_CC, AlwaysAvailable,
Expand Down
13 changes: 10 additions & 3 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5095,23 +5095,30 @@ void irgen::emitAsyncFunctionEntry(IRGenFunction &IGF,
void irgen::emitYieldOnceCoroutineEntry(
IRGenFunction &IGF, CanSILFunctionType fnType,
NativeCCEntryPointArgumentEmission &emission) {
// Use malloc and free as our allocator.
// Use free as our deallocator.
auto deallocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getFreeFn());
auto *buffer = emission.getCoroutineBuffer();
llvm::SmallVector<llvm::Value *, 2> finalArgs;
llvm::Constant *allocFn = nullptr;
if (IGF.getOptions().EmitTypeMallocForCoroFrame) {
if (IGF.getOptions().EmitTypeMallocForCoroFrame
&& !llvm::Triple(IGF.IGM.Triple).isOSLinux()
&& !llvm::Triple(IGF.IGM.Triple).isOSWindows()) {
auto mallocTypeId = IGF.getMallocTypeId();
finalArgs.push_back(mallocTypeId);
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getCoroFrameAllocFn());
// Use swift_coroFrameAllocStub to emit our allocator.
allocFn = IGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(IGF.IGM));
} else {
// Use malloc as our allocator.
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getMallocFn());
}

ArtificialLocation Loc(IGF.getDebugScope(), IGF.IGM.DebugInfo.get(), IGF.Builder);
emitRetconCoroutineEntry(IGF, fnType, buffer,
llvm::Intrinsic::coro_id_retcon_once,
getYieldOnceCoroutineBufferSize(IGF.IGM),
getYieldOnceCoroutineBufferAlignment(IGF.IGM), {},
allocFn, deallocFn, finalArgs);

}

void irgen::emitYieldManyCoroutineEntry(
Expand Down
10 changes: 6 additions & 4 deletions lib/IRGen/GenFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1465,10 +1465,12 @@ class CoroPartialApplicationForwarderEmission
// Call the right 'llvm.coro.id.retcon' variant.
llvm::Value *buffer = origParams.claimNext();
llvm::Value *id;
if (subIGF.IGM.getOptions().EmitTypeMallocForCoroFrame) {
// Use swift_coroFrameAlloc as our allocator.
auto coroAllocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getCoroFrameAllocFn());
auto mallocTypeId = subIGF.getMallocTypeId();
if (subIGF.IGM.getOptions().EmitTypeMallocForCoroFrame
&& !llvm::Triple(subIGF.IGM.Triple).isOSLinux()
&& !llvm::Triple(subIGF.IGM.Triple).isOSWindows()) {
// Use swift_coroFrameAllocStub to emit our allocator.
auto coroAllocFn = subIGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(subIGF.IGM));
auto mallocTypeId = subIGF.getMallocTypeId();
id = subIGF.Builder.CreateIntrinsicCall(
llvm::Intrinsic::coro_id_retcon_once,
{llvm::ConstantInt::get(
Expand Down
36 changes: 36 additions & 0 deletions lib/IRGen/GenFunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,42 @@ namespace irgen {
CanSILFunctionType outType, Explosion &out, bool isOutlined);
CanType getArgumentLoweringType(CanType type, SILParameterInfo paramInfo,
bool isNoEscape);

/// Stub function that weakly links againt the swift_coroFrameAlloc
/// function. This is required for back-deployment.
static llvm::Constant *getCoroFrameAllocStubFn(IRGenModule &IGM) {
return IGM.getOrCreateHelperFunction(
"__swift_coroFrameAllocStub", IGM.Int8PtrTy,
{IGM.SizeTy, IGM.Int64Ty},
[&](IRGenFunction &IGF) {
auto parameters = IGF.collectParameters();
auto *size = parameters.claimNext();
auto coroAllocPtr = IGF.IGM.getCoroFrameAllocFn();
auto coroAllocFn = dyn_cast<llvm::Function>(coroAllocPtr);
coroAllocFn->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
auto *coroFrameAllocFn = IGF.IGM.getOpaquePtr(coroAllocPtr);
auto *nullSwiftCoroFrameAlloc = IGF.Builder.CreateCmp(
llvm::CmpInst::Predicate::ICMP_NE, coroFrameAllocFn,
llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(coroFrameAllocFn->getType())));
auto *coroFrameAllocReturn = IGF.createBasicBlock("return-coroFrameAlloc");
auto *mallocReturn = IGF.createBasicBlock("return-malloc");
IGF.Builder.CreateCondBr(nullSwiftCoroFrameAlloc, coroFrameAllocReturn, mallocReturn);

IGF.Builder.emitBlock(coroFrameAllocReturn);
auto *mallocTypeId = parameters.claimNext();
auto *coroFrameAllocCall = IGF.Builder.CreateCall(IGF.IGM.getCoroFrameAllocFunctionPointer(), {size, mallocTypeId});
IGF.Builder.CreateRet(coroFrameAllocCall);

IGF.Builder.emitBlock(mallocReturn);
auto *mallocCall = IGF.Builder.CreateCall(IGF.IGM.getMallocFunctionPointer(), {size});
IGF.Builder.CreateRet(mallocCall);
},
/*setIsNoInline=*/false,
/*forPrologue=*/false,
/*isPerformanceConstraint=*/false,
/*optionalLinkageOverride=*/nullptr, llvm::CallingConv::C);
}
} // end namespace irgen
} // end namespace swift

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/partial_apply_coro.sil
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=OnoneSimplification -I %t -emit-ir %s -o - | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-cpu
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=OnoneSimplification -I %t -emit-ir -disable-emit-type-malloc-for-coro-frame %s -o - | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-cpu

// REQUIRES: concurrency

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/yield_once.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth
// RUN: %target-swift-frontend -emit-irgen -disable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth

import Builtin

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/yield_once_big.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize
// RUN: %target-swift-frontend -emit-irgen -disable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize
// UNSUPPORTED: CPU=arm64_32

import Builtin
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/yield_once_biggish.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize
// RUN: %target-swift-frontend -emit-irgen -disable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize

// i386 uses a scalar result count of 3 instead of 4, so this test would need
// to be substantially different to test the functionality there. It's easier
Expand Down
25 changes: 22 additions & 3 deletions test/IRGen/yield_once_enable_emit_type_malloc_coro_frame.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -emit-irgen -enable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth
// REQUIRES: OS=macosx || OS=iOS
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth

import Builtin

Expand All @@ -10,8 +11,8 @@ sil @marker : $(Builtin.Int32) -> ()
// CHECK-SAME: [[CORO_ATTRIBUTES:#[0-9]+]]
sil @test_simple : $@yield_once () -> () {
entry:
// CHECK-32: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$sIetA_TC", ptr @swift_coroFrameAlloc, ptr @free, i64 38223)
// CHECK-64: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$sIetA_TC", ptr @swift_coroFrameAlloc, ptr @free, i64 38223)
// CHECK-32: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$sIetA_TC", ptr @__swift_coroFrameAllocStub, ptr @free, i64 38223)
// CHECK-64: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$sIetA_TC", ptr @__swift_coroFrameAllocStub, ptr @free, i64 38223)
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)

// CHECK-NEXT: call swiftcc void @marker(i32 1000)
Expand Down Expand Up @@ -43,6 +44,24 @@ unwind:
// CHECK-NEXT: unreachable
}

// CHECK-32: define linkonce_odr hidden ptr @__swift_coroFrameAllocStub(i32 %0, i64 %1) #1{{( comdat)?}} {
// CHECK-64: define linkonce_odr hidden ptr @__swift_coroFrameAllocStub(i64 %0, i64 %1) #1{{( comdat)?}} {
// CHECK: [[T0:%.*]] = icmp ne ptr @swift_coroFrameAlloc, null
// CHECK: br i1 [[T0]], label %return-coroFrameAlloc, label %return-malloc

// CHECK-LABEL: return-coroFrameAlloc:
// CHECK-32: [[T1:%.*]] = call ptr @swift_coroFrameAlloc(i32 %0, i64 %1)
// CHECK-64: [[T1:%.*]] = call ptr @swift_coroFrameAlloc(i64 %0, i64 %1)
// CHECK: ret ptr [[T1]]

// CHECK-LABEL: return-malloc:
// CHECK-32: [[T2:%.*]] = call ptr @malloc(i32 %0)
// CHECK-64: [[T2:%.*]] = call ptr @malloc(i64 %0)
// CHECK: ret ptr [[T2]]

// CHECK-32: declare extern_weak ptr @swift_coroFrameAlloc(i32, i64)
// CHECK-64: declare extern_weak ptr @swift_coroFrameAlloc(i64, i64)

// CHECK-LABEL: declare{{( dllimport)?}}{{( protected)?}} swiftcc void @"$sIetA_TC"
// CHECK-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE]]), i1)

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/yield_once_indirect.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize
// RUN: %target-swift-frontend -emit-irgen -disable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth -DINT=i%target-ptrsize

import Builtin
import Swift
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/yield_result.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-cpu --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize
// RUN: %target-swift-frontend -emit-irgen -disable-emit-type-malloc-for-coro-frame %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-cpu --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize

import Builtin

Expand Down