This commit is doing a few things:
1. It is centralizing all decisions about whether an operand's owner instruction
or a value's parent instruction is forwarding in each SILInstruction
itself. This will prevent this information from getting out of sync.
2. This allowed me to hide the low level queries in OwnershipUtils.h that
determined if a SILNodeKind was "forwarding". I tried to minimize the amount of
churn in this PR and thus didn't remove the
is{Owned,Ownership,Guaranteed}Forwarding{Use,Value} checks. Instead I left them
alone but added in asserts to make sure that if the old impl ever returns true,
the neew impl does as well. In a subsequent commit, I am going to remove the old
impl in favor of isa queries.
3. I also in the process discovered that there were some instructions that were
being inconsistently marked as forwarding. All of the asserts in the PR caught
these and I fixed these inconsistencies.
Previously FieldIndexCacheBase only had a parent class of
SingleValueInstruction. I need to be able to in certain cases shim in a
SingleValueInstruction subclass as a parent class instead. In my case it is to
imbue ownership forwarding on StructExtractInst.
This commit itself doesn't make that change and instead just always templatizes
using SingleValueInstruction.
I think what was happening here was that we were using one of the superclass
classofs and were getting lucky since in the place I was using this I was
guaranteed to have single value instructions and that is what I wrote as my
first case X ).
I also added more robust checks tieing the older isGuaranteed...* APIs to the
ForwardingOperand API. I also eliminated the notion of Branch being an owned
forwarding instruction. We only used this in one place in the compiler (when
finding owned value introducers), yet we treat a phi as an introducer, so we
would never hit a branch in our search since we would stop at the phi argument.
The bigger picture here is that this means that all "forwarding instructions"
either forward ownership for everything or for everything but owned/unowned.
And for those listening in, I did find one instruction that was from an
ownership forwarding subclass but was not marked as forwarding:
DifferentiableFunctionInst. With this change, we can no longer by mistake have
such errors enter the code base.
Interestingly this problem can only occur if one invokes
MarkUninitializedInst::getKind() directly. Once our instruction is just a
SILInstruction, we call the appropriate method so we didn't notice it.
I used Xcode's refactoring functionality to find all of the invocation
locations.
This makes it easier to understand conceptually why a ValueOwnershipKind with
Any ownership is invalid and also allowed me to explicitly document the lattice
that relates ownership constraints/value ownership kinds.
This allows us to hoist the error case of having a function signature with
conflicting ownership requirements into the creation of the return inst instead
of at the time of computing Operand Constraints.
This is the last part of the Operand Constraint computation that can fail that
once removed will let me use fail to mean any constriant is allowed.
Previously, we always inferred the ownership of the switch_enum from its phi
operands. This forced us to need to model a failure to find a good
OperandOwnershipKindMap in OperandOwnership.cpp. We want to eliminate such
conditions so that we can use failing to find a constraint to mean that a value
can accept any value rather than showing a failure.
This instructions ensures that all instructions, which need to run on the specified executor actually run on that executor.
For details see the description in SIL.rst.
It can already only accept values with none ownership and the merging of
ownership around ownership phis ensure that if we phi this with a partial_apply
or the like, we get the appropriate ownership on any such ownership phi values.
We are now out of SILGen emitting fewer destroy_value unnecessarily on
thin_to_thick functions. This changed some codegen and also forced me to update
some tests/fix AutoDiff.
I also deleted the DebugInfo test mandatoryinlining-wrongdebugscope.swift since:
1. It was depending on these destroys being there.
2. Given the need to improve the test @aprantl suggested I just eliminate it
solving the test failure for me.
Compute 'isLet' from the VarDecl that is available when constructing
AccessedStorage so we don't need to recover the VarDecl for the base
later.
This generally makes more sense and is more efficient, but it will be
necessary when we look past class casts when finding the reference root.
`get_async_continuation[_addr]` begins a suspend operation by accessing the continuation value that can resume
the task, which can then be used in a callback or event handler before executing `await_async_continuation` to
suspend the task.
I don't have a test case for this bug based on the current code. But
the fix is clearly needed to have a unique AccessStorage object for
each property. The AccessPath commits will contain test cases for this
functionality.
Today unchecked_bitwise_cast returns a value with ObjCUnowned ownership. This is
important to do since the instruction can truncate memory meaning we want to
treat it as a new object that must be copied before use.
This means that in OSSA we do not have a purely ossa forwarding unchecked
layout-compatible assuming cast. This role is filled by unchecked_value_cast.
The ``base_addr_for_offset`` instruction creates a base address for offset calculations.
The result can be used by address projections, like ``struct_element_addr``, which themselves return the offset of the projected fields.
IR generation simply creates a null pointer for ``base_addr_for_offset``.
Use TangentStoredPropertyRequest in differentiation transform.
Improve non-differentiability diagnostics regarding invalid stored
property projection instructions:
`struct_extract`, `struct_element_addr`, `ref_element_addr`.
Diagnose the following cases:
- Original property's type does not conform to `Differentiable`.
- Base type's `TangentVector` is not a struct.
- Tangent property not found: base type's `TangentVector` does not have a
stored property with the same name as the original property.
- Tangent property's type is not equal to the original property's
`TangentVector` type.
- Tangent property is not a stored property.
Resolves TF-969 and TF-970.
Currently we only have load [take] in OSSA which needed to be changed.
(copy_addr is not handled in MemBehavior at all, yet)
Even if the memory is physically not modified, conceptually it's "destroyed" when the value is taken.
Optimizations, like TempRValueOpt rely on this behavior when the check for may-writes.
This fixes a MemoryLifetime failure in TempRValueOpt.
`DifferentiableFunctionInst` now stores result indices.
`SILAutoDiffIndices` now stores result indices instead of a source index.
`@differentiable` SIL function types may now have multiple differentiability
result indices and `@noDerivative` resutls.
`@differentiable` AST function types do not have `@noDerivative` results (yet),
so this functionality is not exposed to users.
Resolves TF-689 and TF-1256.
Infrastructural support for TF-983: supporting differentiation of `apply`
instructions with multiple active semantic results.
* a new [immutable] attribute on ref_element_addr and ref_tail_addr
* new instructions: begin_cow_mutation and end_cow_mutation
These new instructions are intended to be used for the stdlib's COW containers, e.g. Array.
They allow more aggressive optimizations, especially for Array.
This became necessary after recent function type changes that keep
substituted generic function types abstract even after substitution to
correctly handle automatic opaque result type substitution.
Instead of performing the opaque result type substitution as part of
substituting the generic args the underlying type will now be reified as
part of looking at the parameter/return types which happens as part of
the function convention apis.
rdar://62560867
MSVC does not realize that the switch is exhaustive and requires that
the path is explicitly marked as unreachable. This silences the C4715
warning ("not all control paths return a value").
We had this for some cast instructions, but not for cast instructions with address-types.
Type dependent operands - like for dynamic self - are important for establishing a def-use relationship between the instruction/argument which defines the type and the instruction which uses the type.
Missing those dependencies can cause instructions or the dynamic-self argument to be removed while the type is still used in a cast instruction.
This change involved some class hierarchy gymnastics in SILInstruction.h.
Fixes a compiler crash.
rdar://problem/61816506
Canonicalizes `differentiable_function` instructions by filling in missing
derivative function operands.
Derivative function emission rules, based on the original function value:
- `function_ref`: look up differentiability witness with the exact or a minimal
superset derivative configuration. Emit a `differentiability_witness_function`
for the derivative function.
- `witness_method`: emit a `witness_method` with the minimal superset derivative
configuration for the derivative function.
- `class_method`: emit a `class_method` with the minimal superset derivative
configuration for the derivative function.
If an *actual* emitted derivative function has a superset derivative
configuration versus the *desired* derivative configuration, create a "subset
parameters thunk" to thunk the actual derivative to the desired type.
For `differentiable_function` instructions formed from curry thunk applications:
clone the curry thunk (with type `(Self) -> (T, ...) -> U`) and create a new
version with type `(Self) -> @differentiable (T, ...) -> U`.
Progress towards TF-1211.
Add `linear_function` and `linear_function_extract` instructions.
`linear_function` creates a `@differentiable(linear)` function-typed value from
an original function operand and a transpose function operand (optional).
`linear_function_extract` extracts either the original or transpose function
value from a `@differentiable(linear)` function.
Resolves TF-1142 and TF-1143.
Add `differentiable_function` and `differentiable_function_extract`
instructions.
`differentiable_function` creates a `@differentiable` function-typed
value from an original function operand and derivative function operands
(optional).
`differentiable_function_extract` extracts either the original or
derivative function value from a `@differentiable` function.
The differentiation transform canonicalizes `differentiable_function`
instructions, filling in derivative function operands if missing.
Resolves TF-1139 and TF-1140.
Otherwise in call frames like the one in the test in this commit get unneeded
ARC traffic. We should never pessimize read only code that doesnt need
side-effects with side-effects if we can avoid it.
I am seeing this a bunch when I look at SIL from projects that use a lot of
protocols. Specifically, one has a sort of trampoline code that wraps a ref
counted object in an existential ref container (which from an ARC perspective
doesn't imply ownership) and then calls a method on it or passes it off to some
other code.
Because of this requirement, there is a copy/destroy that can not be eliminated
unless we can devirt/inline/eliminate the init_existential_ref box, inline
enough that the low level ARC optimizer can hit it. We shouldn't rely on such
properties if we do not need to.
Operands are generally better to return than values since the operand also
enables you to get to the terminator instruction as well. Since so much code in
the compiler already uses the getIncomingPhiValue methods, I reimplemented them
on top of the operand methods.
Found the meaning by looking at when Definite Initialization marks alloc_stack
with that marker.
For those who are unware like me, it means the liveness of the value in the
alloc_stack is conditional in some way (i.e. conditional init, destroy, etc).
The only reason why BranchPropagatedUser existed was because early on in SIL, we
weren't sure if cond_br should be able to handle non-trivial values in
ossa. Now, we have reached the point where we have enough experience to make the
judgement that it is not worth having in the representation due to it not
holding its weight.
Now that in ToT we have banned cond_br from having non-trivial operands in ossa,
I can just eliminate BranchPropagatedUser and replace it with the operands that
we used to construct them!
A few notes:
1. Part of my motiviation in doing this is that I want to change LiveRange to
store operands instead of instructions. This is because we are interested in
being able to understand the LiveRange at a use granularity in cases where we
have multiple operands. While doing this, I discovered that I needed
SILInstructions to use the Linear Lifetime Checker. Then I realized that now was
the time to just unwind BranchPropagatedUser.
2. In certain places in SemanticARCOpts, I had to do add some extra copies to
transform arrays of instructions from LiveRange into their operand form. I am
going to remove them in a subsequent commit when I change LiveRange to work on
operands. I am doing this split to be incremental.
3. I changed isSingleInitAllocStack to have an out array of Operand *. The only
user of this code is today in SemanticARCOpts and this information is fed to the
Linear Lifetime Checker, so I needed to do it.
We can eliminate `convert_function`s that are immediately used as the callee of
an `apply` or `partial_apply`, as well as stacked `convert_function`s that may
arise from this transformation.
The `differentiability_witness_function` instruction looks up a
differentiability witness function (JVP, VJP, or transpose) for a referenced
function via SIL differentiability witnesses.
Add round-trip parsing/serialization and IRGen tests.
Notes:
- Differentiability witnesses for linear functions require more support.
`differentiability_witness_function [transpose]` instructions do not yet
have IRGen.
- Nothing currently generates `differentiability_witness_function` instructions.
The differentiation transform does, but it hasn't been upstreamed yet.
Resolves TF-1141.
For those who are unaware, a transformation terminator is a terminator like
switch_enum/checked_cast_br that always dominate their successor blocks. Since
they dominate their successor blocks by design and transform their input into
the args form, we can validate that they obey guaranteed ownership semantics
just like a forwarding instruction.
Beyond removing unnecessary code bloat, this also makes it significantly more
easier to optimize/work with transformation terminators when converting @owned
-> @guaranteed since we do not need to find end_borrow points when the owned
value is consumed.
<rdar://problem/59097063>