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