This is necessary to fix a recent OSSA bug that breaks common occurrences on
mark_dependence [nonescaping]. Rather than reverting that change above, we make
forward progress toward implicit borrows scopes, as was the original intention.
In the near future, all InteriorPointer instructions will create an implicit
borrow scope. This means we have the option of not emitting extraneous
begin/end_borrow instructions around intructions like ref_element_addr,
open_existential, and project_box. After that, we can also migrate
GuaranteedForwarding instructions like tuple_extract and struct_extract.
We use the formal source type do decide whether a checked_cast_br is
known to succeed/fail. If we don't update it we loose that optimization
That is:
```
checked_cast_br AnyObject in %2 : X to X, bb1, bb2
```
Will not be simplified even though the operand and the destintation type
matches.
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand
This is used for synthetic uses like _ = x that do not act as a true use but
instead only suppress unused variable warnings. This patch just adds the
instruction.
Eventually, we can use it to move the unused variable warning from Sema to SIL
slimmming the type checker down a little bit... but for now I am using it so
that other diagnostic passes can have a SIL instruction (with SIL location) so
that we can emit diagnostics on code like _ = x. Today we just do not emit
anything at all for that case so a diagnostic SIL pass would not see any
instruction that it could emit a diagnostic upon. In the next patch of this
series, I am going to add SILGen support to do that.
This encourages AccessPathWalker clients to handle enclosing mark_deps. In
some cases, it is necessary. The accessBaseWithScopes API now provides both
nested begin_access and mark_dependence.
It defines (and implements) the `base` and `index` properties, which are used in the conforming classes `IndexRawPointerInst`, `IndexAddrInst` and `TailAddrInst`
And move the implementation of `SIL.Type.canBeClass` to the AST Type. The SIL Type just calls the AST Type implementation.
Also rename `SIL.Type.canonicalASTType` -> `SIL.Type.astType`.
* `users`: maps from a sequence of operands to a sequence of instructions
* `users(ofType:)` : as `users`, but filters users of a certain instruction type
* `Value.users`: = `Value.uses.users`
`String(describing:)` does a bunch of dynamic casts
that can be pretty slow. Use interpolation instead,
which bypasses them.
For `swift-frontend`, this brings the time taken
for type-checking an empty file down from ~100ms
to ~70ms.
For `swift build`, this brings the time taken for
a null build down from ~600ms to ~450ms (the
larger delta is presumably due to the fact that
there's much more Swift code in `swift-package`).
Some utilities, like Builder.insert(after:) pass a Builder object that
represents an insertion point. That insertion point is sometimes needed to
determine which instructions to create (endApply vs. abortApply). But there is
no way to recover the insertion point. We don't want to simply return an
instruction, because that could be interpreted in different ways. Instead we
provide insertion block, but only in those situations where it makes sense and can't
be used incorrectly.
And simplify enclosingAccessScope.
These two APIs now directly compute what is being asked for. Previously, each
invocation of enclosingAccessScope would recompute the base and all nested
scopes, but throw away that information. Sometimes we do not want to compute
that information, and other times we need all of it. Instead, provide separate
APIs that do exactly what is needed.
These are common APIs used by other utilities. This avoids quadratic traversals in those
cases. It is also easier to understand and debug.
These utilities will be used in LifetimeDependenceScopeFixup.
LifetimeDependence uses the address of the AccessBase to compute liveness. It is
more convenient to switch over all AccessBase kinds here rather than force all
clients to do it.
AccessBase already identifies a base address as either a .global (addressor) or
a .pointer. When initializing an AccessBase from a pointer_to_address, precisely
identify one of these kinds of accesses, rather than simply marking it
.unidentified.
This used to be a special case in the AccessPathWalker. But that's not the right
place to handle it.
Add `Value.constantAccessPath`. It is like `accessPath`, but ensures that the projectionPath only contains "constant" elements.
This means: if the access contains an `index_addr` projection with a non-constant index, the `projectionPath` does _not_ contain the `index_addr`.
Instead, the `base` is an `AccessBase.index` which refers to the `index_addr`.
I am adding this instruction to express artificially that two non-Sendable
values should be part of the same region. It is meant to be used in cases where
due to unsafe code using Sendable, we stop propagating a non-Sendable dependency
that needs to be made in the same region of a use of said Sendable value. I
included an example in ./docs/SIL.rst of where this comes up with @out results
of continuations.