Commit Graph

11193 Commits

Author SHA1 Message Date
Gábor Horváth
40bea13e68 [6.2][cxx-interop] Delay lowering unowned convention until ownership elimination
Explanation: Unowned result conventions do not work well with OSSA. Retain the
result right after the call when we come out of OSSA so we can treat the
returned value as if it was owned when we do optimizations.

This fix a miscompilation due to the DestroyAddrHoisting pass hoisting destroys
above copies with unowned sources. When the destroyed object was the last
reference to the pointed memory the copy is happening too late resulting in
a use after free.

Issues: rdar://160462854
Original PRs: #84612
Risk: We change where retaining of the unowned return values
happen in the optimization pipeline. It is hard to anticipate all the
possible effects but it should make the optimizer more correct.
Testing: Added a compiler test.
Reviewers: @eeckstein, @atrick
2025-10-08 18:57:54 +01:00
Erik Eckstein
9081edd4c2 Optimizer: fix an ownership violation when duplicating loops
If a guaranteed value is used in a dead-end exit block and the enclosing value is _not_ destroyed in this block, we end up missing the enclosing value as phi-argument after duplicating the loop.
TODO: once we have complete lifetimes we can remove this check again.

rdar://159125605
2025-08-29 17:28:57 +02:00
nate-chandler
5f20a5b8b5 Merge pull request #83962 from nate-chandler/cherrypick/release/6.2/rdar158149082
6.2: [AllocBoxToStack] Don't destroy in dead-ends.
2025-08-28 14:26:38 -07:00
Nate Chandler
8e98bcfefd [AllocBoxToStack] Don't destroy in dead-ends.
It is valid to leak a value on paths into dead-end regions.
Specifically, it is valid to leak an `alloc_box`.  Thus, "final
releases" in dead-end regions may not destroy the box and consequently
may not release its contents.  Therefore it's invalid to lower such final
releases to `dealloc_stack`s, let alone `destroy_addr`s.  The in-general
invalidity of that transformation results in miscompiling whenever a box
is leaked and its projected address is used after such final releases.

Fix this by not treating final releases as boundary markers of the
`alloc_box` and not lowering them to `destroy_addr`s and
`dealloc_stack`s.

rdar://158149082
2025-08-27 17:12:51 -07:00
Erik Eckstein
bf3a05b7a5 SILCombine: fix convert_function -> apply peephole for generic function types
Currently we cannot deal with generic arguments/returns. Bail in this case.

Fixes a compiler crash
rdar://158809851
2025-08-27 17:39:12 +02:00
Jamie
3c3f837830 [SILOptimizer]: fix some missing use after consume diagnostics
Updates ConsumeOperatorCopyableValuesChecker to identify store_borrow
instructions as a liveness-affecting use so that patterns that would
previously slip through undiagnosed are correctly identified. e.g.

```swift
func use<V>(_ v: borrowing V) {}

func f() {
  let a = A()
  _ = consume a
  use(a) // previously would not be diagnosed
}
```

(cherry picked from commit 754a3007d5)
2025-08-04 12:30:06 -05:00
Michael Gottesman
64a53b483e Merge pull request #83084 from gottesmm/release/6.2-rdar155905383
[6.2][concurrency] Make optimize hop to executor more conservative for 6.2 around caller isolation inheriting functions.
2025-07-17 22:04:17 -07:00
Michael Gottesman
48b88b0847 [micro-opt] Flip a check to improve perf. 2025-07-16 12:18:40 -07:00
Michael Gottesman
348720b830 Revert "[rbi] Treat a partial_apply as nonisolated(unsafe) if all of its captures are nonisolated(unsafe)."
This reverts commit 6ce93c8a37.
2025-07-16 09:58:09 -07:00
Michael Gottesman
182149978e [concurrency] Make optimize hop to executor more conservative for 6.2 around caller isolation inheriting functions.
Specifically for 6.2, we are making optimize hop to executor more conservative
around caller isolation inheriting functions. This means that we are:

1. No longer treating calls to caller isolation inheriting functions as having a
hop in their prologue. In terms of this pass, it means that when determining
dead hop to executors, we no longer think that a caller isolation inheriting
function means that an earlier hop to executor is not required.

