Skip to content

[docs] Clarify SIL level TBAA rules. #2147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 7, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 92 additions & 11 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1538,15 +1538,16 @@ Class TBAA

Class instances and other *heap object references* are pointers at the
implementation level, but unlike SIL addresses, they are first class values and
can be ``capture``-d and alias. Swift, however, is memory-safe and statically
can be ``capture``-d and aliased. Swift, however, is memory-safe and statically
typed, so aliasing of classes is constrained by the type system as follows:

* A ``Builtin.NativeObject`` may alias any native Swift heap object,
including a Swift class instance, a box allocated by ``alloc_box``,
or a thick function's closure context.
It may not alias natively Objective-C class instances.
* A ``Builtin.UnknownObject`` may alias any class instance, whether Swift or
Objective-C, but may not alias non-class-instance heap objects.
* A ``Builtin.UnknownObject`` or ``Builtin.BridgeObject`` may alias
any class instance, whether Swift or Objective-C, but may not alias
non-class-instance heap objects.
* Two values of the same class type ``$C`` may alias. Two values of related
class type ``$B`` and ``$D``, where there is a subclass relationship between
``$B`` and ``$D``, may alias. Two values of unrelated class types may not
Expand All @@ -1560,6 +1561,15 @@ typed, so aliasing of classes is constrained by the type system as follows:
potentially alias concrete instances of the generic type, such as
``$C<Int>``, because ``Int`` is a potential substitution for ``T``.

A violation of the above aliasing rules only results in undefined
behavior if the aliasing references are dereferenced within Swift code.
For example,
``_SwiftNativeNS[Array|Dictionary|String]`` classes alias with
``NS[Array|Dictionary|String]`` classes even though they are not
statically related. Since Swift never directly accesses stored
properties on the Foundation classes, this aliasing does not pose a
danger.

Typed Access TBAA
~~~~~~~~~~~~~~~~~

Expand All @@ -1571,15 +1581,86 @@ Define a *typed access* of an address or reference as one of the following:
typed projection operation (e.x. ``ref_element_addr``,
``tuple_element_addr``).

It is undefined behavior to perform a typed access to an address or reference if
the stored object or referent is not an allocated object of the relevant type.
With limited exceptions, it is undefined behavior to perform a typed access to
an address or reference addressed memory is not bound to the relevant type.

This allows the optimizer to assume that two addresses cannot alias if
there does not exist a substitution of archetypes that could cause one
of the types to be the type of a subobject of the other. Additionally,
this applies to the types of the values from which the addresses were
derived via a typed projection.

This allows the optimizer to assume that two addresses cannot alias if there
does not exist a substitution of archetypes that could cause one of the types to
be the type of a subobject of the other. Additionally, this applies to the types
of the values from which the addresses were derived, ignoring "blessed"
alias-introducing operations such as ``pointer_to_address``, the ``bitcast``
intrinsic, and the ``inttoptr`` intrinsic.
Consider the following SIL::

struct Element {
var i: Int
}
struct S1 {
var elt: Element
}
struct S2 {
var elt: Element
}
%adr1 = struct_element_addr %ptr1 : $*S1, #S.elt
%adr2 = struct_element_addr %ptr2 : $*S2, #S.elt

The optimizer may assume that ``%adr1`` does not alias with ``%adr2``
because the values that the addresses are derived from (``%ptr1`` and
``%ptr2``) have unrelated types. However, in the following example,
the optimizer cannot assume that ``%adr1`` does not alias with
``%adr2`` because ``%adr2`` is derived from a cast, and any subsequent
typed operations on the address will refer to the common ``Element`` type::

%adr1 = struct_element_addr %ptr1 : $*S1, #S.elt
%adr2 = pointer_to_address %ptr2 : $Builtin.RawPointer to $*Element

Exceptions to typed access TBAA rules are only allowed for blessed
alias-introducing operations. This permits limited type-punning. The only
current exception is the non-struct ``pointer_to_address`` variant. The
optimizer must be able to defensively determine that none of the *roots* of an
address are alias-introducing operations. An address root is the operation that
produces the address prior to applying any typed projections, indexing, or
casts. The following are valid address roots:

* Object allocation that generates an address, such as ``alloc_stack``
and ``alloc_box``.

* Address-type function arguments. These are crucially *not* considered
alias-introducing operations. It is illegal for the SIL optimizer to
form a new function argument from an arbitrary address-type
value. Doing so would require the optimizer to guarantee that the
new argument is both has a non-alias-introducing address root and
can be properly represented by the calling convention (address types
do not have a fixed representation).

* A strict cast from an untyped pointer, ``pointer_to_address [strict]``. It is
illegal for ``pointer_to_address [strict]`` to derive its address from an
alias-introducing operation's value. A type punned address may only be
produced from an opaque pointer via a non-strict ``pointer_to_address`` at the
point of conversion.

Address-to-address casts, via ``unchecked_addr_cast``, transparently
forward their source's address root, just like typed projections.

Address-type basic block arguments can be conservatively considered
aliasing-introducing operations; they are uncommon enough not to
matter and may eventually be prohibited altogether.

Although some pointer producing intrinsics exist, they do not need to be
considered alias-introducing exceptions to TBAA rules. ``Builtin.inttoptr``
produces a ``Builtin.RawPointer`` which is not interesting because by definition
it may alias with everything. Similarly, the LLVM builtins ``Builtin.bitcast``
and ``Builtin.trunc|sext|zextBitCast`` cannot produce typed pointers. These
pointer values must be converted to an address via ``pointer_to_address`` before
typed access can occur. Whether the ``pointer_to_address`` is strict determines
whether aliasing may occur.

Memory may be rebound to an unrelated type. Addresses to unrelated types may
alias as long as typed access only occurs while memory is bound to the relevant
type. Consequently, the optimizer cannot outright assume that addresses accessed
as unrelated types are nonaliasing. For example, pointer comparison cannot be
eliminated simply because the two addresses derived from those pointers are
accessed as unrelated types at different program points.

Value Dependence
----------------
Expand Down