Skip to content

Commit 3dd9282

Browse files
committed
[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 cc14548 commit 3dd9282

File tree

5 files changed

+67
-8
lines changed

5 files changed

+67
-8
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,13 @@ FUNCTION(Free, c, free, C_CC, AlwaysAvailable,
21022102
FUNCTION(CoroFrameAlloc, Swift, swift_coroFrameAlloc, C_CC, AlwaysAvailable,
21032103
RETURNS(Int8PtrTy),
21042104
ARGS(SizeTy, Int64Ty),
2105-
NO_ATTRS,
2105+
ATTRS(NoUnwind),
2106+
EFFECT(Allocating),
2107+
UNKNOWN_MEMEFFECTS)
2108+
FUNCTION(coroFrameAllocStub, Swift, swift_coroFrameAllocStub, C_CC,
2109+
AlwaysAvailable, RETURNS(Int8PtrTy),
2110+
ARGS(SizeTy, Int64Ty),
2111+
ATTRS(NoUnwind),
21062112
EFFECT(Allocating),
21072113
UNKNOWN_MEMEFFECTS)
21082114

lib/IRGen/GenCall.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5097,16 +5097,18 @@ void irgen::emitAsyncFunctionEntry(IRGenFunction &IGF,
50975097
void irgen::emitYieldOnceCoroutineEntry(
50985098
IRGenFunction &IGF, CanSILFunctionType fnType,
50995099
NativeCCEntryPointArgumentEmission &emission) {
5100-
// Use malloc and free as our allocator.
5100+
// Use free as our deallocator.
51015101
auto deallocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getFreeFn());
51025102
auto *buffer = emission.getCoroutineBuffer();
51035103
llvm::SmallVector<llvm::Value *, 2> finalArgs;
51045104
llvm::Constant *allocFn = nullptr;
51055105
if (IGF.getOptions().EmitTypeMallocForCoroFrame) {
51065106
auto mallocTypeId = IGF.getMallocTypeId();
51075107
finalArgs.push_back(mallocTypeId);
5108-
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getCoroFrameAllocFn());
5108+
// Use swift_coroFrameAllocStub to emit our allocator.
5109+
allocFn = IGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(IGF.IGM));
51095110
} else {
5111+
// Use malloc as our allocator.
51105112
allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getMallocFn());
51115113
}
51125114
emitRetconCoroutineEntry(IGF, fnType, buffer,

lib/IRGen/GenFunc.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,9 +1466,9 @@ class CoroPartialApplicationForwarderEmission
14661466
llvm::Value *buffer = origParams.claimNext();
14671467
llvm::Value *id;
14681468
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();
1469+
// Use swift_coroFrameAllocStub to emit our allocator.
1470+
auto coroAllocFn = subIGF.IGM.getOpaquePtr(getCoroFrameAllocStubFn(subIGF.IGM));
1471+
auto mallocTypeId = subIGF.getMallocTypeId();
14721472
id = subIGF.Builder.CreateIntrinsicCall(
14731473
llvm::Intrinsic::coro_id_retcon_once,
14741474
{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/yield_once_enable_emit_type_malloc_coro_frame.sil

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ sil @marker : $(Builtin.Int32) -> ()
1010
// CHECK-SAME: [[CORO_ATTRIBUTES:#[0-9]+]]
1111
sil @test_simple : $@yield_once () -> () {
1212
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)
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_coroFrameAllocStub, 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_coroFrameAllocStub, ptr @free, i64 38223)
1515
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
1616

1717
// CHECK-NEXT: call swiftcc void @marker(i32 1000)
@@ -43,6 +43,21 @@ unwind:
4343
// CHECK-NEXT: unreachable
4444
}
4545

46+
// CHECK: define linkonce_odr hidden ptr @__swift_coroFrameAllocStub(i64 %0, i64 %1) #1 {
47+
// CHECK-NEXT: entry:
48+
// CHECK-NEXT: %2 = icmp ne ptr @swift_coroFrameAlloc, null
49+
// CHECK-NEXT: br i1 %2, label %return-coroFrameAlloc, label %return-malloc
50+
51+
// CHECK-LABEL: return-coroFrameAlloc:
52+
// CHECK-NEXT: %3 = call ptr @swift_coroFrameAlloc(i64 %0, i64 %1) #2
53+
// CHECK-NEXT: ret ptr %3
54+
55+
// CHECK-LABEL: return-malloc:
56+
// CHECK-NEXT: %4 = call ptr @malloc(i64 %0)
57+
// CHECK-NEXT: ret ptr %4
58+
59+
// CHECK: declare extern_weak ptr @swift_coroFrameAlloc(i64, i64)
60+
4661
// CHECK-LABEL: declare{{( dllimport)?}}{{( protected)?}} swiftcc void @"$sIetA_TC"
4762
// CHECK-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE]]), i1)
4863

0 commit comments

Comments
 (0)