DCE may enqueue a value for lifetime completion and later on erase the
instruction that defines that value. When erasing an instruction, erase
each of its results from the collection of values to complete.
rdar://141560546
DCE deletes ownership forwarding instructions when it doesn’t have useful users.
It inserts destroy_value/end_borrow for its operands to compensate their lifetimes.
DCE also deletes branches when its successor blocks does not have useful instructions.
It deletes blocks and creates a jump to the nearest post dominating block.
When DCE needs to delete a forwarding instruction in a dead block, it cannot just create
lifetime ends of its operands at its position. Use LifetimeCompletion utility in such cases.
rdar://140428721
DCE inserts end_borrow at phi operands when a guaranteed phi becomes dead.
This should be done for reborrows which end the lifetime of the incoming value.
The existing check was not accurate and ended up inserting end_borrow for forwarded values as well.
Fixes rdar://139283745
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
Compute, update and handle borrowed-from instruction in various utilities and passes.
Also, used borrowed-from to simplify `gatherBorrowIntroducers` and `gatherEnclosingValues`.
Replace those utilities by `Value.getBorrowIntroducers` and `Value.getEnclosingValues`, which return a lazily computed Sequence of borrowed/enclosing values.
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.
rdar://123484595
In cea0f00598, `InstructionDeleter` began
deleting `load [take]` instructions. Analogous to how it creates a
`destroy_value` when deleting an instruction which consumes a value, in
the case of deleting a `load [take]` the `InstructionDeleter` inserts a
compensating `destroy_addr`.
Previously, `DeadCodeElimination` did not observe the creation of any
instructions created by the `InstructionDeleter`. In the case of the
newly created `destroy_addr`, DCE didn't mark that the `destroy_addr`
was live and so deleted it. The result was a leak.
Here, this is fixed by passing an `InstModCallbacks`--with an
`onCreateNewInst` implementation--down into `erasePhiArgument` that
eventually invokes the `InstructionDeleter`. When the
`InstructionDeleter` creates a new instruction, DCE marks it live.
For very large control flow graphs the markControllingTerminatorsLive can stack overflow.
Fix this by doing the work iteratively instead of recursively.
rdar://106198943
Previously, findGuaranteedReferenceRoots always stopped searching when
finding a begin_borrow, because it's not an ownership-forwarding
instruction. Here, it is conditionally allowed to keep search through
the borrowee of that begin_borrow if it itself is guaranteed.
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`
The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.
rdar://102362022
Andy some time ago already created the new API but didn't go through and update
the old occurences. I did that in this PR and then deprecated the old API. The
tree is clean, so I could just remove it, but I decided to be nicer to
downstream people by deprecating it first.
This subclass of SILArgument should be eliminated--it's not always a
phi, and whether it is a "phi argument" has nothing whatsoever to do
with the opcode. That is a property of a value's uses, not a property of the
value.
Until then, provide a logical and useful API within the type. This
often avoids the need to explicitly cast to a SILPhiArgument type and
avoids a lot of boilerplate in code that deals with phis.
Note: PhiOperand and PhiValue are improved abstractions on top of this
API. But the SILArgument-level API is still an important bridge
between SILArgument and other phi abstractions.
Previously, visitTransitiveEndBorrows took BorrowedValues. However,
there is at least one kind of borrow--namely,
unchecked_ownership_conversion insts--that is not currently permitted by
the BorrowedValue API. The long term fix is to make BorrowedValue
handle such instructions. For now, change visitTransitiveEndBorrows to
take SILValues so that unchecked_ownership_conversion can be passed to
the API.
rdar://87985420
Fixes SR-15300: Compiler crash when using Builtin.unreachable in
initializers
Otherwise, this triggers an debug info verification assert that
invalid locations must only be on unreachable instructions.
This is why generating lifetime cleanup code should never inherit its
location from its insertion point.
Previously, when encountering a borrow of a guaranteed value, the
end_borrows of that reborrow were marked alive. Only doing that enables
end_borrows of the outer borrow scope can be marked as dead. The result
is that uses of the reborrowed value (including its end_borrow) can
outstrip the outer borrow scope, which is illegal.
Here, the outer borrow scope's end_borrows are marked alive. To do
that, the originally borrowed values have to be identified via
findGuaranteedReferenceRoots.
If a phi argument is dead and it reborrowing it was dependent on some
other value, that other value on which it was dependent may have already
itself been deleted. In that case, the destroy_value would have been
added just before the terminator of the predecessors of the block which
contained the dead phi. So, when deciding where to insert the
end_borrow, iterate backwards from the end of the block, skipping the
terminator updating the insertion point every time a destroy_value
instruction is encountered until we hit an instruction with a different
opcode. This ensures that no matter how many destroy_values may have
been added just before the terminator, the end_borrow will preceed them.
This commit just tweaks the preexisting logic that checked for this
condition. Specifically, the previous code didn't handle the case where
the block contains only a terminator and a destroy_value.