File: coro-suspend-cleanups.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (90 lines) | stat: -rw-r--r-- 3,938 bytes parent folder | download | duplicates (7)
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
// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s

#include "Inputs/coroutine.h"

struct Printy {
  Printy(const char *name) : name(name) {}
  ~Printy() {}
  const char *name;
};

struct coroutine {
  struct promise_type;
  std::coroutine_handle<promise_type> handle;
  ~coroutine() {
    if (handle) handle.destroy();
  }
};

struct coroutine::promise_type {
  coroutine get_return_object() {
    return {std::coroutine_handle<promise_type>::from_promise(*this)};
  }
  std::suspend_never initial_suspend() noexcept { return {}; }
  std::suspend_always final_suspend() noexcept { return {}; }
  void return_void() {}
  void unhandled_exception() {}
};

struct Awaiter : std::suspend_always {
  Printy await_resume() { return {"awaited"}; }
};

int foo() { return 2; }

coroutine ArrayInitCoro() {
  // Verify that:
  //  - We do the necessary stores for array cleanups.
  //  - Array cleanups are called by await.cleanup.
  //  - We activate the cleanup after the first element and deactivate it in await.ready (see cleanup.isactive).

  // CHECK-LABEL: define dso_local void @_Z13ArrayInitCorov
  // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
  // CHECK: %cleanup.isactive = alloca i1, align 1
  Printy arr[2] = {
    Printy("a"),
    // CHECK:       store i1 true, ptr %cleanup.isactive.reload.addr, align 1
    // CHECK-NEXT:  store ptr %arr.reload.addr, ptr %arrayinit.endOfInit.reload.addr, align 8
    // CHECK-NEXT:  call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arr.reload.addr, ptr noundef @.str)
    // CHECK-NEXT:  %arrayinit.element = getelementptr inbounds %struct.Printy, ptr %arr.reload.addr, i64 1
    // CHECK-NEXT:  %arrayinit.element.spill.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
    // CHECK-NEXT:  store ptr %arrayinit.element, ptr %arrayinit.element.spill.addr, align 8
    // CHECK-NEXT:  store ptr %arrayinit.element, ptr %arrayinit.endOfInit.reload.addr, align 8
    co_await Awaiter{}
    // CHECK-NEXT:  @_ZNSt14suspend_always11await_readyEv
    // CHECK-NEXT:  br i1 %{{.+}}, label %await.ready, label %CoroSave30
  };
  // CHECK:       await.cleanup:                                    ; preds = %AfterCoroSuspend{{.*}}
  // CHECK-NEXT:    br label %cleanup{{.*}}.from.await.cleanup

  // CHECK:       cleanup{{.*}}.from.await.cleanup:                      ; preds = %await.cleanup
  // CHECK:         br label %cleanup{{.*}}

  // CHECK:       await.ready:
  // CHECK-NEXT:    %arrayinit.element.reload.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
  // CHECK-NEXT:    %arrayinit.element.reload = load ptr, ptr %arrayinit.element.reload.addr, align 8
  // CHECK-NEXT:    call void @_ZN7Awaiter12await_resumeEv
  // CHECK-NEXT:    store i1 false, ptr %cleanup.isactive.reload.addr, align 1
  // CHECK-NEXT:    br label %cleanup{{.*}}.from.await.ready

  // CHECK:       cleanup{{.*}}:                                         ; preds = %cleanup{{.*}}.from.await.ready, %cleanup{{.*}}.from.await.cleanup
  // CHECK:         %cleanup.is_active = load i1, ptr %cleanup.isactive.reload.addr, align 1
  // CHECK-NEXT:    br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done

  // CHECK:       cleanup.action:
  // CHECK:         %arraydestroy.isempty = icmp eq ptr %arr.reload.addr, %{{.*}}
  // CHECK-NEXT:    br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body.from.cleanup.action
  // Ignore rest of the array cleanup.
}

coroutine ArrayInitWithCoReturn() {
  // CHECK-LABEL: define dso_local void @_Z21ArrayInitWithCoReturnv
  // Verify that we start to emit the array destructor.
  // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
  Printy arr[2] = {"a", ({
                      if (foo()) {
                        co_return;
                      }
                      "b";
                    })};
}