Commit Graph

111 Commits

Author SHA1 Message Date
Andrew Trick a8276e37c2 Fix OSSA utility GuaranteedOwnershipExtension
OSSA utilities have a compile-time micro-optimization for computing the liveness
boundary. It takes advantage of the OSSA property that the consuming uses
post-dominate all uses. But when we extend liveness to incorporate new uses of a
guaranteed value, that optimization no longer applies. As a result, we end up
deleting a destroy_value that is in the middle of the new live range without
creating a new compensating destroy_value. Simply remove the optimization in
this case.

Fixes rdar://172778316: Found a leak due to a consuming
post-dominance failure
2026-03-18 15:04:36 -07:00
Erik Eckstein c993c453bf Optimizer: ignore lexical flags in OwnershipRAUWHelper when running in the optimizer pipeline
In the optimizer (= non mandatory) pipeline we don't need to maintain the lexical flags of `begin_borrow`, etc. anymore.
This enables more optimizations to be done.
2026-03-10 07:56:51 +01:00
Andrew Trick 2120c0502a Another fix for the OSSA RAUW utility for unowned phis
Fixes rdar://169556118 (Assertion: (succ->getSinglePredecessorBlock() == predBB)
function visitInsertionPoints at ValueLifetime.cpp:37.)
2026-02-05 15:01:11 -08:00
Andrew Trick 96bc9aa90c Fix the OSSA RAUW utility for unowned phis
The OwnershipRAUW utility is called by CSE, SILCombine, etc. whenever OSSA
values are substituted or combined. It handles ownership corner cases by
creating new copies. Destroys need to be insert for those new copies after all
original uses. It is impossible to do that when phis are involved. The utility
already checks for phis involving owned or guaranteed values, but unowned phis
were not anticipated.

Fixes rdar://168620481 swift-frontend crash: While running pass
SILFunctionTransform "GenericSpecializer"
2026-01-23 21:56:30 -08:00
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00
Erik Eckstein 2de21c290b Optimizer: clean up handling of nested Swift pass invocations
Pass-invocations can be nested if a module pass creates an inner context for a specific function to modify.

This change
* removes the SwiftPassInvocation instance from SILCombine and let SILCombine use the current SwiftPassInvocation
* correctly use the innermost SwiftPassInvocation in various bridged utilities
2026-01-22 17:41:23 +01:00
Erik Eckstein cc22290eb4 OwnershipOptUtils: fix a wrong debug location when creating destroy_value
When taking the location from the builder's insertion point, we must make sure it's not a return location.
Fixes an assertion failure.
I found this during my work on simplifying borrow scopes
2025-12-19 17:43:59 +01:00
Nate Chandler 017f003147 [OSSA] Fix borrowCopyOverGuaranteedUsers dead-ends.
The utility was computing the boundary of the `copy_value` with the
`end_borrow`s as users.  But there may not be any `end_borrow`s thanks
to dead-ends.  Instead, consider both guaranteed users and any
`end_borrow`s.

Fixes a miscompile in CSE.

rdar://158353230
2025-08-14 17:05:26 -07:00
Nate Chandler 1fe65b0e3d [NFC] Deleted two unused functions. 2025-08-14 16:15:43 -07:00
Andrew Trick 05fcf5fbbc Fix OSSA RAUW utility for move_value that changes ownership.
CSE "looks through" ownership operations, which can lead to problematic substitutions. This fix cleans up owned operands even when the newly substituted value has no ownership.

For example:

    %0 = enum $Optional<Interface>, #Optional.none!enumelt
    %1 = move_value [lexical] %0
    %2 = enum $Optional<Interface>, #Optional.none!enumelt
    %3 = struct $EndpointCommon (%2)
    %4 = struct $EndpointCommon (%1)

CSE combines the two .none enums:

    %0 = enum $Optional<Interface>, #Optional.none!enumelt
    %2 = enum $Optional<Interface>, #Optional.none!enumelt

Then combines the two structs:

    %3 = struct $EndpointCommon (%2)
    %4 = struct $EndpointCommon (%1)

Leaving a dead move_value:

    %1 = move_value [lexical] %0

