Commit Graph

136 Commits

Author SHA1 Message Date
Nate Chandler
429de09f87 [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:26:21 -07:00
Slava Pestov
3b83ac30a1 SILOptimizer: Clean up existential archetype remapping in CSE 2025-04-28 13:47:53 -04: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
a31a603e49 Handle type_value instruction in CSE 2025-02-13 10:30:25 -08:00
Slava Pestov
63028be348 SILCloner: Redo local archetype remapping 2024-08-22 17:17:53 -04:00
Slava Pestov
39b4bda1dc AST: Introduce SubstFlags::SubstituteLocalArchetypes 2024-08-21 14:23:37 -04: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
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
Erik Eckstein
ad3178a403 CSE: fix checking convention of tuple apply results
We didn't catch the case where a function returns a tuple where at least one of the tuple elements is returned as `owned`.
In such a case the apply must not be cse'd.

Fixes a miscompile which results in an over-release.
rdar://121597250
2024-03-06 11:07:56 +01:00
Erik Eckstein
f8640e6ba6 CSE: visit uses of block arguments when replacing an open_existental_ref
Fixes a verifier crash.

rdar://122190393
2024-03-04 23:05:33 +01: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
Meghana Gupta
c8001d86b1 Add a wrapper type SelectEnumOperation
SelectEnumInstBase will be templated in the next commit.
Instead of using templated SelectEnumInstBase everywhere, introduce
a new wrapper type SelectEnumOperation.
2023-06-28 14:29:10 -07:00
Meghana Gupta
5d401fb70a Remove select_value SIL instruction 2023-06-13 14:13:43 -07:00
Erik Eckstein
56c09c3aed CSE: cse builtin "once" calls
`builtin "once"` calls are a result of inlining global accessors
2023-05-08 21:23:36 +02:00
Slava Pestov
d98484050b SILOptimizer: Fix bad hash calculation in CSE
Fixes rdar://problem/108045677.
2023-04-17 16:22:06 -04:00
Slava Pestov
66d601cc40 SILOptimizer: Teach CSE about scalar_pack_index, dynamic_pack_index, tuple_pack_element_addr 2023-04-12 17:33:31 -04:00
Erik Eckstein
8c05024ea6 SIL: move the SILInstruction::MemoryBehavior enum out of SILInstruction into the swift namespace 2023-03-21 15:33:09 +01:00
Anthony Latsis
d650ce47f3 SILOptimizer: Fix some issues with CSE of open_existential_ref
* A direct user might have a dependent result
* An indirect user can also be a terminator instruction
2023-03-13 21:41:02 +03:00
Nate Chandler
1a2b781d3e [CSE] Stack nest at OSSA lowering after inlining.
CSE inlines a portion of lazy property getters.

Now that in OSSA `partial_apply [on_stack]`s are represented as owned
values rather than stack locations, it is possible for their destroys to
violate stack discipline.  A direct lowering of the instructions to
non-OSSA would violate stack nesting.

Previously, when inlining during CSE, it was assumed that the callee
maintained stack discipline.  And, when inlining an OSSA function into a
non-OSSA function, OSSA instructions were lowered directly.  The result
was that stack discipline could be violated when directly lowering
callees with `partial_apply [on_stack]`s that violate stack discipline
upon direct lowering.

Here, when CSE inlining a lazy property getter in OSSA form into a
function lowered out of OSSA form, stack nesting is fixed up.
2023-03-01 11:46:06 -08:00
Meghana Gupta
a0d1b08dd5 Ensure isEqual and getHashValue() are in sync with an invariant in CSE 2023-02-23 12:07:33 -08:00
Meghana Gupta
619b4cd539 CSE: Don't look through ownership instructions for escaped values
CSE relies on OSSA RAUW for lifetime extension when replacing a redundant instruction.
OSSA RAUW however does not handle lifetime extension for escaped base values.
Values escape from ownership via pointer escape, bitwise escape, forwarding unowned operations
and have none or unowned ownership. For all such values do not look through ownership instructions
while determining equality. It is possible to CSE such values with equivalent operands, because the
operand use guarantees lifetime of the base operand.
2023-02-22 21:11:03 -08:00
Erik Eckstein
7d8bf37e5e change to the new llvm::Optional APIs
This is a follow-up of https://github.com/apple/swift/pull/62217
2023-01-25 09:18:36 +01:00
John McCall
d673a45c88 More opened-existential vs. local-archetype fixes in SIL 2023-01-11 03:11:30 -05:00
Erik Eckstein
f082584230 Use the new side effects in CSE 2022-12-21 17:41:46 +01:00
John McCall
f524f3de69 [NFC] Support instructions that define multiple opened archetypes
I've also fixed this so that it should work on instructions that
define multiple values.  Someday we'll change all the open_existential
instructions to produce different values for the type dependency and
the value result; today is not that day, though.
2022-12-13 13:28:13 -05:00
Erik Eckstein
ecbcacdecf SIL Analysis: Rename InvalidationKind::FunctionData to InvalidationKind::Effects
This invalidation kind is used when a compute-effects pass changes function effects.
Also, let optimization passes which don't change effects only invalidate the `FunctionBody` and not `Everything`.
2022-10-20 09:20:28 +02:00
Erik Eckstein
777b42180d SILOptimizer: use the new set data structures in various optimizations 2022-07-13 14:27:50 +02:00
Erik Eckstein
6b7ae416e6 SIL: remove unused instructions thin_function_to_pointer and pointer_to_thin_function 2022-03-25 15:44:59 +01:00
Anthony Latsis
60c85b0108 SILGen: Handle nested opened archetypes and add tests 2022-02-02 02:10:05 +03:00
Erik Eckstein
7c28d7a625 migrate SILInliner to use InstructionDeleter 2021-10-28 18:43:14 +02:00
Andrew Trick
d27d83a8f2 CSE/OSSA avoid endless cloning and reoptimization.
Prevent CSE from introducing useless copies, borrows, and
clones. Otherwise it will endlessly clone and re-cse the same
projections endlessly.

TODO: Most of these cases can be handled GuarateedOwnershipExtension
or extendOwnedLifetime without requiring any copies!
2021-10-13 21:56:46 -07:00
Meghana Gupta
7a35c478b6 CSE: While optimizing lazy property getters, don't inline non-ossa to ossa function (#38184)
Fixes rdar://79781904
2021-07-01 16:44:57 -07:00
Erik Eckstein
6ec788ff09 SIL: remove the SILOpenedArchetypesTracker
Instead, put the archetype->instrution map into SIlModule.

SILOpenedArchetypesTracker tried to maintain and reconstruct the mapping locally, e.g. during a use of SILBuilder.
Having a "global" map in SILModule makes the whole logic _much_ simpler.

I'm wondering why we didn't do this in the first place.

This requires that opened archetypes must be unique in a module - which makes sense. This was the case anyway, except for keypath accessors (which I fixed in the previous commit) and in some sil test files.
2021-04-14 08:36:10 +02:00
Slava Pestov
7ccc41a7b7 SIL: Preliminary support for 'apply [noasync]' calls
Refactor SILGen's ApplyOptions into an OptionSet, add a
DoesNotAwait flag to go with DoesNotThrow, and sink it
all down into SILInstruction.h.

Then, replace the isNonThrowing() flag in ApplyInst and
BeginApplyInst with getApplyOptions(), and plumb it
through to TryApplyInst as well.

Set the flag when SILGen emits a sync call to a reasync
function.

When set, this disables the SIL verifier check against
calling async functions from sync functions.

Finally, this allows us to add end-to-end tests for
rdar://problem/71098795.
2021-03-04 22:41:46 -05:00
Meghana Gupta
dd1c37ae91 CSE OSSA: Enable lookThroughOwnershipInsts for some more instructions 2021-02-15 13:43:58 -08:00
Erik Eckstein
542a378436 SIL: add FunctionRefInst::getReferencedFunction()
If we know that we have a FunctionRefInst (and not another variant of FunctionRefBaseInst), we know that getting the referenced function will not be null (in contrast to FunctionRefBaseInst::getReferencedFunctionOrNull).

NFC
2021-02-09 19:56:43 +01:00
Meghana Gupta
b854df0ebb CSE OSSA: look through ownership instructions for some additional instructions 2021-02-04 12:50:31 -08:00
Erik Eckstein
d33ea9f350 SIL: remove the JointPostDominanceSetComputer helper struct.
Instead make `findJointPostDominatingSet` a stand-alone function.
There is no need to keep the temporary SmallVector alive across multiple calls of findJointPostDominatingSet for the purpose of re-using malloc'ed memory. The worklist usually contains way less elements than its small size.
2021-02-02 10:20:35 +01:00
swift-ci
c0472afa76 Merge remote-tracking branch 'origin/main' into rebranch 2021-01-20 10:13:02 -08:00
Michael Gottesman
73ba521e56 [ownership] Add a new API to OwnershipFixupContext::replaceAllAddressUsesFixingInteriorPointerOwnership.
In OSSA, we enforce that addresses from interior pointer instructions are scoped
within a borrow scope. This means that it is invalid to use such an address
outside of its parent borrow scope and as a result one can not just RAUW an
address value by a dominating address value since the latter may be invalid at
the former. I foresee that I am going to have to solve this problem and so I
decided to write this API to handle the vast majority of cases.

The way this API works is that it:

1. Computes an access path with base for the new value. If we do not have a base
value and a valid access path with root, we bail.

2. Then we check if our base value is the result of an interior pointer
instruction. If it isn't, we are immediately done and can RAUW without further
delay.

3. If we do have an interior pointer instruction, we see if the immediate
guaranteed value we projected from has a single borrow introducer value. If not,
we bail. I think this is reasonable since with time, all guaranteed values will
always only have a single borrow introducing value (once struct, tuple,
destructure_struct, destructure_tuple become reborrows).

4. Then we gather up all inner uses of our access path. If for some reason that
fails, we bail.

5. Then we see if all of those uses are within our borrow scope. If so, we can
RAUW without any further worry.

6. Otherwise, we perform a copy+borrow of our interior pointer's operand value
at the interior pointer, create a copy of the interior pointer instruction upon
this new borrow and then RAUW oldValue with that instead. By construction all
uses of oldValue will be within this new interior pointer scope.
2021-01-17 20:08:24 -08:00
Michael Gottesman
fe4c345d0d [ownership] Make OwnershipFixupContext a dump context struct and instead put its RAUW functionality on OwnershipRAUWHelper.
The reason why I am doing this is that I am building up more utilities based on
passing around this struct of context that do not want it for RAUWing
purposes. So it makes sense on a helper (OwnershipRAUWHelper) that composes with
its state.

Just a refactor, should be NFC.
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
swift-ci
ad05509ac4 Merge remote-tracking branch 'origin/main' into rebranch 2021-01-13 20:32:34 -08:00
Michael Gottesman
ec50d03d76 [ownership] Rename OwnershipFixupContext::replaceAllUsesAndErase{FixingOwnership,}.
The class name is already OwnershipFixupContext... why do we need to include
FixingOwnership in its helpers... its redundant.
2021-01-13 10:43:41 -08:00
swift_jenkins
9f5e4e98f7 Merge remote-tracking branch 'origin/main' into next 2021-01-06 17:12:10 -08:00
Meghana Gupta
30ae4ade1d Fix CSE::processOpenExistentialRef
PR#34895 changed CSE to have common object for OpenedArchetypesTracker and Cloner.
CSE however frees and allocates instructions and this can result in the
Cloner having stale state for deleted instructions whose address may be
re-used while creating new instructions. Using a local object avoids
this.
2021-01-05 17:40:07 -08:00
swift_jenkins
189718aaef Merge remote-tracking branch 'origin/main' into next 2021-01-05 09:01:24 -08:00
Michael Gottesman
3361affe3d Merge pull request #35254 from meg-gupta/csefix1
[NFC] Simplify DenseMapInfo<SimpleValue>::isEqual in CSE
2021-01-04 16:39:40 -08:00
Meghana Gupta
badf0c1c07 [NFC] Simplify DenseMapInfo<SimpleValue>::isEqual in CSE
It is not correct to check if we support ownership rauwing of values in
the isEqual method. Move it to a later point in CSE
2021-01-04 13:26:56 -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