Commit Graph

67 Commits

Author SHA1 Message Date
Susana Monteiro
593f320460 Merge pull request #79325 from swiftlang/susmonteiro/copy-constructor-default-args
[cxx-interop] Prevent usage in Swift of C++ copy constructor with default args
2025-03-04 15:40:22 +00:00
susmonteiro
bc6573ec32 [cxx-interop] Prevent usage in Swift of C++ copy constructor with default args 2025-03-03 13:22:11 +00:00
Erik Eckstein
d918b316c9 TempRValueOptimization: don't optimize copies to mark_dependence base values.
We want to keep the original lifetime of the base. If we would eliminate the base alloc_stack, we risk to insert a destroy_addr too early.
2025-02-10 17:57:47 +01:00
Nate Chandler
8fb0fd2ba4 [TempRValueOpt] Invalidate insts when completing. 2025-01-16 08:18:30 -08:00
Andrew Trick
4612728581 [NFC] Add BeginApplyInst::getEndApplyUses() API.
A begin_apply token may be used by operands that do not end the coroutine:
mark_dependence.

We need an API that gives us only the coroutine-ending uses. This blocks
~Escapable accessors.

end_borrow is considered coroutine-ending even though it does not actually
terminate the coroutine.

We cannot simply ask isLifetimeEnding, because end_apply and abort_apply do not
end any lifetime.
2024-11-18 01:37:00 -08:00
Erik Eckstein
f9b524b1cb AliasAnalysis: a complete overhaul of alias- and memory-behavior analysis
The main changes are:

*) Rewrite everything in swift. So far, parts of memory-behavior analysis were already implemented in swift. Now everything is done in swift and lives in `AliasAnalysis.swift`. This is a big code simplification.

*) Support many more instructions in the memory-behavior analysis - especially OSSA instructions, like `begin_borrow`, `end_borrow`, `store_borrow`, `load_borrow`. The computation of end_borrow effects is now much more precise. Also, partial_apply is now handled more precisely.

*) Simplify and reduce type-based alias analysis (TBAA). The complexity of the old TBAA comes from old days where the language and SIL didn't have strict aliasing and exclusivity rules (e.g. for inout arguments). Now TBAA is only needed for code using unsafe pointers. The new TBAA handles this - and not more. Note that TBAA for classes is already done in `AccessBase.isDistinct`.

*) Handle aliasing in `begin_access [modify]` scopes. We already supported truly immutable scopes like `begin_access [read]` or `ref_element_addr [immutable]`. For `begin_access [modify]` we know that there are no other reads or writes to the access-address within the scope.

*) Don't cache memory-behavior results. It turned out that the hit-miss rate was pretty bad (~ 1:7). The overhead of the cache lookup took as long as recomputing the memory behavior.
2024-07-29 17:33:46 +02:00
Nate Chandler
dd730b849c [LifetimeCompletion] Flag instructions dead_end. 2024-07-03 16:44:35 -07:00
Meghana Gupta
32e72a6732 Allow TempRValueOpt of lexical alloc_stacks when base of copy source has guaranteed convention
A guaranteed function argument is live for the duration of the function.
It should be safe to allow TempRValueOpt when it is the base of the copy source of a lexical alloc_stack.
2024-06-27 16:18:15 -07:00
Tim Kientzle
1098054291 Merge branch 'main' into tbkka-assertions2 2024-06-18 17:52:00 -07:00
Akira Hatanaka
d92f181ace Create two versions (for caller and callee) of the functions that answer questions about parameter convention (#74124)
Create two versions of the following functions:

isConsumedParameter
isGuaranteedParameter
SILParameterInfo::isConsumed
SILParameterInfo::isGuaranteed
SILArgumentConvention::isOwnedConvention
SILArgumentConvention::isGuaranteedConvention

These changes will be needed when we add a new convention for
non-trivial C++ types as the functions will return different answers
depending on whether they are called for the caller or the callee. This
commit doesn't change any functionality.
2024-06-18 09:06:09 -07:00
Tim Kientzle
1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
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)
2024-06-05 19:37:30 -07:00
Nate Chandler
87e4c65e28 [Gardening] SIL: "liferange" -> "liverange" 2024-05-10 15:54:07 -07:00
Nate Chandler
5383df755a [NFC] LifetimeCompletion: Clarify modes.
Completion is done along a boundary, either the availability or the
liveness boundary.  Represent which with a type.  Update docs and names.
2024-05-01 08:57:01 -07:00
Andrew Trick
da3f583492 Add mark_dependence [unresolved]
In preparation for inserting mark_dependence instructions for lifetime
dependencies early, immediately after SILGen. That will simplify the
implementation of borrowed arguments.