which is invalid OSSA. Now, when replacing the owned struct, we add destroys for its operands.

Fixes rdar://156431548 Error! Found a leaked owned value that was never consumed.
2025-07-29 11:18:10 -07:00
Andrew Trick b3a445fb55 Fix BorrowingOperand::getBorrowIntroducingUserResult()
To handle borrowing operands that produce a dependence value but do not create a
nested borrow scope. This includes non-reborrow borrowed-from and guaranteed
mark_dependence [nonescaping].
2025-02-25 23:08:54 -08:00
Meghana Gupta 4561658799 Avoid creating unoptimizable copies in CSE
CSE uses OSSA rauw which creates copies and copies that are created to optimize
across borrow scopes are unoptimizable. This PR avoids this situation for now.
2025-02-19 11:20:43 -08:00
Meghana Gupta 53553fa172 Fix swift::areUsesWithinValueLifetime for guaranteed values
To find if all the uses are within a guaranteed value, we should find all borrow introducers.

swift::findOwnershipReferenceAggregate looks only through forwarding operations with single operands.

For simplicity, continue using swift::findOwnershipReferenceAggregate, but return false when it does
not find a borrow introducer.
2025-01-31 15:10:57 -08:00
Meghana Gupta 27fc324c8c Fix AddressOwnership for unidentified access
AccessBase can have Unindentified kind where the base value maybe
invalid.

Bailout early for such accesses in ownership rauw.
2025-01-28 09:08:38 -08:00
Meghana Gupta 2c256180ce Add new utility swift::areUsesWithinValueLifetime 2025-01-10 16:15:50 -08:00
Erik Eckstein 48b913af4b Optimizer: make the hasOwnershipOperandsOrResults utility available in OwnershipOptUtils 2025-01-02 10:42:01 +01:00
Erik Eckstein 6990a195a3 Optimizer: rename GuaranteedPhiUpdater -> PhiUpdater
Because it now has the replacePhisWithIncomingValues utility, which works for all kind of phis.
2024-12-12 09:09:11 +01:00
Erik Eckstein 09a5a4487a Optimizer: add a utility to replaces phis with the unique incoming values if all incoming values are the same
This is needed after running the SSAUpdater for an existing OSSA value, because the updater can
insert unnecessary phis in the middle of the original liverange which breaks up the original
liverange into smaller ones:

```
   %1 = def_of_owned_value
   %2 = begin_borrow %1
   ...
   br bb2(%1)
 bb2(%3 : @owned $T): // inserted by SSAUpdater
   ...
   end_borrow %2      // use after end-of-lifetime!
   destroy_value %3
```

It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange.
2024-12-12 08:57:57 +01:00
Erik Eckstein 51e3e5ed80 Optimizer: rename BorrowArgumentsUpdater -> GuaranteedPhiUpdater
NFC
2024-11-12 09:26:59 +01:00
Erik Eckstein 6b8c6a3c3b SIL: rename updateBorrowedFrom to updateBorrowArguments
NFC
2024-11-12 09:26:58 +01:00
Tim Kientzle f09fb7dfa4 Update a couple of files to pull assertion helpers from the new header 2024-05-16 12:50:23 -07:00
Erik Eckstein e14c1d1f62 SIL, Optimizer: update and handle borrowed-from instructions
Compute, update and handle borrowed-from instruction in various utilities and passes.
Also, used borrowed-from to simplify `gatherBorrowIntroducers` and `gatherEnclosingValues`.
Replace those utilities by `Value.getBorrowIntroducers` and `Value.getEnclosingValues`, which return a lazily computed Sequence of borrowed/enclosing values.
2024-04-10 13:38:10 +02:00
Michael Gottesman 11f0ff6e32 [sil] Ensure that all SILValues have a parent function by making it so that SILUndef is uniqued at the function instead of module level.
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.

