Commit Graph

94 Commits

Author SHA1 Message Date
Evan Wilde
250082df25 [NFC] Reformat all the LLVMs
Reformatting everything now that we have `llvm` namespaces. I've
separated this from the main commit to help manage merge-conflicts and
for making it a bit easier to read the mega-patch.
2023-06-27 09:03:52 -07:00
Evan Wilde
f3ff561c6f [NFC] add llvm namespace to Optional and None
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
                     bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".

I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
2023-06-27 09:03:52 -07:00
Meghana Gupta
28df449d38 Merge pull request #66723 from meg-gupta/improvefindpointerescape
Refactor swift::findPointerEscape and handle additional cases
2023-06-21 21:04:21 -07:00
Meghana Gupta
031255c2d8 Rename hasPointerEscape -> findPointerEscape 2023-06-20 21:13:55 -07:00
Meghana Gupta
7cb3733e29 Rename OwnershipForwardingMixin -> ForwardingInstruction 2023-06-14 10:40:32 -07:00
Meghana Gupta
5d401fb70a Remove select_value SIL instruction 2023-06-13 14:13:43 -07:00
Meghana Gupta
1dc713e2f7 Add new flags "reborrow" and "escaping" to SILArgument.
"reborrow" flag on the SILArgument avoids transitive walk over the phi operandsi
to determine if it is a reborrow in multiple utilities.
SIL transforms must keep the flag up-to-date by calling SILArgument::setReborrow.
SILVerifier checks to ensure the flag is not invalidated.

Currently "escaping" is not used anywhere.
2023-05-11 12:31:37 -07:00
Nate Chandler
2163269f88 [SemanticARCOpts] Check uses in moved load range.
In https://github.com/apple/swift/pull/65417 , support for promoting
moved-from `load [copy]`s was added.  At that time, the existing logic
was generalized so that the check for whether writes the loaded-from
address occurred: rather than checking whether the writes occurred in
the live-range of the `load [copy]`, it was generalized to check whether
writes occurred in the live range of the "original" value which was
either the `load [copy]` or the `move_value`.  That opened a hole for
writes that occurred between the `load [copy]` and the `move_value`:

```
%v = load [copy] %a
%u = load [take] %a
%m = move_value %v
```

Here, this is fixed by checking both the live-range of the "original"
and also (supposing the original is different from the `load [copy]`)
also the live range of the `load [copy]`.

This required changing the list of consuming uses passed to the
`LinearLifetimeChecker::usesNotContainedWithinLifetime` to include not
just the `destroy_value`s but also the "unknown" consuming uses (i.e.
those that are not forwarding).

