Skip to content

Conversation

@aidan-hall
Copy link
Contributor

@aidan-hall aidan-hall commented Sep 25, 2025

rdar://161182876

There are two key barriers that prevent variadic generic specialisations from being optimised in most cases:

  • Indirect packs in the calling convention: These force the caller to make a large number of stack allocations, since the pack is passed indirectly, and pack elements are currently always pointers, so every element must be stack-allocated separately from the pack.
  • Pack loops and open_pack_element: These perform one iteration per pack element, so the loop body must be generic, with witness_method instructions that cannot be eliminated, since the type they are called on is not known.

Targeted modifications to eliminate these barriers will allow other passes to fully optimise variadic generic specialisations.

This PR only addresses the first barrier, indirect packs as function arguments.

The simplest way to eliminate indirect packs from the calling convention is effectively to move the stack allocations for the packs and pack elements inside the callee, and use the addresses of these local allocations in the main body, which is otherwise unchanged. These allocations can be eliminated by other passes once dynamic pack loops are optimised.

This transformation is performed by a function pass (currently called pack-specialization). For example, it would transform the following specialisation like so:

sil shared @$s11addTogether8doubleUp2xsxxQp_xxQptxxQp_tRvzlFSi_SdSSSJQP_Tg5 : $@convention(thin) (@pack_guaranteed Pack{Int, Double, String, Character}) -> (@pack_out Pack{Int, Double, String, Character}, @pack_out Pack{Int, Double, String, Character}) {
bb0(%0 : $*Pack{Int, Double, String, Character}, %1 : $*Pack{Int, Double, String, Character}, %2 : $*Pack{Int, Double, String, Character}):
  debug_value %2, let, name "xs", argno 1, expr op_deref
  …

sil shared @$s11addTogether8doubleUp2xsxxQp_xxQptxxQp_tRvzlFSi_SdSSSJQP_Tg5Tf8xxx_n : $@convention(thin) (Int, Double, @guaranteed String, @guaranteed Character) -> (Int, Double, @owned String, @owned Character, Int, Double, @owned String, @owned Character) {
bb0(%0 : $Int, %1 : $Double, %2 : $String, %3 : $Character):
  %4 = alloc_pack $Pack{Int, Double, String, Character}
  %5 = scalar_pack_index 0 of $Pack{Int, Double, String, Character}
  %6 = alloc_stack $Int
  store %0 to %6
  …
  debug_value %4, let, name "xs", argno 1, expr op_deref
  …

Note that the return values are all now direct, so bb0 only needs arguments corresponding to the xs parameter pack.

To optimise a pack loop, it must be unrolled. The pack element type is then statically known in each unrolled instance of the body. The existing loop unrolling pass can consistently do this in variadic generic specialisations, since the (known constant) pack length is used as the number of iterations. This still leaves constructs like the following:

  %5 = integer_literal $Builtin.Word, 0
  %6 = dynamic_pack_index %5 of $Pack{Int, Double}
  %7 = open_pack_element %6 of <each A where repeat each A : Numeric> 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

In this context, we could easily replace all instances of the @pack_element type with Int. This would allow the appropriate witness method to be inlined. We will perform this in an instruction simplification for open_pack_element.

@aidan-hall aidan-hall self-assigned this Sep 25, 2025
@aidan-hall aidan-hall added the parameter packs Feature → generics: Parameter packs label Sep 25, 2025
@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macOS

1 similar comment
@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macOS


public var packExpansionPatternType: Type { bridged.getPackExpansionPatternType().type }

public var hasParameterPack: Bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to move (most of) these APIs to TypeProperties so that they are also available for AST.Type and AST.CanonicalType. The SILType implementation forwards them to the AST type, anyway

@aidan-hall aidan-hall marked this pull request as draft October 14, 2025 14:18
eeckstein
eeckstein previously approved these changes Oct 16, 2025
Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great!

@aidan-hall aidan-hall closed this Oct 17, 2025
@aidan-hall aidan-hall deleted the pack-opt branch October 17, 2025 09:40
@aidan-hall aidan-hall restored the pack-opt branch October 17, 2025 09:40
@aidan-hall aidan-hall reopened this Oct 17, 2025
@aidan-hall aidan-hall force-pushed the pack-opt branch 2 times, most recently from 9e37826 to 6b9f9ec Compare October 17, 2025 10:30
@aidan-hall aidan-hall marked this pull request as ready for review October 17, 2025 10:31
@aidan-hall
Copy link
Contributor Author

@swift-ci test

@aidan-hall aidan-hall requested a review from eeckstein October 17, 2025 10:34
@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test linux

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test linux

@aidan-hall aidan-hall dismissed eeckstein’s stale review October 17, 2025 13:29

Many changes have been made since this approval.

@aidan-hall
Copy link
Contributor Author

*a few

@aidan-hall
Copy link
Contributor Author

@swift-ci test windows

@aidan-hall
Copy link
Contributor Author

@swift-ci please smoke benchmark

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test linux

@aidan-hall
Copy link
Contributor Author

@swift-ci test windows

@aidan-hall
Copy link
Contributor Author

@swift-ci test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci test windows

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test

@aidan-hall
Copy link
Contributor Author

@swift-ci smoke test macos

@aidan-hall
Copy link
Contributor Author

@swift-ci Please Test Source Compatibility Release

@aidan-hall
Copy link
Contributor Author

@swift-ci test macos

1 similar comment
@aidan-hall
Copy link
Contributor Author

@swift-ci test macos

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parameter packs Feature → generics: Parameter packs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants