Commit Graph

126 Commits

Author SHA1 Message Date
Andrew Trick
0325e296fe Add an isDeinitBarrier() utility.
Needs to be common across ShrinkBorrowScopes and SSADestroyHoisting.
2021-12-22 01:54:05 -08:00
Nate Chandler
5d85ad393c [SILOpt] Add utility to find guaranteed roots.
The new utility looks through ownership forwarding instructions to find
the original values with guaranteed ownership.
2021-10-27 10:44:18 -07:00
Andrew Trick
e9e3ce7ea5 Add findOwnershipReferenceAggregate().
Simple convenience on top of findOwnershipReferenceRoot to handle
guaranteed values forwarded through struct/tuple extract.

Note: eventually this should be handled by a ReferenceRoot abstraction
that stores the component path.
2021-10-06 09:18:14 -07:00
Andrew Trick
20ee76e07a Add AccessBase::hasLocalOwnershipLifetime()
Replaces AccessStorage::isGuaranteedForFunction().

OSSA utilities need to determine whether two addresses with the same
AccessStorage are directly substitutable without "fixing-up" the OSSA
lifetime. Checking whether the access base is within a local borrow
scope is the first step.
2021-10-06 09:18:14 -07:00
Andrew Trick
150208395e Implement AccessBase::compute(SILValue sourceAddress)
Missing implementation from the previous commit that introduced
AccessBase. Now we can directly ask for an AccessBase value.
2021-10-06 09:18:14 -07:00
Andrew Trick
5f116293e8 Add AccessBase::getOwnershipReferenceRoot.
Trivial convenience helper for OSSA utilities, where it's very common
to need the reference whose ownership lifetime or scope covers the
current access.
2021-10-06 09:18:14 -07:00
Ikko Ashimine
1c0079dd33 SIL: Fix typo in MemAccessUtils.h
begining -> beginning
2021-10-04 21:15:27 +09:00
Andrew Trick
d9619af83f Fix a comment typo in MemAccessUtils.h 2021-10-03 19:25:30 -07:00
Andrew Trick
e85228491d Rename AccessedStorage to AccessStorage
to be consistent with AccessPath and AccessBase.

Otherwise, the arbitrary name difference adds constant friction.
2021-09-21 23:18:24 -07:00
Andrew Trick
354b5c4e17 Add AccessBase abstraction as OSSA helper
Split AccessedStorage functionality in two pieces. This doesn't add
any new logic, it just allows utilities to make queries on the access
base. This is important for OSSA where we often need to find the
borrow scope or ownership root that contains an access.
2021-09-21 19:54:24 -07:00
Andrew Trick
19cff2e6eb Add AccessedStorage::isGuaranteedForFunction
to quickly bypass all liveness checking in many cases.
2021-09-21 09:43:05 -07:00
Meghana Gupta
4f2d4d5635 Fix LoadBorrowImmutabilityAnalysis in cases it raises false errors on destroy_value
We should only flag an error if there is a destroy_value on the first owned root of the access path.
2021-09-09 17:05:58 -07:00
Andrew Trick
1f64871b31 MemAccessUtils: unify Box/Class/Tail storage for consistency and usability
It was originally convenient for exclusivity optimization to treat
boxes specially. We wanted to know that the 'Box' kind was always
uniquely identified. But that's not really important. And now that
AccessedStorage is being used more generally, the inconsistency is
problematic.

A consistent model is also must easier to understand and explain.

This also make the implementation of the utility simpler and more powerful.

Functional changes:

isRCIdentical will look through mark_dependence and mark_uninitialized.

findReferenceRoot is used consistently everywhere increasing analysis precision.
2021-08-09 11:43:40 -07:00
Andrew Trick
9984b81de7 MemAccessUtils cleanup: rename hasIdenticalBase
to hasIdenticalStorage.

