mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #84513 from aidan-hall/pack-opt
Optimize Specializations of Variadic Generics by Eliminating Parameter Packs
This commit is contained in:
@@ -146,6 +146,8 @@ extension TypeProperties {
|
||||
public var isExistentialMetatype: Bool { rawType.bridged.isExistentialMetatypeType() }
|
||||
public var isDynamicSelf: Bool { rawType.bridged.isDynamicSelf()}
|
||||
public var isBox: Bool { rawType.bridged.isBox() }
|
||||
public var isPack: Bool { rawType.bridged.isPack() }
|
||||
public var isSILPack: Bool { rawType.bridged.isSILPack() }
|
||||
|
||||
public var canBeClass: Type.TraitResult { rawType.bridged.canBeClass().result }
|
||||
|
||||
@@ -263,6 +265,14 @@ extension TypeProperties {
|
||||
public func checkConformance(to protocol: ProtocolDecl) -> Conformance {
|
||||
return Conformance(bridged: rawType.bridged.checkConformance(`protocol`.bridged))
|
||||
}
|
||||
|
||||
public var containsSILPackExpansionType: Bool {
|
||||
return rawType.bridged.containsSILPackExpansionType()
|
||||
}
|
||||
|
||||
public var isSILPackElementAddress: Bool {
|
||||
return rawType.bridged.isSILPackElementAddress()
|
||||
}
|
||||
}
|
||||
|
||||
public struct TypeArray : RandomAccessCollection, CustomReflectable {
|
||||
|
||||
@@ -38,4 +38,5 @@ swift_compiler_sources(Optimizer
|
||||
StripObjectHeaders.swift
|
||||
TempLValueElimination.swift
|
||||
TempRValueElimination.swift
|
||||
PackSpecialization.swift
|
||||
)
|
||||
|
||||
@@ -152,8 +152,8 @@ private func specializeClosure(specializedName: String,
|
||||
newParams.append(contentsOf: nonConstantArguments.map { partialApply.parameter(for: $0)! })
|
||||
|
||||
let isGeneric = newParams.contains { $0.type.hasTypeParameter } ||
|
||||
callee.convention.results.contains { $0.type.hasTypeParameter() } ||
|
||||
callee.convention.errorResult?.type.hasTypeParameter() ?? false
|
||||
callee.convention.results.contains { $0.type.hasTypeParameter } ||
|
||||
callee.convention.errorResult?.type.hasTypeParameter ?? false
|
||||
|
||||
let specializedClosure = context.createSpecializedFunctionDeclaration(from: callee,
|
||||
withName: specializedName,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -158,19 +158,43 @@ struct FunctionPassContext : MutatingContext {
|
||||
}
|
||||
}
|
||||
|
||||
func createSpecializedFunctionDeclaration(from original: Function, withName specializedFunctionName: String,
|
||||
withParams specializedParameters: [ParameterInfo],
|
||||
makeThin: Bool = false,
|
||||
makeBare: Bool = false,
|
||||
preserveGenericSignature: Bool = true) -> Function
|
||||
{
|
||||
func mangle(withExplodedPackArguments argIndices: [Int], from original: Function) -> String {
|
||||
return argIndices.withBridgedArrayRef { bridgedArgIndices in
|
||||
String(taking: bridgedPassContext.mangleWithExplodedPackArgs(bridgedArgIndices, original.bridged))
|
||||
}
|
||||
}
|
||||
|
||||
func createSpecializedFunctionDeclaration(
|
||||
from original: Function, withName specializedFunctionName: String,
|
||||
withParams specializedParameters: [ParameterInfo],
|
||||
withResults specializedResults: [ResultInfo]? = nil,
|
||||
makeThin: Bool = false,
|
||||
makeBare: Bool = false,
|
||||
preserveGenericSignature: Bool = true
|
||||
) -> Function {
|
||||
return specializedFunctionName._withBridgedStringRef { nameRef in
|
||||
let bridgedParamInfos = specializedParameters.map { $0._bridged }
|
||||
|
||||
return bridgedParamInfos.withUnsafeBufferPointer { paramBuf in
|
||||
bridgedPassContext.createSpecializedFunctionDeclaration(nameRef, paramBuf.baseAddress, paramBuf.count,
|
||||
original.bridged, makeThin, makeBare,
|
||||
preserveGenericSignature).function
|
||||
|
||||
if let bridgedResultInfos = specializedResults?.map({ $0._bridged }) {
|
||||
|
||||
return bridgedResultInfos.withUnsafeBufferPointer { resultBuf in
|
||||
return bridgedPassContext.createSpecializedFunctionDeclaration(
|
||||
nameRef, paramBuf.baseAddress, paramBuf.count,
|
||||
resultBuf.baseAddress, resultBuf.count,
|
||||
original.bridged, makeThin, makeBare,
|
||||
preserveGenericSignature
|
||||
).function
|
||||
}
|
||||
} else {
|
||||
return bridgedPassContext.createSpecializedFunctionDeclaration(
|
||||
nameRef, paramBuf.baseAddress, paramBuf.count,
|
||||
nil, 0,
|
||||
original.bridged, makeThin, makeBare,
|
||||
preserveGenericSignature
|
||||
).function
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ private func registerSwiftPasses() {
|
||||
registerPass(closureSpecialization, { closureSpecialization.run($0) })
|
||||
registerPass(autodiffClosureSpecialization, { autodiffClosureSpecialization.run($0) })
|
||||
registerPass(loopInvariantCodeMotionPass, { loopInvariantCodeMotionPass.run($0) })
|
||||
registerPass(packSpecialization, { packSpecialization.run($0) })
|
||||
|
||||
// Instruction passes
|
||||
registerForSILCombine(BeginBorrowInst.self, { run(BeginBorrowInst.self, $0) })
|
||||
|
||||
@@ -248,12 +248,33 @@ public struct Builder {
|
||||
return notifyNew(allocStack.getAs(AllocStackInst.self))
|
||||
}
|
||||
|
||||
public func createAllocPack(_ packType: Type) -> AllocPackInst {
|
||||
let allocPack = bridged.createAllocPack(packType.bridged)
|
||||
return notifyNew(allocPack.getAs(AllocPackInst.self))
|
||||
}
|
||||
|
||||
public func createAllocPackMetadata() -> AllocPackMetadataInst {
|
||||
let allocPackMetadata = bridged.createAllocPackMetadata()
|
||||
return notifyNew(allocPackMetadata.getAs(AllocPackMetadataInst.self))
|
||||
}
|
||||
|
||||
public func createAllocPackMetadata(_ packType: Type) -> AllocPackMetadataInst {
|
||||
let allocPackMetadata = bridged.createAllocPackMetadata(packType.bridged)
|
||||
return notifyNew(allocPackMetadata.getAs(AllocPackMetadataInst.self))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func createDeallocStack(_ operand: Value) -> DeallocStackInst {
|
||||
let dr = bridged.createDeallocStack(operand.bridged)
|
||||
return notifyNew(dr.getAs(DeallocStackInst.self))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func createDeallocPack(_ operand: Value) -> DeallocPackInst {
|
||||
let dr = bridged.createDeallocPack(operand.bridged)
|
||||
return notifyNew(dr.getAs(DeallocPackInst.self))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func createDeallocStackRef(_ operand: Value) -> DeallocStackRefInst {
|
||||
let dr = bridged.createDeallocStackRef(operand.bridged)
|
||||
@@ -689,6 +710,11 @@ public struct Builder {
|
||||
return notifyNew(store.getAs(StoreInst.self))
|
||||
}
|
||||
|
||||
public func createStoreBorrow(source: Value, destination: Value) -> StoreBorrowInst {
|
||||
let storeBorrow = bridged.createStoreBorrow(source.bridged, destination.bridged)
|
||||
return notifyNew(storeBorrow.getAs(StoreBorrowInst.self))
|
||||
}
|
||||
|
||||
public func createInitExistentialRef(instance: Value,
|
||||
existentialType: Type,
|
||||
formalConcreteType: CanonicalType,
|
||||
@@ -713,6 +739,22 @@ public struct Builder {
|
||||
return notifyNew(initExistential.getAs(InitExistentialMetatypeInst.self))
|
||||
}
|
||||
|
||||
public func createScalarPackIndex(componentIndex: Int, indexedPackType: CanonicalType) -> ScalarPackIndexInst {
|
||||
let scalarPackIndex = bridged.createScalarPackIndex(SwiftInt(componentIndex), indexedPackType.bridged)
|
||||
return notifyNew(scalarPackIndex.getAs(ScalarPackIndexInst.self))
|
||||
}
|
||||
|
||||
public func createPackElementGet(packIndex: Value, pack: Value, elementType: Type) -> PackElementGetInst {
|
||||
let packElementGet = bridged.createPackElementGet(packIndex.bridged, pack.bridged, elementType.bridged)
|
||||
return notifyNew(packElementGet.getAs(PackElementGetInst.self))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func createPackElementSet(elementValue: Value, packIndex: Value, pack: Value) -> PackElementSetInst {
|
||||
let packElementSet = bridged.createPackElementSet(elementValue.bridged, packIndex.bridged, pack.bridged)
|
||||
return notifyNew(packElementSet.getAs(PackElementSetInst.self))
|
||||
}
|
||||
|
||||
public func createMetatype(
|
||||
ofInstanceType instanceType: CanonicalType,
|
||||
representation: AST.`Type`.MetatypeRepresentation
|
||||
|
||||
@@ -140,17 +140,31 @@ public struct ResultInfo : CustomStringConvertible {
|
||||
/// calling convention of the parameter.
|
||||
///
|
||||
/// TODO: For most purposes, you probably want \c returnValueType.
|
||||
public let type: BridgedASTType
|
||||
public let type: CanonicalType
|
||||
public let convention: ResultConvention
|
||||
public let options: UInt8
|
||||
public let hasLoweredAddresses: Bool
|
||||
|
||||
// Must be kept consistent with 'SILResultInfo::Flag'
|
||||
public enum Flag : UInt8 {
|
||||
case notDifferentiable = 0x1
|
||||
case isSending = 0x2
|
||||
};
|
||||
|
||||
public init(type: CanonicalType, convention: ResultConvention, options: UInt8, hasLoweredAddresses: Bool) {
|
||||
self.type = type
|
||||
self.convention = convention
|
||||
self.options = options
|
||||
self.hasLoweredAddresses = hasLoweredAddresses
|
||||
}
|
||||
|
||||
/// Is this result returned indirectly in SIL? Most formally
|
||||
/// indirect results can be returned directly in SIL. This depends
|
||||
/// on whether the calling function has lowered addresses.
|
||||
public var isSILIndirect: Bool {
|
||||
switch convention {
|
||||
case .indirect:
|
||||
return hasLoweredAddresses || type.isExistentialArchetypeWithError()
|
||||
return hasLoweredAddresses || type.isExistentialArchetypeWithError
|
||||
case .pack:
|
||||
return true
|
||||
case .owned, .unowned, .unownedInnerPointer, .autoreleased, .guaranteed, .guaranteedAddress, .inout:
|
||||
@@ -159,8 +173,11 @@ public struct ResultInfo : CustomStringConvertible {
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
convention.description + ": "
|
||||
+ String(taking: type.getDebugDescription())
|
||||
convention.description + ": " + type.description
|
||||
}
|
||||
|
||||
public func getReturnValueType(function: Function) -> CanonicalType {
|
||||
CanonicalType(bridged: self._bridged.getReturnValueType(function.bridged))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +251,10 @@ public struct ParameterInfo : CustomStringConvertible {
|
||||
public func hasOption(_ flag: Flag) -> Bool {
|
||||
return options & flag.rawValue != 0
|
||||
}
|
||||
|
||||
public func getArgumentType(function: Function) -> CanonicalType {
|
||||
CanonicalType(bridged: self._bridged.getArgumentType(function.bridged))
|
||||
}
|
||||
}
|
||||
|
||||
extension FunctionConvention {
|
||||
@@ -443,17 +464,22 @@ public enum ResultConvention : CustomStringConvertible {
|
||||
|
||||
extension ResultInfo {
|
||||
init(bridged: BridgedResultInfo, hasLoweredAddresses: Bool) {
|
||||
self.type = BridgedASTType(type: bridged.type)
|
||||
self.type = CanonicalType(bridged: bridged.type)
|
||||
self.convention = ResultConvention(bridged: bridged.convention)
|
||||
self.hasLoweredAddresses = hasLoweredAddresses
|
||||
self.options = bridged.options
|
||||
}
|
||||
init?(bridged: OptionalBridgedResultInfo, hasLoweredAddresses: Bool) {
|
||||
guard let t = bridged.type else {
|
||||
if bridged.type.getRawType().type == nil {
|
||||
return nil
|
||||
}
|
||||
self.type = BridgedASTType(type: t)
|
||||
self.type = CanonicalType(bridged: bridged.type)
|
||||
self.convention = ResultConvention(bridged: bridged.convention)
|
||||
self.hasLoweredAddresses = hasLoweredAddresses
|
||||
self.options = bridged.options
|
||||
}
|
||||
public var _bridged: BridgedResultInfo {
|
||||
BridgedResultInfo(type.bridged, convention.bridged, options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +499,20 @@ extension ResultConvention {
|
||||
fatalError("unsupported result convention")
|
||||
}
|
||||
}
|
||||
|
||||
var bridged: BridgedResultConvention {
|
||||
switch self {
|
||||
case .indirect: return .Indirect
|
||||
case .owned: return .Owned
|
||||
case .unowned: return .Unowned
|
||||
case .unownedInnerPointer: return .UnownedInnerPointer
|
||||
case .autoreleased: return .Autoreleased
|
||||
case .pack: return .Pack
|
||||
case .guaranteed: return .Guaranteed
|
||||
case .guaranteedAddress: return .GuaranteedAddress
|
||||
case .inout: return .Inout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ParameterInfo {
|
||||
|
||||
@@ -96,7 +96,7 @@ public class Instruction : CustomStringConvertible, Hashable {
|
||||
BridgedContext.moveInstructionBefore(bridged, otherInstruction.bridged)
|
||||
context.notifyInstructionsChanged()
|
||||
}
|
||||
|
||||
|
||||
public final func copy(before otherInstruction: Instruction, _ context: some MutatingContext) {
|
||||
BridgedContext.copyInstructionBefore(bridged, otherInstruction.bridged)
|
||||
context.notifyInstructionsChanged()
|
||||
@@ -182,7 +182,7 @@ public class Instruction : CustomStringConvertible, Hashable {
|
||||
public static func ==(lhs: Instruction, rhs: Instruction) -> Bool {
|
||||
lhs === rhs
|
||||
}
|
||||
|
||||
|
||||
public func isIdenticalTo(_ otherInst: Instruction) -> Bool {
|
||||
return bridged.isIdenticalTo(otherInst.bridged)
|
||||
}
|
||||
@@ -1094,7 +1094,7 @@ final public class RefElementAddrInst : SingleValueInstruction, UnaryInstruction
|
||||
public var fieldIsLet: Bool { bridged.RefElementAddrInst_fieldIsLet() }
|
||||
|
||||
public var isImmutable: Bool { bridged.RefElementAddrInst_isImmutable() }
|
||||
|
||||
|
||||
public func set(isImmutable: Bool, _ context: some MutatingContext) {
|
||||
context.notifyInstructionsChanged()
|
||||
bridged.RefElementAddrInst_setImmutable(isImmutable)
|
||||
@@ -1141,7 +1141,7 @@ final public class KeyPathInst : SingleValueInstruction {
|
||||
final public
|
||||
class UnconditionalCheckedCastInst : SingleValueInstruction, UnaryInstruction {
|
||||
public override var mayTrap: Bool { true }
|
||||
|
||||
|
||||
public var sourceFormalType: CanonicalType {
|
||||
CanonicalType(bridged: bridged.UnconditionalCheckedCast_getSourceFormalType())
|
||||
}
|
||||
@@ -1814,10 +1814,29 @@ final public class DeallocPackInst : Instruction, UnaryInstruction, Deallocation
|
||||
final public class DeallocPackMetadataInst : Instruction, Deallocation {}
|
||||
|
||||
final public class OpenPackElementInst : SingleValueInstruction {}
|
||||
final public class PackLengthInst : SingleValueInstruction {}
|
||||
final public class DynamicPackIndexInst : SingleValueInstruction {}
|
||||
final public class PackPackIndexInst : SingleValueInstruction {}
|
||||
final public class ScalarPackIndexInst : SingleValueInstruction {}
|
||||
final public class PackLengthInst : SingleValueInstruction {
|
||||
public var packType: CanonicalType {
|
||||
CanonicalType(bridged: bridged.PackLengthInst_getPackType())
|
||||
}
|
||||
}
|
||||
|
||||
public protocol AnyPackIndexInst : SingleValueInstruction {
|
||||
var indexedPackType: CanonicalType { get }
|
||||
}
|
||||
|
||||
extension AnyPackIndexInst {
|
||||
public var indexedPackType: CanonicalType {
|
||||
CanonicalType(bridged: bridged.AnyPackIndexInst_getIndexedPackType())
|
||||
}
|
||||
}
|
||||
|
||||
final public class DynamicPackIndexInst : SingleValueInstruction, AnyPackIndexInst {}
|
||||
final public class PackPackIndexInst : SingleValueInstruction, AnyPackIndexInst {}
|
||||
final public class ScalarPackIndexInst : SingleValueInstruction, AnyPackIndexInst {
|
||||
public var componentIndex: Int {
|
||||
Int(bridged.ScalarPackIndexInst_getComponentIndex())
|
||||
}
|
||||
}
|
||||
|
||||
final public class TuplePackExtractInst: SingleValueInstruction {
|
||||
public var indexOperand: Operand { operands[0] }
|
||||
@@ -1842,7 +1861,7 @@ public class TermInst : Instruction {
|
||||
let succArray = bridged.TermInst_getSuccessors()
|
||||
return SuccessorArray(base: succArray.base, count: succArray.count)
|
||||
}
|
||||
|
||||
|
||||
public var isFunctionExiting: Bool { false }
|
||||
|
||||
public final func replaceBranchTarget(from fromBlock: BasicBlock, to toBlock: BasicBlock, _ context: some MutatingContext) {
|
||||
@@ -1888,6 +1907,9 @@ final public class YieldInst : TermInst {
|
||||
public func convention(of operand: Operand) -> ArgumentConvention {
|
||||
return bridged.YieldInst_getConvention(operand.bridged).convention
|
||||
}
|
||||
|
||||
public var resumeBlock: BasicBlock { bridged.YieldInst_getResumeBB().block }
|
||||
public var unwindBlock: BasicBlock { bridged.YieldInst_getUnwindBB().block }
|
||||
}
|
||||
|
||||
final public class UnwindInst : TermInst {
|
||||
@@ -1997,11 +2019,11 @@ final public class AwaitAsyncContinuationInst : TermInst, UnaryInstruction {
|
||||
|
||||
public struct CheckedCastInstOptions {
|
||||
var storage: UInt8 = 0
|
||||
|
||||
|
||||
var bridged: BridgedInstruction.CheckedCastInstOptions {
|
||||
.init(storage: storage)
|
||||
}
|
||||
|
||||
|
||||
var isolatedConformances: CastingIsolatedConformances {
|
||||
return (storage & 0x01) != 0 ? .prohibit : .allow
|
||||
}
|
||||
|
||||
@@ -113,6 +113,11 @@ public struct Type : TypeProperties, CustomStringConvertible, NoReflectionChildr
|
||||
.init(bridgedOrNil: bridged.getRawLayoutSubstitutedCountType())
|
||||
}
|
||||
|
||||
public var approximateFormalPackType: CanonicalType {
|
||||
precondition(isSILPack);
|
||||
return CanonicalType(bridged: bridged.getApproximateFormalPackType());
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Properties of lowered `SILFunctionType`s
|
||||
//===--------------------------------------------------------------------===//
|
||||
@@ -161,6 +166,11 @@ public struct Type : TypeProperties, CustomStringConvertible, NoReflectionChildr
|
||||
return BoxFieldsArray(boxType: canonicalType, function: function)
|
||||
}
|
||||
|
||||
public var packElements: PackElementArray {
|
||||
precondition(isSILPack)
|
||||
return PackElementArray(type: self)
|
||||
}
|
||||
|
||||
/// Returns nil if the nominal is a resilient type because in this case the complete list
|
||||
/// of fields is not known.
|
||||
public func getNominalFields(in function: Function) -> NominalFieldsArray? {
|
||||
@@ -322,6 +332,17 @@ public struct BoxFieldsArray : RandomAccessCollection, FormattedLikeArray {
|
||||
}
|
||||
}
|
||||
|
||||
public struct PackElementArray : RandomAccessCollection, FormattedLikeArray {
|
||||
fileprivate let type: Type
|
||||
|
||||
public var startIndex: Int { return 0 }
|
||||
public var endIndex: Int { Int(type.bridged.getNumPackElements()) }
|
||||
|
||||
public subscript(_ index: Int) -> Type {
|
||||
type.bridged.getPackElementType(index).type
|
||||
}
|
||||
}
|
||||
|
||||
extension Type: DiagnosticArgument {
|
||||
public func _withBridgedDiagnosticArgument(_ fn: (BridgedDiagnosticArgument) -> Void) {
|
||||
rawType._withBridgedDiagnosticArgument(fn)
|
||||
|
||||
@@ -101,6 +101,10 @@ public enum Ownership {
|
||||
}
|
||||
}
|
||||
|
||||
public init(in function: Function, of type: Type, with convention: ArgumentConvention) {
|
||||
self = Ownership(bridged: BridgedValueOwnership_init(function.bridged, type.bridged, convention.bridged))
|
||||
}
|
||||
|
||||
public var _bridged: BridgedValue.Ownership {
|
||||
switch self {
|
||||
case .unowned: return BridgedValue.Ownership.Unowned
|
||||
|
||||
@@ -139,6 +139,7 @@ set(SWIFT_BENCH_MODULES
|
||||
single-source/ObserverUnappliedMethod
|
||||
single-source/OpaqueConsumingUsers
|
||||
single-source/OpenClose
|
||||
single-source/ParameterPacks
|
||||
single-source/Phonebook
|
||||
single-source/PointerArithmetics
|
||||
single-source/PolymorphicCalls
|
||||
|
||||
53
benchmark/single-source/ParameterPacks.swift
Normal file
53
benchmark/single-source/ParameterPacks.swift
Normal file
@@ -0,0 +1,53 @@
|
||||
//===--- ParameterPacks.swift ---------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This benchmark serves to test the overhead of
|
||||
|
||||
import TestsUtils
|
||||
|
||||
public let benchmarks = [
|
||||
BenchmarkInfo(
|
||||
name: "ParameterPacks.VariadicFibonacci",
|
||||
runFunction: run_ParameterPacksVariadicFibonacci,
|
||||
tags: [.validation])
|
||||
]
|
||||
|
||||
@inline(never)
|
||||
func numericLoop<each T: BinaryInteger>(xs: repeat each T) -> (repeat each T) {
|
||||
return
|
||||
(repeat { x in
|
||||
// Recursive "Fibonacci" function prevents inlining
|
||||
if x <= 1 {
|
||||
return x
|
||||
} else {
|
||||
let (a, b) = numericLoop(xs: x - 1, x - 2)
|
||||
return a + b
|
||||
}
|
||||
}(each xs)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
let expectedResult = (610, 987, 1597)
|
||||
|
||||
@inline(never)
|
||||
public func run_ParameterPacksVariadicFibonacci(_ n: Int) {
|
||||
var result = (0, 0, 0)
|
||||
for _ in 1...n {
|
||||
result = numericLoop(xs: 15, 16, 17)
|
||||
if result != expectedResult {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
check(result == expectedResult)
|
||||
}
|
||||
@@ -143,6 +143,7 @@ import ObserverPartiallyAppliedMethod
|
||||
import ObserverUnappliedMethod
|
||||
import OpaqueConsumingUsers
|
||||
import OpenClose
|
||||
import ParameterPacks
|
||||
import Phonebook
|
||||
import PointerArithmetics
|
||||
import PolymorphicCalls
|
||||
@@ -343,6 +344,7 @@ register(ObserverPartiallyAppliedMethod.benchmarks)
|
||||
register(ObserverUnappliedMethod.benchmarks)
|
||||
register(OpaqueConsumingUsers.benchmarks)
|
||||
register(OpenClose.benchmarks)
|
||||
register(ParameterPacks.benchmarks)
|
||||
register(Phonebook.benchmarks)
|
||||
register(PointerArithmetics.benchmarks)
|
||||
register(PolymorphicCalls.benchmarks)
|
||||
|
||||
@@ -1360,6 +1360,7 @@ Some kinds need arguments, which precede ``Tf``.
|
||||
PASSID ::= '5' // GenericSpecializer,
|
||||
PASSID ::= '6' // MoveDiagnosticInOutToOut,
|
||||
PASSID ::= '7' // AsyncDemotion,
|
||||
PASSID ::= '8' // PackSpecialization,
|
||||
|
||||
FRAGILE ::= 'q'
|
||||
|
||||
|
||||
@@ -2962,6 +2962,8 @@ struct BridgedASTType {
|
||||
BRIDGED_INLINE bool isBuiltinVector() const;
|
||||
BRIDGED_INLINE bool isBuiltinFixedArray() const;
|
||||
BRIDGED_INLINE bool isBox() const;
|
||||
BRIDGED_INLINE bool isPack() const;
|
||||
BRIDGED_INLINE bool isSILPack() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getBuiltinVectorElementType() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getBuiltinFixedArrayElementType() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getBuiltinFixedArraySizeType() const;
|
||||
@@ -2985,7 +2987,9 @@ struct BridgedASTType {
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSubstitutionMap getContextSubstitutionMap() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGenericSignature getInvocationGenericSignatureOfFunctionType() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType subst(BridgedSubstitutionMap substMap) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance checkConformance(BridgedDeclObj proto) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance checkConformance(BridgedDeclObj proto) const;
|
||||
BRIDGED_INLINE bool containsSILPackExpansionType() const;
|
||||
BRIDGED_INLINE bool isSILPackElementAddress() const;
|
||||
};
|
||||
|
||||
class BridgedCanType {
|
||||
|
||||
@@ -538,6 +538,14 @@ bool BridgedASTType::isBox() const {
|
||||
return unbridged()->is<swift::SILBoxType>();
|
||||
}
|
||||
|
||||
bool BridgedASTType::isPack() const {
|
||||
return unbridged()->is<swift::PackType>();
|
||||
}
|
||||
|
||||
bool BridgedASTType::isSILPack() const {
|
||||
return unbridged()->is<swift::SILPackType>();
|
||||
}
|
||||
|
||||
BridgedASTType BridgedASTType::getBuiltinVectorElementType() const {
|
||||
return {unbridged()->castTo<swift::BuiltinVectorType>()->getElementType().getPointer()};
|
||||
}
|
||||
@@ -638,7 +646,15 @@ BridgedASTType BridgedASTType::subst(BridgedSubstitutionMap substMap) const {
|
||||
|
||||
BridgedConformance BridgedASTType::checkConformance(BridgedDeclObj proto) const {
|
||||
return swift::checkConformance(unbridged(), proto.getAs<swift::ProtocolDecl>(), /*allowMissing=*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
bool BridgedASTType::containsSILPackExpansionType() const {
|
||||
return unbridged()->castTo<swift::SILPackType>()->containsPackExpansionType();
|
||||
}
|
||||
|
||||
bool BridgedASTType::isSILPackElementAddress() const {
|
||||
return unbridged()->castTo<swift::SILPackType>()->isElementAddress();
|
||||
}
|
||||
|
||||
static_assert((int)BridgedASTType::TraitResult::IsNot == (int)swift::TypeTraitResult::IsNot);
|
||||
static_assert((int)BridgedASTType::TraitResult::CanBe == (int)swift::TypeTraitResult::CanBe);
|
||||
|
||||
@@ -4835,6 +4835,7 @@ inline bool isIndirectFormalResult(ResultConvention convention) {
|
||||
/// A result type and the rules for returning it.
|
||||
class SILResultInfo {
|
||||
public:
|
||||
// Must be kept consistent with `ResultInfo.Flag` in `FunctionConvention.swift`
|
||||
enum Flag : uint8_t {
|
||||
/// Not differentiable: a `@noDerivative` result.
|
||||
///
|
||||
|
||||
@@ -164,7 +164,8 @@ enum class SpecializationPass : uint8_t {
|
||||
GenericSpecializer,
|
||||
MoveDiagnosticInOutToOut,
|
||||
AsyncDemotion,
|
||||
LAST = AsyncDemotion
|
||||
PackSpecialization,
|
||||
LAST = PackSpecialization
|
||||
};
|
||||
|
||||
constexpr uint8_t MAX_SPECIALIZATION_PASS = 10;
|
||||
|
||||
@@ -85,16 +85,16 @@ class FixedSizeSlab;
|
||||
|
||||
struct BridgedLoop {
|
||||
swift::SILLoop * _Nonnull l;
|
||||
|
||||
|
||||
BRIDGED_INLINE SwiftInt getInnerLoopCount() const;
|
||||
BRIDGED_INLINE BridgedLoop getInnerLoop(SwiftInt index) const;
|
||||
|
||||
|
||||
BRIDGED_INLINE SwiftInt getBasicBlockCount() const;
|
||||
BRIDGED_INLINE BridgedBasicBlock getBasicBlock(SwiftInt index) const;
|
||||
|
||||
|
||||
BRIDGED_INLINE OptionalBridgedBasicBlock getPreheader() const;
|
||||
BRIDGED_INLINE BridgedBasicBlock getHeader() const;
|
||||
|
||||
|
||||
BRIDGED_INLINE bool contains(BridgedBasicBlock block) const;
|
||||
};
|
||||
|
||||
@@ -114,16 +114,23 @@ enum class BridgedResultConvention {
|
||||
};
|
||||
|
||||
struct BridgedResultInfo {
|
||||
swift::TypeBase * _Nonnull type;
|
||||
BridgedCanType type;
|
||||
BridgedResultConvention convention;
|
||||
uint8_t options;
|
||||
|
||||
BRIDGED_INLINE static BridgedResultConvention castToResultConvention(swift::ResultConvention convention);
|
||||
BRIDGED_INLINE BridgedResultInfo(swift::SILResultInfo resultInfo);
|
||||
BridgedResultInfo(BridgedCanType type, BridgedResultConvention conv, uint8_t options)
|
||||
: type(type), convention(conv), options(options) {}
|
||||
BRIDGED_INLINE swift::SILResultInfo unbridged() const;
|
||||
|
||||
BRIDGED_INLINE BridgedCanType getReturnValueType(BridgedFunction f) const;
|
||||
};
|
||||
|
||||
struct OptionalBridgedResultInfo {
|
||||
swift::TypeBase * _Nullable type;
|
||||
BridgedCanType type;
|
||||
BridgedResultConvention convention;
|
||||
uint8_t options;
|
||||
};
|
||||
|
||||
struct BridgedResultInfoArray {
|
||||
@@ -164,6 +171,7 @@ struct BridgedParameterInfo {
|
||||
|
||||
BRIDGED_INLINE BridgedParameterInfo(swift::SILParameterInfo parameterInfo);
|
||||
BRIDGED_INLINE swift::SILParameterInfo unbridged() const;
|
||||
BRIDGED_INLINE BridgedCanType getArgumentType(BridgedFunction f) const;
|
||||
};
|
||||
|
||||
struct BridgedParameterInfoArray {
|
||||
@@ -301,6 +309,10 @@ struct BridgedType {
|
||||
getTupleElementType(SwiftInt idx) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getFunctionTypeWithNoEscape(bool withNoEscape) const;
|
||||
BRIDGED_INLINE BridgedArgumentConvention getCalleeConvention() const;
|
||||
|
||||
BRIDGED_INLINE SwiftInt getNumPackElements() const;
|
||||
BRIDGED_INLINE BridgedType getPackElementType(SwiftInt idx) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getApproximateFormalPackType() const;
|
||||
};
|
||||
|
||||
// SIL Bridging
|
||||
@@ -338,6 +350,11 @@ struct BridgedValue {
|
||||
bool findPointerEscape() const;
|
||||
};
|
||||
|
||||
BRIDGED_INLINE BridgedValue::Ownership
|
||||
BridgedValueOwnership_init(BridgedFunction f, BridgedType type,
|
||||
BridgedArgumentConvention convention);
|
||||
|
||||
|
||||
struct OptionalBridgedValue {
|
||||
OptionalSwiftObject obj;
|
||||
|
||||
@@ -713,7 +730,7 @@ struct BridgedInstruction {
|
||||
// =========================================================================//
|
||||
// Generalized instruction subclasses
|
||||
// =========================================================================//
|
||||
|
||||
|
||||
BRIDGED_INLINE SwiftInt MultipleValueInstruction_getNumResults() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedMultiValueResult MultipleValueInstruction_getResult(SwiftInt index) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSuccessorArray TermInst_getSuccessors() const;
|
||||
@@ -844,6 +861,8 @@ struct BridgedInstruction {
|
||||
BRIDGED_INLINE bool BeginApplyInst_isCalleeAllocated() const;
|
||||
BRIDGED_INLINE SwiftInt TryApplyInst_numArguments() const;
|
||||
BRIDGED_INLINE BridgedArgumentConvention YieldInst_getConvention(BridgedOperand forOperand) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock YieldInst_getResumeBB() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock YieldInst_getUnwindBB() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock BranchInst_getTargetBlock() const;
|
||||
BRIDGED_INLINE SwiftInt SwitchEnumInst_getNumCases() const;
|
||||
BRIDGED_INLINE SwiftInt SwitchEnumInst_getCaseIndex(SwiftInt idx) const;
|
||||
@@ -911,6 +930,9 @@ struct BridgedInstruction {
|
||||
BRIDGED_INLINE SwiftInt FullApplySite_numIndirectResultArguments() const;
|
||||
BRIDGED_INLINE bool ConvertFunctionInst_withoutActuallyEscaping() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType TypeValueInst_getParamType() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType PackLengthInst_getPackType() const;
|
||||
BRIDGED_INLINE SwiftInt ScalarPackIndexInst_getComponentIndex() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType AnyPackIndexInst_getIndexedPackType() const;
|
||||
|
||||
// =========================================================================//
|
||||
// VarDeclInst and DebugVariableInst
|
||||
@@ -1094,13 +1116,13 @@ struct BridgedConstExprFunctionState {
|
||||
swift::SymbolicValueBumpAllocator * _Nonnull allocator;
|
||||
swift::ConstExprEvaluator * _Nonnull constantEvaluator;
|
||||
unsigned int * _Nonnull numEvaluatedSILInstructions;
|
||||
|
||||
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE
|
||||
static BridgedConstExprFunctionState create();
|
||||
|
||||
|
||||
BRIDGED_INLINE
|
||||
bool isConstantValue(BridgedValue value);
|
||||
|
||||
|
||||
BRIDGED_INLINE
|
||||
void deinitialize();
|
||||
};
|
||||
@@ -1215,10 +1237,14 @@ struct BridgedBuilder{
|
||||
bool hasDynamicLifetime, bool isLexical, bool isFromVarDecl, bool wasMoved) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
|
||||
createAllocStack(BridgedType type, bool hasDynamicLifetime, bool isLexical, bool isFromVarDecl, bool wasMoved) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocPack(BridgedType type) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocPackMetadata() const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocPackMetadata(BridgedType type) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocVector(BridgedValue capacity,
|
||||
BridgedType type) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createDeallocStack(BridgedValue operand) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createDeallocStackRef(BridgedValue operand) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createDeallocPack(BridgedValue operand) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAddressToPointer(BridgedValue address,
|
||||
BridgedType pointerTy,
|
||||
bool needsStackProtection) const;
|
||||
@@ -1352,6 +1378,7 @@ struct BridgedBuilder{
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createProjectBox(BridgedValue box, SwiftInt fieldIdx) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createStore(BridgedValue src, BridgedValue dst,
|
||||
SwiftInt ownership) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createStoreBorrow(BridgedValue src, BridgedValue dst) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createInitExistentialRef(BridgedValue instance,
|
||||
BridgedType type,
|
||||
BridgedCanType formalConcreteType,
|
||||
@@ -1359,6 +1386,13 @@ struct BridgedBuilder{
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createInitExistentialMetatype(BridgedValue metatype,
|
||||
BridgedType existentialType,
|
||||
BridgedConformanceArray conformances) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createScalarPackIndex(
|
||||
SwiftInt componentIndex, BridgedCanType indexedPackType) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createPackElementGet(
|
||||
BridgedValue packIndex, BridgedValue pack, BridgedType elementType) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
|
||||
createPackElementSet(BridgedValue elementValue, BridgedValue packIndex,
|
||||
BridgedValue pack) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createMetatype(BridgedCanType instanceType,
|
||||
BridgedASTType::MetatypeRepresentation representation) const;
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEndCOWMutation(BridgedValue instance,
|
||||
@@ -1369,7 +1403,7 @@ struct BridgedBuilder{
|
||||
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createMarkDependenceAddr(
|
||||
BridgedValue value, BridgedValue base, BridgedInstruction::MarkDependenceKind dependenceKind) const;
|
||||
|
||||
|
||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createMarkUninitialized(
|
||||
BridgedValue value, SwiftInt kind) const;
|
||||
|
||||
|
||||
@@ -56,11 +56,25 @@ BridgedResultConvention BridgedResultInfo::castToResultConvention(swift::ResultC
|
||||
return static_cast<BridgedResultConvention>(convention);
|
||||
}
|
||||
|
||||
BridgedResultInfo::BridgedResultInfo(swift::SILResultInfo resultInfo):
|
||||
type(resultInfo.getInterfaceType().getPointer()),
|
||||
convention(castToResultConvention(resultInfo.getConvention()))
|
||||
BridgedResultInfo::BridgedResultInfo(swift::SILResultInfo resultInfo)
|
||||
: type(resultInfo.getInterfaceType()),
|
||||
convention(castToResultConvention(resultInfo.getConvention())),
|
||||
options(resultInfo.getOptions().toRaw())
|
||||
{}
|
||||
|
||||
swift::SILResultInfo BridgedResultInfo::unbridged() const {
|
||||
return swift::SILResultInfo(type.unbridged(),
|
||||
static_cast<swift::ResultConvention>(convention),
|
||||
swift::SILResultInfo::Options(options));
|
||||
}
|
||||
|
||||
BridgedCanType BridgedResultInfo::getReturnValueType(BridgedFunction f) const {
|
||||
const auto function = f.getFunction();
|
||||
return BridgedCanType(unbridged().getReturnValueType(
|
||||
function->getModule(), function->getLoweredFunctionType().getPointer(),
|
||||
function->getTypeExpansionContext()));
|
||||
}
|
||||
|
||||
SwiftInt BridgedResultInfoArray::count() const {
|
||||
return resultInfoArray.unbridged<swift::SILResultInfo>().size();
|
||||
}
|
||||
@@ -125,6 +139,10 @@ inline BridgedArgumentConvention castToArgumentConvention(swift::SILArgumentConv
|
||||
return static_cast<BridgedArgumentConvention>(convention.Value);
|
||||
}
|
||||
|
||||
inline swift::SILArgumentConvention unbridge(BridgedArgumentConvention convention) {
|
||||
return swift::SILArgumentConvention(static_cast<swift::SILArgumentConvention::ConventionType>(convention));
|
||||
}
|
||||
|
||||
BridgedParameterInfo::BridgedParameterInfo(swift::SILParameterInfo parameterInfo):
|
||||
type(parameterInfo.getInterfaceType()),
|
||||
convention(getArgumentConvention(parameterInfo.getConvention())),
|
||||
@@ -136,6 +154,10 @@ swift::SILParameterInfo BridgedParameterInfo::unbridged() const {
|
||||
swift::SILParameterInfo::Options(options));
|
||||
}
|
||||
|
||||
BridgedCanType BridgedParameterInfo::getArgumentType(BridgedFunction f) const {
|
||||
return {unbridged().getArgumentType(f.getFunction())};
|
||||
}
|
||||
|
||||
SwiftInt BridgedParameterInfoArray::count() const {
|
||||
return parameterInfoArray.unbridged<swift::SILParameterInfo>().size();
|
||||
}
|
||||
@@ -245,10 +267,13 @@ OptionalBridgedResultInfo SILFunctionType_getErrorResult(BridgedCanType funcTy)
|
||||
auto fnTy = funcTy.unbridged()->castTo<swift::SILFunctionType>();
|
||||
auto resultInfo = fnTy->getOptionalErrorResult();
|
||||
if (resultInfo) {
|
||||
return {resultInfo->getInterfaceType().getPointer(),
|
||||
BridgedResultInfo::castToResultConvention(resultInfo->getConvention())};
|
||||
return {
|
||||
resultInfo->getInterfaceType(),
|
||||
BridgedResultInfo::castToResultConvention(resultInfo->getConvention()),
|
||||
resultInfo->getOptions().toRaw(),
|
||||
};
|
||||
}
|
||||
return {nullptr, BridgedResultConvention::Indirect};
|
||||
return {BridgedCanType(), BridgedResultConvention::Indirect, 0};
|
||||
|
||||
}
|
||||
|
||||
@@ -452,6 +477,18 @@ BridgedArgumentConvention BridgedType::getCalleeConvention() const {
|
||||
return getArgumentConvention(fnType->getCalleeConvention());
|
||||
}
|
||||
|
||||
SwiftInt BridgedType::getNumPackElements() const {
|
||||
return unbridged().getNumPackElements();
|
||||
}
|
||||
|
||||
BridgedType BridgedType::getPackElementType(SwiftInt idx) const {
|
||||
return unbridged().getPackElementType((unsigned) idx);
|
||||
}
|
||||
|
||||
BridgedCanType BridgedType::getApproximateFormalPackType() const {
|
||||
return unbridged().castTo<swift::SILPackType>()->getApproximateFormalPackType();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BridgedValue
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -506,6 +543,14 @@ BridgedFunction BridgedValue::PlaceholderValue_getParentFunction() const {
|
||||
return {llvm::cast<swift::PlaceholderValue>(getSILValue())->getParent()};
|
||||
}
|
||||
|
||||
BridgedValue::Ownership
|
||||
BridgedValueOwnership_init(BridgedFunction f, BridgedType type,
|
||||
BridgedArgumentConvention convention) {
|
||||
swift::ValueOwnershipKind ownership(*f.getFunction(), type.unbridged(),
|
||||
unbridge(convention));
|
||||
return bridge(ownership);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BridgedOperand
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -1461,6 +1506,14 @@ BridgedArgumentConvention BridgedInstruction::YieldInst_getConvention(BridgedOpe
|
||||
return castToArgumentConvention(getAs<swift::YieldInst>()->getArgumentConventionForOperand(*forOperand.op));
|
||||
}
|
||||
|
||||
BridgedBasicBlock BridgedInstruction::YieldInst_getResumeBB() const {
|
||||
return {getAs<swift::YieldInst>()->getResumeBB()};
|
||||
}
|
||||
|
||||
BridgedBasicBlock BridgedInstruction::YieldInst_getUnwindBB() const {
|
||||
return {getAs<swift::YieldInst>()->getUnwindBB()};
|
||||
}
|
||||
|
||||
BridgedBasicBlock BridgedInstruction::BranchInst_getTargetBlock() const {
|
||||
return {getAs<swift::BranchInst>()->getDestBB()};
|
||||
}
|
||||
@@ -1760,6 +1813,18 @@ BridgedCanType BridgedInstruction::TypeValueInst_getParamType() const {
|
||||
return getAs<swift::TypeValueInst>()->getParamType();
|
||||
}
|
||||
|
||||
BridgedCanType BridgedInstruction::PackLengthInst_getPackType() const {
|
||||
return getAs<swift::PackLengthInst>()->getPackType();
|
||||
}
|
||||
|
||||
SwiftInt BridgedInstruction::ScalarPackIndexInst_getComponentIndex() const {
|
||||
return getAs<swift::ScalarPackIndexInst>()->getComponentIndex();
|
||||
}
|
||||
|
||||
BridgedCanType BridgedInstruction::AnyPackIndexInst_getIndexedPackType() const {
|
||||
return getAs<swift::AnyPackIndexInst>()->getIndexedPackType();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VarDeclInst and DebugVariableInst
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -2281,6 +2346,18 @@ BridgedInstruction BridgedBuilder::createAllocStack(BridgedType type,
|
||||
swift::UsesMoveableValueDebugInfo_t(wasMoved), /*skipVarDeclAssert=*/ true)};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createAllocPack(BridgedType type) const {
|
||||
return {unbridged().createAllocPack(regularLoc(), type.unbridged())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createAllocPackMetadata() const {
|
||||
return {unbridged().createAllocPackMetadata(regularLoc())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createAllocPackMetadata(BridgedType type) const {
|
||||
return {unbridged().createAllocPackMetadata(regularLoc(), type.unbridged())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createDeallocStack(BridgedValue operand) const {
|
||||
return {unbridged().createDeallocStack(regularLoc(), operand.getSILValue())};
|
||||
}
|
||||
@@ -2290,6 +2367,10 @@ BridgedInstruction BridgedBuilder::createDeallocStackRef(BridgedValue operand) c
|
||||
unbridged().createDeallocStackRef(regularLoc(), operand.getSILValue())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createDeallocPack(BridgedValue operand) const {
|
||||
return {unbridged().createDeallocPack(regularLoc(), operand.getSILValue())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createAddressToPointer(BridgedValue address, BridgedType pointerTy,
|
||||
bool needsStackProtection) const {
|
||||
return {unbridged().createAddressToPointer(regularLoc(), address.getSILValue(), pointerTy.unbridged(),
|
||||
@@ -2678,6 +2759,11 @@ BridgedInstruction BridgedBuilder::createStore(BridgedValue src, BridgedValue ds
|
||||
(swift::StoreOwnershipQualifier)ownership)};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createStoreBorrow(BridgedValue src, BridgedValue dst) const {
|
||||
return {unbridged().createStoreBorrow(regularLoc(), src.getSILValue(),
|
||||
dst.getSILValue())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createInitExistentialRef(BridgedValue instance,
|
||||
BridgedType type,
|
||||
BridgedCanType formalConcreteType,
|
||||
@@ -2695,6 +2781,31 @@ BridgedInstruction BridgedBuilder::createInitExistentialMetatype(BridgedValue me
|
||||
conformances.pcArray.unbridged<swift::ProtocolConformanceRef>())};
|
||||
}
|
||||
|
||||
BridgedInstruction
|
||||
BridgedBuilder::createScalarPackIndex(SwiftInt componentIndex,
|
||||
BridgedCanType indexedPackType) const {
|
||||
auto *pt = indexedPackType.unbridged()->castTo<swift::PackType>();
|
||||
return {unbridged().createScalarPackIndex(regularLoc(), componentIndex,
|
||||
swift::CanPackType(pt))};
|
||||
}
|
||||
|
||||
BridgedInstruction
|
||||
BridgedBuilder::createPackElementGet(BridgedValue packIndex, BridgedValue pack,
|
||||
BridgedType elementType) const {
|
||||
return {unbridged().createPackElementGet(
|
||||
regularLoc(), packIndex.getSILValue(), pack.getSILValue(),
|
||||
elementType.unbridged())};
|
||||
}
|
||||
|
||||
BridgedInstruction
|
||||
BridgedBuilder::createPackElementSet(BridgedValue elementValue,
|
||||
BridgedValue packIndex,
|
||||
BridgedValue pack) const {
|
||||
return {unbridged().createPackElementSet(
|
||||
regularLoc(), elementValue.getSILValue(), packIndex.getSILValue(),
|
||||
pack.getSILValue())};
|
||||
}
|
||||
|
||||
BridgedInstruction BridgedBuilder::createMetatype(BridgedCanType instanceType,
|
||||
BridgedASTType::MetatypeRepresentation representation) const {
|
||||
auto *mt =
|
||||
|
||||
@@ -382,6 +382,10 @@ public:
|
||||
/// Whether the type's layout is known to include some flavor of pack.
|
||||
bool isOrContainsPack(const SILFunction &F) const;
|
||||
|
||||
/// Whether the elements of a @pack_owned or @pack_guaranteed pack type are
|
||||
/// direct values or addresses.
|
||||
bool isPackElementAddress() const;
|
||||
|
||||
/// True if the type is an empty tuple or an empty struct or a tuple or
|
||||
/// struct containing only empty types.
|
||||
bool isEmpty(const SILFunction &F) const;
|
||||
@@ -666,6 +670,11 @@ public:
|
||||
return SILType(castTo<TupleType>().getElementType(index), getCategory());
|
||||
}
|
||||
|
||||
unsigned getNumPackElements() const {
|
||||
SILPackType *packTy = castTo<SILPackType>();
|
||||
return packTy->getNumElements();
|
||||
}
|
||||
|
||||
/// Given that this is a pack type, return the lowered type of the
|
||||
/// given pack element. The result will have the same value
|
||||
/// category as the base type.
|
||||
|
||||
@@ -200,6 +200,8 @@ struct BridgedPassContext {
|
||||
BridgedFunction applySiteCallee) const;
|
||||
BridgedOwnedString mangleWithBoxToStackPromotedArgs(BridgedArrayRef bridgedPromotedArgIndices,
|
||||
BridgedFunction bridgedOriginalFunction) const;
|
||||
BridgedOwnedString mangleWithExplodedPackArgs(BridgedArrayRef bridgedPackArgs,
|
||||
BridgedFunction applySiteCallee) const;
|
||||
|
||||
void inlineFunction(BridgedInstruction apply, bool mandatoryInline) const;
|
||||
BRIDGED_INLINE bool eliminateDeadAllocations(BridgedFunction f) const;
|
||||
@@ -269,6 +271,8 @@ struct BridgedPassContext {
|
||||
SWIFT_IMPORT_UNSAFE BridgedFunction createSpecializedFunctionDeclaration(BridgedStringRef specializedName,
|
||||
const BridgedParameterInfo * _Nullable specializedBridgedParams,
|
||||
SwiftInt paramCount,
|
||||
const BridgedResultInfo *_Nullable specializedBridgedResults,
|
||||
SwiftInt resultCount,
|
||||
BridgedFunction bridgedOriginal,
|
||||
bool makeThin,
|
||||
bool makeBare,
|
||||
|
||||
@@ -152,6 +152,8 @@ PASS(TempLValueElimination, "temp-lvalue-elimination",
|
||||
"Remove short-lived immutable temporary l-values")
|
||||
PASS(LoopInvariantCodeMotion, "loop-invariant-code-motion",
|
||||
"New Loop Invariant Code Motion")
|
||||
PASS(PackSpecialization, "pack-specialization",
|
||||
"Specialize uses of parameter packs")
|
||||
|
||||
PASS(ClosureSpecialization, "closure-specialization",
|
||||
"Specialize functions with closure arguments")
|
||||
|
||||
@@ -161,6 +161,11 @@ bool SILType::isOrContainsPack(const SILFunction &F) const {
|
||||
return F.getTypeProperties(contextType).isOrContainsPack();
|
||||
}
|
||||
|
||||
bool SILType::isPackElementAddress() const {
|
||||
SILPackType *packTy = castTo<SILPackType>();
|
||||
return packTy->isElementAddress();
|
||||
}
|
||||
|
||||
bool SILType::isEmpty(const SILFunction &F) const {
|
||||
// Infinite types are never empty.
|
||||
if (F.getTypeProperties(*this).isInfinite()) {
|
||||
|
||||
@@ -525,6 +525,7 @@ void addFunctionPasses(SILPassPipelinePlan &P,
|
||||
// of embedded Swift.
|
||||
if (!P.getOptions().EmbeddedSwift) {
|
||||
P.addGenericSpecializer();
|
||||
P.addPackSpecialization();
|
||||
// Run devirtualizer after the specializer, because many
|
||||
// class_method/witness_method instructions may use concrete types now.
|
||||
P.addDevirtualizer();
|
||||
|
||||
@@ -333,6 +333,24 @@ BridgedOwnedString BridgedPassContext::mangleWithBoxToStackPromotedArgs(
|
||||
return BridgedOwnedString(mangler.mangle());
|
||||
}
|
||||
|
||||
BridgedOwnedString BridgedPassContext::mangleWithExplodedPackArgs(
|
||||
BridgedArrayRef bridgedPackArgs,
|
||||
BridgedFunction applySiteCallee
|
||||
) const {
|
||||
auto pass = Demangle::SpecializationPass::PackSpecialization;
|
||||
|
||||
auto serializedKind = applySiteCallee.getFunction()->getSerializedKind();
|
||||
Mangle::FunctionSignatureSpecializationMangler mangler(
|
||||
applySiteCallee.getFunction()->getASTContext(),
|
||||
pass, serializedKind, applySiteCallee.getFunction());
|
||||
|
||||
for (SwiftInt i : bridgedPackArgs.unbridged<SwiftInt>()) {
|
||||
mangler.setArgumentSROA((unsigned)i);
|
||||
}
|
||||
|
||||
return BridgedOwnedString(mangler.mangle());
|
||||
}
|
||||
|
||||
void BridgedPassContext::fixStackNesting(BridgedFunction function) const {
|
||||
switch (StackNesting::fixNesting(function.getFunction())) {
|
||||
case StackNesting::Changes::None:
|
||||
@@ -372,6 +390,8 @@ BridgedFunction BridgedPassContext::
|
||||
createSpecializedFunctionDeclaration(BridgedStringRef specializedName,
|
||||
const BridgedParameterInfo * _Nullable specializedBridgedParams,
|
||||
SwiftInt paramCount,
|
||||
const BridgedResultInfo * _Nullable specializedBridgedResults,
|
||||
SwiftInt resultCount,
|
||||
BridgedFunction bridgedOriginal,
|
||||
bool makeThin,
|
||||
bool makeBare,
|
||||
@@ -384,6 +404,14 @@ createSpecializedFunctionDeclaration(BridgedStringRef specializedName,
|
||||
specializedParams.push_back(specializedBridgedParams[idx].unbridged());
|
||||
}
|
||||
|
||||
// If no results list is passed, use the original function's results.
|
||||
llvm::SmallVector<SILResultInfo> specializedResults;
|
||||
if (specializedBridgedResults != nullptr) {
|
||||
for (unsigned idx = 0; idx < resultCount; ++idx) {
|
||||
specializedResults.push_back(specializedBridgedResults[idx].unbridged());
|
||||
}
|
||||
}
|
||||
|
||||
// The specialized function is always a thin function. This is important
|
||||
// because we may add additional parameters after the Self parameter of
|
||||
// witness methods. In this case the new function is not a method anymore.
|
||||
@@ -396,7 +424,7 @@ createSpecializedFunctionDeclaration(BridgedStringRef specializedName,
|
||||
extInfo,
|
||||
originalType->getCoroutineKind(),
|
||||
originalType->getCalleeConvention(), specializedParams,
|
||||
originalType->getYields(), originalType->getResults(),
|
||||
originalType->getYields(), specializedBridgedResults ? specializedResults : originalType->getResults(),
|
||||
originalType->getOptionalErrorResult(),
|
||||
preserveGenericSignature ? originalType->getPatternSubstitutions() : SubstitutionMap(),
|
||||
preserveGenericSignature ? originalType->getInvocationSubstitutions() : SubstitutionMap(),
|
||||
|
||||
791
test/SILOptimizer/pack_specialization.sil
Normal file
791
test/SILOptimizer/pack_specialization.sil
Normal file
@@ -0,0 +1,791 @@
|
||||
// RUN: %target-sil-opt %s -pack-specialization | %FileCheck %s
|
||||
|
||||
sil_stage canonical
|
||||
|
||||
import Builtin
|
||||
import Swift
|
||||
|
||||
protocol P {}
|
||||
|
||||
class C : P {}
|
||||
|
||||
// INDIVIDUAL PARAMETER TRANSFORMATION TESTS:
|
||||
//
|
||||
// There are currently 3 conventions for pack parameters: @pack_guaranteed,
|
||||
// @pack_owned and @pack_inout. Each member of an exploded pack parameter will
|
||||
// be mapped to a parameter that has a "direct" (@owned or unowned), @guaranteed
|
||||
// or indirect convention. We rely on the existing code to handle the ownership
|
||||
// and lifetimes of any indirect or @owned parameters, so there are only 3
|
||||
// different ways the pass needs to handle exploded pack elements. Accordingly,
|
||||
// this leads to 9 different cases for how a pack parameter may be transformed,
|
||||
// for which we have written 9 test cases.
|
||||
|
||||
// Check that name mangling, parameter & result pack explosion, local pack allocation, cleanup and use work as expected.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s24copy_pack_int_guaranteedTf8xx_n : $@convention(thin) (Int) -> Int {
|
||||
// CHECK: bb0(%0 : $Int):
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[ADDR:%[0-9]+]] = alloc_stack $Int
|
||||
// CHECK-NEXT: store %0 to [trivial] [[ADDR]]
|
||||
// CHECK-NEXT: pack_element_set [[ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_ADDR:%[0-9]+]] = alloc_stack $Int
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [trivial] [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_stack [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_stack [[ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s24copy_pack_int_guaranteedTf8xx_n'
|
||||
sil [ossa] @copy_pack_int_guaranteed : $@convention(thin) (@pack_guaranteed Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
copy_addr %1 to [init] %0
|
||||
%9 = tuple ()
|
||||
return %9
|
||||
}
|
||||
|
||||
// Check that parameters and results are correctly extracted from and written back to the former argument packs,
|
||||
// including any borrows of indirect parameters.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_int_guaranteed : $@convention(thin) (@pack_guaranteed Pack{Int}) -> @pack_out Pack{Int} {
|
||||
// CHECK: bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
// CHECK: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[IN_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[ARG_ADDR:%[0-9]+]] = pack_element_get [[IN_IDX]] of %1 as $*Int
|
||||
// CHECK-NEXT: [[ARG:%[0-9]+]] = load [trivial] [[ARG_ADDR]]
|
||||
// CHECK: [[FN_REF:%[0-9]+]] = function_ref @$s24copy_pack_int_guaranteedTf8xx_n : $@convention(thin) (Int) -> Int
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[FN_REF]]([[ARG]]) : $@convention(thin) (Int) -> Int
|
||||
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = pack_element_get [[OUT_IDX]] of %0
|
||||
// CHECK-NEXT: store [[RESULT]] to [trivial] [[RESULT_ADDR]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_int_guaranteed'
|
||||
sil [ossa] @call_copy_pack_int_guaranteed : $@convention(thin) (@pack_guaranteed Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1: $*Pack{Int}):
|
||||
%10 = function_ref @copy_pack_int_guaranteed : $@convention(thin) (@pack_guaranteed Pack{Int}) -> @pack_out Pack{Int}
|
||||
%11 = apply %10(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{Int}) -> @pack_out Pack{Int}
|
||||
return %11
|
||||
}
|
||||
|
||||
// As above, for an owned pack.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s19copy_pack_int_ownedTf8xx_n : $@convention(thin) (Int) -> Int {
|
||||
// CHECK: bb0(%0 : $Int):
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[ADDR:%[0-9]+]] = alloc_stack $Int
|
||||
// CHECK-NEXT: store %0 to [trivial] [[ADDR]]
|
||||
// CHECK-NEXT: pack_element_set [[ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_ADDR:%[0-9]+]] = alloc_stack $Int
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [trivial] [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_stack [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_stack [[ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s19copy_pack_int_ownedTf8xx_n'
|
||||
sil [ossa] @copy_pack_int_owned : $@convention(thin) (@pack_owned Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
copy_addr %1 to [init] %0
|
||||
%9 = tuple ()
|
||||
return %9
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_int_owned : $@convention(thin) (@pack_owned Pack{Int}) -> @pack_out Pack{Int} {
|
||||
// CHECK: bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
// CHECK: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[IN_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[ARG_ADDR:%[0-9]+]] = pack_element_get [[IN_IDX]] of %1 as $*Int
|
||||
// CHECK-NEXT: [[ARG:%[0-9]+]] = load [trivial] [[ARG_ADDR]]
|
||||
// CHECK: [[FN_REF:%[0-9]+]] = function_ref @$s19copy_pack_int_ownedTf8xx_n : $@convention(thin) (Int) -> Int
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[FN_REF]]([[ARG]]) : $@convention(thin) (Int) -> Int
|
||||
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = pack_element_get [[OUT_IDX]] of %0
|
||||
// CHECK-NEXT: store [[RESULT]] to [trivial] [[RESULT_ADDR]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_int_owned'
|
||||
sil [ossa] @call_copy_pack_int_owned : $@convention(thin) (@pack_owned Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
%10 = function_ref @copy_pack_int_owned : $@convention(thin) (@pack_owned Pack{Int}) -> @pack_out Pack{Int}
|
||||
%11 = apply %10(%0, %1) : $@convention(thin) (@pack_owned Pack{Int}) -> @pack_out Pack{Int}
|
||||
return %11
|
||||
}
|
||||
|
||||
// As above, for an inout pack.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s19copy_pack_int_inoutTf8xx_n : $@convention(thin) (@inout Int) -> Int {
|
||||
// CHECK: bb0([[ADDR:%[0-9]+]] : $*Int):
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: pack_element_set [[ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[OUT_ADDR:%[0-9]+]] = alloc_stack $Int
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [trivial] [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_stack [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s19copy_pack_int_inoutTf8xx_n'
|
||||
sil [ossa] @copy_pack_int_inout : $@convention(thin) (@pack_inout Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
copy_addr %1 to [init] %0
|
||||
%9 = tuple ()
|
||||
return %9
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_int_inout : $@convention(thin) (@pack_inout Pack{Int}) -> @pack_out Pack{Int} {
|
||||
// CHECK: bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
// CHECK: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[IN_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Int}
|
||||
// CHECK-NEXT: [[ARG_ADDR:%[0-9]+]] = pack_element_get [[IN_IDX]] of %1 as $*Int
|
||||
// CHECK: [[FN_REF:%[0-9]+]] = function_ref @$s19copy_pack_int_inoutTf8xx_n : $@convention(thin) (@inout Int) -> Int
|
||||
// CHECK-NEXT: [[CALL_RESULT:%[0-9]+]] = apply [[FN_REF]]([[ARG_ADDR]]) : $@convention(thin) (@inout Int) -> Int
|
||||
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = pack_element_get [[OUT_IDX]] of %0
|
||||
// CHECK-NEXT: store [[CALL_RESULT]] to [trivial] [[RESULT_ADDR]]
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_int_inout'
|
||||
sil [ossa] @call_copy_pack_int_inout : $@convention(thin) (@pack_inout Pack{Int}) -> @pack_out Pack{Int} {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*Pack{Int}):
|
||||
%10 = function_ref @copy_pack_int_inout : $@convention(thin) (@pack_inout Pack{Int}) -> @pack_out Pack{Int}
|
||||
%11 = apply %10(%0, %1) : $@convention(thin) (@pack_inout Pack{Int}) -> @pack_out Pack{Int}
|
||||
%12 = tuple ()
|
||||
return %12
|
||||
}
|
||||
|
||||
|
||||
// Check that borrowed lifetimes are managed correctly for guaranteed pack-exploded arguments.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s28copy_pack_class_c_guaranteedTf8xx_n : $@convention(thin) (@guaranteed C) -> @owned C {
|
||||
// CHECK: bb0(%0 : @guaranteed $C):
|
||||
// CHECK: [[IN_ADDR:%[0-9]+]] = alloc_stack $C
|
||||
// CHECK: [[BORROW:%[0-9]+]] = store_borrow %0 to [[IN_ADDR]]
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = alloc_stack $C
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [take] [[OUT_ADDR]]
|
||||
// CHECK: end_borrow [[BORROW]]
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s28copy_pack_class_c_guaranteedTf8xx_n'
|
||||
sil [ossa] @copy_pack_class_c_guaranteed : $@convention(thin) (@pack_guaranteed Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
copy_addr %1 to [init] %0
|
||||
%8 = tuple ()
|
||||
return %8
|
||||
}
|
||||
|
||||
// Check that non-trivial guaranteed parameters are correctly borrowed
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_class_c_guaranteed : $@convention(thin) (@pack_guaranteed Pack{C}) -> @pack_out Pack{C} {
|
||||
// CHECK: bb0(%0 : $*Pack{C}, %1 : $*Pack{C})
|
||||
// CHECK: [[IN_C_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*C
|
||||
// CHECK-NEXT: [[BORROW:%[0-9]+]] = load_borrow [[IN_C_PACK_ADDR]]
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s28copy_pack_class_c_guaranteedTf8xx_n : $@convention(thin) (@guaranteed C) -> @owned C
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[BORROW]]) : $@convention(thin) (@guaranteed C) -> @owned C
|
||||
// CHECK-NEXT: end_borrow [[BORROW]]
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*C
|
||||
// CHECK: store [[RESULT]] to [init] [[OUT_ADDR]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_class_c_guaranteed'
|
||||
sil [ossa] @call_copy_pack_class_c_guaranteed : $@convention(thin) (@pack_guaranteed Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
%16 = function_ref @copy_pack_class_c_guaranteed : $@convention(thin) (@pack_guaranteed Pack{C}) -> @pack_out Pack{C}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{C}) -> @pack_out Pack{C}
|
||||
return %17
|
||||
}
|
||||
|
||||
|
||||
// Check that lifetimes are managed correctly for owned pack-exploded arguments.
|
||||
// The original code already manages lifetimes sufficiently, so no additional retains, releases, borrows etc. are necessary.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s23copy_pack_class_c_ownedTf8xx_n : $@convention(thin) (@owned C) -> @owned C {
|
||||
// CHECK: bb0(%0 : @owned $C):
|
||||
// CHECK: [[IN_ADDR:%[0-9]+]] = alloc_stack $C
|
||||
// CHECK: store %0 to [init] [[IN_ADDR]]
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = alloc_stack $C
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [take] [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_stack [[OUT_ADDR]]
|
||||
// CHECK: dealloc_stack [[IN_ADDR]]
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s23copy_pack_class_c_ownedTf8xx_n'
|
||||
sil [ossa] @copy_pack_class_c_owned : $@convention(thin) (@pack_owned Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
copy_addr %1 to [init] %0
|
||||
%8 = tuple ()
|
||||
return %8
|
||||
}
|
||||
|
||||
// Check that non-trivial owned pack-exploded parameters are loaded and passed correctly.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_class_c_owned : $@convention(thin) (@pack_owned Pack{C}) -> @pack_out Pack{C} {
|
||||
// CHECK: bb0(%0 : $*Pack{C}, %1 : $*Pack{C})
|
||||
// CHECK: [[IN_C_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*C
|
||||
// CHECK-NEXT: [[ARGUMENT:%[0-9]+]] = load [take] [[IN_C_PACK_ADDR]]
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s23copy_pack_class_c_ownedTf8xx_n : $@convention(thin) (@owned C) -> @owned C
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[ARGUMENT]]) : $@convention(thin) (@owned C) -> @owned C
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*C
|
||||
// CHECK: store [[RESULT]] to [init] [[OUT_ADDR]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_class_c_owned'
|
||||
sil [ossa] @call_copy_pack_class_c_owned : $@convention(thin) (@pack_owned Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
%16 = function_ref @copy_pack_class_c_owned : $@convention(thin) (@pack_owned Pack{C}) -> @pack_out Pack{C}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_owned Pack{C}) -> @pack_out Pack{C}
|
||||
return %17
|
||||
}
|
||||
|
||||
// As above, for an inout Pack{C}. The code in this function should be almost identical to the @pack_inout Pack{Int} one.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s23copy_pack_class_c_inoutTf8xx_n : $@convention(thin) (@inout C) -> @owned C {
|
||||
// CHECK: bb0([[ADDR:%[0-9]+]] : $*C):
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{C}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{C}
|
||||
// CHECK-NEXT: pack_element_set [[ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{C}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{C}
|
||||
// CHECK-NEXT: [[OUT_ADDR:%[0-9]+]] = alloc_stack $C
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load [take] [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_stack [[OUT_ADDR]]
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s23copy_pack_class_c_inoutTf8xx_n'
|
||||
sil [ossa] @copy_pack_class_c_inout : $@convention(thin) (@pack_inout Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
copy_addr %1 to [init] %0
|
||||
%9 = tuple ()
|
||||
return %9
|
||||
}
|
||||
|
||||
// Check that non-trivial inout pack-exploded parameters are passed correctly.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_class_c_inout : $@convention(thin) (@pack_inout Pack{C}) -> @pack_out Pack{C} {
|
||||
// CHECK: bb0(%0 : $*Pack{C}, %1 : $*Pack{C})
|
||||
// CHECK: [[IN_C_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*C
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s23copy_pack_class_c_inoutTf8xx_n : $@convention(thin) (@inout C) -> @owned C
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[IN_C_PACK_ADDR]]) : $@convention(thin) (@inout C) -> @owned C
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*C
|
||||
// CHECK: store [[RESULT]] to [init] [[OUT_ADDR]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_class_c_inout'
|
||||
sil [ossa] @call_copy_pack_class_c_inout : $@convention(thin) (@pack_inout Pack{C}) -> @pack_out Pack{C} {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
%16 = function_ref @copy_pack_class_c_inout : $@convention(thin) (@pack_inout Pack{C}) -> @pack_out Pack{C}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_inout Pack{C}) -> @pack_out Pack{C}
|
||||
return %17
|
||||
}
|
||||
|
||||
// Check that pack explosion procedure is correct for non-loadable pack element types like any P.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s31copy_pack_protocol_p_guaranteedTf8xx_n : $@convention(thin) (@in_guaranteed any P) -> @out any P {
|
||||
// CHECK: bb0([[OUT_ADDR:%[0-9]+]] : $*any P, [[IN_ADDR:%[0-9]+]] : $*any P)
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[IN_ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[OUT_ADDR]] into [[OUT_IDX]] of [[OUT_PACK]]
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s31copy_pack_protocol_p_guaranteedTf8xx_n'
|
||||
sil [ossa] @copy_pack_protocol_p_guaranteed : $@convention(thin) (@pack_guaranteed Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
copy_addr %1 to [init] %0
|
||||
%7 = tuple ()
|
||||
return %7
|
||||
}
|
||||
|
||||
// Check that indirect result and parameter pack members are correctly extracted and passed to the callee.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_protocol_p_guaranteed : $@convention(thin) (@pack_guaranteed Pack{any P}) -> @pack_out Pack{any P} {
|
||||
// CHECK: bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P})
|
||||
// CHECK: [[OUT_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*any P
|
||||
// CHECK: [[IN_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*any P
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s31copy_pack_protocol_p_guaranteedTf8xx_n : $@convention(thin) (@in_guaranteed any P) -> @out any P
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[OUT_P_PACK_ADDR]], [[IN_P_PACK_ADDR]]) : $@convention(thin) (@in_guaranteed any P) -> @out any P
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_protocol_p_guaranteed'
|
||||
sil [ossa] @call_copy_pack_protocol_p_guaranteed : $@convention(thin) (@pack_guaranteed Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
%16 = function_ref @copy_pack_protocol_p_guaranteed : $@convention(thin) (@pack_guaranteed Pack{any P}) -> @pack_out Pack{any P}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{any P}) -> @pack_out Pack{any P}
|
||||
return %17
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s26copy_pack_protocol_p_ownedTf8xx_n : $@convention(thin) (@in any P) -> @out any P {
|
||||
// CHECK: bb0([[OUT_ADDR:%[0-9]+]] : $*any P, [[IN_ADDR:%[0-9]+]] : $*any P)
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[IN_ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[OUT_ADDR]] into [[OUT_IDX]] of [[OUT_PACK]]
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s26copy_pack_protocol_p_ownedTf8xx_n'
|
||||
sil [ossa] @copy_pack_protocol_p_owned : $@convention(thin) (@pack_owned Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
copy_addr %1 to [init] %0
|
||||
%7 = tuple ()
|
||||
return %7
|
||||
}
|
||||
|
||||
// As above for non-loadable types in owned packs.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_protocol_p_owned : $@convention(thin) (@pack_owned Pack{any P}) -> @pack_out Pack{any P} {
|
||||
// CHECK: bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P})
|
||||
// CHECK: [[OUT_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*any P
|
||||
// CHECK: [[IN_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*any P
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s26copy_pack_protocol_p_ownedTf8xx_n : $@convention(thin) (@in any P) -> @out any P
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[OUT_P_PACK_ADDR]], [[IN_P_PACK_ADDR]]) : $@convention(thin) (@in any P) -> @out any P
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_protocol_p_owned'
|
||||
sil [ossa] @call_copy_pack_protocol_p_owned : $@convention(thin) (@pack_owned Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
%16 = function_ref @copy_pack_protocol_p_owned : $@convention(thin) (@pack_owned Pack{any P}) -> @pack_out Pack{any P}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_owned Pack{any P}) -> @pack_out Pack{any P}
|
||||
return %17
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s26copy_pack_protocol_p_inoutTf8xx_n : $@convention(thin) (@inout any P) -> @out any P {
|
||||
// CHECK: bb0([[OUT_ADDR:%[0-9]+]] : $*any P, [[IN_ADDR:%[0-9]+]] : $*any P)
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[IN_ADDR]] into [[IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{any P}
|
||||
// CHECK-NEXT: [[OUT_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P}
|
||||
// CHECK-NEXT: pack_element_set [[OUT_ADDR]] into [[OUT_IDX]] of [[OUT_PACK]]
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK-NEXT: dealloc_pack [[OUT_PACK]]
|
||||
// CHECK-NEXT: dealloc_pack [[IN_PACK]]
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s26copy_pack_protocol_p_inoutTf8xx_n'
|
||||
sil [ossa] @copy_pack_protocol_p_inout : $@convention(thin) (@pack_inout Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
copy_addr %1 to [init] %0
|
||||
%7 = tuple ()
|
||||
return %7
|
||||
}
|
||||
|
||||
// As above for non-loadable types in inout packs.
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_pack_protocol_p_inout : $@convention(thin) (@pack_inout Pack{any P}) -> @pack_out Pack{any P} {
|
||||
// CHECK: bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P})
|
||||
// CHECK: [[OUT_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[OUT_PACK_GET_IDX:%[0-9]+]] of %0 as $*any P
|
||||
// CHECK: [[IN_P_PACK_ADDR:%[0-9]+]] = pack_element_get [[PACK_GET_IDX:%[0-9]+]] of %1 as $*any P
|
||||
// CHECK: [[SPECIALIZED:%[0-9]+]] = function_ref @$s26copy_pack_protocol_p_inoutTf8xx_n : $@convention(thin) (@inout any P) -> @out any P
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SPECIALIZED]]([[OUT_P_PACK_ADDR]], [[IN_P_PACK_ADDR]]) : $@convention(thin) (@inout any P) -> @out any P
|
||||
// CHECK-NEXT: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_pack_protocol_p_inout'
|
||||
sil [ossa] @call_copy_pack_protocol_p_inout : $@convention(thin) (@pack_inout Pack{any P}) -> @pack_out Pack{any P} {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
%16 = function_ref @copy_pack_protocol_p_inout : $@convention(thin) (@pack_inout Pack{any P}) -> @pack_out Pack{any P}
|
||||
%17 = apply %16(%0, %1) : $@convention(thin) (@pack_inout Pack{any P}) -> @pack_out Pack{any P}
|
||||
return %17
|
||||
}
|
||||
|
||||
// INTERLEAVING PACK AND NON-PACK ARGUMENTS TESTS:
|
||||
//
|
||||
// The new function arguments and return values corresponding to pack parameters
|
||||
// are inserted into the parameter and results lists in the same order as they
|
||||
// are passed in the original pack.
|
||||
//
|
||||
// Other tests cover the callee and call-site modifications necessary to extract
|
||||
// elements from packs. These tests focus primarily on the positions of the
|
||||
// mapped arguments and result values.
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s18interleave_unownedTf8xnxn_n : $@convention(thin) (Builtin.Int64, Builtin.Int32, Builtin.Int64) -> (Builtin.Int64, Builtin.Int32, Builtin.Int64) {
|
||||
// CHECK: bb0([[A1:%[0-9]+]] : $Builtin.Int64, [[A2:%[0-9]+]] : $Builtin.Int32, [[A3:%[0-9]+]] : $Builtin.Int64):
|
||||
// CHECK: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int32}
|
||||
// CHECK: store [[A2]] to [trivial] [[IN_STACK:%[0-9]+]]
|
||||
// CHECK: pack_element_set [[IN_STACK]] into [[IN_IDX:%[0-9]+]] of [[IN_PACK]]
|
||||
// CHECK: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int32}
|
||||
// CHECK: [[OUT_ADDR:%[0-9]+]] = alloc_stack $Builtin.Int32
|
||||
// CHECK: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ([[A1]], [[A3]])
|
||||
// CHECK: ([[R1:%[0-9]+]], [[R3:%[0-9]+]]) = destructure_tuple [[ORIGINAL_RESULT]]
|
||||
// CHECK: [[R2:%[0-9]+]] = load [trivial] [[OUT_ADDR]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = tuple ([[R1]], [[R2]], [[R3]])
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s18interleave_unownedTf8xnxn_n'
|
||||
sil [ossa] @interleave_unowned : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{Builtin.Int32}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{Builtin.Int32}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{Builtin.Int32}, %1 : $Builtin.Int64, %2 : $*Pack{Builtin.Int32}, %3 : $Builtin.Int64):
|
||||
%7 = scalar_pack_index 0 of $Pack{Builtin.Int32}
|
||||
%8 = pack_element_get %7 of %0 as $*Builtin.Int32
|
||||
%9 = pack_element_get %7 of %2 as $*Builtin.Int32
|
||||
copy_addr %9 to [init] %8
|
||||
%12 = tuple (%1, %3)
|
||||
return %12
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_interleave_unowned : $@convention(thin) (@pack_owned Pack{Builtin.Int32}) -> (Builtin.Int64, @pack_out Pack{Builtin.Int32}, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $*Pack{Builtin.Int32}, %1 : $*Pack{Builtin.Int32}):
|
||||
// CHECK: [[FNREF:%[0-9]+]] = function_ref @$s18interleave_unownedTf8xnxn_n
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[FNREF]]
|
||||
// CHECK: ([[R1:%[0-9]+]], [[R2:%[0-9]+]], [[R3:%[0-9]+]]) = destructure_tuple [[RESULT]]
|
||||
// CHECK: store [[R2]] to
|
||||
// CHECK-NEXT: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ([[R1:%[0-9]+]], [[R3:%[0-9]+]])
|
||||
// CHECK-NEXT: return [[ORIGINAL_RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_interleave_unowned'
|
||||
sil [ossa] @call_interleave_unowned : $@convention(thin) (@pack_owned Pack{Builtin.Int32}) -> (Builtin.Int64, @pack_out Pack{Builtin.Int32}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{Builtin.Int32}, %1 : $*Pack{Builtin.Int32}):
|
||||
%6 = integer_literal $Builtin.Int64, 1
|
||||
%12 = integer_literal $Builtin.Int64, 3
|
||||
%14 = function_ref @interleave_unowned : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{Builtin.Int32}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{Builtin.Int32}, Builtin.Int64)
|
||||
%15 = apply %14(%0, %6, %1, %12) : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{Builtin.Int32}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{Builtin.Int32}, Builtin.Int64)
|
||||
return %15
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s17interleave_directTf8xnxn_n : $@convention(thin) (Builtin.Int64, @guaranteed C, Builtin.Int64) -> (Builtin.Int64, @owned C, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $Builtin.Int64, %1 : @guaranteed $C, %2 : $Builtin.Int64):
|
||||
// CHECK: ([[R1:%[0-9]+]], [[R3:%[0-9]+]]) = destructure_tuple
|
||||
// CHECK: [[R2:%[0-9]+]] = load [take]
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ([[R1]], [[R2]], [[R3]])
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s17interleave_directTf8xnxn_n'
|
||||
sil [ossa] @interleave_direct : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{C}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{C}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{C}, %1 : $Builtin.Int64, %2 : $*Pack{C}, %3 : $Builtin.Int64):
|
||||
%7 = scalar_pack_index 0 of $Pack{C}
|
||||
%8 = pack_element_get %7 of %0 as $*C
|
||||
%9 = pack_element_get %7 of %2 as $*C
|
||||
copy_addr %9 to [init] %8
|
||||
%12 = tuple (%1, %3)
|
||||
return %12
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_interleave_direct : $@convention(thin) (@pack_owned Pack{C}) -> (Builtin.Int64, @pack_out Pack{C}, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
// CHECK: [[FNREF:%[0-9]+]] = function_ref @$s17interleave_directTf8xnxn_n
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[FNREF]]
|
||||
// CHECK: ([[R1:%[0-9]+]], [[R2:%[0-9]+]], [[R3:%[0-9]+]]) = destructure_tuple [[RESULT]]
|
||||
// CHECK: store [[R2]] to
|
||||
// CHECK-NEXT: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ([[R1:%[0-9]+]], [[R3:%[0-9]+]])
|
||||
// CHECK: return [[ORIGINAL_RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_interleave_direct'
|
||||
sil [ossa] @call_interleave_direct : $@convention(thin) (@pack_owned Pack{C}) -> (Builtin.Int64, @pack_out Pack{C}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{C}, %1 : $*Pack{C}):
|
||||
%6 = integer_literal $Builtin.Int64, 1
|
||||
%12 = integer_literal $Builtin.Int64, 3
|
||||
%14 = function_ref @interleave_direct : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{C}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{C}, Builtin.Int64)
|
||||
%15 = apply %14(%0, %6, %1, %12) : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{C}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{C}, Builtin.Int64)
|
||||
return %15
|
||||
}
|
||||
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s19interleave_indirectTf8xnxn_n : $@convention(thin) (Builtin.Int64, @in_guaranteed any P, Builtin.Int64) -> (Builtin.Int64, @out any P, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $*any P, %1 : $Builtin.Int64, %2 : $*any P, %3 : $Builtin.Int64):
|
||||
// CHECK: pack_element_set %2 into
|
||||
// CHECK: pack_element_set %0 into
|
||||
// CHECK: pack_element_get [[INDEX:%[0-9]+]] of [[OUT_PACK:%[0-9]+]]
|
||||
// CHECK: pack_element_get [[INDEX]] of [[IN_PACK:%[0-9]+]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = tuple ([[R1:%[0-9]+]], [[R3:%[0-9]+]])
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s19interleave_indirectTf8xnxn_n'
|
||||
sil [ossa] @interleave_indirect : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{any P}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{any P}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $Builtin.Int64, %2 : $*Pack{any P}, %3 : $Builtin.Int64):
|
||||
%7 = scalar_pack_index 0 of $Pack{any P}
|
||||
%8 = pack_element_get %7 of %0 as $*any P
|
||||
%9 = pack_element_get %7 of %2 as $*any P
|
||||
copy_addr %9 to [init] %8
|
||||
%11 = tuple (%1, %3)
|
||||
return %11
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_interleave_indirect : $@convention(thin) (@pack_owned Pack{any P}) -> (Builtin.Int64, @pack_out Pack{any P}, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
// CHECK: [[FNREF:%[0-9]+]] = function_ref @$s19interleave_indirectTf8xnxn_n
|
||||
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[FNREF]]
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function 'call_interleave_indirect'
|
||||
sil [ossa] @call_interleave_indirect : $@convention(thin) (@pack_owned Pack{any P}) -> (Builtin.Int64, @pack_out Pack{any P}, Builtin.Int64) {
|
||||
bb0(%0 : $*Pack{any P}, %1 : $*Pack{any P}):
|
||||
%6 = integer_literal $Builtin.Int64, 1
|
||||
%12 = integer_literal $Builtin.Int64, 3
|
||||
%14 = function_ref @interleave_indirect : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{any P}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{any P}, Builtin.Int64)
|
||||
%15 = apply %14(%0, %6, %1, %12) : $@convention(thin) (Builtin.Int64, @pack_guaranteed Pack{any P}, Builtin.Int64) -> (Builtin.Int64, @pack_out Pack{any P}, Builtin.Int64)
|
||||
return %15
|
||||
}
|
||||
|
||||
// MULTI-ELEMENT PACK TESTS:
|
||||
|
||||
// Since the pack elements are the same type, ensure they are inserted in the correct order.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s09copy_int_B0Tf8xx_n : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> (Builtin.Int64, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
|
||||
// CHECK: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int64, Builtin.Int64}
|
||||
// CHECK: [[IN_IDX_0:%[0-9]+]] = scalar_pack_index 0 of $Pack{Builtin.Int64, Builtin.Int64}
|
||||
// CHECK: [[IN_ADDR_0:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: store %0 to [trivial] [[IN_ADDR_0]]
|
||||
// CHECK: pack_element_set [[IN_ADDR_0]] into [[IN_IDX_0]] of [[IN_PACK]]
|
||||
// CHECK: [[IN_IDX_1:%[0-9]+]] = scalar_pack_index 1 of $Pack{Builtin.Int64, Builtin.Int64}
|
||||
// CHECK: [[IN_ADDR_1:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: store %1 to [trivial] [[IN_ADDR_1]]
|
||||
// CHECK: pack_element_set [[IN_ADDR_1]] into [[IN_IDX_1]] of [[IN_PACK]]
|
||||
// CHECK: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int64, Builtin.Int64}
|
||||
// CHECK: [[OUT_ADDR_0:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: [[OUT_ADDR_1:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK: [[OUT_0:%[0-9]+]] = load [trivial] [[OUT_ADDR_0]]
|
||||
// CHECK: [[OUT_1:%[0-9]+]] = load [trivial] [[OUT_ADDR_1]]
|
||||
// CHECK: [[RESULT:%[0-9]+]] = tuple ([[OUT_0]], [[OUT_1]])
|
||||
// CHECK: return [[RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s09copy_int_B0Tf8xx_n'
|
||||
sil [ossa] @copy_int_int : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, Builtin.Int64}) -> @pack_out Pack{Builtin.Int64, Builtin.Int64} {
|
||||
bb0(%0 : $*Pack{Builtin.Int64, Builtin.Int64}, %1 : $*Pack{Builtin.Int64, Builtin.Int64}):
|
||||
copy_addr %1 to [init] %0
|
||||
%13 = tuple ()
|
||||
return %13
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_int_int : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, Builtin.Int64}) -> @pack_out Pack{Builtin.Int64, Builtin.Int64} {
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_int_int'
|
||||
sil [ossa] @call_copy_int_int : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, Builtin.Int64}) -> @pack_out Pack{Builtin.Int64, Builtin.Int64} {
|
||||
bb0(%0 : $*Pack{Builtin.Int64, Builtin.Int64}, %1: $*Pack{Builtin.Int64, Builtin.Int64}):
|
||||
%2 = function_ref @copy_int_int : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, Builtin.Int64}) -> @pack_out Pack{Builtin.Int64, Builtin.Int64}
|
||||
%3 = apply %2(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, Builtin.Int64}) -> @pack_out Pack{Builtin.Int64, Builtin.Int64}
|
||||
%4 = tuple ()
|
||||
return %4
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s10copy_int_pTf8xx_n : $@convention(thin) (Builtin.Int64, @in_guaranteed any P) -> (Builtin.Int64, @out any P) {
|
||||
// CHECK: bb0(%0 : $*any P, %1 : $Builtin.Int64, %2 : $*any P):
|
||||
// CHECK: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int64, any P}
|
||||
// CHECK: [[IN_ADDR_0:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: store %1 to [trivial] [[IN_ADDR_0]]
|
||||
// CHECK: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int64, any P}
|
||||
// CHECK: [[OUT_ADDR_0:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK: [[OUT_0:%[0-9]+]] = load [trivial] [[OUT_ADDR_0]]
|
||||
// CHECK: return [[OUT_0]]
|
||||
// CHECK-LABEL: } // end sil function '$s10copy_int_pTf8xx_n'
|
||||
sil [ossa] @copy_int_p : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, any P}) -> @pack_out Pack{Builtin.Int64, any P} {
|
||||
bb0(%0 : $*Pack{Builtin.Int64, any P}, %1 : $*Pack{Builtin.Int64, any P}):
|
||||
copy_addr %1 to [init] %0
|
||||
%12 = tuple ()
|
||||
return %12
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_int_p : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, any P}) -> @pack_out Pack{Builtin.Int64, any P} {
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_int_p'
|
||||
sil [ossa] @call_copy_int_p : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, any P}) -> @pack_out Pack{Builtin.Int64, any P} {
|
||||
bb0(%0 : $*Pack{Builtin.Int64, any P}, %1: $*Pack{Builtin.Int64, any P}):
|
||||
%2 = function_ref @copy_int_p : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, any P}) -> @pack_out Pack{Builtin.Int64, any P}
|
||||
%3 = apply %2(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64, any P}) -> @pack_out Pack{Builtin.Int64, any P}
|
||||
%4 = tuple ()
|
||||
return %4
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s10copy_p_intTf8xx_n : $@convention(thin) (@in_guaranteed any P, Builtin.Int64) -> (@out any P, Builtin.Int64) {
|
||||
// CHECK: bb0(%0 : $*any P, %1 : $*any P, %2 : $Builtin.Int64):
|
||||
// CHECK: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{any P, Builtin.Int64}
|
||||
// CHECK: [[IN_ADDR_1:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: store %2 to [trivial] [[IN_ADDR_1]]
|
||||
// CHECK: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{any P, Builtin.Int64}
|
||||
// CHECK: [[OUT_ADDR_0:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK: [[OUT_0:%[0-9]+]] = load [trivial] [[OUT_ADDR_0]]
|
||||
// CHECK: return [[OUT_0]]
|
||||
// CHECK-LABEL: } // end sil function '$s10copy_p_intTf8xx_n'
|
||||
sil [ossa] @copy_p_int : $@convention(thin) (@pack_guaranteed Pack{any P, Builtin.Int64}) -> @pack_out Pack{any P, Builtin.Int64} {
|
||||
bb0(%0 : $*Pack{any P, Builtin.Int64}, %1 : $*Pack{any P, Builtin.Int64}):
|
||||
copy_addr %1 to [init] %0
|
||||
%12 = tuple ()
|
||||
return %12
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_p_int : $@convention(thin) (@pack_guaranteed Pack{any P, Builtin.Int64}) -> @pack_out Pack{any P, Builtin.Int64} {
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_p_int'
|
||||
sil [ossa] @call_copy_p_int : $@convention(thin) (@pack_guaranteed Pack{any P, Builtin.Int64}) -> @pack_out Pack{any P, Builtin.Int64} {
|
||||
bb0(%0 : $*Pack{any P, Builtin.Int64}, %1: $*Pack{any P, Builtin.Int64}):
|
||||
%2 = function_ref @copy_p_int : $@convention(thin) (@pack_guaranteed Pack{any P, Builtin.Int64}) -> @pack_out Pack{any P, Builtin.Int64}
|
||||
%3 = apply %2(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{any P, Builtin.Int64}) -> @pack_out Pack{any P, Builtin.Int64}
|
||||
%4 = tuple ()
|
||||
return %4
|
||||
}
|
||||
|
||||
// Since the pack elements are the same type, ensure they are inserted in the correct order.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s8copy_p_pTf8xx_n : $@convention(thin) (@in_guaranteed any P, @in_guaranteed any P) -> (@out any P, @out any P) {
|
||||
// CHECK: bb0(%0 : $*any P, %1 : $*any P, %2 : $*any P, %3 : $*any P):
|
||||
// CHECK: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{any P, any P}
|
||||
// CHECK-NEXT: [[IN_IDX_0:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P, any P}
|
||||
// CHECK-NEXT: pack_element_set %2 into [[IN_IDX_0]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: [[IN_IDX_1:%[0-9]+]] = scalar_pack_index 1 of $Pack{any P, any P}
|
||||
// CHECK-NEXT: pack_element_set %3 into [[IN_IDX_1]] of [[IN_PACK]]
|
||||
// CHECK: [[OUT_PACK:%[0-9]+]] = alloc_pack $Pack{any P, any P}
|
||||
// CHECK-NEXT: [[OUT_IDX_0:%[0-9]+]] = scalar_pack_index 0 of $Pack{any P, any P}
|
||||
// CHECK-NEXT: pack_element_set %0 into [[OUT_IDX_0]] of [[OUT_PACK]]
|
||||
// CHECK-NEXT: [[OUT_IDX_1:%[0-9]+]] = scalar_pack_index 1 of $Pack{any P, any P}
|
||||
// CHECK-NEXT: pack_element_set %1 into [[OUT_IDX_1]] of [[OUT_PACK]]
|
||||
// CHECK: copy_addr [[IN_PACK]] to [init] [[OUT_PACK]]
|
||||
// CHECK: [[ORIGINAL_RESULT:%[0-9]+]] = tuple ()
|
||||
// CHECK: return [[ORIGINAL_RESULT]]
|
||||
// CHECK-LABEL: } // end sil function '$s8copy_p_pTf8xx_n'
|
||||
sil [ossa] @copy_p_p : $@convention(thin) (@pack_guaranteed Pack{any P, any P}) -> @pack_out Pack{any P, any P} {
|
||||
bb0(%0 : $*Pack{any P, any P}, %1 : $*Pack{any P, any P}):
|
||||
copy_addr %1 to [init] %0
|
||||
%11 = tuple ()
|
||||
return %11
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_copy_p_p : $@convention(thin) (@pack_guaranteed Pack{any P, any P}) -> @pack_out Pack{any P, any P} {
|
||||
// CHECK-LABEL: } // end sil function 'call_copy_p_p'
|
||||
sil [ossa] @call_copy_p_p : $@convention(thin) (@pack_guaranteed Pack{any P, any P}) -> @pack_out Pack{any P, any P} {
|
||||
bb0(%0 : $*Pack{any P, any P}, %1: $*Pack{any P, any P}):
|
||||
%2 = function_ref @copy_p_p : $@convention(thin) (@pack_guaranteed Pack{any P, any P}) -> @pack_out Pack{any P, any P}
|
||||
%3 = apply %2(%0, %1) : $@convention(thin) (@pack_guaranteed Pack{any P, any P}) -> @pack_out Pack{any P, any P}
|
||||
%4 = tuple ()
|
||||
return %4
|
||||
}
|
||||
|
||||
// EDGE CASE TESTS:
|
||||
|
||||
// Deallocation code should not be emitted at the end of a non-exiting terminator block.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s9crashableTf8x_n : $@convention(thin) (Builtin.Int64) -> () {
|
||||
// CHECK: bb0(%0 : $Builtin.Int64):
|
||||
// CHECK-NEXT: [[IN_PACK:%[0-9]+]] = alloc_pack $Pack{Builtin.Int64}
|
||||
// CHECK-NEXT: [[IN_IDX:%[0-9]+]] = scalar_pack_index 0 of $Pack{Builtin.Int64}
|
||||
// CHECK-NEXT: [[IN_ADDR:%[0-9]+]] = alloc_stack $Builtin.Int64
|
||||
// CHECK-NEXT: store %0 to [trivial] [[IN_ADDR]]
|
||||
// CHECK-NEXT: pack_element_set [[IN_ADDR]] into [[IN_IDX]] of [[IN_PACK]]
|
||||
// CHECK-NEXT: unreachable
|
||||
// CHECK-LABEL: } // end sil function '$s9crashableTf8x_n'
|
||||
sil [ossa] @crashable : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64}) -> () {
|
||||
bb0(%0 : $*Pack{Builtin.Int64}):
|
||||
unreachable
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_crashable : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64}) -> () {
|
||||
// CHECK-LABEL: } // end sil function 'call_crashable'
|
||||
sil [ossa] @call_crashable : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64}) -> () {
|
||||
bb0(%0 : $*Pack{Builtin.Int64}):
|
||||
%1 = function_ref @crashable : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64}) -> ()
|
||||
%2 = apply %1(%0) : $@convention(thin) (@pack_guaranteed Pack{Builtin.Int64}) -> ()
|
||||
unreachable
|
||||
}
|
||||
|
||||
// Pack-specialized functions should be converted to have a thin convention,
|
||||
// unless they have a dynamic self parameter.
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s27pack_method_no_dynamic_selfTf8x_n : $@convention(thin) (Int) -> () {
|
||||
// CHECK-LABEL: } // end sil function '$s27pack_method_no_dynamic_selfTf8x_n'
|
||||
sil [ossa] @pack_method_no_dynamic_self : $@convention(method) (@pack_guaranteed Pack{Int}) -> () {
|
||||
bb0(%0 : $*Pack{Int}):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
// If the function does have a dynamic self parameter, it must still be the last
|
||||
// after pack specialization.
|
||||
// CHECK-LABEL: sil shared [ossa] @$s29pack_method_with_dynamic_selfTf8xn_n : $@convention(method) (Int, @thick C.Type) -> () {
|
||||
// CHECK-LABEL: } // end sil function '$s29pack_method_with_dynamic_selfTf8xn_n'
|
||||
sil [ossa] @pack_method_with_dynamic_self : $@convention(method) (@pack_guaranteed Pack{Int}, @thick C.Type) -> () {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $@thick C.Type):
|
||||
%2 = metatype $@thick @dynamic_self C.Type
|
||||
%3 = tuple ()
|
||||
return %3
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_pack_methods : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
// CHECK: bb0(%0 : $*Pack{Int}):
|
||||
// CHECK: function_ref @$s27pack_method_no_dynamic_selfTf8x_n : $@convention(thin) (Int) -> ()
|
||||
// CHECK: function_ref @$s29pack_method_with_dynamic_selfTf8xn_n : $@convention(method) (Int, @thick C.Type) -> ()
|
||||
// CHECK-LABEL: } // end sil function 'call_pack_methods'
|
||||
sil [ossa] @call_pack_methods : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
bb0(%0 : $*Pack{Int}):
|
||||
%1 = function_ref @pack_method_no_dynamic_self : $@convention(method) (@pack_guaranteed Pack{Int}) -> ()
|
||||
%2 = apply %1(%0) : $@convention(method) (@pack_guaranteed Pack{Int}) -> ()
|
||||
|
||||
%3 = metatype $@thick C.Type
|
||||
%4 = function_ref @pack_method_with_dynamic_self : $@convention(method) (@pack_guaranteed Pack{Int}, @thick C.Type) -> ()
|
||||
%5 = apply %4(%0, %3) : $@convention(method) (@pack_guaranteed Pack{Int}, @thick C.Type) -> ()
|
||||
return %2
|
||||
}
|
||||
|
||||
// BAIL OUT CONDITION TESTS:
|
||||
//
|
||||
// Only perform pack specialization on functions that have indirect pack
|
||||
// parameters that contain no pack expansions.
|
||||
//
|
||||
// 2025-10-15: We currently only explode packs with address elements
|
||||
// (SILPackType::isElementAddress), because these are the most common (since
|
||||
// they are created after generic specialization of most variadic generic
|
||||
// functions), and expensive (since they introduce two layers of indirection).
|
||||
// See the shouldExplode computed property in PackSpecialization.swift.
|
||||
//
|
||||
// This is an OSSA-only pass, so caller and callee must both be OSSA.
|
||||
|
||||
|
||||
sil [ossa] @no_packs : $@convention(thin) (Int) -> () {
|
||||
bb0(%0 : $Int):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
sil [ossa] @indirect_pack : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
bb0(%0 : $*Pack{Int}):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
sil [ossa] @direct_pack : $@convention(thin) (@pack_guaranteed @direct Pack{Int}) -> () {
|
||||
bb0(%0 : $*@direct Pack{Int}):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
sil [ossa] @pack_expansion : $@convention(thin) <each A> (@pack_guaranteed Pack{repeat each A}) -> () {
|
||||
bb0(%0 : $*Pack{repeat each A}):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
sil [ossa] @mixed_packs : $@convention(thin) <each A> (@pack_guaranteed Pack{Int}, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each A}) -> () {
|
||||
bb0(%0 : $*Pack{Int}, %1 : $*@direct Pack{Int}, %2 : $*Pack{repeat each A}):
|
||||
%3 = tuple ()
|
||||
return %3
|
||||
}
|
||||
|
||||
sil @non_ossa_callee : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
bb0(%0 : $*Pack{Int}):
|
||||
%1 = tuple ()
|
||||
return %1
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @call_eligibility_tests : $@convention(thin) <each A> (Int, @pack_guaranteed Pack{Int}, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each A}) -> () {
|
||||
// CHECK: bb0(%0 : $Int, %1 : $*Pack{Int}, %2 : $*@direct Pack{Int}, %3 : $*Pack{repeat each A}):
|
||||
// CHECK: function_ref @no_packs : $@convention(thin) (Int) -> ()
|
||||
// CHECK: function_ref @$s13indirect_packTf8x_n : $@convention(thin) (Int) -> ()
|
||||
// CHECK: function_ref @direct_pack : $@convention(thin) (@pack_guaranteed @direct Pack{Int}) -> ()
|
||||
// CHECK: function_ref @pack_expansion : $@convention(thin) <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}) -> ()
|
||||
// CHECK: function_ref @$s11mixed_packsTf8xnn_n : $@convention(thin) <each τ_0_0> (Int, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each τ_0_0}) -> ()
|
||||
// CHECK: function_ref @non_ossa_callee : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
// CHECK-LABEL: } // end sil function 'call_eligibility_tests'
|
||||
sil [ossa] @call_eligibility_tests : $@convention(thin) <each A> (Int, @pack_guaranteed Pack{Int}, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each A}) -> () {
|
||||
bb0(%0 : $Int, %1 : $*Pack{Int}, %2 : $*@direct Pack{Int}, %3 : $*Pack{repeat each A}):
|
||||
%4 = function_ref @no_packs : $@convention(thin) (Int) -> ()
|
||||
%5 = apply %4(%0) : $@convention(thin) (Int) -> ()
|
||||
|
||||
%6 = function_ref @indirect_pack : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
%7 = apply %6(%1) : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
|
||||
%8 = function_ref @direct_pack : $@convention(thin) (@pack_guaranteed @direct Pack{Int}) -> ()
|
||||
%9 = apply %8(%2) : $@convention(thin) (@pack_guaranteed @direct Pack{Int}) -> ()
|
||||
|
||||
%10 = function_ref @pack_expansion : $@convention(thin) <each A> (@pack_guaranteed Pack{repeat each A}) -> ()
|
||||
%11 = apply %10<Pack{repeat each A}>(%3) : $@convention(thin) <each A> (@pack_guaranteed Pack{repeat each A}) -> ()
|
||||
|
||||
%12 = function_ref @mixed_packs : $@convention(thin) <each A> (@pack_guaranteed Pack{Int}, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each A}) -> ()
|
||||
%13 = apply %12<Pack{repeat each A}>(%1, %2, %3) : $@convention(thin) <each A> (@pack_guaranteed Pack{Int}, @pack_guaranteed @direct Pack{Int}, @pack_guaranteed Pack{repeat each A}) -> ()
|
||||
|
||||
|
||||
%14 = function_ref @non_ossa_callee : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
%15 = apply %14(%1) : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
|
||||
%99 = tuple ()
|
||||
return %99
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil @non_ossa_caller : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
// CHECK: function_ref @indirect_pack : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
// CHECK-LABEL: } // end sil function 'non_ossa_caller'
|
||||
sil @non_ossa_caller : $@convention(thin) (@pack_guaranteed Pack{Int}) -> () {
|
||||
bb0(%0 : $*Pack{Int}):
|
||||
%1 = function_ref @indirect_pack : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
%2 = apply %1(%0) : $@convention(thin) (@pack_guaranteed Pack{Int}) -> ()
|
||||
return %2
|
||||
}
|
||||
39
test/SILOptimizer/pack_specialization.swift
Normal file
39
test/SILOptimizer/pack_specialization.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
// RUN: %target-swift-frontend %s -emit-ir -O | %FileCheck %s
|
||||
|
||||
// REQUIRES: swift_in_compiler
|
||||
|
||||
// When no witness methods are called on pack elements, all pack code can be fully eliminated.
|
||||
// CHECK: define {{.*}} { i64, i64, ptr, double } @"$s19pack_specialization8copyPack2xsxxQp_txxQp_tRvzlFSi_SSSdQP_Tg5Tf8xx_n"(i64 %0, i64 %1, ptr %2, double %3)
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: insertvalue
|
||||
// CHECK-NEXT: insertvalue
|
||||
// CHECK-NEXT: insertvalue
|
||||
// CHECK-NEXT: insertvalue
|
||||
// CHECK-NEXT: @swift_bridgeObjectRetain
|
||||
// CHECK-NEXT: ret { i64, i64, ptr, double }
|
||||
@inline(never)
|
||||
func copyPack<each A>(xs: repeat each A) -> (repeat each A) {
|
||||
return (repeat each xs);
|
||||
}
|
||||
|
||||
public func copyPackCaller() -> (Int, String, Double) {
|
||||
return copyPack(xs: 1, "two", 3.0)
|
||||
}
|
||||
|
||||
// The pack specialization pass alone is not enough to eliminate packs when witness methods are called.
|
||||
// CHECK: define {{.*}} i64 @"$s19pack_specialization11addTogether2xsxxQp_txxQp_tRvzSjRzlFSi_QP_Tg5Tf8xx_n"(i64 %0)
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[IN_STACK:%[0-9]+]] = alloca %TSi, align 8
|
||||
// CHECK-NEXT: [[OUT_STACK:%[0-9]+]] = alloca %TSi, align 8
|
||||
// CHECK: store i64 %0, ptr [[IN_STACK]], align 8
|
||||
// CHECK: call swiftcc void @"$ss18AdditiveArithmeticP1poiyxx_xtFZTj"
|
||||
// CHECK: [[RESULT:%[0-9]+]] = load i64, ptr [[OUT_STACK]]
|
||||
// CHECK: ret i64 [[RESULT]]
|
||||
@inline(never)
|
||||
func addTogether<each A: Numeric>(xs: repeat each A) -> (repeat each A) {
|
||||
return (repeat (each xs + each xs))
|
||||
}
|
||||
|
||||
public func addTogetherCaller() -> Int {
|
||||
return addTogether(xs: 1)
|
||||
}
|
||||
Reference in New Issue
Block a user