Marking them unresolved is needed to make OSSA verification
conservative until lifetime dependence diagnostics runs.
2024-02-08 22:53:16 -08:00
Andrew Trick
264cbaea42 Add mark_dependence [nonescaping] flag.
The dependent 'value' may be marked 'nonescaping', which guarantees that the
lifetime dependence is statically enforceable. In this case, the compiler
must be able to follow all values forwarded from the dependent 'value', and
recognize all final (non-forwarded, non-escaping) use points. This implies
that `findPointerEscape` is false. A diagnostic pass checks that the
incoming SIL to verify that these use points are all initially within the
'base' lifetime. Regular 'mark_dependence' semantics ensure that
optimizations cannot violate the lifetime dependence after diagnostics.
2024-01-04 14:47:35 -08:00
Meghana Gupta
332b405bd9 Disable TempRValueOpt when there are users of the temp object preceding the copy 2023-06-05 09:51:54 -07:00
Meghana Gupta
1f4efebbdf Enable temprvalueopt of lexical enum values 2023-04-22 15:11:19 -07:00
Meghana Gupta
38dcfeca13 Merge pull request #65167 from meg-gupta/temprvalueenum
Enable store elimination of enums with uses in multiple blocks
2023-04-17 10:07:55 -07:00
Meghana Gupta
05d64b8d36 Enable store elimination of enums with uses in multiple blocks 2023-04-13 15:15:18 -07:00
Nate Chandler
1938912ceb [TempRValueOpt] NFC: Clarified assertion. 2023-04-12 07:24:41 -07:00
Nate Chandler
10215198da [TempRValueOpt] NFC: Assert no copy of uncopyable. 2023-04-11 10:41:53 -07:00
Nate Chandler
c21338af57 [TempRValueOpt] Fold new destroy_addrs into loads.
To avoid introducing new copies--which is illegal for move-only values--
don't rewrite `load [take]`s and `copy_addr [take]`s as `load [copy]`s
and `copy_addr`s respectively and introduce new `destroy_addr`s after
them.  Instead, get the effect of folding such a newly created
`destroy_addr` into the preceding rewritten `load [copy]` or
`copy_addr`.  Get that effect by neither modifying the `copy_addr [take]`
or `load [take]` nor adding a subsequent `destroy_addr`.

An example for each kind (`load [take]` and `copy_addr [take]`):

```
// Input 1 (`load [take]`)
  copy_addr [take] %src to [init] %tmp
  %val = load [take] %src
// Old Output 1
  %val = load [copy] %src
  destroy_addr %src
// New Output 2
  %val = load [take] %src
```

```
// Input 2 (`copy_addr [take]`)
  copy_addr [take] %src to [init] %tmp
  copy_addr [take] %src to [init] %dst
// Old Output 2
  copy_addr %src to [init] %dst
  destroy_addr %src
// New Output 2
  copy_addr [take] %src to [init] %dst
```