Be precise in preparation for unifying and clarifying the access base model.
2021-08-07 15:26:46 -07:00
Meghana Gupta
9bb0d94860 Fix an edge case in AccessUseDefChainCloner so that canCloneUseDefChain does not assert on seeing begin_access (#38792) 2021-08-06 18:59:31 -07:00
Saleem Abdulrasool
25f437e17d mark some switches as covered (NFCI)
Unfortunately, MSVC does not detect covered switches as clang.  Mark
some of the switches as covered to avoid an unnecessary warning from
MSVC.
2021-06-05 15:30:25 -07:00
Erik Eckstein
09755659a1 SIL: remove the sub-classes of MultipleValueInstructionResult
They are not really needed, because they don't contain any stored properties and for isa-checks we can check the parent instruction.
2021-04-11 19:14:34 +02:00
Michael Gottesman
f6e71d4433 [mem-access-utils] Refactor isSingleInitAllocStack into getSingleInitAllocStackUse and rewrite the former in terms of the first.
This enabled me to expand this API to return the underlying single init use. I
want this information in OptRemarkGen.
2021-03-29 12:10:37 -07:00
Andrew Trick
66752e9724 OSSA: Rewrite address cloning code to fix issues.
Generalize the AccessUseDefChainCloner in MemAccessUtils. It was
always meant to work this way, just needed a client.

Add a new API AccessUseDefChainCloner::canCloneUseDefChain().

Add a bailout for begin_borrow and mark_dependence. Those
projections may appear on an access path, but they can't be
individually cloned without compensating.

Delete InteriorPointerAddressRebaseUseDefChainCloner.

Add a check in OwnershipRAUWHelper for canCloneUseDefChain.

Add test cases for begin_borrow and mark_dependence.
2021-02-24 22:18:21 -08:00
Erik Eckstein
1655e22f62 SIL: fix the == operator for AccessPath
The offset was not compared.
2021-02-04 07:53:32 +01:00
Erik Eckstein
f12ac4c11b SIL: add two utility functions to AccessPath 2021-02-04 07:53:32 +01:00
Saleem Abdulrasool
a8d9637f4a SIL: repair the Windows build after #33987 2020-11-13 08:33:47 -08:00
Andrew Trick
4409f14c78 Merge pull request #33987 from atrick/opt-licm-combined-ldst
Use AccessPath in LICM and split loads for combine load/store hoisting
2020-11-13 00:10:10 -08:00
Andrew Trick
eadefc09a9 AccessPath: Add init_enum_data_addr to "access projections" set.
AccessPath was treating init_enum_data_addr as an address base, which
is not ideal. It should be able to identify the underlying enum object
as the base. This issue was caught by LoadBorrowImmutabilityChecker
during SIL verification.

Instead handle init_enum_data_addr as a access projection that does
not affect the access path. I expect this SIL pattern to disappear
with SIL opaque values, but it still needs to be handled properly
after lowering addresses.

Functionality changes:

- any user of AccessPath now sees enum initialization stores as writes
  to the underlying enum object

- SILGen now generates begin/end access markers for enum
  initialization patterns. (Originally, we did not "see through"
  init_enum_data_addr because we didn't want to generate these
  markers, but that behavior was inconsistent and problematic).

Fixes rdar://70725514 fatal error encountered during compilation;
Unknown instruction: init_enum_data_addr)
2020-11-09 17:36:15 -08:00
Andrew Trick
d9a14836e2 Add a simple AccessUseDefChainCloner. 2020-11-09 09:48:05 -08:00
swift-ci
971932d031 Merge pull request #34159 from atrick/opt-ref-root 2020-10-20 19:19:36 -07:00
Andrew Trick
f31296d63b Fix isRCIdentityPreservingCast to handle trivial-to-reference casts
And add assertions.
2020-10-20 16:57:24 -07:00
Andrew Trick
090d57a092 Look past class casts when finding the reference root.
For class storage AccessedStorage is now close to what some passes use
for RC identity, but it still does not look past wrapping references
in an Optional.
2020-10-20 16:52:26 -07:00
Andrew Trick
9f83ceda3f Add more file-level comments to MemAccessUtils. 2020-10-20 16:45:57 -07:00
Andrew Trick
f6b32aedcd Add AccessedStorageWithBase to conviently recover the base's VarDecl 2020-10-16 15:00:10 -07:00
Andrew Trick
b272dc5e1a Cache 'isLet' within AccessedStorage.
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.
2020-10-16 15:00:10 -07:00
Andrew Trick
6f2cda1390 Add AccessUseVisitor and cleanup related APIs.
Add AccesssedStorage::compute and computeInScope to mirror AccessPath.