2. Treating returns from caller isolation inheriting callees as requiring a
hop. The reason why we are doing this is that we can no longer assume that our
caller will hop after we return.

Post 6.2, there are three main changes we are going to make:

* Forward Dataflow

Caller isolation inheriting functions will no longer be treated as suspension
points meaning that we will be able to propagate hops over them and can assume
that we know the actor that we are on when we enter the function. Practically
this means that trees of calls that involve just nonisolated(nonsending) async
functions will avoid /all/ hop to executor calls since we will be able to
eliminate all of them since the dataflow will just propagate forward from the
entrance that we are already on the actor.

* Backwards Dataflow

A caller isolation inheriting call site will still cause preceding
hop_to_executor functions to be live. This is because we need to ensure that we
are on the caller isolation inheriting actor before we hit the call site. If we
are already on that actor, the hop will be eliminated by the forward pass. But
if the hop has not been eliminated, then the hop must be needed to return us to
the appropriate actor.

We will also keep the behavior that returns from a caller isolation inheriting
function are considered to keep hop to executors alive. If we were able to
propagate to a hop to executor before the return inst with the forward dataflow,
then we know that we are guaranteed to still be on the relevant actor. If the
hop to executor is still there, then we need it to ensure that our caller can
treat the caller isolation inheriting function as a non-suspension point.

rdar://155905383
(cherry picked from commit b3942424c8)
2025-07-15 17:32:19 -07:00
Meghana Gupta
8f00bc4fe8 Bailout from an illegal transformation in semantic arc opts
tryJoinIfDestroyConsumingUseInSameBlock replaces a copy with its operand
when there is no use of the copy's operand between the copy's forwarded consuming use
and the copy operand's destroy in the same block. It is illegal to do this transformation
when there is a non-consuming use of the copy operand after the forwarded consuming use of the copy.

The code checking this illegal case was not considerin the case where the consuming use of the copy
was in the same instruction as the non-consuming use of the copy operand.

rdar://154712867
2025-07-15 03:41:05 -07:00
Meghana Gupta
cfe2a7030f Merge pull request #82963 from meg-gupta/disablefso2
[6.2] Disable function signature optimization on functions with lifetime dependencies
2025-07-14 15:36:46 -07:00
Michael Gottesman
187b1eedf7 Merge pull request #82776 from gottesmm/release/6.2-154139237
[6.2] [nonisolated-nonsending] Make the AST not consider nonisolated(nonsending) to be an actor isolation crossing point.
2025-07-14 13:19:55 -07:00
Meghana Gupta
6e2065106e Merge pull request #82974 from meg-gupta/disablerrnccp
[6.2] Disable retain and release sinking when rc root values are ~Copyable
2025-07-14 12:48:27 -07:00
Meghana Gupta
212e55e055 [6.2] Fix SILCombine of inject_enum_addr when the enum is non-trivial but payload is trivial 2025-07-10 17:17:25 -07:00
Meghana Gupta
5c85c65278 Disable retain and release sinking when rc root values are ~Copyable 2025-07-10 16:13:13 -07:00
Meghana Gupta
1e6f93e0e1 Disable function signature optimization on functions with lifetime dependencies
If a function has lifetime dependencies, disable FSO's dead param optimization. Dead params maybe dependency sources and we should not delete them. It is also problematic to dead code params that are not dependency sources, since lifetime dependent sources are stored as indices and deleting dead parameters will require recomputation of these indices.
2025-07-10 11:35:23 -07:00
Michael Gottesman
f920aba2f9 [rbi] Use interned StringRefs for diagnostics instead of SmallString<64>.
This makes the code easier to write and also prevents any lifetime issues from a
diagnostic outliving the SmallString due to diagnostic transactions.

(cherry picked from commit 010fa39f31)
2025-07-09 12:25:06 -07:00
Michael Gottesman
85fafa5b1e [rbi] Begin tracking if a function argument is from a nonisolated(nonsending) parameter and adjust printing as appropriate.
Specifically in terms of printing, if NonisolatedNonsendingByDefault is enabled,
we print out things as nonisolated/task-isolated and @concurrent/@concurrent
task-isolated. If said feature is disabled, we print out things as
nonisolated(nonsending)/nonisolated(nonsending) task-isolated and
nonisolated/task-isolated. This ensures in the default case, diagnostics do not
change and we always print out things to match the expected meaning of
nonisolated depending on the mode.

