Skip to content

Commit 72fc4e3

Browse files
committed
docs: document the existing @_effects() attributes
1 parent fb00bc3 commit 72fc4e3

File tree

1 file changed

+105
-1
lines changed

1 file changed

+105
-1
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,111 @@ already infer from static analysis.
124124
Changing the implementation in a way that violates the optimizer's assumptions
125125
about the effects results in undefined behavior.
126126

127-
For more details, see [OptimizerEffects.rst](/docs/proposals/OptimizerEffects.rst).
127+
### `@_effects(readnone)`
128+
129+
Defines that the function does not have any observable memory reads or writes
130+
or any other observable side effects.
131+
132+
This does not mean that the function cannot read or write memory at all.
133+
For example, it’s allowed to allocate and write to local objects inside the
134+
function. For example, the following `readnone` function allocates an array and
135+
writes to the array buffer
136+
137+
```swift
138+
@_effects(readnone)
139+
func lookup(_ i: Int) -> Int {
140+
let a = [7, 3 ,6, 9]
141+
return a[i]
142+
}
143+
```
144+
145+
A function can be marked as readnone if two calls of the same function with the
146+
same parameters can be simplified to one call (e.g. by the CSE optimization)
147+
without changing the semantics of the program.
148+
For example,
149+
150+
```swift
151+
let a = lookup(i)
152+
// some other code, including memory writes
153+
let b = lookup(i)
154+
```
155+
is equivalent to
156+
157+
```swift
158+
let a = lookup(i)
159+
// some other code, including memory writes
160+
let b = a
161+
```
162+
163+
Some conclusions:
164+
165+
* A `readnone` function must not return a newly allocated class instance.
166+
167+
* A `readnone` function can return a newly allocated copy-on-write object, like
168+
an Array, because COW data types conceptually behave like value types.
169+
170+
* A `readnone` function must not release any parameter or any object indirectly
171+
referenced from a parameter.
172+
173+
* Any kind of observable side-effects are not allowed, like `print`, file IO, etc.
174+
175+
### `@_effects(readonly)`
176+
177+
Defines that the function does not have any observable memory writes or any
178+
other observable side effects, beside reading of memory.
179+
180+
Similar to `readnone`, a `readonly` function is allowed to write to local objects.
181+
182+
A function can be marked as `readonly` if it’s save to eliminate a call to such
183+
a function in case its return value is not used.
184+
Example:
185+
186+
```swift
187+
@_effects(readonly)
188+
func lookup2(_ instance: SomeClass) -> Int {
189+
let a = [7, 3 ,6, 9]
190+
return a[instance.i]
191+
}
192+
```
193+
194+
It is legal to eliminate an unused call to this function:
195+
196+
```
197+
_ = lookup2(i) // can be completely eliminated
198+
```
199+
200+
Note that it would not be legal to CSE two calls to this function, because
201+
between those calls the member `i` of the class instance could be modified:
202+
203+
```swift
204+
let a = lookup2(instance)
205+
instance.i += 1
206+
let b = lookup2(instance) // cannot be CSE'd with the first call
207+
```
208+
209+
The same conclusions as for `readnone` also apply to `readonly`.
210+
211+
### `@_effects(releasenone)`
212+
213+
Defines that the function does not release any class instance.
214+
215+
This effect must be used with care.
216+
There are several code patterns which release objects in a non-obvious way.
217+
For example:
218+
219+
* A parameter which is passed to an “owned” argument (and not stored), like
220+
initializer arguments.
221+
222+
* Assignments, because they release the old value
223+
224+
* COW data types, e.g. Strings. Conceptually they are value types, but
225+
internally the keep a reference counted buffer.
226+
227+
* Class references deep inside a hierarchy of value types.
228+
229+
### `@_effects(readwrite)`
230+
231+
This effect is not used by the compiler.
128232

129233
## `@_exported`
130234

0 commit comments

Comments
 (0)