@@ -161,6 +161,9 @@ idioms, it becomes overly burdensome to evolve these APIs over time.
161
161
162
162
## ` AccessedStorage ` and ` AccessPath `
163
163
164
+ TODO: move this section to a separate document and refer to it from
165
+ SIL.rst.
166
+
164
167
The ` AccessedStorage ` and ` AccessPath ` types formalize memory access
165
168
in SIL. Given an address-typed SIL value, it is possible to
166
169
reliably identify the storage location of the accessed
@@ -193,17 +196,17 @@ address is immutable for the duration of its access scope
193
196
194
197
Computing ` AccessedStorage ` and ` AccessPath ` for any given SIL address
195
198
involves a use-def traversal to determine the origin of the
196
- address. It may traverse operations on address, pointer, box, and
197
- reference types . The logic that formalizes which SIL operations may be
198
- involved in the def-use chain is encapsulated with the
199
- ` AccessUseDefChainVisitor ` . The traversal can be customized by
200
- implementing this visitor. Customization is not expected to change the
201
- meaning of AccessedStorage or AccessPath. Rather, it is intended for
202
- additional pass-specific book-keeping or for higher-level convenience
203
- APIs that operate on the use-def chain bypassing AccessedStorage
204
- completely.
205
-
206
- Access def-use chains are divided by four points: the "root", the
199
+ address. It may traverse operations on values of type address,
200
+ Builtin.RawPointer, box, and reference . The logic that
201
+ formalizes which SIL operations may be involved in the def-use chain
202
+ is encapsulated with the ` AccessUseDefChainVisitor ` . The traversal can
203
+ be customized by implementing this visitor. Customization is not
204
+ expected to change the meaning of AccessedStorage or
205
+ AccessPath. Rather, it is intended for additional pass-specific
206
+ book-keeping or for higher-level convenience APIs that operate on the
207
+ use-def chain bypassing AccessedStorage completely.
208
+
209
+ Access def-use chains are divided by four points: the object "root", the
207
210
access "base", the outer-most "access" scope, and the "address" of a
208
211
memory operation. For example:
209
212
```
@@ -222,18 +225,28 @@ memory operation. For example:
222
225
end_access %access : $*S
223
226
```
224
227
228
+ OR
229
+
230
+ ```
231
+ %root = alloc_box $S
232
+ %base = project_box %root : ${ var S }
233
+ %access = begin_access [read] [static] %base : $*S
234
+ %address = struct_element_addr %access : $*S, #.field
235
+ %value = load [trivial] %address : $*Int64
236
+ end_access %access : $*S
237
+ ```
238
+
225
239
#### Reference root
226
240
227
241
The first part of the def-use chain computes the formal access base
228
- from the root of the object (e.g. `alloc_ref ->
229
- ref_element_addr`). The reference root might be a locally allocated
230
- object, a function argument, a function result, or a reference loaded
231
- from storage. There is no enforcement on the type of operation that
232
- can produce a reference; however, only reference types or
233
- Builtin.BridgeObject types are only allowed in this part of the
242
+ from the root of the object (e.g. ` alloc_ref -> ref_element_addr ` and
243
+ ` alloc_box -> project_box ` ). The reference root might be a locally
244
+ allocated object, a function argument, a function result, or a
245
+ reference loaded from storage. There is no enforcement on the type of
246
+ operation that can produce a reference; however, only reference types, Builtin.BridgeObject types, and box types are allowed in this part of the
234
247
def-use chain. The reference root is the greatest common ancestor in
235
248
the def-use graph that can identify an object by a single SILValue. If
236
- the root as an ` alloc_ref ` , then it is * uniquely identified* . The
249
+ the root is an ` alloc_ref ` , then it is * uniquely identified* . The
237
250
def-use chain from the root to the base may contain reference casts
238
251
(` isRCIdentityPreservingCast ` ) and phis.
239
252
@@ -268,29 +281,45 @@ formal access base. The reference root is only one component of an
268
281
` AccessedStorage ` location. AccessedStorage also identifies the class
269
282
property being accessed within that object.
270
283
284
+ A reference root may be borrowed, so the use-def path from the base to
285
+ the root may cross a borrow scope. This means that uses of one base
286
+ may not be replaced with a different base even if it has the same
287
+ AccessedStorage because they may not be contained within the same
288
+ borrow scope. However, this is the only part of the access path that
289
+ may be borrowed. Address uses with the same base can be substituted
290
+ without checking the borrow scope.
291
+
271
292
#### Access base
272
293
273
- The access base is the SILValue produced by an instruction that
274
- directly identifies the kind of storage being accessed without further
275
- use-def traversal. Common access bases are ` alloc_box ` , ` alloc_stack ` ,
276
- ` global_addr ` , ` ref_element_addr ` , and function arguments (see
294
+ The access base is the address or Builtin.RawPointer type SILValue
295
+ produced by an instruction that directly identifies the kind of
296
+ storage being accessed without further use-def traversal. Common
297
+ access bases are ` alloc_stack ` , ` global_addr ` ,
298
+ ` ref_element_addr ` , ` project_box ` , and function arguments (see
277
299
` AccessedStorage::Kind ` ).
278
300
279
301
The access base is the same as the "root" SILValue for all storage
280
- kinds except global and class storage. Global storage has no root. For
281
- class storage the root is the SILValue that identifies object,
282
- described as the "reference root" above.
302
+ kinds except global and reference storage. Reference storage includes
303
+ class, tail and box storage. Global storage has no root. For reference
304
+ storage the root is the SILValue that identifies object, described as
305
+ the "reference root" above.
283
306
284
307
"Box" storage is uniquely identified by an ` alloc_box `
285
308
instruction. Therefore, we consider the ` alloc_box ` to be the base of
286
309
the access. Box storage does not apply to all box types or box
287
310
projections, which may instead originate from arguments or indirect
288
311
enums for example.
289
312
313
+ An access scope, identified by a ` begin_access ` marker, may only occur
314
+ on the def-use path between the access base and any address
315
+ projections. The def-use path from the root to the base cannot cross
316
+ an access scope. Likewise, the def-use between an access projection
317
+ and the memory operation cannot cross an access scope.
318
+
290
319
Typically, the base is the address-type source operand of a
291
320
` begin_access ` . However, the path from the access base to the
292
321
` begin_access ` may include * storage casts* (see
293
- ` isAccessedStorageCast ` ). It may involve address, pointer, and box
322
+ ` isAccessedStorageCast ` ). It may involve address an pointer
294
323
types, and may traverse phis. For some kinds of storage, the base may
295
324
itself even be a non-address pointer. For phis that cannot be uniquely
296
325
resolved, the base may even be a box type.
@@ -322,9 +351,9 @@ which address storage is always uniquely determined. Currently, if a
322
351
(non-address) phi on the access path from ` base ` to ` access ` does not
323
352
have a common base, then it is considered an invalid access (the
324
353
AccessedStorage object is not valid). SIL verification ensures that a
325
- formal access always has valid AccessedStorage (WIP). In other words, the
326
- source of a ` begin_access ` marker must be a single, non-phi base. In
327
- the future, for further simplicity, we may generally disallow box and
354
+ formal access always has valid AccessedStorage (WIP). In other words,
355
+ the source of a ` begin_access ` marker must be a single, non-phi
356
+ base. In the future, for further simplicity, we may also disallow
328
357
pointer phis unless they have a common base.
329
358
330
359
Not all SIL memory access is part of a formal access, but the
@@ -334,8 +363,8 @@ the use-def search does not begin at a `begin_access` marker. For
334
363
non-formal access, SIL verification is not as strict. An invalid
335
364
access is allowed, but handled conservatively. This is safe as long as
336
365
those non-formal accesses can never alias with class and global
337
- storage. Class and global access is always guarded by formal access
338
- markers--at least until static markers are stripped from SIL.
366
+ storage. Class and global access must always be guarded by formal
367
+ access markers--at least until static markers are stripped from SIL.
339
368
340
369
#### Nested access
341
370
0 commit comments