I also updated the tests as appropriate/added some more tests/added to the
SendNonSendable education notes information about this.

(cherry picked from commit 14634b6847)
2025-07-09 12:25:03 -07:00
Michael Gottesman
ca8cdc1fd7 [rbi] Thread through a SILFunction into print routines so we can access LangOpts.Features so we can change how we print based off of NonisolatedNonsendingByDefault.
We do not actually use this information yet though... This is just to ease
review.

(cherry picked from commit 4433ab8d81)
2025-07-09 12:24:17 -07:00
Michael Gottesman
0ec2527bdc [rbi] Wrap use ActorIsolation::printForDiagnostics with our own SILIsolationInfo::printActorIsolationForDiagnostics.
I am doing this so that I can change how we emit the diagnostics just for
SendNonSendable depending on if NonisolatedNonsendingByDefault is enabled
without touching the rest of the compiler.

This does not actually change any of the actual output though.

(cherry picked from commit 4ce4fc4f95)
2025-07-09 12:24:17 -07:00
Anthony Latsis
f5d547cd44 AST: Cut down on DescriptiveDeclKind usage in DiagnosticsSIL.def
(cherry picked from commit 5c190b9613)
2025-07-09 12:24:17 -07:00
Michael Gottesman
f24ff98f9a [nonisolated-nonsending] Make the AST not consider nonisolated(nonsending) to be an actor isolation crossing point.
We were effectively working around this previously at the SIL level. This caused
us not to obey the semantics of the actual evolution proposal. As an example of
this, in the following, x should not be considered main actor isolated:

```swift
nonisolated(nonsending) func useValue<T>(_ t: T) async {}
@MainActor func test() async {
  let x = NS()
  await useValue(x)
  print(x)
}
```

we should just consider this to be a merge and since useValue does not have any
MainActor isolated parameters, x should not be main actor isolated and we should
not emit an error here.

I also fixed a separate issue where we were allowing for parameters of
nonisolated(nonsending) functions to be passed to @concurrent functions. We
cannot allow for this to happen since the nonisolated(nonsending) parameters
/could/ be actor isolated. Of course, we have lost that static information at
this point so we cannot allow for it. Given that we have the actual dynamic
actor isolation information, we could dynamically allow for the parameters to be
passed... but that is something that is speculative and is definitely outside of
the scope of this patch.

rdar://154139237
(cherry picked from commit c12c99fb73)
2025-07-09 12:24:17 -07:00
nate-chandler
0cd265d0f8 Merge pull request #82903 from nate-chandler/cherrypick/release/6.2/rdar155059418
6.2: [ODL] Visit objc_method insts.
2025-07-09 11:16:10 -07:00
Michael Gottesman
5361765212 Merge pull request #82428 from gottesmm/release/6.2-144111950
[6.2][rbi] Treat a partial_apply as nonisolated(unsafe) if all of its captures are nonisolated(unsafe).
2025-07-09 11:06:52 -07:00
Doug Gregor
1d86ed5f15 [Region analysis] Simplify logic for dynamic casts by making them less special
Extend and use SILIsolationInfo::getConformanceIsolation() for the dynamic
cast instructions.
2025-07-08 17:33:33 -07:00
Doug Gregor
066fa0b828 [Region isolation] Re-simplify handling of init_existential* instructions
Centralize the logic for figuring out the conformances for the various
init_existential* instructions in a SILIsolationInfo static method, and
always go through that when handling "assign" semantics. This way, we
can use CONSTANT_TRANSLATION again for these instructions, or a simpler
decision process between Assign and LookThrough.

The actually undoes a small change made earlier when we stopped looking
through `init_existential_value` instructions. Now we do when there are
no isolated conformances.
2025-07-08 17:33:33 -07:00
Doug Gregor
22ca6b98e5 [Region isolation] Factor SILIsolationInfo creation into static methods
Better match the style of SILIsolationInfo by moving the code for determining
SILIsolationInfo from conformances or dynamic casts to existentials into
static `getXYZ` methods on SILIsolationInfo.