rdar://107839979
2023-04-11 10:41:53 -07:00
Nate Chandler
d2e4d5395f [TempRValueOpt] NFC: Renamed variable.
In preparation for "folding" an "inserted destroy" into a load [copy] or
copy_addr, rename the variable that indicates whether the copyInst's
source must be deinitialized after its last "load".
2023-04-11 10:41:53 -07:00
Nate Chandler
ed623d7b64 [NFC] Shortened SIL [init] flag.
Instead of writing out [initalization] for some instructions, use [init]
everywhere.
2022-10-27 10:38:54 -07:00
Josh Soref
730b16c569 Spelling siloptimizer
* access
* accessed
* accesses
* accessor
* acquiring
* across
* activated
* additive
* address
* addresses'
* aggregated
* analysis
* and
* appropriately
* archetype
* argument
* associated
* availability
* barriers
* because
* been
* beginning
* belongs
* beneficial
* blocks
* borrow
* builtin
* cannot
* canonical
* canonicalize
* clazz
* cleanup
* coalesceable
* coalesced
* comparisons
* completely
* component
* computed
* concrete
* conjunction
* conservatively
* constituent
* construct
* consuming
* containing
* covered
* creates
* critical
* dataflow
* declaration
* defined
* defining
* definition
* deinitialization
* deliberately
* dependencies
* dependent
* deserialized
* destroy
* deterministic
* deterministically
* devirtualizes
* diagnostic
* diagnostics
* differentiation
* disable
* discipline
* dominate
* dominates
* don't
* element
* eliminate
* eliminating
* elimination
* embedded
* encounter
* epilogue
* epsilon
* escape
* escaping
* essential
* evaluating
* evaluation
* evaluator
* executing
* existential
* existentials
* explicit
* expression
* extended
* extension
* extract
* for
* from
* function
* generic
* guarantee
* guaranteed
* happened
* heuristic
* however
* identifiable
* immediately
* implementation
* improper
* include
* infinite
* initialize
* initialized
* initializer
* inside
* instruction
* interference
* interferes
* interleaved
* internal
* intersection
* intractable
* intrinsic
* invalidates
* irreducible
* irrelevant
* language
* lifetime
* literal
* looks
* materialize
* meaning
* mergeable
* might
* mimics
* modification
* modifies
* multiple
* mutating
* necessarily
* necessary
* needsmultiplecopies
* nonetheless
* nothing
* occurred
* occurs
* optimization
* optimizing
* original
* outside
* overflow
* overlapping
* overridden
* owned
* ownership
* parallel
* parameter
* paths
* patterns
* pipeline
* plottable
* possible
* potentially
* practically
* preamble
* precede
* preceding
* predecessor
* preferable
* preparation
* probably
* projection
* properties
* property
* protocol
* reabstraction
* reachable
* recognized
* recursive
* recursively
* redundant
* reentrancy
* referenced
* registry
* reinitialization
* reload
* represent
* requires
* response
* responsible
* retrieving
* returned
* returning
* returns
* rewriting
* rewritten
* sample
* scenarios
* scope
* should
* sideeffects
* similar
* simplify
* simplifycfg
* somewhat
* spaghetti
* specialization
* specializations
* specialized
* specially
* statistically
* substitute
* substitution
* succeeds
* successful
* successfully
* successor
* superfluous
* surprisingly
* suspension
* swift
* targeted
* that
* that our
* the
* therefore
* this
* those
* threshold
* through
* transform
* transformation
* truncated
* ultimate
* unchecked
* uninitialized
* unlikely
* unmanaged
* unoptimized key
* updataflow
* usefulness
* utilities
* villain
* whenever
* writes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2022-10-03 18:31:33 -04:00
Erik Eckstein
bd1651169c TempRValueOpt: fix a wrong assert.
The assert was too restrictive.
Fixes a crash.

rdar://99386994
2022-09-01 15:51:40 +02:00
Nate Chandler
7ed618fb5e [TempRValueOpts] Opt some lexical alloc_stacks.
Previously, whenever an alloc_stack [lexical] was seen, optimization
bailed conservatively.

In the fullness of time, we should optimize an alloc_stack [lexical] so
long as:
(1) the root of the source of the store/copy_addr is lexical
(2) the range in which the alloc_stack [lexical] contains the value
    store'd/copy_addr'd into it (i.e. the range ending at
    destroy_addr/etc) is contained within the live range of that lexical
    root

Here, an incremental step in that direction is taken: if the base of the
accessed storage of the source of a copy_addr is a guaranteed function
argument, then we know
(1) the base is lexical--guaranteed function arguments are always
    lexical
(2) the range in which the alloc_stack contains the value copy_addr'd in
    is trivially contained within the range of that lexical root--the
    live range of a guaranteed function argument is the whole function

Added TODOs for the full optimization.
2022-08-12 11:37:19 -07:00
Erik Eckstein
777b42180d SILOptimizer: use the new set data structures in various optimizations 2022-07-13 14:27:50 +02:00
Erik Eckstein
2eda3b3bcb TempRValueOpt: don't move end_access instructions after a terminator instruction.
When extending access scopes, prevent that we end up with an `end_access` after the block's terminator.

Fixes a verifier crash.

rdar://85020372
2022-06-27 19:55:37 +02:00
Erik Eckstein
90695d9cdf TempRValueElimination: fix a problem with leaking enum values
When optimizing an enum `store` to an `alloc_stack`, require that all uses are in the same block.
Otherwise it could be a `switch_enum` of an optional where the none-case does not have a destroy of the enum value.
After transforming such an `alloc_stack`, the value would leak in the none-case block.

