Skip to content

Commit 5e2f20b

Browse files
authored
[SUA][IRGen] Add stub for swift_coroFrameAlloc that weakly links against the runtime function (#79889)
* [SUA][IRGen] Add stub for swift_coroFrameAlloc that weakly links against the runtime function This commit modifies IRGen to emit a stub function `__swift_coroFrameAllocStub` instead of the newly introduced swift-rt function `swift_coroFrameAlloc`. The stub checks whether the runtime has the symbol `swift_coroFrameAlloc` and dispatches to it if it exists, uses `malloc` otherwise. This ensures the ability to back deploy the feature to older OS targets. rdar://145239850
1 parent 5d1ce01 commit 5e2f20b

12 files changed

+87
-17
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ class IRGenOptions {
647647
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
648648
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
649649
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
650-
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false),
650+
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(true),
651651
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false),
652652
UseCoroCCX8664(false), UseCoroCCArm64(false),
653653
MergeableTraps(false),

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,6 +2105,12 @@ FUNCTION(CoroFrameAlloc, Swift, swift_coroFrameAlloc, C_CC, AlwaysAvailable,
21052105
NO_ATTRS,
21062106
EFFECT(RuntimeEffect::Allocating),
21072107
UNKNOWN_MEMEFFECTS)
2108+
FUNCTION(coroFrameAllocStub, Swift, swift_coroFrameAllocStub, C_CC,
2109+
AlwaysAvailable, RETURNS(Int8PtrTy),
2110+
ARGS(SizeTy, Int64Ty),
2111+
ATTRS(NoUnwind),
2112+
EFFECT(RuntimeEffect::Allocating),
2113+
UNKNOWN_MEMEFFECTS)
21082114

21092115
// void *_Block_copy(void *block);
21102116
FUNCTION(BlockCopy, BlocksRuntime, _Block_copy, C_CC, AlwaysAvailable,

lib/IRGen/GenCall.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5095,23 +5095,30 @@ void irgen::emitAsyncFunctionEntry(IRGenFunction &IGF,
50955095
void irgen::emitYieldOnceCoroutineEntry(
50965096
IRGenFunction &IGF, CanSILFunctionType fnType,
50975097
NativeCCEntryPointArgumentEmission &emission) {
5098-
// Use malloc and free as our allocator.
5098+
// Use free as our deallocator.
50995099
auto deallocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getFreeFn());
51005100
auto *buffer = emission.getCoroutineBuffer();
51015101
llvm::SmallVector<llvm::Value *, 2> finalArgs;
51025102
llvm::Constant *allocFn = nullptr;
5103-
if (IGF.getOptions().EmitTypeMallocForCoroFrame) {
5103+
if (IGF.getOptions().EmitTypeMallocForCoroFrame
5104+
&& !llvm::Triple(IGF.IGM.Triple).isOSLinux()
5105+
&& !llvm::Triple(IGF.IGM.Triple).isOSWindows()) {
51045106
auto mallocTypeId = IGF.getMallocTypeId();
51055107
finalArgs.push_back(mallocTypeId);
5106-
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getCoroFrameAllocFn());
5108+
// Use swift_coroFrameAllocStub to emit our allocator.
5109+
allocFn = IGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(IGF.IGM));
51075110
} else {
5111+
// Use malloc as our allocator.
51085112
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getMallocFn());
51095113
}
5114+
5115+
ArtificialLocation Loc(IGF.getDebugScope(), IGF.IGM.DebugInfo.get(), IGF.Builder);
51105116
emitRetconCoroutineEntry(IGF, fnType, buffer,
51115117
llvm::Intrinsic::coro_id_retcon_once,
51125118
getYieldOnceCoroutineBufferSize(IGF.IGM),
51135119
getYieldOnceCoroutineBufferAlignment(IGF.IGM), {},
51145120
allocFn, deallocFn, finalArgs);
5121+
51155122
}
51165123