Other than adding an assertion regarding disconnected regions, no
intended functionality change.
2025-07-08 17:33:33 -07:00
Doug Gregor
6637960bdc [SE-0470] Track the potential introduction of isolated conformances in regions
When we introduce isolation due to a (potential) isolated conformance,
keep track of the protocol to which the conformance could be
introduced. Use this information for two reasons:

1. Downgrade the error to a warning in Swift < 7, because we are newly
diagnosing these
2. Add a note indicating where the isolated conformance could be introduced.

(cherry picked from commit 02c34bb830)
2025-07-08 17:32:06 -07:00
Doug Gregor
900a4cc90f Extend region analysis to account for isolated conformances
When a conformance becomes part of a value, and that conformance could
potentially be isolated, the value cannot leave that particular
isolation domain. For example, if we perform a runtime lookup for a
conformance to P as part of a dynamic cast `as? any P`, the
conformance to P used in the cast could be isolated. Therefore, it is
not safe to transfer the resulting value to another concurrency domain.

Model this in region analysis by considering whether instructions that
add conformances could end up introducing isolated conformances. In
such cases, merge the regions with either the isolation of the
conformance itself (if known) or with the region of the task (making
them task-isolated). This prevents such values from being sent.

Note that `@concurrent` functions, which never dynamically execute on
an actor, cannot pick up isolated conformances.

Fixes issue #82550 / rdar://154437489

(cherry picked from commit 62770ff2d7)
2025-07-08 17:29:52 -07:00
Nate Chandler
ba0b2e7c51 [ODL] Visit objc_method insts.
No update is needed for the values they produce.  This pass should
really be refactored not to crash on instructions that aren't explicitly
listed or at least not to compile if not every instruction is listed.

rdar://155059418
2025-07-08 17:24:41 -07:00
Michael Gottesman
6ce93c8a37 [rbi] Treat a partial_apply as nonisolated(unsafe) if all of its captures are nonisolated(unsafe).
rdar://144111950
(cherry picked from commit 010443c854)
2025-07-08 13:35:52 -07:00
Erik Eckstein
33c91065b7 Optimizer: add var insertedPhis in SSAUpdater 2025-07-04 20:37:45 +02:00
nate-chandler
dd6813f1b8 Merge pull request #82788 from nate-chandler/cherrypick/release/6.2/rdar153693915
6.2: [Mem2Reg] Don't promote proj(unchecked_addr_cast).
2025-07-04 00:20:11 -07:00
eeckstein
bf3dd8c577 Merge pull request #82764 from eeckstein/fix-mandatory-perf-opt-6.2
[6.2] MandatoryPerformanceOptimizations: don't de-virtualize a generic class method call to specialized method
2025-07-04 07:54:01 +02:00
Nate Chandler
211299d4d2 [Mem2Reg] Don't promote proj(unchecked_addr_cast).
In OSSA, the result of an `unchecked_bitwise_cast` must immediately be
copied or `unchecked_bitwise_cast`'d again.  In particular, it is not
permitted to borrow it.  For example, the result can't be borrowed for
the purpose of performinig additional projections (`struct_extract`,
`tuple_extract`) on the borrowed value.  Consequently, we cannot promote
an address if such a promotion would result in such a pattern.  That
means we can't promote an address `%addr` which is used like
`struct_element_addr(unchecked_addr_cast(%addr))` or
`tuple_element_addr(unchecked_addr_cast(%addr))`.  We can still promote
`unchecked_addr_cast(unchecked_addr_cast(%addr))`.

In ownership-lowered SIL, this doesn't apply and we can still promote
address with such projections.

rdar://153693915
2025-07-03 15:32:41 -07:00
Erik Eckstein
849a5e9082 MandatoryPerformanceOptimizations: don't de-virtualize a generic class method call to specialized method
This results in wrong argument/return calling conventions.
First, the method call must be specialized. Only then the call can be de-virtualized.
Usually, it's done in this order anyway, because the `class_method` instruction is located before the `apply`.
But when inlining functions, the order (in the worklist) can be the other way round.

