1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// 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
// 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
// to just rule out i386 for now. If we end up with many similar exceptions,
// we should turn this into a REQUIRES instead.
// UNSUPPORTED: CPU=i386
// UNSUPPORTED: CPU=arm64_32
import Builtin
import Swift
sil @marker : $(Builtin.Int32) -> ()
class SomeClass {}
sil_vtable SomeClass {}
class SomeSubclass : SomeClass {}
sil_vtable SomeSubclass {}
// This is designed to be small enough that we'll want to pass it directly,
// but large enough that yielding it will exceed what we can return directly.
struct Biggish<T: SomeClass> {
var a: T
var b: T
var c: T
var d: T
}
sil @make_biggish : $<T: SomeClass> () -> (@owned Biggish<T>)
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { ptr, ptr, ptr, ptr } @test_simple
// CHECK-32-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE:16]]) %0, ptr %C)
// CHECK-64-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE:32]]) %0, ptr %C)
sil [ossa] @test_simple : $@yield_once <C: SomeClass> () -> (@yields @owned Biggish<C>) {
entry:
// Allocate space for the indirect spillover.
// CHECK: [[SPILLS:%.*]] = alloca [[SPILLS_T:{ ptr, ptr }]]
// CHECK-32-SAME: , align 4
// CHECK-64-SAME: , align 8
// Coroutine setup.
// 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)
// 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)
// CHECK-NEXT: [[BEGIN:%.*]] = call ptr @llvm.coro.begin(token [[ID]], ptr null)
// CHECK-NEXT: store ptr
// CHECK-NEXT: call swiftcc void @marker(i32 1000)
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%1000 = integer_literal $Builtin.Int32, 1000
apply %marker(%1000) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: [[T0:%.*]] = call swiftcc [[BIGGISH:{ ptr, ptr, ptr, ptr }]] @make_biggish(ptr %C)
// CHECK-NEXT: [[R0:%.*]] = extractvalue [[BIGGISH]] [[T0]], 0
// CHECK-NEXT: [[R1:%.*]] = extractvalue [[BIGGISH]] [[T0]], 1
// CHECK-NEXT: [[R2:%.*]] = extractvalue [[BIGGISH]] [[T0]], 2
// CHECK-NEXT: [[R3:%.*]] = extractvalue [[BIGGISH]] [[T0]], 3
%make = function_ref @make_biggish : $@convention(thin) <T: SomeClass> () -> (@owned Biggish<T>)
%value = apply %make<C>() : $@convention(thin) <T: SomeClass> () -> (@owned Biggish<T>)
// Write the spilled objects to the buffer.
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[SPILLS]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[SPILLS_T]], ptr [[SPILLS]], i32 0, i32 0
// CHECK-NEXT: store ptr [[R2]], ptr [[T0]]
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[SPILLS_T]], ptr [[SPILLS]], i32 0, i32 1
// CHECK-NEXT: store ptr [[R3]], ptr [[T0]]
// Suspend.
// CHECK-NEXT: [[IS_UNWIND:%.*]] = call i1 (...) @llvm.coro.suspend.retcon.i1(ptr [[R0]], ptr [[R1]], ptr [[SPILLS]])
// Clean up the spills buffer.
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[SPILLS]])
// CHECK-NEXT: br i1 [[IS_UNWIND]]
yield %value : $Biggish<C>, resume resume, unwind unwind
resume:
// CHECK: call swiftcc void @marker(i32 2000)
%2000 = integer_literal $Builtin.Int32, 2000
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK: br label %coro.end
%ret = tuple ()
return %ret : $()
unwind:
// CHECK: call swiftcc void @marker(i32 3000)
%3000 = integer_literal $Builtin.Int32, 3000
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK: br label %coro.end
unwind
// CHECK: coro.end:
// CHECK: call i1 @llvm.coro.end(ptr [[BEGIN]], i1 false)
// CHECK-NEXT: unreachable
}
// CHECK-LABEL: declare{{( dllimport)?}}{{( protected)?}} swiftcc void @"$s18yield_once_biggish7BiggishVyxGAA9SomeClassCRbzlIetAYx_TC"
// CHECK-SAME: (ptr noalias dereferenceable([[BUFFER_SIZE]]), i1)
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_simple_call(i1 %0)
sil [ossa] @test_simple_call : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
// Allocate the buffer.
// CHECK: [[T0:%.*]] = alloca {{\[}}[[BUFFER_SIZE]] x i8], align [[BUFFER_ALIGN]]
// CHECK-NEXT: [[BUFFER:%.*]] = getelementptr inbounds {{\[}}[[BUFFER_SIZE]] x i8], ptr [[T0]], i32 0, i32 0
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
// CHECK-NEXT: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s18yield_once_biggish12SomeSubclassCMa"([[INT]] 0)
// CHECK-NEXT: [[SUBCLASS:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// Prepare the continuation function pointer to block analysis.
// CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.coro.prepare.retcon(ptr @test_simple
// Call the function pointer.
// CHECK-NEXT: [[RAMP_RESULT:%.*]] = call swiftcc [[RAMP_RESULT_T:{ ptr, ptr, ptr, ptr }]] [[T0]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], ptr [[SUBCLASS]])
// CHECK-NEXT: [[CONTINUATION:%.*]] = extractvalue [[RAMP_RESULT_T]] [[RAMP_RESULT]], 0
// CHECK-NEXT: [[R0_ORIG:%.*]] = extractvalue [[RAMP_RESULT_T]] [[RAMP_RESULT]], 1
// CHECK-NEXT: [[R1_ORIG:%.*]] = extractvalue [[RAMP_RESULT_T]] [[RAMP_RESULT]], 2
// CHECK-NEXT: [[SPILLS:%.*]] = extractvalue [[RAMP_RESULT_T]] [[RAMP_RESULT]], 3
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[SPILLS_T]], ptr [[SPILLS]], i32 0, i32 0
// CHECK-NEXT: [[R2_ORIG:%.*]] = load ptr, ptr [[T0]], align
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[SPILLS_T]], ptr [[SPILLS]], i32 0, i32 1
// CHECK-NEXT: [[R3_ORIG:%.*]] = load ptr, ptr [[T0]], align
%0 = function_ref @test_simple : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @owned Biggish<T>)
(%value, %token) = begin_apply %0<SomeSubclass>() : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @owned Biggish<T>)
// Branch.
// CHECK-NEXT: br i1 %0,
cond_br %flag, yes, no
yes:
// CHECK-64-ptrauth: ptrtoint
// CHECK-64-ptrauth-NEXT: ptrauth.blend
// CHECK: call swiftcc void [[CONTINUATION]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 false)
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
end_apply %token
// CHECK-NEXT: br label
br cont
no:
// CHECK-64-ptrauth: ptrtoint
// CHECK-64-ptrauth-NEXT: ptrauth.blend
// CHECK: call swiftcc void [[CONTINUATION]](ptr noalias dereferenceable([[BUFFER_SIZE]]) [[BUFFER]], i1 true)
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 [[BUFFER_SIZE]], ptr [[BUFFER]])
abort_apply %token
// CHECK-NEXT: br label
br cont
cont:
// CHECK: call void @swift_release(ptr [[R0_ORIG]])
// CHECK-NEXT: call void @swift_release(ptr [[R1_ORIG]])
// CHECK-NEXT: call void @swift_release(ptr [[R2_ORIG]])
// CHECK-NEXT: call void @swift_release(ptr [[R3_ORIG]])
destroy_value %value : $Biggish<SomeSubclass>
// CHECK-NEXT: ret void
%ret = tuple ()
return %ret : $()
}
|