rdar://123484595
2024-02-27 13:14:47 -08:00
Ben Barham f292ec9784 Use the new template deduction guides rather than makeArrayRef
LLVM has removed `make*ArrayRef`, migrate all references to their
constructor equivalent.
2024-02-23 20:04:51 -08:00
Meghana Gupta ce242691a6 Bail out of ossa rauw for move only values 2024-01-05 23:10:45 -08:00
Evan Wilde 309aed4925 Add SmallSetVector replacement
llvm::SmallSetVector changed semantics
(https://reviews.llvm.org/D152497) resulting in build failures in Swift.
The old semantics allowed usage of types that did not have an
`operator==` because `SmallDenseSet` uses `DenseSetInfo<T>::isEqual` to
determine equality. The new implementation switched to using
`std::find`, which internally uses `operator==`. This type is used
pretty frequently with `swift::Type`, which intentionally deletes
`operator==` as it is not the canonical type and therefore cannot be
compared in normal circumstances.

This patch adds a new type-alias to the Swift namespace that provides
the old semantic behavior for `SmallSetVector`. I've also gone through
and replaced usages of `llvm::SmallSetVector` with the
`Swift::SmallSetVector` in places where we're storing a type that
doesn't implement or explicitly deletes `operator==`. The changes to
`llvm::SmallSetVector` should improve compile-time performance, so I
left the `llvm::SmallSetVector` where possible.
2023-07-25 12:28:27 -07:00
Meghana Gupta 3f6bfca2f9 Merge pull request #64554 from meg-gupta/fixsilcombineubci
Fix OSSA RAUW utility's insertion point
2023-03-24 12:26:06 -04:00
Meghana Gupta a4c693fcf3 Update OSSA RAUW utils to insert borrows before the value being replaced 2023-03-23 11:45:51 -07:00
Andrew Trick 15796e3ff9 PrunedLiveness: add a SILFunction argument
So that liveness can migrate to using a SILBitfield.
2023-03-22 01:36:48 -07:00
Andrew Trick f9861ec9c0 Add APIs for terminator results that forward ownership.
Add TermInst::forwardedOperand.

Add SILArgument::forwardedTerminatorResultOperand. This API will be
moved into a proper TerminatorResult abstraction.

Remove getSingleTerminatorOperand, which could be misused because it's
not necessarilly forwarding ownership.

Remove the isTransformationTerminator API, which is not useful or well
defined.

Rewrite several instances of complex logic to handle block arguments
with the simple terminator result API. This defines away potential
bugs where we don't detect casts that perform implicit conversion.

Replace uses of the SILPhiArgument type and code that explicitly
handle block arguments. Control flow is irrelevant in these
situations. SILPhiArgument needs to be deleted ASAP. Instead, use
simple APIs like SILArgument::isTerminatorResult(). Eventually this
will be replaced by a TerminatorResult type.
2022-12-12 12:37:35 -08:00
Allan Shortlidge 4f8d33ffb5 SILOptimizer: Break circular dependency with SIL library by moving extendStoreBorrow(). 2022-10-27 15:29:37 -07:00
Andrew Trick d386d1ba05 Fix OSSA RAUW perform() to handle replaceAllUsesWith for terminators 2022-10-22 21:57:47 -07:00
Andrew Trick 40e03ef782 Update passes to use SSAPrunedLiveness or MultiDefPrunedLiveness 2022-10-04 13:27:47 -07:00
Andrew Trick ca503b54b7 Redesign PrunedLiveness APIs, introducing live ranges
First restore the basic PrunedLiveness abstraction to its original
intention. Move code outside of the basic abstraction that polutes the
abstraction and is fundamentally wrong from the perspective of the
liveness abstraction.

Most clients need to reason about live ranges, including the def
points, not just liveness based on use points. Add a PrunedLiveRange
layer of types that understand where the live range is
defined. Knowing where the live range is defined (the kill set) helps
reliably check that arbitrary points are within the boundary. This
way, the client doesn't need to be manage this on its own. We can also
support holes in the live range for non-SSA liveness. This makes it
safe and correct for the way liveness is now being used. This layer
safety handles:

- multiple defs
- instructions that are both uses and defs
- dead values
- unreachable code
- self-loops

So it's no longer the client's responsibility to check these things!

Add SSAPrunedLiveness and MultiDefPrunedLiveness to safely handle each
situation.

Split code that I can't figure out into
DiagnosticPrunedLiveness. Hopefully it will be deleted soon.
2022-10-04 13:27:44 -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
Michael Gottesman 1e6187c4f4 [sil] Update all usages of old API SILValue::getOwnershipKind() in favor of new ValueBase::getOwnershipKind().
Andy some time ago already created the new API but didn't go through and update
the old occurences. I did that in this PR and then deprecated the old API. The
tree is clean, so I could just remove it, but I decided to be nicer to
downstream people by deprecating it first.
2022-07-26 11:46:23 -07:00
Andrew Trick 9dba1c1fb5 Temporary fix for OSSA RAUW utilities.
This fix unblocks unrelated optimizer commits. A unit test will be
introduced with those commits.

The RAUW utility does not correctly handle reborrows. It is in the
middle of being rewritten. For now, simply bail out since this isn't
an important case to optimize.
2022-02-17 23:55:32 -08:00
Andrew Trick 1c8f142a73 OwnershipOptUtils - computeGuaranteedBoundary 2022-02-16 12:23:01 -08:00
Nate Chandler f8bcfe2328 [RAUW] Allow RAUWing some lexical values.
RAUWing a lexical value with a non-lexical value is illegal because it
would result in the value's lifetime being shortened without regard to
deinit barriers.  RAUWing _with_ a lexical value is LEGAL so long as
doing so doesn't extend its lifetime.
2022-02-10 16:28:41 -08:00
Nate Chandler 689c6ac37c [OwnershipOptUtils] Don't RAUW lexical values.
Replacing all uses of a lexical value with another value, even another
lexical value, may change the lifetime of the value in ways that aren't
permitted for a lexical lifetime.
2022-01-27 15:20:02 -08:00
Andrew Trick febde3da2f SemanticARCOpts fix - remove deadEndBlocks checks
SemanticARCOptVisitor::performGuaranteedCopyValueOptimization was
converting this SIL

    %borrow = begin_borrow %copiedValue
    %copy = copy_value %borrow
    %borrowCopy = begin_borrow %copy
    end_borrow %borrow
    end_borrow %borrowCopy
    destroy_value %copy
    // something something
    unreachable

into

    %borrow = begin_borrow %copiedValue
    %innerBorrow = begin_borrow %borrow
    end_borrow %borrow
    end_borrow %innerBorrow
    // something something
    unreachable

Dead-end blocks are simply irrelevant for this
optimization. Unfortunately, there were multiple layers of attempted
workarounds that were hiding the real problem, except in rare cases.

Thanks Nate Chandler for reducing the test.
2021-12-09 20:23:17 -08:00
Saleem Abdulrasool 910fbee14e gardening: make c++98-compat-extra-semi an error
This cleans up 90 instances of this warning and reduces the build spew
when building on Linux.  This helps identify actual issues when
building which can get lost in the stream of warning messages.  It also
helps restore the ability to build the compiler with gcc.
2021-11-27 11:40:17 -08:00
Andrew Trick f9d31ca116 InstructionDeleter ctor moves callbacks to fix iterator invalidation
The InstructionDeleter needs to move the callbacks during construction
to prevent the client code from using the old callbacks.

Fixes iterator invalidation bugs.
2021-11-18 11:38:08 -08:00
Andrew Trick c86d112891 Update #include for InstructionDeleter.h 2021-11-18 11:38:08 -08:00
swift-ci d034448e2d Merge pull request #40004 from meg-gupta/fixossautiledgecase 2021-11-17 19:41:28 -08:00
Meghana Gupta 4924b65bee In GuaranteedOwnershipExtension::Status::ExtendLifetime mode, also extend the borrow scope if needed 2021-11-01 15:04:02 -07:00
Meghana Gupta e9df26803b Add new api makeGuaranteedValueAvailable 2021-11-01 14:03:22 -07:00
Meghana Gupta 04293732cf Add new apis to OwnershipLifetimeExtender 2021-11-01 14:03:16 -07:00
Kuba Mracek 8158cdf5e5 Revert "Merge pull request #39805 from atrick/oou-opt-rauw"
This reverts commit df26a6d740, reversing
changes made to f9643fd3a2.
2021-10-22 12:29:10 -07:00
Andrew Trick 463922c386 Allow RAUW to optimize struct_extract from function args 2021-10-18 14:16:40 -07:00