Commit Graph

55 Commits

Author SHA1 Message Date
Erik Eckstein
d2fc6eb3b5 AliasAnalysis: make AliasAnalysis a function analysis and simplify the cache keys
Instead of caching alias results globally for the module, make AliasAnalysis a FunctionAnalysisBase which caches the alias results per function.
Why?
* So far the result caches could only grow. They were reset when they reached a certain size. This was not ideal. Now, they are invalidated whenever the function changes.
* It was not possible to actually invalidate an alias analysis result. This is required, for example in TempRValueOpt and TempLValueOpt (so far it was done manually with invalidateInstruction).
* Type based alias analysis results were also cached for the whole module, while it is actually dependent on the function, because it depends on the function's resilience expansion. This was a potential bug.

I also added a new PassManager API to directly get a function-base analysis:
    getAnalysis(SILFunction *f)

The second change of this commit is the removal of the instruction-index indirection for the cache keys. Now the cache keys directly work on instruction pointers instead of instruction indices. This reduces the number of hash table lookups for a cache lookup from 3 to 1.
This indirection was needed to avoid dangling instruction pointers in the cache keys. But this is not needed anymore, because of the new delayed instruction deletion mechanism.
2021-05-26 21:57:54 +02:00
Erik Eckstein
3701de4731 AliasAnalysis: check for immutable scopes.
If the "regular" alias analysis thinks that an instruction may write to an address, check if the instruction is in an immutable scope of V.
That means that even if we don't know anything about the instruction (e.g. a call to an unknown function), we can be sure that it cannot write to the address.

An immutable scope is for example a read-only begin_access/end_access scope.
Another example is a borrow scope of an immutable copy-on-write buffer, for example:
   %b = begin_borrow %array_buffer
   %addr = ref_element_addr [immutable] %b : $BufferType, #BufferType.someField
2021-05-18 10:14:44 +02:00
Erik Eckstein
ed7a8026d6 ValueEnumerator: make the index type unsigned instead of size_t
This reduces the size of the index from 8 to 4 bytes, which is important in AliasAnalysis where we use pairs of such indices.
2021-05-18 08:56:22 +02:00
Erik Eckstein
67ce72cebb MemBehavior: fix minor bugs for `begin_access and end_access`.
* ``begin_access [modify]`` returned MayWrite, but "modify" means, it can be a read as well.
Instead, return MayReadWrite. Only for ``begin_access [init]`` return MayWrite.
This is more or less cosmetic - probably this bug had no real impact on any optimization.

* ``begin_access [deinit]`` needs to return MayReadWrite for the same reason ``destroy_addr`` returns MayReadWrite (see SILInstruction::MemoryBehavior).
2021-03-24 12:16:07 +01:00
Erik Eckstein
f7296ed903 SIL: fix bugs in the MemBehavior cache invalidation mechanism.
When a non-value instruction (e.g. a destroy_addr) was deleted, the corresponding cache entry in MemoryBehaviorCache was not invalidated.
If a new instruction was allocated at the same memory location, the old - and invalid - cache entry was re-used.

This bug triggered a SIL memory lifetime failure in TempRValueElimination.

https://bugs.swift.org/browse/SR-13985
rdar://problem/72614608

