brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · 7b7d141 Raw
396 lines · cpp
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 %s3 4namespace std {5template <typename... T>6struct coroutine_traits;7 8template <typename Promise = void> struct coroutine_handle;9 10template <>11struct coroutine_handle<void> {12  void *ptr;13  static coroutine_handle from_address(void *);14  void *address();15};16 17template <typename Promise>18struct coroutine_handle : coroutine_handle<> {19  static coroutine_handle from_address(void *) noexcept;20};21 22} // namespace std23 24struct init_susp {25  bool await_ready();26  void await_suspend(std::coroutine_handle<>);27  void await_resume();28};29struct final_susp {30  bool await_ready() noexcept;31  void await_suspend(std::coroutine_handle<>) noexcept;32  void await_resume() noexcept;33};34 35struct suspend_always {36  int stuff;37  bool await_ready();38  void await_suspend(std::coroutine_handle<>);39  void await_resume();40};41 42template <>43struct 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(53extern "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(ptr60  // 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.suspend75  // ---------------------------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_resume91  // --------------------------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(ptr99  // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(100  // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)101 102  // Await suspend wrapper103  // CHECK: define internal {{.*}} @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 scalar110  // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}111  // CHECK: call void @_ZN14suspend_always13await_suspendESt16coroutine_handleIvE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])112}113 114struct 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 122template <>123struct 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(134extern "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.suspend151  // ---------------------------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 suspend155  // -------------------------------------------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 wrapper165  // CHECK: define internal {{.*}} 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 scalar172  // 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 177struct ComplexAwaiter {178  template <typename F> void await_suspend(F);179  bool await_ready();180  _Complex float await_resume();181};182extern "C" void UseComplex(_Complex float);183 184// CHECK-LABEL: @TestComplex(185extern "C" void TestComplex() {186  UseComplex(co_await ComplexAwaiter{});187  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr188  // CHECK: call void @UseComplex(<2 x float> %{{.+}})189 190  co_await ComplexAwaiter{};191  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr192 193  _Complex float Val = co_await ComplexAwaiter{};194  // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr195}196 197struct Aggr { int X, Y, Z; ~Aggr(); };198struct AggrAwaiter {199  template <typename F> void await_suspend(F);200  bool await_ready();201  Aggr await_resume();202};203 204extern "C" void Whatever();205extern "C" void UseAggr(Aggr&&);206 207// FIXME: Once the cleanup code is in, add testing that destructors for Aggr208// are invoked properly on the cleanup branches.209 210// CHECK-LABEL: @TestAggr(211extern "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 232struct ScalarAwaiter {233  template <typename F> void await_suspend(F);234  bool await_ready();235  int await_resume();236};237 238extern "C" void UseScalar(int);239 240// CHECK-LABEL: @TestScalar(241extern "C" void TestScalar() {242  UseScalar(co_await ScalarAwaiter{});243  // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr244  // CHECK: call void @UseScalar(i32 %[[Result]])245 246  int Val = co_await ScalarAwaiter{};247  // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr248  // 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(ptr254}255 256// Test operator co_await codegen.257enum class MyInt: int {};258ScalarAwaiter operator co_await(MyInt);259 260struct MyAgg {261  AggrAwaiter operator co_await();262};263 264// CHECK-LABEL: @TestOpAwait(265extern "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(276extern "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(ptr283 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(ptr291}292 293// Verifies that we don't crash when awaiting on an lvalue.294// CHECK-LABEL: @_Z11AwaitLValuev(295void AwaitLValue() {296  suspend_always lval;297  co_await lval;298}299 300struct RefTag { };301 302struct AwaitResumeReturnsLValue {303  bool await_ready();304  void await_suspend(std::coroutine_handle<>);305  RefTag& await_resume();306};307 308template <>309struct 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)322void 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 352struct TailCallAwait {353  bool await_ready();354  std::coroutine_handle<> await_suspend(std::coroutine_handle<>);355  void await_resume();356};357 358// CHECK-LABEL: @TestTailcall(359extern "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.suspend372  // ---------------------------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 wrapper382  // CHECK: define internal {{.*}} 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 scalar389  // 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 0392  // 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