This assertion was triggering when deleting scope-ending operations whose
operand had been replaced with an undef:
end_borrow undef
Related to rdar://156431548
This was triggered during simplify-cfg by after adding blocks to the worklist,
then later cleaning up dead instructions in the worklist blocks. I'm unable to
create a test case based on simplify-cfg because the assertion is completely
unrelated to the optimization that adds blocks to the worklist.
Currently we delete dead drop_deinit instructions in InstructionDeleter.
For address results, we may end up with ownership errors after being promoted to value forms.
For value results, fixLifetimes mode of InstructionDeleter will insert an illegal destroy_value
rdar://151104993
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)
A destroy_value of Optional.none can be deleted.
A move-only struct with deinit has a non trivial SILType but OwnershipKind::None,
such values cannot be deleted.
It's better to ask SILType if it is MoveOnly than go to the AST type and
ask if it is noncopyable, because some types in SIL do not have a
well-defined notion of conformance in the AST.
These calls were being made on types either with a type parameter, or a
SIL-only type that doesn't actually have conformances.
In such cases, it's better to use SILType's move-only query methods.
Previously, `isScopeAffectingInstructionDead` determined that
an otherwise satisfactory `load` was not dead if it was a `load [take]`.
The immediate effect was that dead `load [take]`s were not deleted. The
downstream effect was that otherwise dead graphs of instructions would
not be deleted. This was especially a problem for OSLogOptimization
which deletes a great deal of code.
Here, the InstructionDeleter is taught to compensate for the deletion of
such `load [take]` by inserting `destroy_addr`s in their stead.
rdar://117011668
In the C++ sources it is slightly more convenient to dump to stderr than
to print to stdout, but it is rather more unsightly to print to stderr
from the Swift sources. Switch to stdout. Also allows the dump
functions to be marked debug only.
I think from SIL's perspective, it should only worry about whether the
type is move-only. That includes MoveOnlyWrapped SILTypes and regular
types that cannot be copied.
Most of the code querying `SILType::isPureMoveOnly` is in SILGen, where
it's very likely that the original AST type is sitting around already.
In such cases, I think it's fine to ask the AST type if it is
noncopyable. The clarity of only asking the ASTType if it's noncopyable
is beneficial, I think.
Deleting instructions which produce such values could result in
shortening the lifetime of a move-only value. This is illegal because
according to language rules, the lifetime of move-only values is fixed.
rdar://114351349
Fix isScopeAffectingInstructionDead to use this new API. A stdlib
assert, which has "program_termination" semantics, should not be
considered read-only.
isReadOnlyConstantEvaluableCall API:
/// Return true iff the \p applySite is constant-evaluable and read-only.
///
/// Functions annotated as "constant_evaluable" are assumed to be "side-effect
/// free", unless their signature and substitution map indicates otherwise. A
/// constant_evaluable function call is read only unless it:
/// (1) has generic parameters
/// (2) has inout parameters
/// (3) has indirect results
///
/// Read-only constant evaluable functions can do only the following and
/// nothing else:
/// (1) The call may read any memory location.
/// (2) The call may destroy owned parameters i.e., consume them.
/// (3) The call may write into memory locations newly created by the call.
/// (4) The call may use assertions, which traps at runtime on failure.
/// (5) The call may return a non-generic value.
///
/// Essentially, these are calls whose "effect" is visible only in their return
/// value or through the parameters that are destroyed. The return value
/// is also guaranteed to have value semantics as it is non-generic and
/// reference semantics is not constant evaluable.