Skip to content

Commit 0b8efc9

Browse files
authored
[SUA][IRGen] Change IRGen to emit calls to swift_coroFrameAlloc (#79384)
When TMO is enabled, change IRGen to pass the newly introduced runtime function `swift_coroFrameAlloc` (and pass an additional argument — the hash value) instead of `malloc` when it inserts calls to `coro_id_retcon_once`. The hashValue is computed based on the current function name (computed in `getDiscriminatorForString`) rdar://141235957
1 parent 8337815 commit 0b8efc9

13 files changed

+225
-30
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,9 @@ class IRGenOptions {
488488

489489
unsigned EmitAsyncFramePushPopMetadata : 1;
490490

491+
// Whether to emit typed malloc during coroutine frame allocation.
492+
unsigned EmitTypeMallocForCoroFrame : 1;
493+
491494
// Whether to use the yield_once ABI when emitting yield_once_2 coroutines.
492495
unsigned EmitYieldOnce2AsYieldOnce : 1;
493496

@@ -597,8 +600,9 @@ class IRGenOptions {
597600
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
598601
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
599602
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
600-
EmitAsyncFramePushPopMetadata(true), EmitYieldOnce2AsYieldOnce(true),
601-
AsyncFramePointerAll(false), UseProfilingMarkerThunks(false),
603+
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false),
604+
EmitYieldOnce2AsYieldOnce(true), AsyncFramePointerAll(false),
605+
UseProfilingMarkerThunks(false),
602606
DebugInfoForProfiling(false), CmdArgs(),
603607
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
604608
TypeInfoFilter(TypeInfoDumpFilter::All),

include/swift/Option/FrontendOptions.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,13 @@ def disable_async_frame_push_pop_metadata :
13451345
Flag<["-"], "disable-async-frame-push-pop-metadata">,
13461346
HelpText<"Disable async frame push pop metadata">;
13471347

1348+
def enable_emit_type_malloc_for_coro_frame :
1349+
Flag<["-"], "enable-emit-type-malloc-for-coro-frame">,
1350+
HelpText<"Enable emitting typed malloc for coroutine frame allocation">;
1351+
def disable_emit_type_malloc_for_coro_frame :
1352+
Flag<["-"], "disable-emit-type-malloc-for-coro-frame">,
1353+
HelpText<"Disable emitting typed malloc for coroutine frame allocation">;
1354+
13481355
def enable_async_frame_pointer_all :
13491356
Flag<["-"], "enable-async-frame-pointer-all">,
13501357
HelpText<"Always emit async frame stack frames (frame-pointer=all)">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
36303630
Args.hasFlag(OPT_enable_async_frame_push_pop_metadata,
36313631
OPT_disable_async_frame_push_pop_metadata,
36323632
Opts.EmitAsyncFramePushPopMetadata);
3633+
Opts.EmitTypeMallocForCoroFrame =
3634+
Args.hasFlag(OPT_enable_emit_type_malloc_for_coro_frame,
3635+
OPT_disable_emit_type_malloc_for_coro_frame,
3636+
Opts.EmitTypeMallocForCoroFrame);
36333637
Opts.AsyncFramePointerAll = Args.hasFlag(OPT_enable_async_frame_pointer_all,
36343638
OPT_disable_async_frame_pointer_all,
36353639
Opts.AsyncFramePointerAll);

lib/IRGen/GenCall.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4818,20 +4818,41 @@ emitRetconCoroutineEntry(IRGenFunction &IGF, CanSILFunctionType fnType,
48184818
auto prototype =
48194819
IGF.IGM.getOpaquePtr(IGF.IGM.getAddrOfContinuationPrototype(fnType));
48204820

4821-
// Use malloc and free as our allocator.
4822-
auto allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getMallocFn());
4821+
4822+
4823+
// Use free as our deallocator.
48234824
auto deallocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getFreeFn());
48244825

48254826
// Call the right 'llvm.coro.id.retcon' variant.
48264827
llvm::Value *buffer = emission.getCoroutineBuffer();
4827-
llvm::Value *id = IGF.Builder.CreateIntrinsicCall(idIntrinsic, {
4828-
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferSize.getValue()),
4829-
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferAlignment.getValue()),
4830-
buffer,
4831-
prototype,
4832-
allocFn,
4833-
deallocFn
4834-
});
4828+
4829+
llvm::Value *id;
4830+
if (IGF.getOptions().EmitTypeMallocForCoroFrame) {
4831+
// Use swift_coroFrameAlloc as our allocator.
4832+
auto coroAllocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getCoroFrameAllocFn());
4833+
auto mallocTypeId = IGF.getMallocTypeId();
4834+
id = IGF.Builder.CreateIntrinsicCall(idIntrinsic, {
4835+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferSize.getValue()),
4836+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferAlignment.getValue()),
4837+
buffer,
4838+
prototype,
4839+
coroAllocFn,
4840+
deallocFn,
4841+
mallocTypeId
4842+
});
4843+
} else {
4844+
// Use mallocas our allocator.
4845+
auto allocFn = IGF.IGM.getOpaquePtr(IGF.IGM.getMallocFn());
4846+
id = IGF.Builder.CreateIntrinsicCall(idIntrinsic, {
4847+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferSize.getValue()),
4848+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, bufferAlignment.getValue()),
4849+
buffer,
4850+
prototype,
4851+
allocFn,
4852+
deallocFn
4853+
});
4854+
}
4855+
48354856

