-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimizer: Rework peephole optimizations to replace existential (archetypes) with concrete types #79674
Optimizer: Rework peephole optimizations to replace existential (archetypes) with concrete types #79674
Conversation
@swift-ci test |
@swift-ci benchmark |
@swift-ci apple silicon benchmark |
@swift-ci test source compatibility |
@@ -28,6 +28,15 @@ public struct SubstitutionMap: CustomStringConvertible { | |||
public init() { | |||
self.bridged = BridgedSubstitutionMap() | |||
} | |||
|
|||
public init(forGenericSignatureOf functionType: CanonicalType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should just take a generic signature and not a generic function type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have GenericSignature bridged to Swift yet. I can do this in a follow up PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, I included it in this PR
I haven't looked at the new implementation yet. I'll just repeat the same advice I gave when the original version was checked in. Attempting to pattern match backward starting at the call site is a misguided approach. Normal compilers would do this kind of optimization using forward sparse constant propagation (SCCP), which propagates type information as well as constants. |
acb2617
to
64f6fe2
Compare
This is not what's happening here. The peephole optimizations run in SILCombine's worklist loop so information is (also) propagated in forward direction. And SCCP - well we don't do it in the whole compiler. And especially for this purpose it would be over-engineered. An existential which is conditionally initialized with two different concrete types (and one case is dead, depending on the other type) is really a very esoteric corner case. We need to make sure to be able to optimize the common cases - and we are not there, yet. |
Right, from your description it sounded like was your approach. I'm surprised it was possible without new instructions. That's a good approach as long as each individual transform is clearly moving in one direction toward a simpler or canonical form. A big problem with peepholes is that two different optimizations might not agree on the canonical form. |
Yes, I'm not suggesting doing that instead of this PR. I'm just repeating my advice from a decade ago so it isn't forgotten. It's a simpler way to do specialization vs backward pattern matching and not that difficult, expensive, or complicated. It's similar to how much simpler it is to propagate "borrowed-from" information using forward data flow vs. backward recursion (find-adjacent-phi) |
64f6fe2
to
1f60301
Compare
@swift-ci test |
@swift-ci apple silicon benchmark |
@swift-ci test source compatibility |
Check if an operand's instruction has been deleted in `UseList.next()`. This allows to delete an instruction, which has two uses of a value, during use-list iteration.
There is no `isNominal` property in SIL.Type.
* getting the formal source and target types of casts * `isFromVarDecl` and `usesMoveableValueDebugInfo` for AllocStackInst * WitnessMethod APIs * `TryApply.isNonAsync`
The optional C++ type was bridged to a non-optional Swift type. The correct way is to bridged the non-optional C++ type to the non-optional Swift type.
* `createCheckedCastAddrBranch` * `createUnconditionalCheckedCastAddr` * `createDebugValue` * `createWitnessMethod` * `createInitEnumDataAddr`
…ing the conformances in an Array Instead of a ConformanceArray
…ting SILCombine visit function. So far a `SILCombineSimplifiable` could only replace a SILCombine visit implementation. With the `SWIFT_SILCOMBINE_PASS_WITH_LEGACY` (to be used in Passes.def) it's possible to keep an existing C++ implementation and on top of that add a Swift Simplification pass.
…ypes. Replace `unconditional_checked_cast` to an existential metatype with an `init_existential_metatype`, it the source is a conforming type. Note that init_existential_metatype is better than unconditional_checked_cast because it does not need to do any runtime casting.
* factor out common methods of AST Type/CanonicalType into a `TypeProperties` protocol. * add more APIs to AST Type/CanoncialType. * move `MetatypeRepresentation` from SIL.Type to AST.Type and implement it with a swift enum. * let `Builder.createMetatype` get a CanonicalType as instance type, because the instance type must not be a lowered type.
And simplify the implementation of `var Instruction.definedOperands`
…rns a sequence of the specific instruction class and not a sequence of `Instruction`
* `func Instruction.dominatesInSameBlock(_ otherInst: Instruction) -> Bool` * `var Instruction.concreteTypeOfDependentExistentialArchetype`
and add `var Type.invocationGenericSignatureOfFunctionType`
And let it conform to `NoReflectionChildren` to make it's debug dump in lldb nicer
…y instructions If an apply uses an existential archetype (`@opened("...")`) and the concrete type is known, replace the existential archetype with the concrete type 1. in the apply's substitution map 2. in the arguments, e.g. by inserting address casts For example: ``` %5 = apply %1<@opend("...")>(%2) : <τ_0_0> (τ_0_0) -> () ``` -> ``` %4 = unchecked_addr_cast %2 to $*ConcreteType %5 = apply %1<ConcreteType>(%4) : <τ_0_0> (τ_0_0) -> () ```
…itness_method instructions
* Reimplement most of the logic in Swift as an Instruction simplification and remove the old code from SILCombine * support more cases of existential archetype replacements: For example: ``` %0 = alloc_stack $any P %1 = init_existential_addr %0, $T use %1 ``` is transformed to ``` %0 = alloc_stack $T use %0 ``` Also, if the alloc_stack is already an opened existential and the concrete type is known, replace it as well: ``` %0 = metatype $@thick T.Type %1 = init_existential_metatype %0, $@thick any P.Type %2 = open_existential_metatype %1 : $@thick any P.Type to $@thick (@opened("X", P) Self).Type ... %3 = alloc_stack $@opened("X", any P) Self use %3 ``` is transformed to ``` ... %3 = alloc_stack $T use %3 ```
Don't get the swift source version string, but the debug dump string
1f60301
to
26c7310
Compare
@swift-ci test |
Those optimizations were done in SILCombine, but the implementation is very complicated.
This PR starts to de-compose the complex logic into small instruction simplifications.
It also adds the ability to figure out the concrete type of metatype existentials - which was missing in the current implementation in SILCombine.
This lets us optimize code like
This PR also contains a lot of Swift SIL infrastructure improvements.
See the commit messages for details.
Fixes an optimization deficiency
rdar://139199849