From d2f2cf97b58e0a9872a81177fed24c404326660f Mon Sep 17 00:00:00 2001 From: Elsa Keirouz Date: Tue, 4 Nov 2025 12:38:02 +0000 Subject: [PATCH 1/3] [SIL][Optimizer] eliminate @pack_element types * 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 --- SwiftCompilerSources/Sources/AST/Type.swift | 4 +++ .../SimplifyAllocStack.swift | 34 +++++++++++++++++++ .../SimplifyUncheckedAddrCast.swift | 22 ++++++++++++ .../SimplifyWitnessMethod.swift | 29 ++++++++++++++++ .../Optimizer/Utilities/OptUtils.swift | 18 ++++++++++ include/swift/AST/ASTBridging.h | 1 + include/swift/AST/ASTBridgingImpl.h | 5 +++ 7 files changed, 113 insertions(+) diff --git a/SwiftCompilerSources/Sources/AST/Type.swift b/SwiftCompilerSources/Sources/AST/Type.swift index d6a5a7558b605..7d1ebd202ade9 100644 --- a/SwiftCompilerSources/Sources/AST/Type.swift +++ b/SwiftCompilerSources/Sources/AST/Type.swift @@ -273,6 +273,10 @@ extension TypeProperties { public var isSILPackElementAddress: Bool { return rawType.bridged.isSILPackElementAddress() } + + public func getPackElementType(_ index: Int) -> Type { + return Type(bridged: rawType.bridged.getPackElementType(index)); + } } public struct TypeArray : RandomAccessCollection, CustomReflectable { diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift index 5c99b3d8f8d4d..4368a4283f472 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift @@ -19,6 +19,7 @@ extension AllocStackInst : Simplifiable, SILCombineSimplifiable { return } _ = optimizeExistential(context) + _ = optimizePackElement(context) } } @@ -302,4 +303,37 @@ private extension AllocStackInst { } return concreteType } + + /// Replaces an alloc_stack of an Pack Element by an alloc_stack of the concrete type. + /// + /// For example: + /// ``` + /// %0 = alloc_stack $@pack_element(...) ... + /// use %1 + /// ``` + /// is transformed to + /// ``` + /// %0 = alloc_stack $T + /// use %0 + /// ``` + /// + private func optimizePackElement(_ context: SimplifyContext) -> Bool { + guard let concreteType = concreteTypeOfDependentPackElementArchetype else { + return false + } + + let builder = Builder(before: self, context) + let newAlloc = builder.createAllocStack(concreteType.loweredType(in: parentFunction), + hasDynamicLifetime: hasDynamicLifetime, + isLexical: isLexical, + isFromVarDecl: isFromVarDecl, + usesMoveableValueDebugInfo: usesMoveableValueDebugInfo) + for use in uses { + // FIXME: Are there any specific cases to handle? + use.set(to: newAlloc, context) + } + context.erase(instruction: self) + return true + } + } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift index d8455d555aef8..5c4cc8f1be9df 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift @@ -45,6 +45,16 @@ extension UncheckedAddrCastInst : OnoneSimplifiable, SILCombineSimplifiable { // %1 = vector_base_addr %0 : $*Builtin.FixedArray // ``` _ = optimizeVectorBaseCast(context) + + // ``` + // %1 = unchecked_addr_cast %0 to $*pack_element("...") ... + // ``` + // -> + // ``` + // %1 = unchecked_addr_cast %0 to $T + // ``` + _ = optimizePackElement(context) + } } @@ -78,4 +88,16 @@ private extension UncheckedAddrCastInst { } return false } + + private func optimizePackElement(_ context: SimplifyContext) -> Bool { + guard let concreteType = concreteTypeOfDependentPackElementArchetype else { + return false + } + + let builder = Builder(before: self, context) + let newCast = builder.createUncheckedAddrCast(from: fromAddress, + to:concreteType.loweredType(in: parentFunction).addressType) + self.replace(with: newCast, context) + return true + } } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift index 293e4703f2df0..a5e646634a7db 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift @@ -16,6 +16,7 @@ import SIL extension WitnessMethodInst : Simplifiable, SILCombineSimplifiable { func simplify(_ context: SimplifyContext) { _ = tryReplaceExistentialArchetype(of: self, context) + _ = tryReplacePackElementArchetype(of: self, context) } } @@ -46,3 +47,31 @@ private func tryReplaceExistentialArchetype(of witnessMethod: WitnessMethodInst, witnessMethod.replace(with: newWmi, context) return true } + +/// If the witness_method operates on a pack element archetype (`@pack_element("...")`) and the concrete +/// type is known, replace the pack element archetype with the concrete type. +/// For example: +/// ``` +/// %3 = witness_method $@pack_element("...") Self, #P.foo, %2 +/// ``` +/// -> +/// ``` +/// %3 = witness_method $ConcreteType, #P.foo, %2 +/// ``` +private func tryReplacePackElementArchetype(of witnessMethod: WitnessMethodInst, _ context: SimplifyContext) -> Bool { + guard let concreteType = witnessMethod.concreteTypeOfDependentPackElementArchetype else { + return false + } + let conf = concreteType.checkConformance(to: witnessMethod.lookupProtocol) + guard conf.isValid else { + return false + } + + let builder = Builder(before: witnessMethod, context) + let newWmi = builder.createWitnessMethod(lookupType: concreteType, + conformance: conf, + member: witnessMethod.member, + methodType: witnessMethod.type) + witnessMethod.replace(with: newWmi, context) + return true +} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index c5d256f221aa2..1d6a3a12fe006 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -547,6 +547,24 @@ extension Instruction { return nil } + var concreteTypeOfDependentPackElementArchetype: CanonicalType? { + // For simplicity only support a single type dependent operand, which is true in most of the cases anyway. + if let openArchetypeOp = typeDependentOperands.singleElement, + // Match the sequence + // %1 = integer_literal $Builtin.Word, (integer value) + // %2 = dynamic_pack_index %1 of $Pack{...} + // %3 = open_pack_element %2 of ... + // this_instruction_which_uses $*@pack_element(...) // type-defs: %3 + let ope = openArchetypeOp.value as? OpenPackElementInst, + let dpi = ope.operands.first?.value as? DynamicPackIndexInst, + let ili = dpi.operands.first?.value as? IntegerLiteralInst, + let index = ili.value + { + return dpi.indexedPackType.getPackElementType(index).canonical + } + return nil + } + /// Returns true if a destroy of `type` must not be moved across this instruction. func isBarrierForDestroy(of type: Type, _ context: some Context) -> Bool { let instEffects = memoryEffects diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index f8ec724c7e19f..87019939c2405 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -2990,6 +2990,7 @@ struct BridgedASTType { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance checkConformance(BridgedDeclObj proto) const; BRIDGED_INLINE bool containsSILPackExpansionType() const; BRIDGED_INLINE bool isSILPackElementAddress() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getPackElementType(SwiftInt index) const; }; class BridgedCanType { diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 4b19480088f9a..dcbc9dd02e362 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -656,6 +656,11 @@ bool BridgedASTType::isSILPackElementAddress() const { return unbridged()->castTo()->isElementAddress(); } +BridgedASTType BridgedASTType::getPackElementType(SwiftInt index) const { + ASSERT(index >= 0); + return {unbridged()->castTo()->getElementType(index).getPointer()}; +} + static_assert((int)BridgedASTType::TraitResult::IsNot == (int)swift::TypeTraitResult::IsNot); static_assert((int)BridgedASTType::TraitResult::CanBe == (int)swift::TypeTraitResult::CanBe); static_assert((int)BridgedASTType::TraitResult::Is == (int)swift::TypeTraitResult::Is); From e2edde79e91fac9d40fb6579164c6716df522eea Mon Sep 17 00:00:00 2001 From: Elsa Keirouz Date: Thu, 6 Nov 2025 11:15:25 +0000 Subject: [PATCH 2/3] (fixup later) clean up code --- SwiftCompilerSources/Sources/AST/Type.swift | 4 ++-- .../SimplifyAllocStack.swift | 10 +++++++--- .../SimplifyUncheckedAddrCast.swift | 12 +++++++---- .../SimplifyWitnessMethod.swift | 4 +++- .../Optimizer/Utilities/OptUtils.swift | 2 +- include/swift/AST/ASTBridging.h | 20 +++++++++---------- include/swift/AST/ASTBridgingImpl.h | 5 ++--- 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/SwiftCompilerSources/Sources/AST/Type.swift b/SwiftCompilerSources/Sources/AST/Type.swift index 7d1ebd202ade9..ca75593b643f8 100644 --- a/SwiftCompilerSources/Sources/AST/Type.swift +++ b/SwiftCompilerSources/Sources/AST/Type.swift @@ -274,8 +274,8 @@ extension TypeProperties { return rawType.bridged.isSILPackElementAddress() } - public func getPackElementType(_ index: Int) -> Type { - return Type(bridged: rawType.bridged.getPackElementType(index)); + public var packElementTypes: TypeArray { + return TypeArray(bridged: rawType.bridged.getPackElementTypes()) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift index 4368a4283f472..c8f5b989d338b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift @@ -18,7 +18,9 @@ extension AllocStackInst : Simplifiable, SILCombineSimplifiable { if optimizeEnum(context) { return } - _ = optimizeExistential(context) + if optimizeExistential(context) { + return + } _ = optimizePackElement(context) } } @@ -308,8 +310,10 @@ private extension AllocStackInst { /// /// For example: /// ``` - /// %0 = alloc_stack $@pack_element(...) ... - /// use %1 + /// %1 = dynamic_pack_index %0 of $Pack{T, U} + /// %2 = open_pack_element %1 of <...> at ... + /// %3 = alloc_stack $@pack_element(...) ... + /// use %3 /// ``` /// is transformed to /// ``` diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift index 5c4cc8f1be9df..06f843565068c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyUncheckedAddrCast.swift @@ -44,17 +44,21 @@ extension UncheckedAddrCastInst : OnoneSimplifiable, SILCombineSimplifiable { // ``` // %1 = vector_base_addr %0 : $*Builtin.FixedArray // ``` - _ = optimizeVectorBaseCast(context) + if optimizeVectorBaseCast(context) { + return + } // ``` - // %1 = unchecked_addr_cast %0 to $*pack_element("...") ... + // %2 = dynamic_pack_index %1 of $Pack{T, U} + // %3 = open_pack_element %2 of <...> at ... + // %4 = pack_element_get %3 of %11 as $*Int + // %5 = unchecked_addr_cast %4 to $*@pack_element(..) // ``` // -> // ``` // %1 = unchecked_addr_cast %0 to $T // ``` _ = optimizePackElement(context) - } } @@ -96,7 +100,7 @@ private extension UncheckedAddrCastInst { let builder = Builder(before: self, context) let newCast = builder.createUncheckedAddrCast(from: fromAddress, - to:concreteType.loweredType(in: parentFunction).addressType) + to: concreteType.loweredType(in: parentFunction).addressType) self.replace(with: newCast, context) return true } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift index a5e646634a7db..5d9daa70a5f17 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyWitnessMethod.swift @@ -15,7 +15,9 @@ import SIL extension WitnessMethodInst : Simplifiable, SILCombineSimplifiable { func simplify(_ context: SimplifyContext) { - _ = tryReplaceExistentialArchetype(of: self, context) + if tryReplaceExistentialArchetype(of: self, context) { + return + } _ = tryReplacePackElementArchetype(of: self, context) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 1d6a3a12fe006..39b48fa7de206 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -560,7 +560,7 @@ extension Instruction { let ili = dpi.operands.first?.value as? IntegerLiteralInst, let index = ili.value { - return dpi.indexedPackType.getPackElementType(index).canonical + return dpi.indexedPackType.packElementTypes[index].canonical } return nil } diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 87019939c2405..13622a84cdd44 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -2911,6 +2911,15 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedMacroDefinitionKind : size_t { BridgedBuiltinIsolationMacro, }; +struct BridgedASTTypeArray { + BridgedArrayRef typeArray; + + SwiftInt getCount() const { return SwiftInt(typeArray.Length); } + + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE + BridgedASTType getAt(SwiftInt index) const; +}; + struct BridgedASTType { enum class TraitResult { IsNot, @@ -2990,7 +2999,7 @@ struct BridgedASTType { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance checkConformance(BridgedDeclObj proto) const; BRIDGED_INLINE bool containsSILPackExpansionType() const; BRIDGED_INLINE bool isSILPackElementAddress() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getPackElementType(SwiftInt index) const; + BRIDGED_INLINE BridgedASTTypeArray getPackElementTypes() const; }; class BridgedCanType { @@ -3003,15 +3012,6 @@ class BridgedCanType { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getRawType() const; }; -struct BridgedASTTypeArray { - BridgedArrayRef typeArray; - - SwiftInt getCount() const { return SwiftInt(typeArray.Length); } - - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE - BridgedASTType getAt(SwiftInt index) const; -}; - struct BridgedConformance { void * _Nullable opaqueValue; diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index dcbc9dd02e362..90f894d304dda 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -656,9 +656,8 @@ bool BridgedASTType::isSILPackElementAddress() const { return unbridged()->castTo()->isElementAddress(); } -BridgedASTType BridgedASTType::getPackElementType(SwiftInt index) const { - ASSERT(index >= 0); - return {unbridged()->castTo()->getElementType(index).getPointer()}; +BRIDGED_INLINE BridgedASTTypeArray BridgedASTType::getPackElementTypes() const { + return {unbridged()->castTo()->getElementTypes()}; } static_assert((int)BridgedASTType::TraitResult::IsNot == (int)swift::TypeTraitResult::IsNot); From 71d3673a1e7f900103cae16608dc4ef746b88910 Mon Sep 17 00:00:00 2001 From: Elsa Keirouz Date: Thu, 6 Nov 2025 18:02:25 +0000 Subject: [PATCH 3/3] (to fixup later) simplify alloc stack safely --- .../InstructionSimplification/SimplifyAllocStack.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift index c8f5b989d338b..2ffbcf6e8c8dd 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift @@ -332,11 +332,10 @@ private extension AllocStackInst { isLexical: isLexical, isFromVarDecl: isFromVarDecl, usesMoveableValueDebugInfo: usesMoveableValueDebugInfo) - for use in uses { - // FIXME: Are there any specific cases to handle? - use.set(to: newAlloc, context) - } - context.erase(instruction: self) + let builderAfter = Builder(after: self, context) + let addrCast = builderAfter.createUncheckedAddrCast(from: newAlloc, to: self.type.addressType) + uses.replaceAll(with: addrCast, context) + self.replace(with: newAlloc, context) return true }