-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[SIL][Optimizer] eliminate @pack_element types #85333
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
base: main
Are you sure you want to change the base?
[SIL][Optimizer] eliminate @pack_element types #85333
Conversation
SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift
Show resolved
Hide resolved
| isLexical: isLexical, | ||
| isFromVarDecl: isFromVarDecl, | ||
| usesMoveableValueDebugInfo: usesMoveableValueDebugInfo) | ||
| for use in uses { |
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.
There is a shorter way to replace all uses: uses.replaceAll(with:).
And in combination with erasing the original instruction: SingleValueInstruction.replace(with:)
| isFromVarDecl: isFromVarDecl, | ||
| usesMoveableValueDebugInfo: usesMoveableValueDebugInfo) | ||
| for use in uses { | ||
| // FIXME: Are there any specific cases to handle? |
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.
yes! You cannot replace a value with a new value which has a different type without looking at the specific using instructions.
The safest thing to do is to cast the new alloc_stack back to the original pack existential type and let other peephole optimizations clean that up:
%1 = alloc_stack $@pack_element(...)
->
%0 = alloc_stack $T
%1 = unchecked_addr_cast %0 to $*@pack_element(...)
For example, if an original use is an unchecked_addr_cast itself, the resulting double address casts will be optimized away.
However, you might need to add some peephole optimizations for the address cast, e.g. optimize unchecked_addr_cast - witness_method pairs
...tCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift
Outdated
Show resolved
Hide resolved
...tCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift
Show resolved
Hide resolved
...tCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift
Outdated
Show resolved
Hide resolved
SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift
Outdated
Show resolved
Hide resolved
4db84e1 to
ae181f8
Compare
* SwiftCompilerSources/Sources/AST/Type.swift * SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift * SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift * SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift * SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift * include/swift/AST/ASTBridging.h * include/swift/AST/ASTBridgingImpl.h
491bbf8 to
71d3673
Compare
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.
Hmm. Can we reasonably just ask SILCloner to canonicalize this, so that we don't end up with pack_element archetypes that can be resolved to a concrete type in the first place? Otherwise I'm concerned that we're going to play whack-a-mole with every instruction that takes a type operand.
I think this can be done elegantly with a combination of
- specializing the cloning of
DynamicPackIndexInstto turn it into aScalarPackIndexInstwhen the index value is aninteger_literaland there's a prefix of non-expansion element types in the pack (which I don't think you're checking for), and - specializing the cloning of
OpenPackElementInstwhen the index is aScalarPackIndexInst.
The result of OpenPackElementInst is only used as a type-dependent operand for uses of the local archetype it produces, so it should be fine to simply not create a corresponding value in the clone.
You may also need to do some similar canonicalization with PackPackIndexInst; the test case is a variadic generic function that creates a larger pack, e.g.
func foo<each T>(values: repeat each T) {}
func bar<each T>(values: repeat each T) {
foo(values: repeat each values, 1, 2, 3)
}
Most variadic generic functions contain loops that iterate over the elements of their Pack parameters. Since the types of the pack elements are unknown, witness table methods are used to perform operations on the current pack element in each iteration. After specialization, these loops are usually unrolled, since there is a fixed list of pack element types. In the unrolled code, it should be possible to eliminate the witness table lookups. This is not possible because of the @pack_element types introduced to refer to pack elements:
%5 = integer_literal $Builtin.Word, 0
%6 = dynamic_pack_index %5 of $Pack{Int, Double}
%7 = open_pack_element %6 of at <Pack{Int, Double}>, shape $each A, uuid "063BDCF4-98A3-11F0-B2E8-929C59BC796C"
%20 = witness_method $@pack_element("063BDCF4-98A3-11F0-B2E8-929C59BC796C") each A, #Numeric."*" …
%21 = apply %20<@pack_element("063BDCF4-98A3-11F0-B2E8-929C59BC796C") each A>(%10, %14, %18, %11) … // type-defs: %7
This simplification aims to eliminate all instances of @pack_element types from specialized functions by replacing those with the underlying concrete type. This allows the appropriate witness method, as well as other functions, to be inlined.
This computed attribute is used in the simplifications of witness_method, alloc_stack, unchecked_addr_cast and apply.