Allow recovering the begin_access for Nested storage.

Adds AccessedStorage.visitRoots().
2020-10-16 15:00:10 -07:00
Andrew Trick
9c69d0242d MemAccessUtils comment 2020-10-16 15:00:10 -07:00
Andrew Trick
712e1abec6 AccessedStorage and AccessPath documentation. 2020-10-16 15:00:10 -07:00
Andrew Trick
b2d1ac1631 Add AccessPathVerification pass and run it in the pipeline. 2020-10-16 15:00:10 -07:00
Andrew Trick
cc0aa2f8b8 Add an AccessPath abstraction and formalize memory access
Things that have come up recently but are somewhat blocked on this:

- Moving AccessMarkerElimination down in the pipeline
- SemanticARCOpts correctness and improvements
- AliasAnalysis improvements
- LICM performance regressions
- RLE/DSE improvements

Begin to formalize the model for valid memory access in SIL. Ignoring
ownership, every access is a def-use chain in three parts:

object root -> formal access base -> memory operation address

AccessPath abstracts over this path and standardizes the identity of a
memory access throughout the optimizer. This abstraction is the basis
for a new AccessPathVerification.

With that verification, we now have all the properties we need for the
type of analysis requires for exclusivity enforcement, but now
generalized for any memory analysis. This is suitable for an extremely
lightweight analysis with no side data structures. We currently have a
massive amount of ad-hoc memory analysis throughout SIL, which is
incredibly unmaintainable, bug-prone, and not performance-robust. We
can begin taking advantage of this verifably complete model to solve
that problem.

The properties this gives us are:

Access analysis must be complete over memory operations: every memory
operation needs a recognizable valid access. An access can be
unidentified only to the extent that it is rooted in some non-address
type and we can prove that it is at least *not* part of an access to a
nominal class or global property. Pointer provenance is also required
for future IRGen-level bitfield optimizations.

Access analysis must be complete over address users: for an identified
object root all memory accesses including subobjects must be
discoverable.

Access analysis must be symmetric: use-def and def-use analysis must
be consistent.

AccessPath is merely a wrapper around the existing accessed-storage
utilities and IndexTrieNode. Existing passes already very succesfully
use this approach, but in an ad-hoc way. With a general utility we
can:

- update passes to use this approach to identify memory access,
  reducing the space and time complexity of those algorithms.

- implement an inexpensive on-the-fly, debug mode address lifetime analysis

- implement a lightweight debug mode alias analysis

- ultimately improve the power, efficiency, and maintainability of
  full alias analysis

- make our type-based alias analysis sensistive to the access path
2020-10-16 15:00:10 -07:00
Andrew Trick
6ecbeefd50 Add AccessedStorage::Tail access kind and remove more checks.
Distinguish ref_tail_addr storage from the other storage classes.

We didn't have this originally because be don't expect a begin_access
to directly operate on tail storage. It could occur after inlining, at
least with static access markers. More importantly it helps ditinguish
regular formal accesses from other unidentified access, so we probably
should have always had this.

At any rate, it's particularly important when AccessedStorage is
generalized to arbitrary memory access.

The immediate motivation is to add an AccessPath utility, which will
need to distinguish tail storage.

In the process, rewrite AccessedStorage::isDistinct. This could have a
large positive impact on exclusivity performance.
2020-07-20 16:42:53 -07:00
Andrew Trick
0a5ba3f402 Refine AccessUseDefChainVisitor.
Prepare to reuse this visitor for an AccessPath utility.

Remove visitIncomplete. Add visitCast and visitPathComponent.