Fixes a compiler crash.
rdar://154631438
2025-07-03 13:21:27 +02:00
Erik Eckstein
a538252a77 MoveOnlyWrappedTypeEliminator: handle EndCOWMutationAddr
fixes a compiler crash
rdar://154416511
2025-07-03 13:10:00 +02:00
Nate Chandler
b730144497 [CSE] Fix combine of type_value.
The instruction has no operands but has a param type.  Hash and compare
the type and the type and the param type.

rdar://154652254
2025-07-01 14:30:59 -07:00
eeckstein
8c47b59d7d Merge pull request #82560 from eeckstein/fix-closure-specializer-6.2
[6.2] ClosureSpecializer: don't specialize captures of stack-allocated Objective-C blocks
2025-06-30 18:18:10 +02:00
nate-chandler
9b8e749027 Merge pull request #82573 from nate-chandler/cherrypick/release/6.2/rdar154407327
6.2: [DestroyAddrHoisting] Don't fold into read access.
2025-06-27 19:35:58 -07:00
Nate Chandler
9acdc921e0 [DestroyAddrHoisting] Don't fold into read access.
Narrowly fix a long-standing bug where destroy_addrs would be hoisted
into read access scopes, leaving the scope as a read despite the fact
that it modifies memory.  This is a problem for utilities which expect
access scopes to provide correct summaries.  Do this by refusing to fold
into access scopes which are marked `[read]`.

In a follow-up, we can reenable this folding, promoting each access
scope to a modify.  Doing so requires checking that there are no access
scopes which overlap with any of the access scopes which would be
promoted to modify.

rdar://154407327
2025-06-27 11:54:19 -07:00
Erik Eckstein
995264913f ClosureSpecializer: don't specialize captures of stack-allocated Objective-C blocks
Bail if the closure captures an ObjectiveC block which might _not_ be copied onto the heap, i.e optimized by SimplifyCopyBlock.
We can't do this because the optimization inserts retains+releases for captured arguments.
That's not possible for stack-allocated blocks.

Fixes a mis-compile
rdar://154241245
2025-06-27 20:08:51 +02:00
Erik Eckstein
728f37abf0 SemanticARCOpts: don't ignore dead-end blocks in the liverange analysis
This can result in wrong ARC optimizations in dead-end blocks.
Fixes a SIL verification error.

rdar://154356277
2025-06-27 07:03:23 +02:00
Andrew Trick
2052d2c61e Fix MoveOnlyObjectCheckerPImpl::check() for mark_dependence.
Handle the presence of mark_dependence instructions after a begin_apply.

Fixes a compiler crash:
"copy of noncopyable typed value. This is a compiler bug. ..."

(cherry picked from commit 7a29d9d8b6)
2025-06-24 12:54:39 -07:00
Andrew Trick
4cd7f450a3 Fix MoveOnlyObjectCheckerPImpl::check() changed flag
Extract the special pattern matching logic that is otherwise unrelated to the
check() function. This makes it obvious that the implementation was failing to
set the 'changed' flag whenever needed.

(cherry picked from commit c41715ce8c)
2025-06-24 12:54:39 -07:00
Andrew Trick
1fa15f23fe Fix SILCombine of MarkDependenceInst.
Do not eliminate a mark_dependence on a begin_apply scope even though the token
has a trivial type.

Ideally, token would have a non-trivial Builtin type to avoid special cases.

(only relevant on 6.2)
2025-06-24 12:54:39 -07:00
Jamie
11525cabf8 [SILOptimizer]: slow OSSA lifetime canonicalization mitigation
OSSA lifetime canonicalization can take a very long time in certain
cases in which there are large basic blocks. to mitigate this, add logic
to skip walking the liveness boundary for extending liveness to dead
ends when there aren't any dead ends in the function.

Updates `DeadEndBlocks` with a new `isEmpty` method and cache to
determine if there are any dead-end blocks in a given function.

(cherry picked from commit 1f3f830fc7)
2025-06-22 18:08:06 -05:00
Meghana Gupta
2bbc1c393c Merge pull request #82224 from meg-gupta/fixinlinercrashcp
[6.2] Fix an inliner crash when inlining begin_apply with scoped lifetime dependence
2025-06-13 23:06:36 -07:00
Meghana Gupta
d5b82a3b7c [6.2] Fix an inliner crash when inlining begin_apply with scoped lifetime dependence 2025-06-13 14:18:29 -07:00