1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \ 2 // RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s 3 4 namespace std { 5 namespace experimental { 6 template <typename... T> 7 struct coroutine_traits; 8 9 template <typename Promise = void> struct coroutine_handle; 10 11 template <> 12 struct coroutine_handle<void> { 13 void *ptr; 14 static coroutine_handle from_address(void *); 15 }; 16 17 template <typename Promise> 18 struct coroutine_handle : coroutine_handle<> { 19 static coroutine_handle from_address(void *); 20 }; 21 22 } 23 } 24 25 struct init_susp { 26 bool await_ready(); 27 void await_suspend(std::experimental::coroutine_handle<>); 28 void await_resume(); 29 }; 30 struct final_susp { 31 bool await_ready(); 32 void await_suspend(std::experimental::coroutine_handle<>); 33 void await_resume(); 34 }; 35 36 struct suspend_always { 37 int stuff; 38 bool await_ready(); 39 void await_suspend(std::experimental::coroutine_handle<>); 40 void await_resume(); 41 }; 42 43 template<> 44 struct std::experimental::coroutine_traits<void> { 45 struct promise_type { 46 void get_return_object(); 47 init_susp initial_suspend(); 48 final_susp final_suspend(); 49 void return_void(); 50 }; 51 }; 52 53 // CHECK-LABEL: f0( 54 extern "C" void f0() { 55 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( 56 57 // See if initial_suspend was issued: 58 // ---------------------------------- 59 // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv( 60 // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp* 61 // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save( 62 // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false) 63 64 co_await suspend_always{}; 65 // See if we need to suspend: 66 // -------------------------- 67 // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]]) 68 // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]] 69 70 // If we are suspending: 71 // --------------------- 72 // CHECK: [[SUSPEND_BB]]: 73 // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save( 74 // --------------------------- 75 // Build the coroutine handle and pass it to await_suspend 76 // --------------------------- 77 // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]]) 78 // ... many lines of code to coerce coroutine_handle into an i8* scalar 79 // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}} 80 // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]]) 81 // ------------------------- 82 // Generate a suspend point: 83 // ------------------------- 84 // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false) 85 // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [ 86 // CHECK: i8 0, label %[[READY_BB]] 87 // CHECK: i8 1, label %[[CLEANUP_BB:.+]] 88 // CHECK: ] 89 90 // Cleanup code goes here: 91 // ----------------------- 92 // CHECK: [[CLEANUP_BB]]: 93 94 // When coroutine is resumed, call await_resume 95 // -------------------------- 96 // CHECK: [[READY_BB]]: 97 // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]]) 98 99 // See if final_suspend was issued: 100 // ---------------------------------- 101 // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv( 102 // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp* 103 // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save( 104 // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true) 105 } 106 107 struct suspend_maybe { 108 float stuff; 109 ~suspend_maybe(); 110 bool await_ready(); 111 bool await_suspend(std::experimental::coroutine_handle<>); 112 void await_resume(); 113 }; 114 115 116 template<> 117 struct std::experimental::coroutine_traits<void,int> { 118 struct promise_type { 119 void get_return_object(); 120 init_susp initial_suspend(); 121 final_susp final_suspend(); 122 void return_void(); 123 suspend_maybe yield_value(int); 124 }; 125 }; 126 127 // CHECK-LABEL: f1( 128 extern "C" void f1(int) { 129 // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits<void, int>::promise_type" 130 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( 131 co_yield 42; 132 // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits<void, int>::promise_type"* %[[PROMISE]], i32 42) 133 134 // See if we need to suspend: 135 // -------------------------- 136 // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]]) 137 // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]] 138 139 // If we are suspending: 140 // --------------------- 141 // CHECK: [[SUSPEND_BB]]: 142 // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save( 143 // --------------------------- 144 // Build the coroutine handle and pass it to await_suspend 145 // --------------------------- 146 // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]]) 147 // ... many lines of code to coerce coroutine_handle into an i8* scalar 148 // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}} 149 // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_maybe* %[[AWAITABLE]], i8* %[[CH]]) 150 // ------------------------------------------- 151 // See if await_suspend decided not to suspend 152 // ------------------------------------------- 153 // CHECK: br i1 %[[YES]], label %[[SUSPEND_PLEASE:.+]], label %[[READY_BB]] 154 155 // CHECK: [[SUSPEND_PLEASE]]: 156 // CHECK: call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false) 157 158 // CHECK: [[READY_BB]]: 159 // CHECK: call void @_ZN13suspend_maybe12await_resumeEv(%struct.suspend_maybe* %[[AWAITABLE]]) 160 } 161 162 struct ComplexAwaiter { 163 template <typename F> void await_suspend(F); 164 bool await_ready(); 165 _Complex float await_resume(); 166 }; 167 extern "C" void UseComplex(_Complex float); 168 169 // CHECK-LABEL: @TestComplex( 170 extern "C" void TestComplex() { 171 UseComplex(co_await ComplexAwaiter{}); 172 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter* 173 // CHECK: call void @UseComplex(<2 x float> %{{.+}}) 174 175 co_await ComplexAwaiter{}; 176 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter* 177 178 _Complex float Val = co_await ComplexAwaiter{}; 179 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter* 180 } 181 182 struct Aggr { int X, Y, Z; ~Aggr(); }; 183 struct AggrAwaiter { 184 template <typename F> void await_suspend(F); 185 bool await_ready(); 186 Aggr await_resume(); 187 }; 188 189 extern "C" void Whatever(); 190 extern "C" void UseAggr(Aggr&&); 191 192 // FIXME: Once the cleanup code is in, add testing that destructors for Aggr 193 // are invoked properly on the cleanup branches. 194 195 // CHECK-LABEL: @TestAggr( 196 extern "C" void TestAggr() { 197 UseAggr(co_await AggrAwaiter{}); 198 Whatever(); 199 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume:.+]], 200 // CHECK: call void @UseAggr(%struct.Aggr* dereferenceable(12) %[[AwaitResume]]) 201 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume]]) 202 // CHECK: call void @Whatever() 203 204 co_await AggrAwaiter{}; 205 Whatever(); 206 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume2:.+]], 207 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume2]]) 208 // CHECK: call void @Whatever() 209 210 Aggr Val = co_await AggrAwaiter{}; 211 Whatever(); 212 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume3:.+]], 213 // CHECK: call void @Whatever() 214 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume3]]) 215 } 216 217 struct ScalarAwaiter { 218 template <typename F> void await_suspend(F); 219 bool await_ready(); 220 int await_resume(); 221 }; 222 223 extern "C" void UseScalar(int); 224 225 // CHECK-LABEL: @TestScalar( 226 extern "C" void TestScalar() { 227 UseScalar(co_await ScalarAwaiter{}); 228 // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* 229 // CHECK: call void @UseScalar(i32 %[[Result]]) 230 231 int Val = co_await ScalarAwaiter{}; 232 // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* 233 // CHECK: store i32 %[[Result2]], i32* %Val 234 235 co_await ScalarAwaiter{}; 236 // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* 237 } 238 239 // Test operator co_await codegen. 240 enum class MyInt: int {}; 241 ScalarAwaiter operator co_await(MyInt); 242 243 struct MyAgg { 244 AggrAwaiter operator co_await(); 245 }; 246 247 // CHECK-LABEL: @TestOpAwait( 248 extern "C" void TestOpAwait() { 249 co_await MyInt(42); 250 // CHECK: call void @_Zaw5MyInt(i32 42) 251 // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* % 252 253 co_await MyAgg{}; 254 // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* % 255 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret % 256 } 257 258 // CHECK-LABEL: EndlessLoop( 259 extern "C" void EndlessLoop() { 260 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( 261 262 // See if initial_suspend was issued: 263 // ---------------------------------- 264 // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv( 265 // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp* 266 267 for (;;) 268 co_await suspend_always{}; 269 270 // Verify that final_suspend was NOT issued: 271 // ---------------------------------- 272 // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv( 273 // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp* 274 } 275 276 // Verifies that we don't crash when awaiting on an lvalue. 277 // CHECK-LABEL: @_Z11AwaitLValuev( 278 void AwaitLValue() { 279 suspend_always lval; 280 co_await lval; 281 } 282 283 struct RefTag { }; 284 285 struct AwaitResumeReturnsLValue { 286 bool await_ready(); 287 void await_suspend(std::experimental::coroutine_handle<>); 288 RefTag& await_resume(); 289 }; 290 291 292 template<> 293 struct std::experimental::coroutine_traits<void,double> { 294 struct promise_type { 295 void get_return_object(); 296 init_susp initial_suspend(); 297 final_susp final_suspend(); 298 void return_void(); 299 AwaitResumeReturnsLValue yield_value(int); 300 }; 301 }; 302 303 // Verifies that we don't crash when returning an lvalue from an await_resume() 304 // expression. 305 // CHECK-LABEL: define void @_Z18AwaitReturnsLValued(double) 306 void AwaitReturnsLValue(double) { 307 AwaitResumeReturnsLValue a; 308 // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue, 309 // CHECK: %[[XVAR:.+]] = alloca %struct.RefTag*, 310 311 // CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*, 312 // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue, 313 314 // CHECK: %[[ZVAR:.+]] = alloca %struct.RefTag*, 315 // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue, 316 317 // CHECK: %[[RES1:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[AVAR]]) 318 // CHECK-NEXT: store %struct.RefTag* %[[RES1]], %struct.RefTag** %[[XVAR]], 319 RefTag& x = co_await a; 320 321 // CHECK: %[[RES2:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP1]]) 322 // CHECK-NEXT: store %struct.RefTag* %[[RES2]], %struct.RefTag** %[[YVAR]], 323 324 RefTag& y = co_await AwaitResumeReturnsLValue{}; 325 // CHECK: %[[RES3:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP2]]) 326 // CHECK-NEXT: store %struct.RefTag* %[[RES3]], %struct.RefTag** %[[ZVAR]], 327 RefTag& z = co_yield 42; 328 } 329