annotate docs/Coroutines.rst @ 148:63bd29f05246

merged
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 14 Aug 2019 19:46:37 +0900
parents c2174574ed3a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1 =====================================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
2 Coroutines in LLVM
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
3 =====================================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
5 .. contents::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
6 :local:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
7 :depth: 3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
9 .. warning::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
10 This is a work in progress. Compatibility across LLVM releases is not
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
11 guaranteed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
12
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
13 Introduction
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
14 ============
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
15
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
16 .. _coroutine handle:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
17
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
18 LLVM coroutines are functions that have one or more `suspend points`_.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
19 When a suspend point is reached, the execution of a coroutine is suspended and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
20 control is returned back to its caller. A suspended coroutine can be resumed
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
21 to continue execution from the last suspend point or it can be destroyed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
22
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
23 In the following example, we call function `f` (which may or may not be a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
24 coroutine itself) that returns a handle to a suspended coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
25 (**coroutine handle**) that is used by `main` to resume the coroutine twice and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
26 then destroy it:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
27
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
28 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
29
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
30 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
31 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
32 %hdl = call i8* @f(i32 4)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
33 call void @llvm.coro.resume(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
34 call void @llvm.coro.resume(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
35 call void @llvm.coro.destroy(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
36 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
37 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
38
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
39 .. _coroutine frame:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
40
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
41 In addition to the function stack frame which exists when a coroutine is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
42 executing, there is an additional region of storage that contains objects that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
43 keep the coroutine state when a coroutine is suspended. This region of storage
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
44 is called **coroutine frame**. It is created when a coroutine is called and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
45 destroyed when a coroutine runs to completion or destroyed by a call to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
46 the `coro.destroy`_ intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
47
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
48 An LLVM coroutine is represented as an LLVM function that has calls to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
49 `coroutine intrinsics`_ defining the structure of the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
50 After lowering, a coroutine is split into several
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
51 functions that represent three different ways of how control can enter the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
52 coroutine:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
53
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
54 1. a ramp function, which represents an initial invocation of the coroutine that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
55 creates the coroutine frame and executes the coroutine code until it
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
56 encounters a suspend point or reaches the end of the function;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
57
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
58 2. a coroutine resume function that is invoked when the coroutine is resumed;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
59
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
60 3. a coroutine destroy function that is invoked when the coroutine is destroyed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
61
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
62 .. note:: Splitting out resume and destroy functions are just one of the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
63 possible ways of lowering the coroutine. We chose it for initial
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
64 implementation as it matches closely the mental model and results in
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
65 reasonably nice code.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
66
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
67 Coroutines by Example
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
68 =====================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
69
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
70 Coroutine Representation
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
71 ------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
72
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
73 Let's look at an example of an LLVM coroutine with the behavior sketched
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
74 by the following pseudo-code.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
75
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
76 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
77
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
78 void *f(int n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
79 for(;;) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
80 print(n++);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
81 <suspend> // returns a coroutine handle on first suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
82 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
83 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
84
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
85 This coroutine calls some function `print` with value `n` as an argument and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
86 suspends execution. Every time this coroutine resumes, it calls `print` again with an argument one bigger than the last time. This coroutine never completes by itself and must be destroyed explicitly. If we use this coroutine with
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
87 a `main` shown in the previous section. It will call `print` with values 4, 5
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
88 and 6 after which the coroutine will be destroyed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
89
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
90 The LLVM IR for this coroutine looks like this:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
91
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
92 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
93
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
94 define i8* @f(i32 %n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
95 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
96 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
97 %size = call i32 @llvm.coro.size.i32()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
98 %alloc = call i8* @malloc(i32 %size)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
99 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
100 br label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
101 loop:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
102 %n.val = phi i32 [ %n, %entry ], [ %inc, %loop ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
103 %inc = add nsw i32 %n.val, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
104 call void @print(i32 %n.val)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
105 %0 = call i8 @llvm.coro.suspend(token none, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
106 switch i8 %0, label %suspend [i8 0, label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
107 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
108 cleanup:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
109 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
110 call void @free(i8* %mem)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
111 br label %suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
112 suspend:
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
113 %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
114 ret i8* %hdl
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
115 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
116
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
117 The `entry` block establishes the coroutine frame. The `coro.size`_ intrinsic is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
118 lowered to a constant representing the size required for the coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
119 The `coro.begin`_ intrinsic initializes the coroutine frame and returns the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
120 coroutine handle. The second parameter of `coro.begin` is given a block of memory
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
121 to be used if the coroutine frame needs to be allocated dynamically.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
122 The `coro.id`_ intrinsic serves as coroutine identity useful in cases when the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
123 `coro.begin`_ intrinsic get duplicated by optimization passes such as
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
124 jump-threading.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
125
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
126 The `cleanup` block destroys the coroutine frame. The `coro.free`_ intrinsic,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
127 given the coroutine handle, returns a pointer of the memory block to be freed or
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
128 `null` if the coroutine frame was not allocated dynamically. The `cleanup`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
129 block is entered when coroutine runs to completion by itself or destroyed via
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
130 call to the `coro.destroy`_ intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
131
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
132 The `suspend` block contains code to be executed when coroutine runs to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
133 completion or suspended. The `coro.end`_ intrinsic marks the point where
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
134 a coroutine needs to return control back to the caller if it is not an initial
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
135 invocation of the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
136
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
137 The `loop` blocks represents the body of the coroutine. The `coro.suspend`_
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
138 intrinsic in combination with the following switch indicates what happens to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
139 control flow when a coroutine is suspended (default case), resumed (case 0) or
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
140 destroyed (case 1).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
141
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
142 Coroutine Transformation
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
143 ------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
144
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
145 One of the steps of coroutine lowering is building the coroutine frame. The
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
146 def-use chains are analyzed to determine which objects need be kept alive across
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
147 suspend points. In the coroutine shown in the previous section, use of virtual register
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
148 `%n.val` is separated from the definition by a suspend point, therefore, it
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
149 cannot reside on the stack frame since the latter goes away once the coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
150 is suspended and control is returned back to the caller. An i32 slot is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
151 allocated in the coroutine frame and `%n.val` is spilled and reloaded from that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
152 slot as needed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
153
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
154 We also store addresses of the resume and destroy functions so that the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
155 `coro.resume` and `coro.destroy` intrinsics can resume and destroy the coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
156 when its identity cannot be determined statically at compile time. For our
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
157 example, the coroutine frame will be:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
158
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
159 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
160
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
161 %f.frame = type { void (%f.frame*)*, void (%f.frame*)*, i32 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
162
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
163 After resume and destroy parts are outlined, function `f` will contain only the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
164 code responsible for creation and initialization of the coroutine frame and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
165 execution of the coroutine until a suspend point is reached:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
166
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
167 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
168
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
169 define i8* @f(i32 %n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
170 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
171 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
172 %alloc = call noalias i8* @malloc(i32 24)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
173 %0 = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
174 %frame = bitcast i8* %0 to %f.frame*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
175 %1 = getelementptr %f.frame, %f.frame* %frame, i32 0, i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
176 store void (%f.frame*)* @f.resume, void (%f.frame*)** %1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
177 %2 = getelementptr %f.frame, %f.frame* %frame, i32 0, i32 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
178 store void (%f.frame*)* @f.destroy, void (%f.frame*)** %2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
179
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
180 %inc = add nsw i32 %n, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
181 %inc.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
182 store i32 %inc, i32* %inc.spill.addr
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
183 call void @print(i32 %n)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
184
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
185 ret i8* %frame
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
186 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
187
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
188 Outlined resume part of the coroutine will reside in function `f.resume`:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
189
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
190 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
191
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
192 define internal fastcc void @f.resume(%f.frame* %frame.ptr.resume) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
193 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
194 %inc.spill.addr = getelementptr %f.frame, %f.frame* %frame.ptr.resume, i64 0, i32 2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
195 %inc.spill = load i32, i32* %inc.spill.addr, align 4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
196 %inc = add i32 %n.val, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
197 store i32 %inc, i32* %inc.spill.addr, align 4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
198 tail call void @print(i32 %inc)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
199 ret void
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
200 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
201
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
202 Whereas function `f.destroy` will contain the cleanup code for the coroutine:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
203
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
204 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
205
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
206 define internal fastcc void @f.destroy(%f.frame* %frame.ptr.destroy) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
207 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
208 %0 = bitcast %f.frame* %frame.ptr.destroy to i8*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
209 tail call void @free(i8* %0)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
210 ret void
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
211 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
212
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
213 Avoiding Heap Allocations
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
214 -------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
215
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
216 A particular coroutine usage pattern, which is illustrated by the `main`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
217 function in the overview section, where a coroutine is created, manipulated and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
218 destroyed by the same calling function, is common for coroutines implementing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
219 RAII idiom and is suitable for allocation elision optimization which avoid
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
220 dynamic allocation by storing the coroutine frame as a static `alloca` in its
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
221 caller.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
222
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
223 In the entry block, we will call `coro.alloc`_ intrinsic that will return `true`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
224 when dynamic allocation is required, and `false` if dynamic allocation is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
225 elided.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
226
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
227 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
228
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
229 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
230 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
231 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
232 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
233 dyn.alloc:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
234 %size = call i32 @llvm.coro.size.i32()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
235 %alloc = call i8* @CustomAlloc(i32 %size)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
236 br label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
237 coro.begin:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
238 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
239 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
240
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
241 In the cleanup block, we will make freeing the coroutine frame conditional on
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
242 `coro.free`_ intrinsic. If allocation is elided, `coro.free`_ returns `null`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
243 thus skipping the deallocation code:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
244
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
245 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
246
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
247 cleanup:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
248 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
249 %need.dyn.free = icmp ne i8* %mem, null
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
250 br i1 %need.dyn.free, label %dyn.free, label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
251 dyn.free:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
252 call void @CustomFree(i8* %mem)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
253 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
254 if.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
255 ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
256
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
257 With allocations and deallocations represented as described as above, after
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
258 coroutine heap allocation elision optimization, the resulting main will be:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
259
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
260 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
261
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
262 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
263 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
264 call void @print(i32 4)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
265 call void @print(i32 5)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
266 call void @print(i32 6)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
267 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
268 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
269
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
270 Multiple Suspend Points
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
271 -----------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
272
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
273 Let's consider the coroutine that has more than one suspend point:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
274
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
275 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
276
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
277 void *f(int n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
278 for(;;) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
279 print(n++);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
280 <suspend>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
281 print(-n);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
282 <suspend>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
283 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
284 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
285
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
286 Matching LLVM code would look like (with the rest of the code remaining the same
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
287 as the code in the previous section):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
288
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
289 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
290
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
291 loop:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
292 %n.addr = phi i32 [ %n, %entry ], [ %inc, %loop.resume ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
293 call void @print(i32 %n.addr) #4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
294 %2 = call i8 @llvm.coro.suspend(token none, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
295 switch i8 %2, label %suspend [i8 0, label %loop.resume
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
296 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
297 loop.resume:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
298 %inc = add nsw i32 %n.addr, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
299 %sub = xor i32 %n.addr, -1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
300 call void @print(i32 %sub)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
301 %3 = call i8 @llvm.coro.suspend(token none, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
302 switch i8 %3, label %suspend [i8 0, label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
303 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
304
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
305 In this case, the coroutine frame would include a suspend index that will
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
306 indicate at which suspend point the coroutine needs to resume. The resume
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
307 function will use an index to jump to an appropriate basic block and will look
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
308 as follows:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
309
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
310 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
311
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
312 define internal fastcc void @f.Resume(%f.Frame* %FramePtr) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
313 entry.Resume:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
314 %index.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i64 0, i32 2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
315 %index = load i8, i8* %index.addr, align 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
316 %switch = icmp eq i8 %index, 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
317 %n.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i64 0, i32 3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
318 %n = load i32, i32* %n.addr, align 4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
319 br i1 %switch, label %loop.resume, label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
320
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
321 loop.resume:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
322 %sub = xor i32 %n, -1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
323 call void @print(i32 %sub)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
324 br label %suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
325 loop:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
326 %inc = add nsw i32 %n, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
327 store i32 %inc, i32* %n.addr, align 4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
328 tail call void @print(i32 %inc)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
329 br label %suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
330
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
331 suspend:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
332 %storemerge = phi i8 [ 0, %loop ], [ 1, %loop.resume ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
333 store i8 %storemerge, i8* %index.addr, align 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
334 ret void
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
335 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
336
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
337 If different cleanup code needs to get executed for different suspend points,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
338 a similar switch will be in the `f.destroy` function.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
339
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
340 .. note ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
341
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
342 Using suspend index in a coroutine state and having a switch in `f.resume` and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
343 `f.destroy` is one of the possible implementation strategies. We explored
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
344 another option where a distinct `f.resume1`, `f.resume2`, etc. are created for
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
345 every suspend point, and instead of storing an index, the resume and destroy
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
346 function pointers are updated at every suspend. Early testing showed that the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
347 current approach is easier on the optimizer than the latter so it is a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
348 lowering strategy implemented at the moment.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
349
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
350 Distinct Save and Suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
351 -------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
352
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
353 In the previous example, setting a resume index (or some other state change that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
354 needs to happen to prepare a coroutine for resumption) happens at the same time as
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
355 a suspension of a coroutine. However, in certain cases, it is necessary to control
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
356 when coroutine is prepared for resumption and when it is suspended.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
357
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
358 In the following example, a coroutine represents some activity that is driven
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
359 by completions of asynchronous operations `async_op1` and `async_op2` which get
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
360 a coroutine handle as a parameter and resume the coroutine once async
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
361 operation is finished.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
362
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
363 .. code-block:: text
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
364
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
365 void g() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
366 for (;;)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
367 if (cond()) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
368 async_op1(<coroutine-handle>); // will resume once async_op1 completes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
369 <suspend>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
370 do_one();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
371 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
372 else {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
373 async_op2(<coroutine-handle>); // will resume once async_op2 completes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
374 <suspend>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
375 do_two();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
376 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
377 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
378 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
379
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
380 In this case, coroutine should be ready for resumption prior to a call to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
381 `async_op1` and `async_op2`. The `coro.save`_ intrinsic is used to indicate a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
382 point when coroutine should be ready for resumption (namely, when a resume index
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
383 should be stored in the coroutine frame, so that it can be resumed at the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
384 correct resume point):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
385
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
386 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
387
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
388 if.true:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
389 %save1 = call token @llvm.coro.save(i8* %hdl)
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
390 call void @async_op1(i8* %hdl)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
391 %suspend1 = call i1 @llvm.coro.suspend(token %save1, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
392 switch i8 %suspend1, label %suspend [i8 0, label %resume1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
393 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
394 if.false:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
395 %save2 = call token @llvm.coro.save(i8* %hdl)
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
396 call void @async_op2(i8* %hdl)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
397 %suspend2 = call i1 @llvm.coro.suspend(token %save2, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
398 switch i8 %suspend1, label %suspend [i8 0, label %resume2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
399 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
400
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
401 .. _coroutine promise:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
402
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
403 Coroutine Promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
404 -----------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
405
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
406 A coroutine author or a frontend may designate a distinguished `alloca` that can
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
407 be used to communicate with the coroutine. This distinguished alloca is called
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
408 **coroutine promise** and is provided as the second parameter to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
409 `coro.id`_ intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
410
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
411 The following coroutine designates a 32 bit integer `promise` and uses it to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
412 store the current value produced by a coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
413
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
414 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
415
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
416 define i8* @f(i32 %n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
417 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
418 %promise = alloca i32
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
419 %pv = bitcast i32* %promise to i8*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
420 %id = call token @llvm.coro.id(i32 0, i8* %pv, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
421 %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
422 br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
423 dyn.alloc:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
424 %size = call i32 @llvm.coro.size.i32()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
425 %alloc = call i8* @malloc(i32 %size)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
426 br label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
427 coro.begin:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
428 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
429 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
430 br label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
431 loop:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
432 %n.val = phi i32 [ %n, %coro.begin ], [ %inc, %loop ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
433 %inc = add nsw i32 %n.val, 1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
434 store i32 %n.val, i32* %promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
435 %0 = call i8 @llvm.coro.suspend(token none, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
436 switch i8 %0, label %suspend [i8 0, label %loop
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
437 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
438 cleanup:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
439 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
440 call void @free(i8* %mem)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
441 br label %suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
442 suspend:
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
443 %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
444 ret i8* %hdl
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
445 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
446
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
447 A coroutine consumer can rely on the `coro.promise`_ intrinsic to access the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
448 coroutine promise.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
449
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
450 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
451
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
452 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
453 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
454 %hdl = call i8* @f(i32 4)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
455 %promise.addr.raw = call i8* @llvm.coro.promise(i8* %hdl, i32 4, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
456 %promise.addr = bitcast i8* %promise.addr.raw to i32*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
457 %val0 = load i32, i32* %promise.addr
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
458 call void @print(i32 %val0)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
459 call void @llvm.coro.resume(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
460 %val1 = load i32, i32* %promise.addr
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
461 call void @print(i32 %val1)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
462 call void @llvm.coro.resume(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
463 %val2 = load i32, i32* %promise.addr
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
464 call void @print(i32 %val2)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
465 call void @llvm.coro.destroy(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
466 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
467 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
468
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
469 After example in this section is compiled, result of the compilation will be:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
470
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
471 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
472
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
473 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
474 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
475 tail call void @print(i32 4)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
476 tail call void @print(i32 5)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
477 tail call void @print(i32 6)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
478 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
479 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
480
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
481 .. _final:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
482 .. _final suspend:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
483
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
484 Final Suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
485 -------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
486
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
487 A coroutine author or a frontend may designate a particular suspend to be final,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
488 by setting the second argument of the `coro.suspend`_ intrinsic to `true`.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
489 Such a suspend point has two properties:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
490
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
491 * it is possible to check whether a suspended coroutine is at the final suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
492 point via `coro.done`_ intrinsic;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
493
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
494 * a resumption of a coroutine stopped at the final suspend point leads to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
495 undefined behavior. The only possible action for a coroutine at a final
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
496 suspend point is destroying it via `coro.destroy`_ intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
497
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
498 From the user perspective, the final suspend point represents an idea of a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
499 coroutine reaching the end. From the compiler perspective, it is an optimization
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
500 opportunity for reducing number of resume points (and therefore switch cases) in
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
501 the resume function.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
502
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
503 The following is an example of a function that keeps resuming the coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
504 until the final suspend point is reached after which point the coroutine is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
505 destroyed:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
506
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
507 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
508
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
509 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
510 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
511 %hdl = call i8* @f(i32 4)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
512 br label %while
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
513 while:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
514 call void @llvm.coro.resume(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
515 %done = call i1 @llvm.coro.done(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
516 br i1 %done, label %end, label %while
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
517 end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
518 call void @llvm.coro.destroy(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
519 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
520 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
521
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
522 Usually, final suspend point is a frontend injected suspend point that does not
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
523 correspond to any explicitly authored suspend point of the high level language.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
524 For example, for a Python generator that has only one suspend point:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
525
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
526 .. code-block:: python
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
527
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
528 def coroutine(n):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
529 for i in range(n):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
530 yield i
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
531
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
532 Python frontend would inject two more suspend points, so that the actual code
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
533 looks like this:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
534
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
535 .. code-block:: c
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
536
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
537 void* coroutine(int n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
538 int current_value;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
539 <designate current_value to be coroutine promise>
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
540 <SUSPEND> // injected suspend point, so that the coroutine starts suspended
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
541 for (int i = 0; i < n; ++i) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
542 current_value = i; <SUSPEND>; // corresponds to "yield i"
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
543 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
544 <SUSPEND final=true> // injected final suspend point
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
545 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
546
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
547 and python iterator `__next__` would look like:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
548
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
549 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
550
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
551 int __next__(void* hdl) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
552 coro.resume(hdl);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
553 if (coro.done(hdl)) throw StopIteration();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
554 return *(int*)coro.promise(hdl, 4, false);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
555 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
556
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
557 Intrinsics
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
558 ==========
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
559
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
560 Coroutine Manipulation Intrinsics
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
561 ---------------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
562
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
563 Intrinsics described in this section are used to manipulate an existing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
564 coroutine. They can be used in any function which happen to have a pointer
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
565 to a `coroutine frame`_ or a pointer to a `coroutine promise`_.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
566
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
567 .. _coro.destroy:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
568
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
569 'llvm.coro.destroy' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
570 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
571
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
572 Syntax:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
573 """""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
574
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
575 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
576
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
577 declare void @llvm.coro.destroy(i8* <handle>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
578
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
579 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
580 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
581
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
582 The '``llvm.coro.destroy``' intrinsic destroys a suspended
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
583 coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
584
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
585 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
586 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
587
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
588 The argument is a coroutine handle to a suspended coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
589
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
590 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
591 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
592
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
593 When possible, the `coro.destroy` intrinsic is replaced with a direct call to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
594 the coroutine destroy function. Otherwise it is replaced with an indirect call
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
595 based on the function pointer for the destroy function stored in the coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
596 frame. Destroying a coroutine that is not suspended leads to undefined behavior.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
597
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
598 .. _coro.resume:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
599
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
600 'llvm.coro.resume' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
601 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
602
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
603 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
604
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
605 declare void @llvm.coro.resume(i8* <handle>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
606
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
607 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
608 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
609
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
610 The '``llvm.coro.resume``' intrinsic resumes a suspended coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
611
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
612 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
613 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
614
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
615 The argument is a handle to a suspended coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
616
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
617 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
618 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
619
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
620 When possible, the `coro.resume` intrinsic is replaced with a direct call to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
621 coroutine resume function. Otherwise it is replaced with an indirect call based
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
622 on the function pointer for the resume function stored in the coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
623 Resuming a coroutine that is not suspended leads to undefined behavior.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
624
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
625 .. _coro.done:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
626
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
627 'llvm.coro.done' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
628 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
629
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
630 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
631
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
632 declare i1 @llvm.coro.done(i8* <handle>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
633
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
634 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
635 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
636
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
637 The '``llvm.coro.done``' intrinsic checks whether a suspended coroutine is at
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
638 the final suspend point or not.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
639
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
640 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
641 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
642
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
643 The argument is a handle to a suspended coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
644
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
645 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
646 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
647
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
648 Using this intrinsic on a coroutine that does not have a `final suspend`_ point
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
649 or on a coroutine that is not suspended leads to undefined behavior.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
650
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
651 .. _coro.promise:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
652
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
653 'llvm.coro.promise' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
654 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
655
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
656 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
657
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
658 declare i8* @llvm.coro.promise(i8* <ptr>, i32 <alignment>, i1 <from>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
659
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
660 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
661 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
662
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
663 The '``llvm.coro.promise``' intrinsic obtains a pointer to a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
664 `coroutine promise`_ given a coroutine handle and vice versa.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
665
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
666 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
667 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
668
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
669 The first argument is a handle to a coroutine if `from` is false. Otherwise,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
670 it is a pointer to a coroutine promise.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
671
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
672 The second argument is an alignment requirements of the promise.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
673 If a frontend designated `%promise = alloca i32` as a promise, the alignment
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
674 argument to `coro.promise` should be the alignment of `i32` on the target
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
675 platform. If a frontend designated `%promise = alloca i32, align 16` as a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
676 promise, the alignment argument should be 16.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
677 This argument only accepts constants.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
678
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
679 The third argument is a boolean indicating a direction of the transformation.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
680 If `from` is true, the intrinsic returns a coroutine handle given a pointer
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
681 to a promise. If `from` is false, the intrinsics return a pointer to a promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
682 from a coroutine handle. This argument only accepts constants.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
683
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
684 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
685 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
686
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
687 Using this intrinsic on a coroutine that does not have a coroutine promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
688 leads to undefined behavior. It is possible to read and modify coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
689 promise of the coroutine which is currently executing. The coroutine author and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
690 a coroutine user are responsible to makes sure there is no data races.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
691
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
692 Example:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
693 """"""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
694
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
695 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
696
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
697 define i8* @f(i32 %n) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
698 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
699 %promise = alloca i32
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
700 %pv = bitcast i32* %promise to i8*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
701 ; the second argument to coro.id points to the coroutine promise.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
702 %id = call token @llvm.coro.id(i32 0, i8* %pv, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
703 ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
704 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
705 ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
706 store i32 42, i32* %promise ; store something into the promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
707 ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
708 ret i8* %hdl
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
709 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
710
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
711 define i32 @main() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
712 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
713 %hdl = call i8* @f(i32 4) ; starts the coroutine and returns its handle
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
714 %promise.addr.raw = call i8* @llvm.coro.promise(i8* %hdl, i32 4, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
715 %promise.addr = bitcast i8* %promise.addr.raw to i32*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
716 %val = load i32, i32* %promise.addr ; load a value from the promise
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
717 call void @print(i32 %val)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
718 call void @llvm.coro.destroy(i8* %hdl)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
719 ret i32 0
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
720 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
721
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
722 .. _coroutine intrinsics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
723
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
724 Coroutine Structure Intrinsics
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
725 ------------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
726 Intrinsics described in this section are used within a coroutine to describe
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
727 the coroutine structure. They should not be used outside of a coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
728
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
729 .. _coro.size:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
730
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
731 'llvm.coro.size' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
732 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
733 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
734
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
735 declare i32 @llvm.coro.size.i32()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
736 declare i64 @llvm.coro.size.i64()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
737
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
738 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
739 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
740
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
741 The '``llvm.coro.size``' intrinsic returns the number of bytes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
742 required to store a `coroutine frame`_.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
743
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
744 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
745 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
746
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
747 None
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
748
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
749 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
750 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
751
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
752 The `coro.size` intrinsic is lowered to a constant representing the size of
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
753 the coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
754
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
755 .. _coro.begin:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
756
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
757 'llvm.coro.begin' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
758 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
759 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
760
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
761 declare i8* @llvm.coro.begin(token <id>, i8* <mem>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
762
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
763 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
764 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
765
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
766 The '``llvm.coro.begin``' intrinsic returns an address of the coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
767
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
768 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
769 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
770
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
771 The first argument is a token returned by a call to '``llvm.coro.id``'
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
772 identifying the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
773
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
774 The second argument is a pointer to a block of memory where coroutine frame
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
775 will be stored if it is allocated dynamically.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
776
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
777 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
778 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
779
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
780 Depending on the alignment requirements of the objects in the coroutine frame
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
781 and/or on the codegen compactness reasons the pointer returned from `coro.begin`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
782 may be at offset to the `%mem` argument. (This could be beneficial if
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
783 instructions that express relative access to data can be more compactly encoded
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
784 with small positive and negative offsets).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
785
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
786 A frontend should emit exactly one `coro.begin` intrinsic per coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
787
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
788 .. _coro.free:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
789
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
790 'llvm.coro.free' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
791 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
792 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
793
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
794 declare i8* @llvm.coro.free(token %id, i8* <frame>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
795
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
796 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
797 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
798
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
799 The '``llvm.coro.free``' intrinsic returns a pointer to a block of memory where
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
800 coroutine frame is stored or `null` if this instance of a coroutine did not use
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
801 dynamically allocated memory for its coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
802
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
803 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
804 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
805
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
806 The first argument is a token returned by a call to '``llvm.coro.id``'
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
807 identifying the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
808
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
809 The second argument is a pointer to the coroutine frame. This should be the same
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
810 pointer that was returned by prior `coro.begin` call.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
811
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
812 Example (custom deallocation function):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
813 """""""""""""""""""""""""""""""""""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
814
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
815 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
816
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
817 cleanup:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
818 %mem = call i8* @llvm.coro.free(token %id, i8* %frame)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
819 %mem_not_null = icmp ne i8* %mem, null
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
820 br i1 %mem_not_null, label %if.then, label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
821 if.then:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
822 call void @CustomFree(i8* %mem)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
823 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
824 if.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
825 ret void
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
826
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
827 Example (standard deallocation functions):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
828 """"""""""""""""""""""""""""""""""""""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
829
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
830 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
831
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
832 cleanup:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
833 %mem = call i8* @llvm.coro.free(token %id, i8* %frame)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
834 call void @free(i8* %mem)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
835 ret void
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
836
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
837 .. _coro.alloc:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
838
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
839 'llvm.coro.alloc' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
840 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
841 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
842
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
843 declare i1 @llvm.coro.alloc(token <id>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
844
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
845 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
846 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
847
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
848 The '``llvm.coro.alloc``' intrinsic returns `true` if dynamic allocation is
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
849 required to obtain a memory for the coroutine frame and `false` otherwise.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
850
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
851 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
852 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
853
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
854 The first argument is a token returned by a call to '``llvm.coro.id``'
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
855 identifying the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
856
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
857 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
858 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
859
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
860 A frontend should emit at most one `coro.alloc` intrinsic per coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
861 The intrinsic is used to suppress dynamic allocation of the coroutine frame
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
862 when possible.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
863
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
864 Example:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
865 """"""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
866
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
867 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
868
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
869 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
870 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
871 %dyn.alloc.required = call i1 @llvm.coro.alloc(token %id)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
872 br i1 %dyn.alloc.required, label %coro.alloc, label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
873
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
874 coro.alloc:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
875 %frame.size = call i32 @llvm.coro.size()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
876 %alloc = call i8* @MyAlloc(i32 %frame.size)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
877 br label %coro.begin
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
878
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
879 coro.begin:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
880 %phi = phi i8* [ null, %entry ], [ %alloc, %coro.alloc ]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
881 %frame = call i8* @llvm.coro.begin(token %id, i8* %phi)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
882
147
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
883 .. _coro.noop:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
884
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
885 'llvm.coro.noop' Intrinsic
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
886 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
887 ::
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
888
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
889 declare i8* @llvm.coro.noop()
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
890
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
891 Overview:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
892 """""""""
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
893
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
894 The '``llvm.coro.noop``' intrinsic returns an address of the coroutine frame of
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
895 a coroutine that does nothing when resumed or destroyed.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
896
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
897 Arguments:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
898 """"""""""
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
899
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
900 None
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
901
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
902 Semantics:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
903 """"""""""
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
904
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
905 This intrinsic is lowered to refer to a private constant coroutine frame. The
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
906 resume and destroy handlers for this frame are empty functions that do nothing.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
907 Note that in different translation units llvm.coro.noop may return different pointers.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 121
diff changeset
908
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
909 .. _coro.frame:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
910
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
911 'llvm.coro.frame' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
912 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
913 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
914
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
915 declare i8* @llvm.coro.frame()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
916
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
917 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
918 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
919
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
920 The '``llvm.coro.frame``' intrinsic returns an address of the coroutine frame of
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
921 the enclosing coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
922
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
923 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
924 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
925
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
926 None
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
927
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
928 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
929 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
930
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
931 This intrinsic is lowered to refer to the `coro.begin`_ instruction. This is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
932 a frontend convenience intrinsic that makes it easier to refer to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
933 coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
934
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
935 .. _coro.id:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
936
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
937 'llvm.coro.id' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
938 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
939 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
940
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
941 declare token @llvm.coro.id(i32 <align>, i8* <promise>, i8* <coroaddr>,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
942 i8* <fnaddrs>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
943
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
944 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
945 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
946
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
947 The '``llvm.coro.id``' intrinsic returns a token identifying a coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
948
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
949 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
950 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
951
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
952 The first argument provides information on the alignment of the memory returned
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
953 by the allocation function and given to `coro.begin` by the first argument. If
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
954 this argument is 0, the memory is assumed to be aligned to 2 * sizeof(i8*).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
955 This argument only accepts constants.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
956
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
957 The second argument, if not `null`, designates a particular alloca instruction
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
958 to be a `coroutine promise`_.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
959
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
960 The third argument is `null` coming out of the frontend. The CoroEarly pass sets
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
961 this argument to point to the function this coro.id belongs to.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
962
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
963 The fourth argument is `null` before coroutine is split, and later is replaced
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
964 to point to a private global constant array containing function pointers to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
965 outlined resume and destroy parts of the coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
966
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
967
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
968 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
969 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
970
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
971 The purpose of this intrinsic is to tie together `coro.id`, `coro.alloc` and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
972 `coro.begin` belonging to the same coroutine to prevent optimization passes from
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
973 duplicating any of these instructions unless entire body of the coroutine is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
974 duplicated.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
975
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
976 A frontend should emit exactly one `coro.id` intrinsic per coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
977
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
978 .. _coro.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
979
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
980 'llvm.coro.end' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
981 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
982 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
983
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
984 declare i1 @llvm.coro.end(i8* <handle>, i1 <unwind>)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
985
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
986 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
987 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
988
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
989 The '``llvm.coro.end``' marks the point where execution of the resume part of
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
990 the coroutine should end and control should return to the caller.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
991
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
992
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
993 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
994 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
995
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
996 The first argument should refer to the coroutine handle of the enclosing
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
997 coroutine. A frontend is allowed to supply null as the first parameter, in this
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
998 case `coro-early` pass will replace the null with an appropriate coroutine
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
999 handle value.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1000
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1001 The second argument should be `true` if this coro.end is in the block that is
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1002 part of the unwind sequence leaving the coroutine body due to an exception and
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1003 `false` otherwise.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1004
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1005 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1006 """"""""""
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1007 The purpose of this intrinsic is to allow frontends to mark the cleanup and
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1008 other code that is only relevant during the initial invocation of the coroutine
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1009 and should not be present in resume and destroy parts.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1010
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1011 This intrinsic is lowered when a coroutine is split into
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1012 the start, resume and destroy parts. In the start part, it is a no-op,
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1013 in resume and destroy parts, it is replaced with `ret void` instruction and
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1014 the rest of the block containing `coro.end` instruction is discarded.
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1015 In landing pads it is replaced with an appropriate instruction to unwind to
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1016 caller. The handling of coro.end differs depending on whether the target is
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1017 using landingpad or WinEH exception model.
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1018
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1019 For landingpad based exception model, it is expected that frontend uses the
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1020 `coro.end`_ intrinsic as follows:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1021
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1022 .. code-block:: llvm
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1023
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1024 ehcleanup:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1025 %InResumePart = call i1 @llvm.coro.end(i8* null, i1 true)
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1026 br i1 %InResumePart, label %eh.resume, label %cleanup.cont
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1027
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1028 cleanup.cont:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1029 ; rest of the cleanup
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1030
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1031 eh.resume:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1032 %exn = load i8*, i8** %exn.slot, align 8
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1033 %sel = load i32, i32* %ehselector.slot, align 4
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1034 %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1035 %lpad.val29 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1036 resume { i8*, i32 } %lpad.val29
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1037
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1038 The `CoroSpit` pass replaces `coro.end` with ``True`` in the resume functions,
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1039 thus leading to immediate unwind to the caller, whereas in start function it
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1040 is replaced with ``False``, thus allowing to proceed to the rest of the cleanup
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1041 code that is only needed during initial invocation of the coroutine.
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1042
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1043 For Windows Exception handling model, a frontend should attach a funclet bundle
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1044 referring to an enclosing cleanuppad as follows:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1045
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1046 .. code-block:: llvm
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1047
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1048 ehcleanup:
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1049 %tok = cleanuppad within none []
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1050 %unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ]
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1051 cleanupret from %tok unwind label %RestOfTheCleanup
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1052
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1053 The `CoroSplit` pass, if the funclet bundle is present, will insert
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1054 ``cleanupret from %tok unwind to caller`` before
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1055 the `coro.end`_ intrinsic and will remove the rest of the block.
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1056
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1057 The following table summarizes the handling of `coro.end`_ intrinsic.
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1058
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1059 +--------------------------+-------------------+-------------------------------+
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1060 | | In Start Function | In Resume/Destroy Functions |
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1061 +--------------------------+-------------------+-------------------------------+
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1062 |unwind=false | nothing |``ret void`` |
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1063 +------------+-------------+-------------------+-------------------------------+
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1064 | | WinEH | nothing |``cleanupret unwind to caller``|
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1065 |unwind=true +-------------+-------------------+-------------------------------+
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1066 | | Landingpad | nothing | nothing |
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1067 +------------+-------------+-------------------+-------------------------------+
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1068
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1069 .. _coro.suspend:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1070 .. _suspend points:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1071
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1072 'llvm.coro.suspend' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1073 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1074 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1075
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1076 declare i8 @llvm.coro.suspend(token <save>, i1 <final>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1077
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1078 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1079 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1080
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1081 The '``llvm.coro.suspend``' marks the point where execution of the coroutine
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1082 need to get suspended and control returned back to the caller.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1083 Conditional branches consuming the result of this intrinsic lead to basic blocks
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1084 where coroutine should proceed when suspended (-1), resumed (0) or destroyed
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1085 (1).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1086
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1087 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1088 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1089
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1090 The first argument refers to a token of `coro.save` intrinsic that marks the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1091 point when coroutine state is prepared for suspension. If `none` token is passed,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1092 the intrinsic behaves as if there were a `coro.save` immediately preceding
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1093 the `coro.suspend` intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1094
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1095 The second argument indicates whether this suspension point is `final`_.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1096 The second argument only accepts constants. If more than one suspend point is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1097 designated as final, the resume and destroy branches should lead to the same
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1098 basic blocks.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1099
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1100 Example (normal suspend point):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1101 """""""""""""""""""""""""""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1102
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1103 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1104
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1105 %0 = call i8 @llvm.coro.suspend(token none, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1106 switch i8 %0, label %suspend [i8 0, label %resume
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1107 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1108
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1109 Example (final suspend point):
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1110 """"""""""""""""""""""""""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1111
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1112 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1113
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1114 while.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1115 %s.final = call i8 @llvm.coro.suspend(token none, i1 true)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1116 switch i8 %s.final, label %suspend [i8 0, label %trap
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1117 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1118 trap:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1119 call void @llvm.trap()
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1120 unreachable
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1121
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1122 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1123 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1124
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1125 If a coroutine that was suspended at the suspend point marked by this intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1126 is resumed via `coro.resume`_ the control will transfer to the basic block
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1127 of the 0-case. If it is resumed via `coro.destroy`_, it will proceed to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1128 basic block indicated by the 1-case. To suspend, coroutine proceed to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1129 default label.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1130
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1131 If suspend intrinsic is marked as final, it can consider the `true` branch
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1132 unreachable and can perform optimizations that can take advantage of that fact.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1133
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1134 .. _coro.save:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1135
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1136 'llvm.coro.save' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1137 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1138 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1139
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1140 declare token @llvm.coro.save(i8* <handle>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1141
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1142 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1143 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1144
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1145 The '``llvm.coro.save``' marks the point where a coroutine need to update its
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1146 state to prepare for resumption to be considered suspended (and thus eligible
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1147 for resumption).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1148
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1149 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1150 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1151
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1152 The first argument points to a coroutine handle of the enclosing coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1153
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1154 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1155 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1156
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1157 Whatever coroutine state changes are required to enable resumption of
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1158 the coroutine from the corresponding suspend point should be done at the point
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1159 of `coro.save` intrinsic.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1160
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1161 Example:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1162 """"""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1163
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1164 Separate save and suspend points are necessary when a coroutine is used to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1165 represent an asynchronous control flow driven by callbacks representing
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1166 completions of asynchronous operations.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1167
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1168 In such a case, a coroutine should be ready for resumption prior to a call to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1169 `async_op` function that may trigger resumption of a coroutine from the same or
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1170 a different thread possibly prior to `async_op` call returning control back
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1171 to the coroutine:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1172
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1173 .. code-block:: llvm
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1174
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1175 %save1 = call token @llvm.coro.save(i8* %hdl)
121
803732b1fca8 LLVM 5.0
kono
parents: 120
diff changeset
1176 call void @async_op1(i8* %hdl)
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1177 %suspend1 = call i1 @llvm.coro.suspend(token %save1, i1 false)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1178 switch i8 %suspend1, label %suspend [i8 0, label %resume1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1179 i8 1, label %cleanup]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1180
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1181 .. _coro.param:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1182
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1183 'llvm.coro.param' Intrinsic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1184 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1185 ::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1186
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1187 declare i1 @llvm.coro.param(i8* <original>, i8* <copy>)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1188
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1189 Overview:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1190 """""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1191
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1192 The '``llvm.coro.param``' is used by a frontend to mark up the code used to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1193 construct and destruct copies of the parameters. If the optimizer discovers that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1194 a particular parameter copy is not used after any suspends, it can remove the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1195 construction and destruction of the copy by replacing corresponding coro.param
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1196 with `i1 false` and replacing any use of the `copy` with the `original`.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1197
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1198 Arguments:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1199 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1200
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1201 The first argument points to an `alloca` storing the value of a parameter to a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1202 coroutine.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1203
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1204 The second argument points to an `alloca` storing the value of the copy of that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1205 parameter.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1206
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1207 Semantics:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1208 """"""""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1209
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1210 The optimizer is free to always replace this intrinsic with `i1 true`.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1211
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1212 The optimizer is also allowed to replace it with `i1 false` provided that the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1213 parameter copy is only used prior to control flow reaching any of the suspend
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1214 points. The code that would be DCE'd if the `coro.param` is replaced with
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1215 `i1 false` is not considered to be a use of the parameter copy.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1216
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1217 The frontend can emit this intrinsic if its language rules allow for this
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1218 optimization.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1219
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1220 Example:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1221 """"""""
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1222 Consider the following example. A coroutine takes two parameters `a` and `b`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1223 that has a destructor and a move constructor.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1224
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1225 .. code-block:: c++
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1226
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1227 struct A { ~A(); A(A&&); bool foo(); void bar(); };
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1228
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1229 task<int> f(A a, A b) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1230 if (a.foo())
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1231 return 42;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1232
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1233 a.bar();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1234 co_await read_async(); // introduces suspend point
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1235 b.bar();
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1236 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1237
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1238 Note that, uses of `b` is used after a suspend point and thus must be copied
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1239 into a coroutine frame, whereas `a` does not have to, since it never used
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1240 after suspend.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1241
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1242 A frontend can create parameter copies for `a` and `b` as follows:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1243
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1244 .. code-block:: text
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1245
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1246 task<int> f(A a', A b') {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1247 a = alloca A;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1248 b = alloca A;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1249 // move parameters to its copies
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1250 if (coro.param(a', a)) A::A(a, A&& a');
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1251 if (coro.param(b', b)) A::A(b, A&& b');
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1252 ...
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1253 // destroy parameters copies
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1254 if (coro.param(a', a)) A::~A(a);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1255 if (coro.param(b', b)) A::~A(b);
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1256 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1257
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1258 The optimizer can replace coro.param(a',a) with `i1 false` and replace all uses
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1259 of `a` with `a'`, since it is not used after suspend.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1260
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1261 The optimizer must replace coro.param(b', b) with `i1 true`, since `b` is used
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1262 after suspend and therefore, it has to reside in the coroutine frame.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1263
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1264 Coroutine Transformation Passes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1265 ===============================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1266 CoroEarly
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1267 ---------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1268 The pass CoroEarly lowers coroutine intrinsics that hide the details of the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1269 structure of the coroutine frame, but, otherwise not needed to be preserved to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1270 help later coroutine passes. This pass lowers `coro.frame`_, `coro.done`_,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1271 and `coro.promise`_ intrinsics.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1272
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1273 .. _CoroSplit:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1274
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1275 CoroSplit
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1276 ---------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1277 The pass CoroSplit buides coroutine frame and outlines resume and destroy parts
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1278 into separate functions.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1279
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1280 CoroElide
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1281 ---------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1282 The pass CoroElide examines if the inlined coroutine is eligible for heap
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1283 allocation elision optimization. If so, it replaces
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1284 `coro.begin` intrinsic with an address of a coroutine frame placed on its caller
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1285 and replaces `coro.alloc` and `coro.free` intrinsics with `false` and `null`
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1286 respectively to remove the deallocation code.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1287 This pass also replaces `coro.resume` and `coro.destroy` intrinsics with direct
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1288 calls to resume and destroy functions for a particular coroutine where possible.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1289
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1290 CoroCleanup
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1291 -----------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1292 This pass runs late to lower all coroutine related intrinsics not replaced by
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1293 earlier passes.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1294
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1295 Areas Requiring Attention
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1296 =========================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1297 #. A coroutine frame is bigger than it could be. Adding stack packing and stack
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1298 coloring like optimization on the coroutine frame will result in tighter
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1299 coroutine frames.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1300
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1301 #. Take advantage of the lifetime intrinsics for the data that goes into the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1302 coroutine frame. Leave lifetime intrinsics as is for the data that stays in
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1303 allocas.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1304
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1305 #. The CoroElide optimization pass relies on coroutine ramp function to be
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1306 inlined. It would be beneficial to split the ramp function further to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1307 increase the chance that it will get inlined into its caller.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1308
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1309 #. Design a convention that would make it possible to apply coroutine heap
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1310 elision optimization across ABI boundaries.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1311
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1312 #. Cannot handle coroutines with `inalloca` parameters (used in x86 on Windows).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1313
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1314 #. Alignment is ignored by coro.begin and coro.free intrinsics.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1315
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1316 #. Make required changes to make sure that coroutine optimizations work with
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1317 LTO.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1318
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1319 #. More tests, more tests, more tests