This change only affects arguments (and specifically only `@inout`
arguments since promotion for `@in` arguments isn't supported) because a
totally different code path is followed for `alloc_stack`s which regards
`load [take]`s as an "init" of the address (concretely,
`getSingleInitAllocStackUse` returns `truea for the above example if `%a` is
an `alloc_stack`).

rdar://108745323
2023-05-01 18:30:22 -07:00
Nate Chandler
f039d40086 [SemanticARCOpts] Load_borrow moved load [copy]s.
In the context of promoting a `load [copy]` to a `load_borrow`, allow
the value representing the lifetime of the load to differ from the `load
[copy]` itself--it may either be the load or its only user.

If promoting the `load [copy]` to a `load_borrow` with the load itself
as the lifetime representative fails, look for a single `move_value` use
of the load.  If found, attempt the optimization again with the
`move_value` as the lifetime representative.

rdar://108514447
2023-04-25 11:37:30 -07:00
Nate Chandler
8287d2e9ef [SemanticARC] NFC: Extracted opt from visit.
In preparation to attempt two variations of the optimization, added
performLoadCopyToLoadBorrowOptimization and call it from visitLoadInst.
2023-04-25 11:37:30 -07:00
Nate Chandler
b686e81085 [OwnershipUtils] Add move as OwnedValueIntroducer. 2023-04-25 11:37:30 -07:00
Nate Chandler
a4ac481ecb [SemanticARCOpts] Keep owned lexical lifetimes.
Prevent joining lifetimes of copies with destroyed owned lexical values
if there may be deinit barriers between the final consume of the copy
and the destroy of the lexical value.

rdar://108014714
2023-04-13 14:36:37 -07:00
Andrew Trick
26a62645b4 Fix MandatoryARCOpts tryJoiningCopyValueLiveRangeWithOperand.
Fix a miscompile in Debug builds at -Onone.

This optimization ignores uses of owned values that aren't enclosed in
borrow scopes. This is fairly eggregious since project_box
instructions are never borrowed, which means that all local variables
have this problem.

This is a well-known issue that occurs throughout OSSA
optimizations. The reason that we don't see the problem often is that
the optimizations are hidden behind a pile of ad-hoc pattern matching,
so they only kick in for simple cases. This approach to optimization
is great at hiding problems for a long time.

We're attempting to design away this class of problems in the next
release. Until then, it's one miscompile at a time.

Fixes rdar://107420448 (Variable mutation in block isn't reflected
in outer scope: new behavior in swift 5.9)
2023-03-31 20:33:53 -07:00
swift-ci
095d84dc48 Merge pull request #64440 from meg-gupta/disablesemarcoptsedgecase
Disable owned to guaranteed phi transformation when the borrow introducers have a local scope
2023-03-17 12:10:20 -07:00
Meghana Gupta
21e829bace Disable owned to guaranteed phi transformation when the borrow introducers have a local scope
In the absence of this bailout, reborrows can be introduced while replacing the @owned value with
a local borrow introducer. Since lifetime adjustment for this case was not implemented, disable here.

rdar://106757446
2023-03-17 09:43:08 -07:00
Nate Chandler
ceb941d1d1 [NFC] Extracted isRedundantMoveValue.
Extracted the predicate from inline in RedundantMoveValueElimination
into the new function which can now be called from elsewhere
(CopyPropagation).
2023-03-15 07:38:59 -07:00
Nate Chandler
5f561ed596 [SAO] Add RedundantMoveValueElimination.
Adds to SemanticARCOpts a new step of removing move_value instructions
if they are redundant.  A move_value is redundant if it adds no new
information or optimization opportunities.

An example of adding information: a lifetime becoming lexical.  The new
lifetime's destroys cannot be hoisted over deinit barriers.

An example of adding an optimization opportunity: the original value
escapes but the value produced by the move_value does not escape.  So
destroys of the new value can be hoisted more aggressively.
2023-03-10 10:49:53 -08:00
Andrew Trick
103a6fefb8 LinearLifetimeChecker - make DeadEndBlocks optional 2023-03-01 21:41:46 -08:00
Meghana Gupta
b10563909c Update isGuaranteedForwarding api and delete isGuaranteedForwardingPhi api 2022-12-13 12:51:25 -08: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
Erik Eckstein
ab1b343dad use new llvm::Optional API
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`

The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.

rdar://102362022
2022-11-21 19:44:24 +01:00
Meghana Gupta
730b513fad [SemanticARCOpts] Remove unnecessary borrow scope for @guaranteed function arg when used as a phi operand 2022-10-21 22:31:04 -07:00
Meghana Gupta
9b01b87b4b Update SemanticARCOpts for @guaranteed forwarding phi support 2022-10-19 19:54:28 -07:00
Andrew Trick
6346bf55c5 Rename areUsesWithinTransitiveScope to ...ExtendedScope
Start using consistent terminolfy in ownership utils.

A transitive use set follows transitive uses within an ownership
lifetime. It does not rely on complete inner scopes. An extended use
set is not necessarilly transitive but does look across
lifetime-ending uses: copies of owned values and/or reborrows of
guaranteed values. Whether lifetime extension refers to copies or
reborrow is context dependent.
2022-10-04 13:27:48 -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
Nate Chandler
46fe0f7128 [Gardening] Tweaked comment grammar. 2022-08-21 21:44:31 -07:00
Nate Chandler
b467319cce [NFC] Removed unused variable. 2022-08-21 21:44:30 -07: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
Meghana Gupta
1f9ffc07ee Fix OwnershipLiveRange for @owned values getting transformed to none values via switch_enum (#60101) 2022-07-18 16:22:01 -07:00
Meghana Gupta
dc9308e13b Rename areUsesWithinLocalScope -> areUsesWithinTransitiveScope 2022-06-24 21:32:04 -07:00
Andrew Trick
64ec981f3b Rename isDirectlyForwarding to preservesOwnership. 2022-04-12 22:23:17 -07:00
Nate Chandler
a1c1b32a8c [MemAccessUtils] Added RelativeAccessStorageWithBase.
The new "relative" version of AccessStorageWithBase carries additional
information about the walk from the specified address back to the base.
For now, that includes the original address and the most transformative
sort of cast that was encountered.
2022-03-14 09:46:02 -07:00
Andrew Trick
05224aaa1f Improve the SILInstruction::getOperandValues() API.
Add NonTypeDependentOperandToValue predicate for composability.

Add a getNonTypeDependentOperandValues(), which can be used as a functor.

The skipTypeDependentOperands parameter complicated the API.
2022-02-15 13:24:29 -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
Nate Chandler
f0bd5839a2 [OwnershipUtils] Extracted utility for common use.
Promoted isRedundantLexicalBeginBorrow function to OwnershipUtils so
that it can be used in more than just SemanticARCOpts.
2021-12-07 17:51:18 -08:00
Nate Chandler
75b351eda0 [Gardening] Updated comment. 2021-12-07 17:04:49 -08:00
Nate Chandler
5e8f369d06 [Gardening] Merged two conditions. 2021-12-07 17:04:49 -08:00
Nate Chandler
bfd78d669b [SemanticARCOpts] Strip some lexical borrow scopes.
If a value's lifetime is preserved by a different lexical scope, it is
fine to strip a different scope.  Specifically, if it is preserved by
being a guaranteed argument or a nested borrow of an outer lexical
scope, allow a lexical borrow scope to be stripped.
2021-12-07 09:43:58 -08:00
Michael Gottesman
8e5fb2164a [sil] Ban casting AnyObject with a guaranteed ownership forwarding checked_cast_br and fix up semantic-arc-opts given that.
The reason why I am doing this is that currently checked_cast_br of an AnyObject
may return a different value due to boxing. As an example, this can occur when
performing a checked_cast_br of a __SwiftValue(AnyHashable(Klass())).

To model this in SIL, I added to OwnershipForwardingMixin a bit of information
that states if the instruction directly forwards ownership with a default value
of true. In checked_cast_br's constructor though I specialize this behavior if
the source type is AnyObject and thus mark the checked_cast_br as not directly
forwarding its operand. If an OwnershipForwardingMixin directly forwards
ownership, one can assume that if it forwards ownership, it will always do so in
a way that ensures that each forwarded value is rc-identical to whatever result
it algebraically forwards ownership to. So in the context of checked_cast_br, it
means that the source value is rc-identical to the argument of the success and
default blocks.

I added a verifier check to CheckedCastBr that makes sure that it can never
forward guaranteed ownership and have a source type of AnyObject.

In SemanticARCOpts, I modified the code that builds extended live ranges of
owned values (*) to check if a OwnershipForwardingMixin is directly
forwarding. If it is not directly forwarding, then we treat the use just as an
unknown consuming use. This will then prevent us from converting such an owned
value to guaranteed appropriately in such a case.

I also in SILGen needed to change checked_cast_br emission in SILGenBuilder to
perform an ensurePlusOne on the input operand (converting it to +1 with an
appropriate cleanup) if the source type is an AnyObject. I found this via the
verifier check catching this behavior from SILGen when compiling libswift. This
just shows how important IR verification of invariants can be.

(*) For those unaware, SemanticARCOpts contains a model of an owned value and
all forwarding uses of it called an OwnershipLiveRange.

rdar://85710101
2021-11-29 15:39:00 -08: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
Andrew Trick
8996fb8af2 Add functionality to the OSSA BorrowedValue utility.
This abstraction is heavily used to ask about the current borrow scope
enclosing some uses. Give it the functionality it needs.

Add BorrowedValue::computeLiveness(PrunedLiveness). Get the borrow
scope's live range. A trivial 4-line implementation.

Cleanup BorrowedValue::areUsesWithinScope(). Quick check to see if a set
of uses known to be dominated by the borrow are within the borrow scope.

Add BorrowedValue::hasReborrow(). Is this local borrow scope
reborrowed? If not, then it's local scope-ending operations are the
end of its required lifetime.

Simplify BorrowedValue::gatherReborrows() to use OperandOwnership::Reborrow.
2021-10-06 15:48:08 -07:00
Meghana Gupta
22c288942b Fix OOB access in SemanticARCOpts (#39351) 2021-09-22 18:17:41 -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
Michael Gottesman
5f69bf583c [semantic-arc] Ignore type dependent uses when using a worklist to check for writes.
Otherwise, we hit misc crashes. The worklist should have always been filtering
these. I wonder why we have never hit this issue before.

I added a new API that filters out type dependent uses called
ValueBase::getNonTypeDependentUses() to make it easier to perform def->use
worklist traversal ignoring these uses. This mirrors the APIs that we have
created for filtering type dependent operands when performing use->def worklist
traversal.

I also noticed that we are not eliminating a load [copy] that we could in the
test case. I am going to file a separate bug report for that work.

rdar://79781943
2021-07-07 16:00:14 -07:00
Andrew Trick
573df892e7 Fix BorrowingOperand more.
Don't allow an owned call argument to be considered a valid BorrowingOperand.

More generally, make sure there is a perfect equivalence between valid
BorrowingOperand and the corresponding OperandOwnership kind.
2021-06-30 15:20:19 -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
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
Michael Gottesman
85de7c9970 [semantic-arc] Add a comment dexplaining that isSingleInitAllocStack does not necessarily contain operands of destroy_addr now that it handles checked_cast_addr_br, unchecked_checked_cast_addr. 2021-03-29 12:16:49 -07:00
Andrew Trick
b689b1dabe Rename GuaranteedARCOpts to MandatoryARCOpts.
This bleeds into the implementation where "guaranteed" is used
everywhere to talk about optimization of guaranteed values. We need to
use mandatory to indicate we're talking about the pass pipeline.
2021-03-02 22:20:13 -08:00
Michael Gottesman
62d554669c [ownership] Rename OwnershipForwardingMixin::{get,set}OwnershipKind() -> {get,set}ForwardingOwnershipKind().
TLDR: This is just an NFC rename in preparation for changing
SILValue::getOwnershipKind() of any forwarding instructions to return
OwnershipKind::None if they have a trivial result despite forwarding ownership
that isn't OwnershipKind::None (consider an unchecked_enum_data of a trivial
payload from a non-trivial enum).

This ensures that one does not by mistake use this routine instead of
SILValue::getOwnershipKind(). The reason why these two things must be
distinguished is that the forwarding ownership kind of an instruction that
inherits from OwnershipForwardingMixin is explicitly not the ValueOwnershipKind
of the result of the instruction. Instead it is a separate piece of state that:

1. For certain forwarding instructions, defines the OwnershipConstraint of the
forwarding instruction.

2. Defines the ownership kind of the result of the value. If the result of the
value is non-trivial then it is exactly the set ownership kind. If the result is
trivial, we use OwnershipKind::None instead. As an example of this, consider an
unchecked_enum_data that extracts from a non-trivial enum a trivial payload:

```
enum Either {
case int(Int)
case obj(Klass)
}

%1 = load_borrow %0 : $*Either
%2 = unchecked_enum_data %1 : $Either, #Either.int!enumelt.1 // Int type
end_borrow %1 : $Either
```

If we were to identify the forwarding ownership kind (guaranteed) of
unchecked_enum_data with the value ownership kind of its result, we would
violate ownership since we would be passing a guaranteed value to the operand of
the unchecked_enum_data that will only accept values with
OwnershipKind::None. =><=.
2021-02-04 16:53:50 -08:00