Handle phis in a separate visitor. This simplifies the main
visitor. In the long-term, we may be able to eliminate the pointer-phi
visitor entirely. For now, this lets us enforce that all phi paths
follow the same access path.
2020-07-19 19:15:44 -07:00
Andrew Trick
5826e75b00 Generalize the MemAccessUtils API.
For use outside access enforcement passes.

Add isUniquelyIdentifiedAfterEnforcement.

Rename functions for clarity and generality.

Rename isUniquelyIdentifiedOrClass to isFormalAccessBase.

Rename findAccessedStorage to identifyFormalAccess.

Rename findAccessedStorageNonNested to findAccessedStorage.

Part of generalizing the utility for use outside the access
enforcement passes.
2020-07-17 10:13:20 -07:00
Andrew Trick
73c4fb91f2 Rewrite MemAccessUtils comments.
Update, clarify, and prepare for generalization.
2020-07-17 10:12:29 -07:00
Andrew Trick
3766962f28 Teach stripCasts (and getUnderlyingObject) about begin_access.
This was blocking EscapeAnalysis and many other analyses from handling
access markers.
2020-07-11 16:32:01 -07:00
Andrew Trick
3543cf85c4 Cleanup MemAccessUtils.
Organize the utilities in this file by section to make subsequent
diffs easier to read and prepare for adding more utilities.
2020-07-09 14:31:45 -07:00
Andrew Trick
8636c39259 Fix assert in MemAccessUtils isLetAccess
Assertion failed:
(accessedAddress == getAccessedAddress(accessedAddress) &&
"caller must find the address root"), function isLetAddress,
file /Users/rjmccall/dev/swift/swift/lib/SIL/Utils/MemAccessUtils.cpp,
line 63.

Teach the getAccessedAddress utility to iterate through nested access
markers with projections interposed.

Fixes <rdar://problem/61464370>
Crash in SILOptimizer/access_marker_verify.swift
2020-04-08 22:04:16 -07:00
Andrew Trick
ec1545fac2 Fix the getAddressAccess API.
The API was accidentally undefined, presumably because I checked in
the wrong code or there was a bad merge. The API will be used by
upcoming commits.

Meanwhile, getAccessedAddress was not stripping access markers, which
means some analysis may have been too conservative.

This fix could expose issues by making existing analyses more effective.
2020-04-02 18:49:46 -07:00
swift-ci
6e7184287c Merge pull request #30204 from atrick/no-borrow-address 2020-03-04 19:23:46 -08:00
Andrew Trick
653a5aae2a Prevent begin_borrow on addresses and cleanup address access utils. 2020-03-04 16:32:08 -08:00
Michael Gottesman
be16822af9 [ownership] Remove BranchPropagatedUser.
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.
2020-03-04 07:35:23 -08:00
Andrew Trick
badc5658bb Fix SIL MemBehavior queries with access markers.
This is in prepration for other bug fixes.

Clarify the SIL utilities that return canonical address values for
formal access given the address used by some memory operation:

- stripAccessMarkers
- getAddressAccess
- getAccessedAddress

These are closely related to the code in MemAccessUtils.

Make sure passes use these utilities consistently so that
optimizations aren't defeated by normal variations in SIL patterns.

Create an isLetAddress() utility alongside these basic utilities to
make sure it is used consistently with the address corresponding to
formal access. When this query is used inconsistently, it defeats
optimization. It can also cause correctness bugs because some
optimizations assume that 'let' initialization is only performed on a
unique address value.

Functional changes to Memory Behavior:

- An instruction with side effects now conservatively still has side
  effects even when the queried value is a 'let'. Let values are
  certainly sensitive to side effects, such as the parent object being
  deallocated.

- Return the correct MemBehavior for begin/end_access markers.
2020-03-03 09:24:18 -08:00
Michael Gottesman
61e5653000 [semantic-arc-opts] Convert load [copy] -> load_borrow given single init alloc_stack. 2019-12-09 11:33:50 -08:00
Joe Groff
0e3987a4fc Factor out a visitor from findAccessedStorage.
The same logic for looking through projection paths is useful elsewhere.
2019-08-29 16:08:17 -07:00