This change also fixes another problem (which I found by inspection): Individual result values of MultipleValueInstructions were not invalidated correctly.
2021-01-06 11:29:57 +01:00
Meghana Gupta
81107e4235 Improve handling of copy_value and destroy_value in (#35011)
MemoryBehaviorVisitor

- Also, compute use points for destroy_value
- Cleanup explicit checks for refcount instructions in RLE
2020-12-14 22:44:58 -08:00
Michael Gottesman
c3681a6eef [membehavior] Fix base memory behavior/releasing of Load/Store for ownership.
load, store in ossa can have side-effects and stores can release. Specifically:

Memory Behavior
---------------

* Load: unqualified, trivial, take have a read side-effect, but copy retains so
  has side-effects.

* Store: unqualified, trivial, init may write but assign releases so it may have
  side-effects.

Release Behavior
----------------

* Load: No changes.

* Store: May release if store has assign as an ownership qualifier.
2020-11-11 15:32:32 -08:00
Andrew Trick
fd8f723f60 Merge pull request #34126 from atrick/add-accesspath
Add an AccessPath abstraction and formalize memory access
2020-10-19 10:17:27 -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
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
Erik Eckstein
007351223e MemBehavior: handle begin_access when checking for apply side-effects. 2020-10-16 16:32:48 +02:00
Erik Eckstein
b0c9e69b6f SideEffectAnalysis: don't assume that arguments with trivial type cannot be pointers.
Even values of trivial type can contain a Builtin.RawPointer, which can be used to read/write from/to.

To compensate for the removed check, enable the escape-analysis check in MemBehavior (as it was before).

This fixes a recently introduced miscompile.
rdar://problem/70220876
2020-10-13 11:32:47 +02:00
Erik Eckstein
d4a6bd39b6 SILOptimizer: improve MemBehavior for apply instructions.
1. Do a better alias analysis for "function-local" objects, like alloc_stack and inout parameters
2. Fully support try_apply and begin/end/abort_apply

So far we fully relied on escape analysis. But escape analysis has some shortcomings with SIL address-types.
Therefore, handle two common cases, alloc_stack and inout parameters, with alias analysis.
This gives better results.
The biggest change here is to do a quick check if the address escapes via an address_to_pointer instructions.
2020-10-09 20:54:58 +02:00
Erik Eckstein
aced5c74df SILOptimizer: Remove InspectionMode from MemBehehaviorVisitor
The InspectionMode was never set to anything else than "IgnoreRetains"
2020-10-09 20:54:58 +02:00
Erik Eckstein
c82f78b218 AliasAnalysis: handle copy_addr in MemBehaviorVisitor.
Only let copy_addr have side effects if the source or destination really aliases with the address in question.
2020-06-22 13:47:31 +02:00
Erik Eckstein
547d527258 AliasAnalysis: consider a take from an address as an write
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.
2020-06-22 13:47:31 +02:00
Erik Eckstein
f96f9368b4 SIL: define begin_cow_mutation to have side effects.
This fixes a correctness issue.
The begin_cow_mutation instruction has dependencies with instructions which retain the buffer operand.
This prevents optimizations from moving begin_cow_mutation instructions across such retain instructions.
2020-06-08 10:24:29 +02:00
Saleem Abdulrasool
fa46f7131c sprinkle some llvm_unreachable for MSVC (NFC)
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").
2020-04-24 18:59:07 -07:00
Andrew Trick
7145a80fa2 Fix MemBehavior calls to getAccessedAddress to avoid an assert.
Fixes <rdar://60046018> assert: (v->getType().isAddress())
in getAccessedAddress.

MemBehavior compares known memory accesses with some arbitrary value,
which may not be an address. However, we should not call utilities
that work on accessed addresses with an arbitrary value.

This assert is a result of very recent changes to gradually make
memory access utilities more type safe and introduce the concept of a
canonical accessed address. In the future, we may even have a wrapper
type for such a thing. In the SIL optimizer, there are several
different notions of what constitutes the base of a memory
access. Mismatches can lead to subtle bugs.
2020-03-13 09:30:48 -07: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
7ee5ad7318 [sil] Rename {,Strong}Copy{Unowned,Unmanaged}. 2019-10-26 17:03:47 -07:00
Michael Gottesman
5fc1d1d349 [ownership] Define a new instruction copy_unmanaged_value.
This provides a singular instruction for convert an unmanaged value to a ref,
then strong_retain it. I expanded the definition of UNCHECKED_REF_STORAGE to
include these copy like instructions. This instruction is valid in all SIL.

The reason why I am adding this instruction is that currently when we emit an
access to an unowned (unsafe) ivar, we use an unmanaged_to_ref and a strong
retain. This can look to the optimizer like a strong retain that can potentially
be optimized. By combining the two together into a new instruction, we can avoid
this potential problem since the pattern matching will break.
2019-08-25 21:26:40 -07:00
Bob Wilson
8e330ee344 NFC: Fix indentation around the newly renamed LLVM_DEBUG macro.
Jordan used a sed command to rename DEBUG to LLVM_DEBUG. That caused some
lines to wrap and messed up indentiation for multi-line arguments.
2018-07-21 00:56:18 -07:00
Jordan Rose
cefb0b62ba Replace old DEBUG macro with new LLVM_DEBUG
...using a sed command provided by Vedant:

$ find . -name \*.cpp -print -exec sed -i "" -E "s/ DEBUG\(/ LLVM_DEBUG(/g" {} \;
2018-07-20 14:37:26 -07:00
David Zarzycki
03b7eae9ed [SILOptimizer] NFC: Adopt reference storage type meta-programming macros 2018-06-30 06:44:33 -04:00
Michael Gottesman
97367d3dd4 [ownership] Do not lower copy_unowned_value to strong_retain_unowned.
The major important thing here is that by using copy_unowned_value we can
guarantee that the non-ownership SIL ARC optimizer will treat the release
associated with the strong_retain_unowned as on a distinc rc-identity from its
argument. As an example of this problem consider the following SILGen like
output:

----
%1 = copy_value %0 : $Builtin.NativeObject
%2 = ref_to_unowned %1
%3 = copy_unowned_value %2
destroy_value %1
...
destroy_value %3
----

In this case, we are converting a strong reference to an unowned value and then
lifetime extending the value past the original value. After eliminating
ownership this lowers to:

----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
strong_retain_unowned %1
strong_release %0
...
strong_release %0
----

From an RC identity perspective, we have now blurred the lines in between %3 and
%1 in the previous example. This can then result in the following miscompile:

----
%1 = ref_to_unowned %0
strong_retain_unowned %1
...
strong_release %0
----

In this case, it is possible that we created a lifetime gap that will then cause
strong_retain_unowned to assert. By not lowering copy_unowned_value throughout
the SIL pipeline, we instead get this after lowering:

----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
%2 = copy_unowned_value %1
strong_release %0
...
strong_release %2
----

And we do not miscompile since we preserved the high level rc identity
pairing.

There shouldn't be any performance impact since we do not really optimize
strong_retain_unowned at the SIL level. I went through all of the places that
strong_retain_unowned was referenced and added appropriate handling for
copy_unowned_value.

rdar://41328987

**NOTE** I am going to remove strong_retain_unowned in a forthcoming commit. I
just want something more minimal for cherry-picking purposes.
2018-06-27 13:02:58 -07:00
Andrew Trick
cdcb7c7a2c [NFC] SideEffectAnalysis refactoring and cleanup.
Make this a generic analysis so that it can be used to analyze any
kind of function effect.

FunctionSideEffect becomes a trivial specialization of the analysis.

The immediate need for this is to introduce an new
AccessedStorageAnalysis, although I foresee it as a generally very
useful utility. This way, new kinds of function effects can be
computed without adding any complexity or compile time to
FunctionSideEffects. We have the flexibility of computing different
kinds of function effects at different points in the pipeline.

In the case of AccessedStorageAnalysis, it will compute both
FunctionSideEffects and FunctionAccessedStorage in the same pass by
implementing a simple wrapper on top of FunctionEffects.

This cleanup reflects my feeling that nested classes make the code
extremely unreadable unless they are very small and either private or
only used directly via its parent class. It's easier to see how these
classes compose with a flat type system.

In addition to enabling new kinds of function effects analyses, I
think this makes the implementation of side effect analysis easier to
understand by separating concerns.
2018-04-16 17:05:04 -07:00
Erik Eckstein
3adf59561f Fix wrong usage of escape analysis in MemBehavior
The EscapeAnalysis:canEscapeTo function was actually broken, because it did not detect all escapes of a reference/pointer.
I completely replaced the implementation with the correct one (canObjectOrContentEscapeTo) and removed the now obsolete canObjectOrContentEscapeTo.
Fixes a miscompile.

rdar://problem/39161309
2018-04-11 10:20:36 -07:00
Joe Shajrawi
f732ea66ef Builtins: add ValueToBridgeObject instruction 2018-02-12 13:27:59 +02:00
Erik Eckstein
db69b8d433 SideEffectAnalysis: don't assume the worst side-effects for a release instruction
Instead let the client decide what to do with this.
Sometimes the client knows what side effect a release instruction really has.
2018-01-19 11:32:35 -08:00
eeckstein
b126b62256 Revert "Optimization changes to completely fold OptionSet literals" 2018-01-18 22:05:07 -08:00
Erik Eckstein
9907ffc09d SideEffectAnalysis: don't assume the worst side-effects for a release instruction
Instead let the client decide what to do with this.
Sometimes the client knows what side effect a release instruction really has.
2018-01-18 18:27:17 -08:00
Chris Lattner
415cd50ba2 Reduce array abstraction on apple platforms dealing with literals (#13665)
* Reduce array abstraction on apple platforms dealing with literals

Part of the ongoing quest to reduce swift array literal abstraction
penalties: make the SIL optimizer able to eliminate bridging overhead
 when dealing with array literals.

Introduce a new classify_bridge_object SIL instruction to handle the
logic of extracting platform specific bits from a Builtin.BridgeObject
value that indicate whether it contains a ObjC tagged pointer object,
or a normal ObjC object. This allows the SIL optimizer to eliminate
these, which allows constant folding a ton of code. On the example
added to test/SILOptimizer/static_arrays.swift, this results in 4x
less SIL code, and also leads to a lot more commonality between linux
and apple platform codegen when passing an array literal.

This also introduces a couple of SIL combines for patterns that occur
in the array literal passing case.
2018-01-02 15:23:48 -08:00
Michael Gottesman
4c80c4d66f Address John's feedback.
Specifically to commits:

36a8d0d5c0
6df5462ee2

rdar://31521023
2017-10-25 13:48:51 -07:00
Michael Gottesman
6df5462ee2 [sil] Add support for multiple value instructions by adding MultipleValueInstruction{,Result}.
rdar://31521023
2017-10-24 18:36:37 -07:00
John McCall
ab3f77baf2 Make SILInstruction no longer a subclass of ValueBase and
introduce a common superclass, SILNode.

This is in preparation for allowing instructions to have multiple
results.  It is also a somewhat more elegant representation for
instructions that have zero results.  Instructions that are known
to have exactly one result inherit from a class, SingleValueInstruction,
that subclasses both ValueBase and SILInstruction.  Some care must be
taken when working with SILNode pointers and testing for equality;
please see the comment on SILNode for more information.

A number of SIL passes needed to be updated in order to handle this
new distinction between SIL values and SIL instructions.

Note that the SIL parser is now stricter about not trying to assign
a result value from an instruction (like 'return' or 'strong_retain')
that does not produce any.
2017-09-25 02:06:26 -04:00
Jordan Rose
63a9943a46 Trivial updates for upstream LLVM changes.
- BitRig is gone
- llvm::enumerate's element type now uses methods instead of fields

No intended functionality change.
2017-07-25 14:11:03 -07:00
Johannes Weiß
c7990f2abd redundant load elimination for @in_guaranteed-only funcs 2017-07-24 18:22:50 +01:00
practicalswift
6d1ae2a39c [gardening] 2016 → 2017 2017-01-06 16:41:22 +01:00
practicalswift
797b80765f [gardening] Use the correct base URL (https://swift.org) in references to the Swift website
Remove all references to the old non-TLS enabled base URL (http://swift.org)
2016-11-20 17:36:03 +01:00
Roman Levenstein
2736329062 [sil-escape-analysis] Make sure that dealloc_ref and set_deallocating do not have any effect on escaping. 2016-09-15 22:10:25 -07:00
Erik Eckstein
74d44b74e7 SIL: remove SILValue::getDef and add a cast operator to ValueBase * as a repelacement. NFC. 2016-01-25 15:00:49 -08:00
Erik Eckstein
506ab9809f SIL: remove getTyp() from SILValue 2016-01-25 15:00:49 -08:00
practicalswift
71e00fefa1 [gardening] Fix typos: "word word" (two spaces) → "word word" (one space) 2016-01-24 21:27:16 +01:00
Erik Eckstein
2db6f3d213 SIL: remove multiple result values from SILValue
As there are no instructions left which produce multiple result values, this is a NFC regarding the generated SIL and generated code.
Although this commit is large, most changes are straightforward adoptions to the changes in the ValueBase and SILValue classes.
2016-01-21 10:30:31 -08:00
Zach Panzarino
e3a4147ac9 Update copyright date 2015-12-31 23:28:40 +00:00
Xin Tong
f9450ea6ab Avoid extraneous generation of AACache and MBCache keys 2015-12-24 09:24:56 -08:00
Xin Tong
47afcd4adc Regenerate cache key after the valueenumeraor is invalidated. Exposed by another painful memory behavior cache bug 2015-12-24 00:30:11 -08:00
Erik Eckstein
f8c82889b8 Fix wrong combination of MemoryBehavior.
Instead of taking the maximum we need to handle the special case MayRead + MayWrite = MayReadWrite
2015-12-23 13:50:08 -08:00
Xin Tong
17fe37d715 Use a separate valueenumerator for alias cache and memory behavior cache
If we use a shared valueenumerator, imagine the case when one of the AAcache or MBcache
is cleared and we clear the valueenumerator.

This could give rise to collisions (false positives) in the not-yet-cleared cache!
2015-12-22 22:53:32 -08:00