Skip to content

Commit 6687fca

Browse files
authored
Merge pull request #32808 from gottesmm/pr-a7cb4e56fe39ba260ca4bb9090ec74f9b3537eaa
[docs] Begin adding section describing OSSA.
2 parents fb74ba2 + 8da5616 commit 6687fca

File tree

1 file changed

+259
-3
lines changed

1 file changed

+259
-3
lines changed

docs/SIL.rst

Lines changed: 259 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,10 @@ Basic Blocks
10351035

10361036
sil-basic-block ::= sil-label sil-instruction-def* sil-terminator
10371037
sil-label ::= sil-identifier ('(' sil-argument (',' sil-argument)* ')')? ':'
1038-
sil-argument ::= sil-value-name ':' sil-type
1038+
sil-value-ownership-kind ::= @owned
1039+
sil-value-ownership-kind ::= @guaranteed
1040+
sil-value-ownership-kind ::= @unowned
1041+
sil-argument ::= sil-value-name ':' sil-value-ownership-kind? sil-type
10391042

10401043
sil-instruction-result ::= sil-value-name
10411044
sil-instruction-result ::= '(' (sil-value-name (',' sil-value-name)*)? ')'
@@ -1067,12 +1070,12 @@ block::
10671070
Arguments to the entry point basic block, which has no predecessor,
10681071
are bound by the function's caller::
10691072