48364857
// Call 'llvm.coro.begin', just for consistency with the normal pattern.
48374858
// This serves as a handle that we can pass around to other intrinsics.

lib/IRGen/GenFunc.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,13 +1459,30 @@ class CoroPartialApplicationForwarderEmission
14591459
cast<SILFunctionType>(
14601460
unsubstType->mapTypeOutOfContext()->getCanonicalType())));
14611461

1462-
// Use malloc and free as our allocator.
1463-
auto allocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getMallocFn());
1462+
1463+
// Use free as our allocator.
14641464
auto deallocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getFreeFn());
14651465

14661466
// Call the right 'llvm.coro.id.retcon' variant.
14671467
llvm::Value *buffer = origParams.claimNext();
1468-
llvm::Value *id = subIGF.Builder.CreateIntrinsicCall(
1468+
llvm::Value *id;
1469+
if (subIGF.IGM.getOptions().EmitTypeMallocForCoroFrame) {
1470+
// Use swift_coroFrameAlloc as our allocator.
1471+
auto coroAllocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getCoroFrameAllocFn());
1472+
auto mallocTypeId = subIGF.getMallocTypeId();
1473+
id = subIGF.Builder.CreateIntrinsicCall(
1474+
llvm::Intrinsic::coro_id_retcon_once,
1475+
{llvm::ConstantInt::get(
1476+
subIGF.IGM.Int32Ty,
1477+
getYieldOnceCoroutineBufferSize(subIGF.IGM).getValue()),
1478+
llvm::ConstantInt::get(
1479+
subIGF.IGM.Int32Ty,
1480+
getYieldOnceCoroutineBufferAlignment(subIGF.IGM).getValue()),
1481+
buffer, prototype, coroAllocFn, deallocFn, mallocTypeId});
1482+
} else {
1483+
// Use malloc as our allocator.
1484+
auto allocFn = subIGF.IGM.getOpaquePtr(subIGF.IGM.getMallocFn());
1485+
id = subIGF.Builder.CreateIntrinsicCall(
14691486
llvm::Intrinsic::coro_id_retcon_once,
14701487
{llvm::ConstantInt::get(
14711488
subIGF.IGM.Int32Ty,
@@ -1474,6 +1491,7 @@ class CoroPartialApplicationForwarderEmission
14741491
subIGF.IGM.Int32Ty,
14751492
getYieldOnceCoroutineBufferAlignment(subIGF.IGM).getValue()),
14761493
buffer, prototype, allocFn, deallocFn});
1494+
}
14771495