51175124
void irgen::emitYieldManyCoroutineEntry(

lib/IRGen/GenFunc.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,10 +1465,12 @@ class CoroPartialApplicationForwarderEmission
14651465
// Call the right 'llvm.coro.id.retcon' variant.
14661466
llvm::Value *buffer = origParams.claimNext();
14671467
llvm::Value *id;
1468-
if (subIGF.IGM.getOptions().EmitTypeMallocForCoroFrame) {
1469-
// Use swift_coroFrameAlloc as our allocator.
1470-
auto coroAllocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getCoroFrameAllocFn());
1471-
auto mallocTypeId = subIGF.getMallocTypeId();
1468+
if (subIGF.IGM.getOptions().EmitTypeMallocForCoroFrame
1469+
&& !llvm::Triple(subIGF.IGM.Triple).isOSLinux()
1470+
&& !llvm::Triple(subIGF.IGM.Triple).isOSWindows()) {
1471+
// Use swift_coroFrameAllocStub to emit our allocator.
1472+
auto coroAllocFn = subIGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(subIGF.IGM));
1473+
auto mallocTypeId = subIGF.getMallocTypeId();
14721474
id = subIGF.Builder.CreateIntrinsicCall(
14731475
llvm::Intrinsic::coro_id_retcon_once,
14741476
{llvm::ConstantInt::get(

lib/IRGen/GenFunc.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,42 @@ namespace irgen {
6161
CanSILFunctionType outType, Explosion &out, bool isOutlined);
6262
CanType getArgumentLoweringType(CanType type, SILParameterInfo paramInfo,
6363
bool isNoEscape);
64+
65+
/// Stub function that weakly links againt the swift_coroFrameAlloc
66+
/// function. This is required for back-deployment.
67+
static llvm::Constant *getCoroFrameAllocStubFn(IRGenModule &IGM) {
68+
return IGM.getOrCreateHelperFunction(
69+
"__swift_coroFrameAllocStub", IGM.Int8PtrTy,
70+
{IGM.SizeTy, IGM.Int64Ty},
71+
[&](IRGenFunction &IGF) {
72+
auto parameters = IGF.collectParameters();
73+
auto *size = parameters.claimNext();
74+
auto coroAllocPtr = IGF.IGM.getCoroFrameAllocFn();
75+
auto coroAllocFn = dyn_cast<llvm::Function>(coroAllocPtr);
76+
coroAllocFn->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
77+
auto *coroFrameAllocFn = IGF.IGM.getOpaquePtr(coroAllocPtr);
78+
auto *nullSwiftCoroFrameAlloc = IGF.Builder.CreateCmp(
79+
llvm::CmpInst::Predicate::ICMP_NE, coroFrameAllocFn,
80+
llvm::ConstantPointerNull::get(
81+
cast<llvm::PointerType>(coroFrameAllocFn->getType())));
82+
auto *coroFrameAllocReturn = IGF.createBasicBlock("return-coroFrameAlloc");
83+
auto *mallocReturn = IGF.createBasicBlock("return-malloc");
84+
IGF.Builder.CreateCondBr(nullSwiftCoroFrameAlloc, coroFrameAllocReturn, mallocReturn);
85+
86+
IGF.Builder.emitBlock(coroFrameAllocReturn);
87+
auto *mallocTypeId = parameters.claimNext();
88+
auto *coroFrameAllocCall = IGF.Builder.CreateCall(IGF.IGM.getCoroFrameAllocFunctionPointer(), {size, mallocTypeId});
89+
IGF.Builder.CreateRet(coroFrameAllocCall);
90+
91+
IGF.Builder.emitBlock(mallocReturn);
92+
auto *mallocCall = IGF.Builder.CreateCall(IGF.IGM.getMallocFunctionPointer(), {size});
93+
IGF.Builder.CreateRet(mallocCall);
94+
},
95+
/*setIsNoInline=*/false,
96+
/*forPrologue=*/false,
97+
/*isPerformanceConstraint=*/false,
98+
/*optionalLinkageOverride=*/nullptr, llvm::CallingConv::C);
99+
}
64100
} // end namespace irgen
65101
} // end namespace swift
66102

test/IRGen/partial_apply_coro.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// 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
3-
// 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
3+
// 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
44

55
// REQUIRES: concurrency
66

test/IRGen/yield_once.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth
1+
// 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
22

33
import Builtin
44

test/IRGen/yield_once_big.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 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
1+
// 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
22
// UNSUPPORTED: CPU=arm64_32
33

44
import Builtin

test/IRGen/yield_once_biggish.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 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
1+
// 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
22

33
// i386 uses a scalar result count of 3 instead of 4, so this test would need
44
// to be substantially different to test the functionality there. It's easier

test/IRGen/yield_once_enable_emit_type_malloc_coro_frame.sil

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// 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
1+
// REQUIRES: OS=macosx || OS=iOS
2+
// RUN: %target-swift-frontend -emit-irgen %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-ptrsize-%target-ptrauth
23

34
import Builtin
45

@@ -10,8 +11,8 @@ sil @marker : $(Builtin.Int32) -> ()
1011
// CHECK-SAME: [[CORO_ATTRIBUTES:#[0-9]+]]
1112
sil @test_simple : $@yield_once () -> () {
1213
entry:
13-
// 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)
14-
// 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)
14+
// 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)
15+
// 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)
1516
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
1617

1718
// CHECK-NEXT: call swiftcc void @marker(i32 1000)
@@ -43,6 +44,24 @@ unwind:
4344
// CHECK-NEXT: unreachable
4445
}
4546

47+
// CHECK-32: define linkonce_odr hidden ptr @__swift_coroFrameAllocStub(i32 %0, i64 %1) #1{{( comdat)?}} {
48+
// CHECK-64: define linkonce_odr hidden ptr @__swift_coroFrameAllocStub(i64 %0, i64 %1) #1{{( comdat)?}} {
49+
// CHECK: [[T0:%.*]] = icmp ne ptr @swift_coroFrameAlloc, null
50+
// CHECK: br i1 [[T0]], label %return-coroFrameAlloc, label %return-malloc
51+
52+
// CHECK-LABEL: return-coroFrameAlloc:
53+
// CHECK-32: [[T1:%.*]] = call ptr @swift_coroFrameAlloc(i32 %0, i64 %1)
54+
// CHECK-64: [[T1:%.*]] = call ptr @swift_coroFrameAlloc(i64 %0, i64 %1)
55+
// CHECK: ret ptr [[T1]]
56+
57+
// CHECK-LABEL: return-malloc:
58+
// CHECK-32: [[T2:%.*]] = call ptr @malloc(i32 %0)
59+
// CHECK-64: [[T2:%.*]] = call ptr @malloc(i64 %0)
60+
// CHECK: ret ptr [[T2]]
61+
62+
// CHECK-32: declare extern_weak ptr @swift_coroFrameAlloc(i32, i64)
63+
// CHECK-64: declare extern_weak ptr @swift_coroFrameAlloc(i64, i64)
64+
4665
// CHECK-LABEL: declare{{( dllimport)?}}{{( protected)?}} swiftcc void @"$sIetA_TC"
4766
// CHECK-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE]]), i1)
4867

test/IRGen/yield_once_indirect.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 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
1+
// 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
22

33
import Builtin
44
import Swift

test/IRGen/yield_result.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 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
1+
// 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
22

33
import Builtin
44

0 commit comments

Comments
 (0)