1070-
sil @foo : $(Int) -> Int {
1073+
sil @foo : $@convention(thin) (Int) -> Int {
10711074
bb0(%x : $Int):
10721075
return %x : $Int
10731076
}
10741077

1075-
sil @bar : $(Int, Int) -> () {
1078+
sil @bar : $@convention(thin) (Int, Int) -> () {
10761079
bb0(%x : $Int, %y : $Int):
10771080
%foo = function_ref @foo
10781081
%1 = apply %foo(%x) : $(Int) -> Int
@@ -1081,6 +1084,17 @@ are bound by the function's caller::
10811084
return %3 : $()
10821085
}
10831086

1087+
When a function is in Ownership SSA, arguments additionally have an explicit
1088+
annotated convention that describe the ownership semantics of the argument
1089+
value::
1090+
1091+
sil [ossa] @baz : $@convention(thin) (Int, @owned String, @guaranteed String, @unowned String) -> () {
1092+
bb0(%x : $Int, %y : @owned $String, %z : @guaranteed $String, %w : @unowned $String):
1093+
...
1094+
}
1095+
1096+
Note that the first argument (``%x``) has an implicit ownership kind of
1097+
``@none`` since all trivial values have ``@none`` ownership.
10841098

10851099
Debug Information
10861100
~~~~~~~~~~~~~~~~~
@@ -1579,6 +1593,248 @@ of functions returning uninhabited types. An ``unreachable`` instruction that
15791593
survives guaranteed DCE and is not immediately preceded by a no-return
15801594
application is a dataflow error.
15811595

1596+
Ownership SSA
1597+
-------------
1598+
1599+
A SILFunction marked with the ``[ossa]`` function attribute is considered to be
1600+
in Ownership SSA form. Ownership SSA is an augmented version of SSA that
1601+
enforces ownership invariants by imbuing value-operand edges with semantic
1602+
ownership information. All SIL values are statically assigned an ownership kind
1603+
that defines the ownership semantics that the value models. All SIL operands
1604+
that use a SIL value are required to be able to be semantically partitioned in
1605+
between "normal uses" that just require the value to be live and "consuming
1606+
uses" that end the lifetime of the value and after which the value can no longer
1607+
be used. Since operands that are consuming uses end a value's lifetime,
1608+
naturally we must have that the consuming use points jointly post-dominate all
1609+
non-consuming use points and that a value must be consumed exactly once along
1610+
all reachable program paths, preventing leaks and use-after-frees. As an
1611+
example, consider the following SIL example with partitioned defs/uses annotated
1612+
inline::
1613+
1614+
sil @stash_and_cast : $@convention(thin) (@owned Klass) -> @owned SuperKlass {
1615+
bb0(%kls1 : @owned $Klass): // Definition of %kls1
1616+
1617+
// "Normal Use" kls1.
1618+
// Definition of %kls2.
1619+
%kls2 = copy_value %kls1 : $Klass
1620+
1621+
// "Consuming Use" of %kls2 to store it into a global. Stores in ossa are
1622+
// consuming since memory is generally assumed to have "owned"
1623+
// semantics. After this instruction executes, we can no longer use %kls2
1624+
// without triggering an ownership violation.
1625+
store %kls2 to [init] %globalMem : $*Klass
1626+
1627+
// "Consuming Use" of %kls1.
1628+
// Definition of %kls1Casted.
1629+
%kls1Casted = upcast %kls1 : $Klass to $SuperKlass
1630+
1631+
// "Consuming Use" of %kls1Casted
1632+
return %kls1Casted : $SuperKlass
1633+
}
1634+
1635+
Notice how every value in the SIL above has a partionable set of uses with
1636+
normal uses always before consuming uses. Any such violations of ownership
1637+
semantics would trigger a static SILVerifier error allowing us to know that we
1638+
do not have any leaks or use-after-frees in the above code.
1639+
1640+
The semantics in the previous example is of just one form of ownership semantics
1641+
supported: "owned" semantics. In SIL, we support four different ownership kinds:
1642+
1643+
* **None**. This is used to represent values that do not require memory
1644+
management and are outside of Ownership SSA invariants. Examples: trivial
1645+
values (e.x.: Int, Float), non-payloaded cases of non-trivial enums (e.x.:
1646+
Optional<T>.none), all address types.
1647+
1648+
* **Owned**. A value that exists independently of any other value and is
1649+
consumed exactly once along all paths through a function by either a
1650+
destroy_value (actually destroying the value) or by a consuming instruction
1651+
that rebinds the value in some manner (e.x.: apply, casts, store).
1652+
1653+
* **Guaranteed**. A value with a scoped lifetime whose liveness is dependent on
1654+
the lifetime of some other "base" owned or guaranteed value. Consumed by
1655+
end_borrow instructions. The "base" value is statically guaranteed to be live
1656+
at all of the value's paired end_borrow instructions.
1657+
1658+
* **Unowned**. A value that is only guaranteed to be instantaneously valid and
1659+
must be copied before the value is used in an ``@owned`` or ``@guaranteed``
1660+
context. This is needed both to model argument values with the ObjC unsafe
1661+
unowned argument convention and also to model the ownership resulting from
1662+
bitcasting a trivial type to a non-trivial type. This value should never be
1663+
consumed.
1664+
1665+
We describe each of these semantics in more detail below.
1666+
1667+
Value Ownership Kind
1668+
~~~~~~~~~~~~~~~~~~~~
1669+
1670+
Owned
1671+
`````
1672+
1673+
Owned ownership models "move only" values. We require that each such value is
1674+
consumed exactly once along all program paths. The IR verifier will flag values
1675+
that are not consumed along a path as a leak and any double consumes as
1676+
use-after-frees. We model move operations via "forwarding uses" such as casts
1677+
and transforming terminators (e.x.: `switch_enum`_, `checked_cast_br`_) that
1678+
transform the input value, consuming it in the process, and producing a new
1679+
transformed owned value as a result.
1680+
1681+
Putting this all together, one can view each owned SIL value as being
1682+
effectively a "move only value" except when explicitly copied by a
1683+
copy_value. This of course implies that ARC operations can be assumed to only
1684+
semantically effect the specific value that they are applied to /and/ that each
1685+
ARC constraint is able to be verified independently for each owned SILValue
1686+
derived from the ARC object. As an example, consider the following Swift/SIL::
1687+
1688+
// testcase.swift.
1689+
func doSomething(x : Klass) -> OtherKlass? {
1690+
return x as? OtherKlass
1691+
}
1692+
1693+
// testcase.sil. A possible SILGen lowering
1694+
sil [ossa] @doSomething : $@convention(thin) (@guaranteed Klass) -> () {
1695+
bb0(%0 : @guaranteed Klass):
1696+
// Definition of '%1'
1697+
%1 = copy_value %0 : $Klass
1698+
1699+
// Consume '%1'. This means '%1' can no longer be used after this point. We
1700+
// rebind '%1' in the destination blocks (bbYes, bbNo).
1701+
checked_cast_br %1 : $Klass to $OtherKlass, bbYes, bbNo
1702+
1703+
bbYes(%2 : @owned $OtherKlass): // On success, the checked_cast_br forwards
1704+
// '%1' into '%2' after casting to OtherKlass.
1705+
1706+
// Forward '%2' into '%3'. '%2' can not be used past this point in the
1707+
// function.
1708+
%3 = enum $Optional<OtherKlass>, case #Optional.some!enumelt, %2 : $OtherKlass
1709+
1710+
// Forward '%3' into the branch. '%3' can not be used past this point.
1711+
br bbEpilog(%3 : $Optional<OtherKlass>)
1712+
1713+
bbNo(%3 : @owned $Klass): // On failure, since we consumed '%1' already, we
1714+
// return the original '%1' as a new value '%3'
1715+
// so we can use it below.
1716+
// Actually destroy the underlying copy (``%1``) created by the copy_value
1717+
// in bb0.
1718+
destroy_value %3 : $Klass
1719+
1720+
// We want to return nil here. So we create a new non-payloaded enum and
1721+
// pass it off to bbEpilog.
1722+
%4 = enum $Optional<OtherKlass>, case #Optional.none!enumelt
1723+
br bbEpilog(%4 : $Optional<OtherKlass>)
1724+
1725+
bbEpilog(%5 : @owned $Optional<OtherKlass>):
1726+
// Consumes '%5' to return to caller.
1727+
return %5 : $Optional<OtherKlass>
1728+
}
1729+
1730+
Notice how our individual copy (``%1``) threads its way through the IR using
1731+
forwarding of ``@owned`` ownership. These forwarding operations partition the
1732+
lifetime of the result of the copy_value into a set of disjoint individual owned
1733+
lifetimes (``%2``, ``%3``, ``%5``).
1734+
1735+
Guaranteed
1736+
``````````
1737+
1738+
Guaranteed ownership models values that have a scoped dependent lifetime on a
1739+
"base value" with owned or guaranteed ownership. Due to this lifetime
1740+
dependence, the base value is required to be statically live over the entire
1741+
scope where the guaranteed value is valid.
1742+
1743+
These explicit scopes are introduced into SIL by begin scope instructions (e.x.:
1744+
`begin_borrow`_, `load_borrow`_) that are paired with sets of jointly
1745+
post-dominating scope ending instructions (e.x.: `end_borrow`_)::
1746+
1747+
sil [ossa] @guaranteed_values : $@convention(thin) (@owned Klass) -> () {
1748+
bb0(%0 : @owned $Klass):
1749+
%1 = begin_borrow %0 : $Klass
1750+
cond_br ..., bb1, bb2
1751+
1752+
bb1:
1753+
...
1754+
end_borrow %1 : $Klass
1755+
destroy_value %0 : $Klass
1756+
br bb3
1757+
1758+
bb2:
1759+
...
1760+
end_borrow %1 : $Klass
1761+
destroy_value %0 : $Klass
1762+
br bb3
1763+
1764+
bb3:
1765+
...
1766+
}
1767+
1768+
Notice how the `end_borrow`_ allow for a SIL generator to communicate to
1769+
optimizations that they can never shrink the lifetime of ``%0`` by moving
1770+
`destroy_value`_ above ``%1``.
1771+
1772+
Values with guaranteed ownership follow a dataflow rule that states that
1773+
non-consuming "forwarding" uses of the guaranteed value are also guaranteed and
1774+
are recursively validated as being in the original values scope. This was a
1775+
choice we made to reduce idempotent scopes in the IR::
1776+
1777+
sil [ossa] @get_first_elt : $@convention(thin) (@guaranteed (String, String)) -> @owned String {
1778+
bb0(%0 : @guaranteed $(String, String)):
1779+
// %1 is validated as if it was apart of %0 and does not need its own begin_borrow/end_borrow.
1780+
%1 = tuple_extract %0 : $(String, String)
1781+
// So this copy_value is treated as a use of %0.
1782+
%2 = copy_value %1 : $String
1783+
return %2 : $String
1784+
}
1785+
1786+
None
1787+
````
1788+
1789+
Values with None ownership are inert values that exist outside of the guarantees
1790+
of Ownership SSA. Some examples of such values are:
1791+
1792+
* Trivially typed values such as: Int, Float, Double
1793+
* Non-payloaded non-trivial enums.
1794+
* Address types.
1795+
1796+
Since values with none ownership exist outside of ownership SSA, they can be
1797+
used like normal SSA without violating ownership SSA invariants. This does not
1798+
mean that code does not potentially violate other SIL rules (consider memory
1799+
lifetime invariants)::
1800+
1801+
sil @none_values : $@convention(thin) (Int, @in Klass) -> Int {
1802+
bb0(%0 : $Int, %1 : $*Klass):
1803+
1804+
// %0, %1 are normal SSA values that can be used anywhere in the function
1805+
// without breaking Ownership SSA invariants. It could violate other
1806+
// invariants if for instance, we load from %1 after we destroy the object
1807+
// there.
1808+
destroy_addr %1 : $*Klass
1809+
1810+
// If uncommented, this would violate memory lifetime invariants due to
1811+
// the ``destroy_addr %1`` above. But this would not violate the rules of
1812+
// Ownership SSA since addresses exist outside of the guarantees of
1813+
// Ownership SSA.
1814+
//
1815+
// %2 = load [take] %1 : $*Klass
1816+
1817+
// I can return this object without worrying about needing to copy since
1818+
// none objects can be arbitrarily returned.
1819+
return %0 : $Int
1820+
}
1821+
1822+
Unowned
1823+
```````
1824+
1825+
This is a form of ownership that is used to model two different use cases:
1826+
1827+
* Arguments of functions with ObjC convention. This convention requires the
1828+
callee to copy the value before using it (preferably before any other code
1829+
runs). We do not model this flow sensitive property in SIL today, but we do
1830+
not allow for unowned values to be passed as owned or guaranteed values
1831+
without copying it first.
1832+
1833+
* Values that are a conversion from a trivial value with None ownership to a
1834+
non-trivial value. As an example of this consider an unsafe bit cast of a
1835+
trivial pointer to a class. In that case, since we have no reason to assume
1836+
that the object will remain alive, we need to make a copy of the value.
1837+
15821838
Runtime Failure
15831839
---------------
15841840

0 commit comments

Comments
 (0)