14781496
// Call 'llvm.coro.begin', just for consistency with the normal pattern.
14791497
// This serves as a handle that we can pass around to other intrinsics.

lib/IRGen/GenPointerAuth.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,3 +767,7 @@ void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer,
767767
addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(),
768768
llvm::ConstantInt::get(IGM().Int64Ty, otherDiscriminator));
769769
}
770+
771+
llvm::ConstantInt* IRGenFunction::getMallocTypeId() {
772+
return getDiscriminatorForString(IGM, CurFn->getName());
773+
}

lib/IRGen/IRGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ class IRGenFunction {
142142
Address getCalleeTypedErrorResultSlot(SILType errorType);
143143
void setCalleeTypedErrorResultSlot(Address addr);
144144

145+
llvm::ConstantInt* getMallocTypeId();
146+
145147
/// Are we currently emitting a coroutine?
146148
bool isCoroutine() {
147149
return CoroutineHandle != nullptr;

test/IRGen/yield_once.sil

Lines changed: 2 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 @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$sIetA_TC", ptr @malloc, ptr @free)
14-
// CHECK-64: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$sIetA_TC", ptr @malloc, ptr @free)
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 @malloc, ptr @free)
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 @malloc, ptr @free)
1515
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
1616

1717
// CHECK-NEXT: call swiftcc void @marker(i32 1000)

test/IRGen/yield_once_big.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ entry:
4444
// CHECK-64-SAME: , align 8
4545

4646
// Coroutine setup.
47-
// CHECK-32-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s14yield_once_big3BigVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
48-
// CHECK-64-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s14yield_once_big3BigVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
47+
// CHECK-32-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s14yield_once_big3BigVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
48+
// CHECK-64-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s14yield_once_big3BigVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
4949
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
5050
// CHECK-NEXT: store ptr
5151

@@ -181,8 +181,8 @@ entry(%arg : $*BigWrapper<C>):
181181
// CHECK-64-SAME: , align 8
182182

183183
// Coroutine setup.
184-
// CHECK-32-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s14yield_once_big10BigWrapperVyxGAA0D0VyxGAA9SomeClassCRbzlIetAnYn_TC", ptr @malloc, ptr @free)
185-
// CHECK-64-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s14yield_once_big10BigWrapperVyxGAA0D0VyxGAA9SomeClassCRbzlIetAnYn_TC", ptr @malloc, ptr @free)
184+
// CHECK-32-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s14yield_once_big10BigWrapperVyxGAA0D0VyxGAA9SomeClassCRbzlIetAnYn_TC", ptr @malloc, ptr @free)
185+
// CHECK-64-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s14yield_once_big10BigWrapperVyxGAA0D0VyxGAA9SomeClassCRbzlIetAnYn_TC", ptr @malloc, ptr @free)
186186
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
187187
// CHECK-NEXT: store ptr
188188

test/IRGen/yield_once_biggish.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ entry:
4040
// CHECK-64-SAME: , align 8
4141

