Specifically, we are putting dealloc_stack, destroy_box into the Releases array
in PMOMemoryUseCollector only to ignore them in the only place that we use the
Releases array in PredictableMemOpts.
Just a part of a series of small cleanups I found over the break in PMO that I
am landing in preparation for landing patches that fix PMO for ownership.
This was done early on during the split of predictable mem opts from DI. This
has been done for a long time, so eliminate the "Ownership" basename suffix.
When building on Windows, the std::string being passed will on the
stack, where the destructor will be invoked before the return, nil'ing
out reference. This causes incorrect behaviour when building the
diagnostic or FIXITs. Explicitly create the StringRef to prevent the
std::string from being invalidated.
These are vestigal remnants of the code when it needed to support DI and
PredMemOpts. Since both of the passes have been split, these are now dead in
PMO. So eliminate them.
This is the first in a sequence of patches that implement various optimizations
to transform load [copy] into load_borrow.
The optimization works by looking for a load [copy] that:
1. Only has destroy_value as consuming users. This implies that we do not need
to pass off the in memory value at +1 and that we can use a +0 value.
2. Is loading from a memory location that is never written to or only written to
after all uses of the load [copy].
and then RAUW the load [copy] with a load_borrow and convertes the destroy_value
to end_borrow.
NOTE: I also a .def file for AccessedStorage so we can do visitors over the
kinds. The reason I want to do this is to ensure that people update these
optimizations if we add new storage kinds.
I am doing this for two reasons:
1. I want to use this in a different optimization where we optimize load [copy]
=> load_borrow.
2. This will ensure that if/when the ownership APIs change to use isConsume/etc
instead of the current operand ownership map, the optimization will be easy to
update.
Compiler passes that intermingle analysis with mutation of the CFG
are fraught with danger. The bug here was that a single AssignInst
could appear twice in DI's Uses list, once as a store use and once
as a load use.
When processing Uses, we would lower AssignInsts on the fly. We would
take care to erase the instruction pointer from the current Use, but
if a subsequent Use *also* referenced the now-deleted AssignInst, we
would crash.
Handle this in the standard way: instead of lowering assignments
right away, just build a list of assignments that we're planning on
lowering and process them all at the very end.
This has the added benefit of simplifying the code, because we no
longer have to work as hard to keep the state of the Uses list
consistent while lowering AssignInsts. The rest of DI should not
care that the lowering got postponed either, since it was already
expected to handle any ordering of elements in the Uses list, so
it could not assume that any particular AssignInst has been lowered.
Fixes <https://bugs.swift.org/browse/SR-9451>.
In a previous commit, I banned in the verifier any SILValue from producing
ValueOwnershipKind::Any in preparation for this.
This change arises out of discussions in between John, Andy, and I around
ValueOwnershipKind::Trivial. The specific realization was that this ownership
kind was an unnecessary conflation of the a type system idea (triviality) with
an ownership idea (@any, an ownership kind that is compatible with any other
ownership kind at value merge points and can only create). This caused the
ownership model to have to contort to handle the non-payloaded or trivial cases
of non-trivial enums. This is unnecessary if we just eliminate the any case and
in the verifier separately verify that trivial => @any (notice that we do not
verify that @any => trivial).
NOTE: This is technically an NFC intended change since I am just replacing
Trivial with Any. That is why if you look at the tests you will see that I
actually did not need to update anything except removing some @trivial ownership
since @any ownership is represented without writing @any in the parsed sil.
rdar://46294760
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
This is in preparation for verifying that when ownership verification is enabled
that only enums and trivial values can have any ownership. I am doing this in
preparation for eliminating ValueOwnershipKind::Trivial.
rdar://46294760
Implements a constant interpreter that can deal with basic integer operations.
Summary of the features that it includes:
* builtin integer values, and builtin integer insts
* struct and tuple values, and insts that construct and extract them (necessary to use stdlib integers)
* function referencing and application (necessary to call stdlib integer functions)
* error handling data structures and logic, for telling you why your value is not evaluatable
* metatype values (not necessary for integers, but it's only a few extra lines, so I thought it would be more trouble than it's worth to put them in a separate PR)
* conditional branches (ditto)
On Windows at least, the std::string associated with the name of the
property would be copy constructed before being passed to the diagnostic
engine. The resultant DiagnosticArgument in the InFlightDiagnostic
would hold a StringRef to the copy-constructed std::string. However,
because the arguments are inalloca'ed on Windows, the copy constructed
string would be destructed before the return of the argument.
Fortunately, this would result in the standard library overwriting the
string and the use-after-free would fail to print the argument.
Explicitly construct the StringRef before passing the name to the
diagnostic to avoid the use-after-free.
Inlining has always been quadratic for no good reason. There was a
special hack for single-block callees that allowed linear inlining.
Instead, the now iterates over blocks and instructions in reverse,
splitting blocks as it inlines. There no longer needs to be special
case for single block callees, and the inliner is linear for all kinds
of callees.
This further simplifies and cleans up the code. There are just a few
basic invariants that the common inliner needs to provide about how
blocks are split and laid out. We can do this if we don't add hacks
for special cases within the inliner. Those invariants allow the
inliner clients to be much simpler and more efficient.
PerformanceInliner still needs to be fixed.
Fixes SR-9223: Inliner exhibits slow compilation time with a large
static array.
A recent SILCloner rewrite removed a special case hack for single
basic block callee functions:
commit c6865c0dff
Merge: 76e6c4157e9e440d13a6
Author: Andrew Trick <atrick@apple.com>
Date: Thu Oct 11 14:23:32 2018
Merge pull request #19786 from atrick/silcloner-cleanup
SILCloner and SILInliner rewrite.
Instead, the new inliner simply merges trivial unconditional branches
after inlining the return block. This way, the CFG is always in
canonical state after inlining. This is more robust, and avoids
interfering with subsequent SIL passes when non-single-block callees
are inlined.
The problem is that inlining a series of calls within a large block
could result in interleaved block splitting and merging operations,
which is quadratic in the block size. This showed up when inlining the
tens of thousands of array subscript calls emitted for a large array
initialization.
The first half of the fix is to simply defer block merging until all
calls are inlined. We can't expect SimplifyCFG to run immediately
after inlining, nor would we want to do that, *especially* for
mandatory inlining. This fix instead exposes block merging as a
trivial utility.
Note: by eliminating some unconditional branches, this change could
reduce the number of debug locations emitted. This does not
fundamentally change any debug information guarantee, and I was unable
to observe any behavior difference in the debugger.
This takes advantage of my restricting Semantic ARC Opts to run only on the
stdlib since we know it passes the ownership verifier. Using that I
reimplemented this optimization in a more robust, elegant, general
way. Specifically, we now will eliminate any SILGen copy_value on a guaranteed
argument all of whose uses are either destroy_values or instructions that can
accept guaranteed parameters. To be clear: This means that the value must be
consumed in the same function only be destroy_value.
Since we know that the lifetime of the guaranteed parameter will be larger than
any owned value created/destroyed in the body, we do not need to check that the
copy_value's destroy_value set is joint post-dominated by the set of end_borrows.
That will have to be added to turn this into a general optimization.
`#assert` is a new static assertion statement that will let us write
tests for the new constant evaluation infrastructure that we are working
on. `#assert` works by lowering to a `Builtin.poundAssert` SIL
instruction. The constant evaluation infrastructure will look for these
SIL instructions, const-evaluate their conditions, and emit errors if
the conditions are non-constant or false.
This commit implements parsing, typechecking and SILGen for `#assert`.
In this commit I added a more convenient API for doing this sort of operation.
Specifically: SILBuilder::emitScopedBorrowOperation. This performs either a
load_borrow or begin_borrow, then calls a user provided closure, and finally
inserts the end_borrow after the scope has closed.
rdar://43398898
Remove the compiler support for exclusivity warnings.
Leave runtime support for exclusivity warnings in non-release builds
only for unit testing convenience.
Remove a test case that checked the warning log output.
Modify test cases that relied on successful compilation in the
presence of exclusivity violations.
Fixes: <rdar://problem/45146046> Remaining -swift-version 3 tests for exclusivity
* [SILOptimizer] Don't diagnose infinite recursion if a branch terminates the program
This patch augments the infinite recursion checker to not warn if a
branch terminates, but still warns if a branch calls into something with
@_semantics("programtermination_point"). This way, calling fatalError
doesn't disqualify you for the diagnostic, but calling exit does.
This also removes the warning workaround in the standard library, and
annotates the internal _assertionFailure functions as
programtermination_points, so they get this treatment too.
* Fix formatting in SILInstructions.cpp
* Re-add missing test
Mostly functionally neutral:
- may fix latent bugs.
- may reduce useless basic blocks after inlining.
This rewrite encapsulates the cloner's internal state, providing a
clean API for the CRTP subclasses. The subclasses are rewritten to use
the exposed API and extension points. This makes it much easier to
understand, work with, and extend SIL cloners, which are central to
many optimization passes. Basic SIL invariants are now clearly
expressed and enforced. There is no longer a intricate dance between
multiple levels of subclasses operating on underlying low-level data
structures. All of the logic needed to keep the original SIL in a
consistent state is contained within the SILCloner itself. Subclasses
only need to be responsible for their own modifications.
The immediate motiviation is to make CFG updates self-contained so
that SIL remains in a valid state. This will allow the removal of
critical edge splitting hacks and will allow general SIL utilities to
take advantage of the fact that we don't allow critical edges.
This rewrite establishes a simple principal that should be followed
everywhere: aside from the primitive mutation APIs on SIL data types,
each SIL utility is responsibile for leaving SIL in a valid state and
the logic for doing so should exist in one central location.
This includes, for example:
- Generating a valid CFG, splitting edges if needed.
- Returning a valid instruction iterator if any instructions are removed.
- Updating dominance.
- Updating SSA (block arguments).
(Dominance info and SSA properties are fundamental to SIL verification).
LoopInfo is also somewhat fundamental to SIL, and should generally be
updated, but it isn't required.
This also fixes some latent bugs related to iterator invalidation in
recursivelyDeleteTriviallyDeadInstructions and SILInliner. Note that
the SILModule deletion callback should be avoided. It can be useful as
a simple cache invalidation mechanism, but it is otherwise bug prone,
too limited to be very useful, and basically bad design. Utilities
that mutate should return a valid instruction iterator and provide
their own deletion callbacks.
This patch augments the infinite recursion checker to not warn if a
branch terminates, but still warns if a branch calls into something with
`@_semantics("arc.programtermination_point")`. This way, calling `fatalError`
doesn't disqualify you for the diagnostic, but calling `exit` does.
This also removes the warning workaround in the standard library, and
annotates the internal _assertionFailure functions as
`programtermination_point`s, so they get this treatment too.
* [SILOptimizer] Clean up infinite recursion diagnostic pass
NFC. This cleans up the pass to avoid the extra lambda and to clear up
the ordering of what check is supposed to come before what.
* Address review comments
NOTE: This is not the final form of how operand ownership restraints will be
represented. This patch is instead an incremental change that extracts out this
functionality from the ownership verifier as a pure refactor.
rdar://44667493
The reason why I am doing this is now that once we have the
OperandOwnershipKindMap I can write this optimization in a more robust,
aggressive manner. My hope is that I can eliminate all copy_value of guaranteed
parameters all of whose uses could accept a guaranteed parameter. This is given
to me by the OperandOwnershipKindMap.
Additionally, I found that the way the analysis was using the OwnershipVerifier
was not sound on non-ownership verified SIL. Rather than fix it, I just turned
it off for that case.
rdar://44667493
Previously, the `__consuming` decl modifier failed to get propagated to the value ownership of the
method's `self` parameter, causing it to effectively be a no-op. Fix this, and address some of the
downstream issues this exposes:
- `coerceCallArguments` in the type checker failing to handle the single `__owned` parameter case
- Various places in SILGen and optimizer passes that made inappropriate assertions that `self`
was always passed guaranteed