Fixes a OSSA verification error.
2022-03-08 15:47:14 +01:00
Nate Chandler
3bb1766a5f [SILOptimizer] Keep lexical lifetime markers.
Previously, TempRValueElimination would peephole simple alloc_stacks,
even when they were lexical; here, they are left for Mem2Reg to properly
handle.

Previously, SemanticARCOpts would eliminate lexical begin_borrows,
incorrectly allowing the lifetime of the value borrowed by them to be
observably shortened.  Here, those borrow scopes are not eliminated if
they are lexical.

Added an executable test that verifies that a local variable strongly
referencing a delegate object keeps that delegate alive through the call
to an object that weakly references the delegate and calls out to it.
2021-10-22 15:00:23 -07:00
Meghana Gupta
308704d335 Fix TempRVO on OSSA for load_borrow
This PR makes sure the destroy_addr of the copy source is inserted after
end_borrow of its direct or indirect load_borrow.
2021-10-11 23:37:28 -07:00
Erik Eckstein
f494f370a5 TempRValueOpt: Support yield
This is one step of eliminating a copy_addr in the Array's subscript read coroutine

rdar://53996328
2021-05-27 09:59:34 +02:00
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
Michael Gottesman
b6bfea1f39 [sil-optimizer] Get rid of the InstModCallback constructors in favor of onDelete/onCreatedNewInst/etc.
Without this when constructing an InstModCallback it is hard to distinguish
which closure is meant for which operation when passed to the constructor of
InstModCallback (if this was in Swift, we could use argument labels, but we do
not have such things in c++).

This new value type sort of formulation makes it unambiguous which callback is
used for what when constructing one of these.
2021-04-26 23:33:33 -07:00
Erik Eckstein
9b16a94e8d TempRValueOpt: small fixes/improvements for extending access scopes
Don't move an end_access over a (non-aliasing) end_access. This would destroy the proper nesting of accesses.
Also, add some comments, asserts and tests.
2021-03-24 12:51:30 +01:00
Erik Eckstein
7c454e3eed TempRValueOpt: extend access scopes
Try to move an end_access down to extend the access scope over all uses of the temporary.
For example:

   %a = begin_access %src
   copy_addr %a to [initialization] %temp : $*T
   end_access %a
   use %temp

We must not replace %temp with %a after the end_access. Instead we try to move the end_access after "use %temp".

This fixes generation of invalid SIL and/or the invalid removal of access checks.
2021-03-22 21:54:41 +01:00
Michael Gottesman
5136581648 [inst-simplify] Fail simplification if we have ownership and are not passed a non-null deadEndBlocks.
I am trying to be more careful about this rather than letting someone make this
mistake in the future. I also added some comments and a DeadEndBlocks instance
to TempRValueElimination so that it gets full simplifications in OSSA.
2021-01-17 20:08:24 -08:00
Michael Gottesman
aa38be6d98 [inst-simplify] Hide simplifyInstruction in favor of using simplifyAndReplaceAllSimplifiedUsesAndErase.
Currently all of these places in the code base perform simplifyInstruction and
then a replaceAllSimplifiedUsesAndErase(...). This is a bad pattern since:

1. simplifyInstruction assumes its result will be passed to
   replaceAllSimplifiedUsesAndErase. So by leaving these as separate things, we
   allow for users to pointlessly make this mistake.

2. I am going to implement in a subsequent commit a utility that lifetime
   extends interior pointer bases when replacing an address with an interior
   pointer derived address. To do this efficiently, I want to reuse state I
   compute during simplifyInstruction during the actual RAUW meaning that if the
   two operations are split, that is difficult without extending the API. So by
   removing this, I can make the transform and eliminate mistakes at the same
   time.
2021-01-17 20:08:24 -08:00
Robert Widmann
ffdd55a577 Correct a Most Vexing Parse in -asserts Builds
This thing looks like a function prototype otherwise.
2021-01-05 19:53:03 -08:00
Michael Gottesman
0de00d1ce4 [sil-inst-opt] Improve performance of InstModCallbacks by eliminating indirect call along default callback path.
Specifically before this PR, if a caller did not customize a specific callback
of InstModCallbacks, we would store a static default std::function into
InstModCallbacks. This means that we always would have an indirect jump. That is
unfortunate since this code is often called in loops.