4242
// Coroutine setup.
43-
// CHECK-32-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s18yield_once_biggish7BiggishVyxGAA9SomeClassCRbzlIetAYx_TC", ptr @malloc, ptr @free)
44-
// CHECK-64-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s18yield_once_biggish7BiggishVyxGAA9SomeClassCRbzlIetAYx_TC", ptr @malloc, ptr @free)
43+
// CHECK-32-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s18yield_once_biggish7BiggishVyxGAA9SomeClassCRbzlIetAYx_TC", ptr @malloc, ptr @free)
44+
// CHECK-64-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s18yield_once_biggish7BiggishVyxGAA9SomeClassCRbzlIetAYx_TC", ptr @malloc, ptr @free)
4545
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
4646
// CHECK-NEXT: store ptr
4747
// CHECK-NEXT: call swiftcc void @marker(i32 1000)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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
2+
3+
import Builtin
4+
5+
sil @marker : $(Builtin.Int32) -> ()
6+
7+
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc ptr @test_simple
8+
// CHECK-32-SAME: ptr noalias dereferenceable([[BUFFER_SIZE:16]]) %0)
9+
// CHECK-64-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE:32]]) %0)
10+
// CHECK-SAME: [[CORO_ATTRIBUTES:#[0-9]+]]
11+
sil @test_simple : $@yield_once () -> () {
12+
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)
15+
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
16+
17+
// CHECK-NEXT: call swiftcc void @marker(i32 1000)
18+
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
19+
%1000 = integer_literal $Builtin.Int32, 1000
20+
apply %marker(%1000) : $@convention(thin) (Builtin.Int32) -> ()
21+
22+
// CHECK-NEXT: [[IS_UNWIND:%.*]] = call i1 (...) @llvm.coro.suspend.retcon.i1()
23+
// CHECK-NEXT: br i1 [[IS_UNWIND]]
24+
yield (), resume resume, unwind unwind
25+
26+
resume:
27+
// CHECK: call swiftcc void @marker(i32 2000)
28+
%2000 = integer_literal $Builtin.Int32, 2000
29+
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
30+
// CHECK: br label %coro.end
31+
%ret = tuple ()
32+
return %ret : $()
33+
34+
unwind:
35+
// CHECK: call swiftcc void @marker(i32 3000)
36+
%3000 = integer_literal $Builtin.Int32, 3000
37+
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
38+
// CHECK: br label %coro.end
39+
unwind
40+
41+
// CHECK: coro.end:
42+
// CHECK: call i1 @llvm.coro.end(ptr [[BEGIN]], i1 false, token none)
43+
// CHECK-NEXT: unreachable
44+
}
45+
46+
// CHECK-LABEL: declare{{( dllimport)?}}{{( protected)?}} swiftcc void @"$sIetA_TC"
47+
// CHECK-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE]]), i1)
48+
49+
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_simple_call(i1 %0)
50+
sil @test_simple_call : $(Builtin.Int1) -> () {
51+
entry(%flag : $Builtin.Int1):
52+
// Allocate the buffer.
53+
// CHECK: [[T0:%.*]] = alloca {{\[}}[[BUFFER_SIZE]] x i8], align [[BUFFER_ALIGN]]
54+
// CHECK-NEXT: [[BUFFER:%.*]] = getelementptr inbounds {{\[}}[[BUFFER_SIZE]] x i8], ptr [[T0]], i32 0, i32 0
55+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
56+
57+
// Prepare the continuation function pointer to block analysis.
58+
// CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.coro.prepare.retcon(ptr @test_simple)
59+
// Call the function pointer.
60+
// CHECK-NEXT: [[CONTINUATION:%.*]] = call swiftcc ptr [[T0]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]])
61+
%0 = function_ref @test_simple : $@convention(thin) @yield_once () -> ()
62+
%token = begin_apply %0() : $@convention(thin) @yield_once () -> ()
63+
64+
// Branch.
65+
// CHECK-NEXT: br i1 %0,
66+
cond_br %flag, yes, no
67+
68+
yes:
69+
// CHECK-64-ptrauth: ptrtoint
70+
// CHECK-64-ptrauth-NEXT: ptrauth.blend
71+
// CHECK: call swiftcc void [[CONTINUATION]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false)
72+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
73+
end_apply %token as $()
74+
75+
// CHECK-NEXT: br label
76+
br cont
77+
78+
no:
79+
// CHECK-64-ptrauth: ptrtoint
80+
// CHECK-64-ptrauth-NEXT: ptrauth.blend
81+
// CHECK: call swiftcc void [[CONTINUATION]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true)
82+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
83+
abort_apply %token
84+
85+
// CHECK-NEXT: br label
86+
br cont
87+
88+
cont:
89+
// CHECK: ret void
90+
%ret = tuple ()
91+
return %ret : $()
92+
}
93+
94+
sil @yields_pair : $@yield_once @convention(thin) () -> (@yields Builtin.Int32, @yields Builtin.Int32)
95+
96+
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_yields_pair()
97+
sil @test_yields_pair : $() -> () {
98+
entry:
99+
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
100+
101+
// Allocate the buffer.
102+
// CHECK: [[T0:%.*]] = alloca {{\[}}[[BUFFER_SIZE]] x i8], align [[BUFFER_ALIGN]]
103+
// CHECK-NEXT: [[BUFFER:%.*]] = getelementptr inbounds {{\[}}[[BUFFER_SIZE]] x i8], ptr [[T0]], i32 0, i32 0
104+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
105+
106+
// Prepare the continuation function pointer to block analysis.
107+
// CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.coro.prepare.retcon(ptr @yields_pair)
108+
// Call the function pointer.
109+
// CHECK-NEXT: [[PACKED:%.*]] = call swiftcc { ptr, i32, i32 } [[T0]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]])
110+
// CHECK-NEXT: [[CONTINUATION:%.*]] = extractvalue { ptr, i32, i32 } [[PACKED]], 0
111+
// CHECK-NEXT: [[FIRST:%.*]] = extractvalue { ptr, i32, i32 } [[PACKED]], 1
112+
// CHECK-NEXT: [[SECOND:%.*]] = extractvalue { ptr, i32, i32 } [[PACKED]], 2
113+
%coro = function_ref @yields_pair : $@yield_once @convention(thin) () -> (@yields Builtin.Int32, @yields Builtin.Int32)
114+
(%first, %second, %token) = begin_apply %coro() : $@yield_once @convention(thin) () -> (@yields Builtin.Int32, @yields Builtin.Int32)
115+
116+
// CHECK-NEXT: call swiftcc void @marker(i32 [[FIRST]])
117+
apply %marker(%first) : $@convention(thin) (Builtin.Int32) -> ()
118+
119+
// CHECK-64-ptrauth-NEXT: ptrtoint
120+
// CHECK-64-ptrauth-NEXT: ptrauth.blend
121+
// CHECK-NEXT: call swiftcc void [[CONTINUATION]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false)
122+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
123+
end_apply %token as $()
124+
125+
// CHECK-NEXT: call swiftcc void @marker(i32 [[SECOND]])
126+
apply %marker(%second) : $@convention(thin) (Builtin.Int32) -> ()
127+
128+
// CHECK-NEXT: ret void
129+
%ret = tuple ()
130+
return %ret : $()
131+
}
132+
133+
134+
// CHECK: attributes [[CORO_ATTRIBUTES]] =
135+
// CHECK-SAME: noinline

test/IRGen/yield_once_indirect.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ entry:
3030
// CHECK-64-SAME: , align 8
3131

3232
// Coroutine setup.
33-
// CHECK-32-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s19yield_once_indirect8IndirectVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
34-
// CHECK-64-NEXT: [[ID:%.*]] = call token @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s19yield_once_indirect8IndirectVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
33+
// CHECK-32-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:4]], ptr %0, ptr @"$s19yield_once_indirect8IndirectVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
34+
// CHECK-64-NEXT: [[ID:%.*]] = call token (i32, i32, ptr, ptr, ptr, ptr, ...) @llvm.coro.id.retcon.once(i32 [[BUFFER_SIZE]], i32 [[BUFFER_ALIGN:8]], ptr %0, ptr @"$s19yield_once_indirect8IndirectVyxGAA9SomeClassCRbzlIetAYi_TC", ptr @malloc, ptr @free)
3535
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
3636
// CHECK-NEXT: store ptr
3737
// CHECK-NEXT: call swiftcc void @marker(i32 1000)

0 commit comments

Comments
 (0)