In this PR, I eliminate this problem by:

1. I made all of the actual callback std::function in InstModCallback private
   and gave them a "Func" postfix (e.x.: deleteInst -> deleteInstFunc).

2. I created public methods with the old callback names to actually call the
   callbacks. This ensured that as long as we are not escaping callbacks from
   InstModCallback, this PR would not result in the need for any source changes
   since we are changing a call of a std::function field to a call to a method.

3. I changed all of the places that were escaping inst mod's callbacks to take
   an InstModCallback. We shouldn't be doing that anyway.

4. I changed the default value of each callback in InstModCallbacks to be a
   nullptr and changed the public helper methods to check if a callback is
   null. If the callback is not null, it is called, otherwise the getter falls
   back to an inline default implementation of the operation.

All together this means that the cost of a plain InstModCallback is reduced and
one pays an indirect function cost price as one customizes it further which is
better scalability.

P.S. as a little extra thing, I added a madeChange field onto the
InstModCallback. Now that we have the helpers calling the callbacks, I can
easily insert instrumentation like this, allowing for users to pass in
InstModCallback and see if anything was RAUWed without needing to specify a
callback.
2021-01-04 12:51:55 -08:00
Erik Eckstein
423169ce5c SILOptimizer: update alias analysis in TempRValueOpt and TempLValueOpt
When instructions are changed within a pass in a way that affects subsequent alias queries in the same pass run,
their alias analysis information must be invalidated.
Otherwise it can result in miscompiles and/or invalid SIL.

rdar://71924430
2020-12-03 13:53:57 +01:00
Erik Eckstein
1e5f3bd253 TempRValueOpt: only do the check for "unusual" temp object destruction in non-OSSA mode.
In OSSA, memory locations are always destroyed in a "visible" way, e.g. with destroy_addr or load [take].
2020-10-16 17:27:32 +02:00
Erik Eckstein
262c7b251f TempRValueOpt: don't allow copy_addr [take] from a projection of the temporary.
This fixes a memory lifetime failure.
2020-10-16 17:27:32 +02:00
Erik Eckstein
4557f151b1 TempRValueOpt: fix the placement of destroy_addr in case of a copy_addr [take]
Instead of reusing the existing destroy_addr (or load/copy_addr [take]) of the temporary, insert a new destroy_addr - at the correct location.
This fixes a memory lifetime failure in case the copy-source is modified (actually: re-initialized) after the last use of the temporary: E.g. (before copy elimination):

copy_addr [take] %src to [initialization] %temp
%x = load %temp // last use of %temp
store %y to [init] %src
destroy_addr %temp

The correct location for the destroy_addr is after the last use (after copy elimination):

%x = load %src
destroy_addr %src
store %y to [init] %src

rdar://problem/69757314
2020-10-16 17:27:32 +02:00
Erik Eckstein
6310dfcc93 TempRValueOpt: fix the handling of load [take]
load [take] was not considered as a use and it was not detected if it's in a different basic block.
This fixes a miscompile in case there is a modification of the copy-source before a load [take].

rdar://problem/69757314
2020-10-16 16:32:48 +02:00
Erik Eckstein
7c293d8de9 TempRValueOpt: fix the handling of begin_access
Consider the related end_access instructions as uses to correctly mark the end of the lifetime of the temporary.
This fixes a miscompile in case there is a modification of the copy-source between an begin_access and end_access.
2020-10-16 16:32:48 +02:00
Erik Eckstein
d569031f1a TempRValueOpt: move the mayWrite-check for applies from collectLoads to checkNoSourceModification
... where it belongs.
This is mostly refactoring, but it also fixes a bug: we don't recurse into a begin_access in collectLoads.
If there is an apply in such a scope, the mayWrite-check wouldn't be done.
In checkNoSourceModification all instructions are visited, so the check is always done.
2020-10-16 16:32:48 +02:00
Erik Eckstein
673b8873ab TempRValueOpt: refactoring: simplify the signature of collectLoads
It's sufficient to pass the operand instead of the operand, the user and the operand value.
NFC.
2020-10-16 16:32:48 +02:00
Erik Eckstein
68db2e7c6c TempRValueOpt: don't use collectLoads in tryOptimizeStoreIntoTemp
This refactoring removes a lot of special-casing in collectLoads and also makes tryOptimizeStoreIntoTemp simpler.
It's a NFC.
2020-10-16 16:32:48 +02:00