From c3612bafb8bec50af6520e757b38e603d0a90d6f Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 16:14:19 +0200 Subject: [PATCH 01/10] SIL: make `var OperandArray.values` available for all kind of operand sequences --- .../FunctionPasses/ConstantCapturePropagation.swift | 2 +- .../FunctionPasses/InitializeStaticGlobals.swift | 2 +- .../InstructionSimplification/SimplifyCondBranch.swift | 4 ++-- .../Sources/Optimizer/Utilities/OptUtils.swift | 4 ++-- SwiftCompilerSources/Sources/SIL/Argument.swift | 2 +- SwiftCompilerSources/Sources/SIL/Operand.swift | 8 ++++---- .../Sources/SIL/Utilities/BorrowUtils.swift | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift index 30173df36a0f1..fc282ac863820 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift @@ -112,7 +112,7 @@ private func constantPropagateCaptures(of partialApply: PartialApplyInst, _ cont // Escaping closures consume their arguments. Therefore we need to destroy the removed argument values. addCompensatingDestroys(for: constArgs, context) } - let newArguments = nonConstArgs.map { $0.value } + let newArguments = Array(nonConstArgs.values) rewritePartialApply(partialApply, withSpecialized: specializedCallee, arguments: newArguments, context) } diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/InitializeStaticGlobals.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/InitializeStaticGlobals.swift index 0bd84db9458a0..2526ac706327d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/InitializeStaticGlobals.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/InitializeStaticGlobals.swift @@ -404,7 +404,7 @@ private extension Value { case is LoadInst: return true case is StructInst, is TupleInst: - worklist.pushIfNotVisited(contentsOf: (v as! Instruction).operands.lazy.map { $0.value }) + worklist.pushIfNotVisited(contentsOf: (v as! Instruction).operands.values) case let ei as EnumInst: if let payload = ei.payload { worklist.pushIfNotVisited(payload) diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCondBranch.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCondBranch.swift index 222c07badadbb..08af5d25b6241 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCondBranch.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCondBranch.swift @@ -27,9 +27,9 @@ private extension CondBranchInst { } let builder = Builder(before: self, context) if conditionValue == 0 { - builder.createBranch(to: falseBlock, arguments: Array(falseOperands.map { $0.value })) + builder.createBranch(to: falseBlock, arguments: Array(falseOperands.values)) } else { - builder.createBranch(to: trueBlock, arguments: Array(trueOperands.map { $0.value })) + builder.createBranch(to: trueBlock, arguments: Array(trueOperands.values)) } context.erase(instruction: self) } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 1dcedbd60049a..ce72e4c753eaa 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -71,7 +71,7 @@ extension Value { } switch v { case let fw as ForwardingInstruction: - worklist.pushIfNotVisited(contentsOf: fw.definedOperands.lazy.map { $0.value }) + worklist.pushIfNotVisited(contentsOf: fw.definedOperands.values) case let bf as BorrowedFromInst: worklist.pushIfNotVisited(bf.borrowedValue) case let bb as BeginBorrowInst: @@ -82,7 +82,7 @@ extension Value { } else if let termResult = TerminatorResult(arg), let fw = termResult.terminator as? ForwardingInstruction { - worklist.pushIfNotVisited(contentsOf: fw.definedOperands.lazy.map { $0.value }) + worklist.pushIfNotVisited(contentsOf: fw.definedOperands.values) } default: continue diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index 8a9c861366501..febd27f9af5dc 100644 --- a/SwiftCompilerSources/Sources/SIL/Argument.swift +++ b/SwiftCompilerSources/Sources/SIL/Argument.swift @@ -170,7 +170,7 @@ public struct Phi { } public var incomingValues: LazyMapSequence, Value> { - incomingOperands.lazy.map { $0.value } + incomingOperands.values } public var isReborrow: Bool { value.isReborrow } diff --git a/SwiftCompilerSources/Sources/SIL/Operand.swift b/SwiftCompilerSources/Sources/SIL/Operand.swift index afee393cba57e..cda27da5f934c 100644 --- a/SwiftCompilerSources/Sources/SIL/Operand.swift +++ b/SwiftCompilerSources/Sources/SIL/Operand.swift @@ -104,10 +104,6 @@ public struct OperandArray : RandomAccessCollection, CustomReflectable { base: OptionalBridgedOperand(op: base.advancedBy(bounds.lowerBound).op), count: bounds.upperBound - bounds.lowerBound) } - - public var values: LazyMapSequence.Elements, Value> { - self.lazy.map { $0.value } - } } public struct UseList : CollectionLikeSequence { @@ -143,6 +139,10 @@ public struct UseList : CollectionLikeSequence { } extension Sequence where Element == Operand { + public var values: LazyMapSequence { + self.lazy.map { $0.value } + } + public var singleUse: Operand? { var result: Operand? = nil for op in self { diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift index 776abdc7faeea..187dc228c153b 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift @@ -534,7 +534,7 @@ public final class EnclosingValueIterator : IteratorProtocol { } else if let forwardingInst = value.forwardingInstruction { // Recurse through guaranteed forwarding non-phi instructions. let ops = forwardingInst.forwardedOperands - worklist.pushIfNotVisited(contentsOf: ops.lazy.map { $0.value }) + worklist.pushIfNotVisited(contentsOf: ops.values) } else if value.isGuaranteedApplyResult { let selfArgument = (value as! ApplyInst).arguments.last! worklist.pushIfNotVisited(selfArgument) From 2cd625a367b7b5cc787a7d19da0ff8c3dbbf73e2 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 17:29:02 +0200 Subject: [PATCH 02/10] Optimizer: add the `Builder.insertCleanupAtFunctionExits` utility --- .../FunctionPasses/ConstantCapturePropagation.swift | 3 +-- .../Optimizer/ModulePasses/StackProtection.swift | 10 +++------- .../Sources/Optimizer/Utilities/OptUtils.swift | 12 ++++++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift index fc282ac863820..1f3abb6e6b1f1 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift @@ -195,8 +195,7 @@ private func cloneArgument(_ argumentOp: Operand, if partialApply.calleeArgumentConventions[calleeArgIdx].isGuaranteed { // If the original argument was passed as guaranteed, i.e. is _not_ destroyed in the closure, we have // to destroy the cloned argument at function exits. - for block in targetFunction.blocks where block.terminator.isFunctionExiting { - let builder = Builder(before: block.terminator, context) + Builder.insertCleanupAtFunctionExits(of: targetFunction, context) { builder in builder.emitDestroy(of: clonedArg) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift index 46f802afbb2f1..586ebe6751486 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift @@ -339,13 +339,9 @@ private struct StackProtectionOptimization { builder.createCopyAddr(from: argument, to: temporary, takeSource: true, initializeDest: true) - for block in function.blocks { - let terminator = block.terminator - if terminator.isFunctionExiting { - let exitBuilder = Builder(before: terminator, location: terminator.location.asAutoGenerated, context) - exitBuilder.createCopyAddr(from: temporary, to: argument, takeSource: true, initializeDest: true) - exitBuilder.createDeallocStack(temporary) - } + Builder.insertCleanupAtFunctionExits(of: function, context) { builder in + builder.createCopyAddr(from: temporary, to: argument, takeSource: true, initializeDest: true) + builder.createDeallocStack(temporary) } log("move addr protection in \(function.name): \(argument)") diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index ce72e4c753eaa..801c0fbf2ce9a 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -262,6 +262,18 @@ extension Builder { } } + static func insertCleanupAtFunctionExits( + of function: Function, + _ context: some MutatingContext, + insert: (Builder) -> () + ) { + for exitBlock in function.blocks where exitBlock.terminator.isFunctionExiting { + let terminator = exitBlock.terminator + let builder = Builder(before: terminator, location: terminator.location.asCleanup, context) + insert(builder) + } + } + func destroyCapturedArgs(for paiOnStack: PartialApplyInst) { precondition(paiOnStack.isOnStack, "Function must only be called for `partial_apply`s on stack!") self.bridged.destroyCapturedArgs(paiOnStack.bridged) From 898b8754bfc250b8d432a2b554b31aae369eda99 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 19:08:31 +0200 Subject: [PATCH 03/10] SIL: add some Instruction/Builder APIs * `var UncheckedValueCastInst.fromValue` * `BeginApplyInst.isNonThrowing` and `BeginApplyInst.isNonAsync` * `Builder.createUncheckedValueCast` --- SwiftCompilerSources/Sources/SIL/Builder.swift | 5 +++++ SwiftCompilerSources/Sources/SIL/Instruction.swift | 7 ++++++- include/swift/SIL/SILBridging.h | 4 ++++ include/swift/SIL/SILBridgingImpl.h | 13 +++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/SwiftCompilerSources/Sources/SIL/Builder.swift b/SwiftCompilerSources/Sources/SIL/Builder.swift index 5072bf4759393..a452695eca9b8 100644 --- a/SwiftCompilerSources/Sources/SIL/Builder.swift +++ b/SwiftCompilerSources/Sources/SIL/Builder.swift @@ -289,6 +289,11 @@ public struct Builder { return notifyNew(cast.getAs(UncheckedAddrCastInst.self)) } + public func createUncheckedValueCast(from value: Value, to type: Type) -> UncheckedValueCastInst { + let cast = bridged.createUncheckedValueCast(value.bridged, type.bridged) + return notifyNew(cast.getAs(UncheckedValueCastInst.self)) + } + public func createUpcast(from value: Value, to type: Type) -> UpcastInst { let cast = bridged.createUpcast(value.bridged, type.bridged) return notifyNew(cast.getAs(UpcastInst.self)) diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 6786cb516f2f2..d979f467e92e7 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -788,7 +788,9 @@ final public class UncheckedTrivialBitCastInst : SingleValueInstruction, UnaryIn } final public class UncheckedBitwiseCastInst : SingleValueInstruction, UnaryInstruction {} -final public class UncheckedValueCastInst : SingleValueInstruction, UnaryInstruction {} +final public class UncheckedValueCastInst : SingleValueInstruction, UnaryInstruction { + public var fromValue: Value { operand.value } +} final public class RefToRawPointerInst : SingleValueInstruction, UnaryInstruction {} final public class RefToUnmanagedInst : SingleValueInstruction, UnaryInstruction {} @@ -1719,6 +1721,9 @@ final public class BeginApplyInst : MultipleValueInstruction, FullApplySite { public var yieldedValues: Results { Results(inst: self, numResults: resultCount - (isCalleeAllocated ? 2 : 1)) } + + public var isNonThrowing: Bool { bridged.BeginApplyInst_getNonThrowing() } + public var isNonAsync: Bool { bridged.BeginApplyInst_getNonAsync() } } final public class EndApplyInst : SingleValueInstruction, UnaryInstruction { diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 4384c1132fcff..ae9195737c88b 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -816,6 +816,8 @@ struct BridgedInstruction { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGenericSpecializationInformation ApplyInst_getSpecializationInfo() const; BRIDGED_INLINE bool TryApplyInst_getNonAsync() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGenericSpecializationInformation TryApplyInst_getSpecializationInfo() const; + BRIDGED_INLINE bool BeginApplyInst_getNonThrowing() const; + BRIDGED_INLINE bool BeginApplyInst_getNonAsync() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclRef ClassMethodInst_getMember() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclRef WitnessMethodInst_getMember() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType WitnessMethodInst_getLookupType() const; @@ -1229,6 +1231,8 @@ struct BridgedBuilder{ BridgedType type) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedAddrCast(BridgedValue op, BridgedType type) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUncheckedValueCast(BridgedValue op, + BridgedType type) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUpcast(BridgedValue op, BridgedType type) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCheckedCastAddrBranch( BridgedValue source, BridgedCanType sourceFormalType, diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index e5c031d7fbf45..6eb30038e1ea0 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -1349,6 +1349,14 @@ BridgedGenericSpecializationInformation BridgedInstruction::TryApplyInst_getSpec return {getAs()->getSpecializationInfo()}; } +bool BridgedInstruction::BeginApplyInst_getNonThrowing() const { + return getAs()->isNonThrowing(); +} + +bool BridgedInstruction::BeginApplyInst_getNonAsync() const { + return getAs()->isNonAsync(); +} + BridgedDeclRef BridgedInstruction::ClassMethodInst_getMember() const { return getAs()->getMember(); } @@ -2301,6 +2309,11 @@ BridgedInstruction BridgedBuilder::createUncheckedAddrCast(BridgedValue op, Brid type.unbridged())}; } +BridgedInstruction BridgedBuilder::createUncheckedValueCast(BridgedValue op, BridgedType type) const { + return {unbridged().createUncheckedValueCast(regularLoc(), op.getSILValue(), + type.unbridged())}; +} + BridgedInstruction BridgedBuilder::createUpcast(BridgedValue op, BridgedType type) const { return {unbridged().createUpcast(regularLoc(), op.getSILValue(), type.unbridged())}; From 08696eeb9201fa0640f136283bfd616541319013 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 19:12:22 +0200 Subject: [PATCH 04/10] Cloner: set the cloner's builder insertion point to the entry block when creating a new entry block in the cloned function This allows clients to directly clone specific instructions into the new entry block --- SwiftCompilerSources/Sources/SIL/Utilities/Cloner.swift | 4 +++- include/swift/SIL/SILBridging.h | 1 + lib/SIL/Utils/SILBridging.cpp | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/Cloner.swift b/SwiftCompilerSources/Sources/SIL/Utilities/Cloner.swift index 175cb09212e44..e010a16642048 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/Cloner.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/Cloner.swift @@ -67,7 +67,9 @@ public struct Cloner { if let entryBlock = targetFunction.blocks.first { return entryBlock } - return targetFunction.appendNewBlock(context) + let entryBlock = targetFunction.appendNewBlock(context) + bridged.setInsertionBlockIfNotSet(entryBlock.bridged) + return entryBlock } public func cloneFunctionBody(from originalFunction: Function, entryBlockArguments: [Value]) { diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index ae9195737c88b..e2a75e09139df 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -1549,6 +1549,7 @@ struct BridgedCloner { void recordClonedInstruction(BridgedInstruction origInst, BridgedInstruction clonedInst) const; void recordFoldedValue(BridgedValue orig, BridgedValue mapped) const; BridgedInstruction clone(BridgedInstruction inst) const; + void setInsertionBlockIfNotSet(BridgedBasicBlock block) const; }; struct BridgedTypeSubstCloner { diff --git a/lib/SIL/Utils/SILBridging.cpp b/lib/SIL/Utils/SILBridging.cpp index e7ce4b1210241..b4f9c97941ae9 100644 --- a/lib/SIL/Utils/SILBridging.cpp +++ b/lib/SIL/Utils/SILBridging.cpp @@ -699,6 +699,11 @@ BridgedInstruction BridgedCloner::clone(BridgedInstruction inst) const { return {cloner->cloneInst(inst.unbridged())->asSILNode()}; } +void BridgedCloner::setInsertionBlockIfNotSet(BridgedBasicBlock block) const { + if (!cloner->getBuilder().hasValidInsertionPoint()) + cloner->getBuilder().setInsertionPoint(block.unbridged()); +} + BridgedBasicBlock BridgedCloner::getClonedBasicBlock(BridgedBasicBlock originalBasicBlock) const { return { cloner->getOpBasicBlock(originalBasicBlock.unbridged()) }; } From 272fd224b28d2c4cced8490a988963fb652596e7 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 19:34:57 +0200 Subject: [PATCH 05/10] SILCloner: support cloning the whole function if the client already provided the cloned entry block --- include/swift/SIL/SILCloner.h | 37 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 6a396047c2e95..8efd611a50e34 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -217,6 +217,8 @@ class SILCloner : protected SILInstructionVisitor { ArrayRef entryArgs, bool replaceOriginalFunctionInPlace = false); + void cloneFunctionBody(SILFunction *F); + /// Clone all blocks in this function and all instructions in those /// blocks. /// @@ -835,9 +837,31 @@ void SILCloner::cloneFunctionBody(SILFunction *F, commonFixUp(F); } +template +void SILCloner::cloneFunctionBody(SILFunction *F) { + assert(!Builder.getFunction().empty() && "Expect the entry block to already be created"); + + assert(F != &Builder.getFunction() && "Must clone into a new function."); + assert(BBMap.empty() && "This API does not allow clients to map blocks."); + + SILBasicBlock *clonedEntryBB = Builder.getFunction().getEntryBlock(); + BBMap.insert(std::make_pair(&*F->begin(), clonedEntryBB)); + + Builder.setInsertionPoint(clonedEntryBB); + + // This will layout all newly cloned blocks immediate after clonedEntryBB. + visitBlocksDepthFirst(&*F->begin()); + + commonFixUp(F); +} + template void SILCloner::cloneFunction(SILFunction *origF) { SILFunction *newF = &Builder.getFunction(); + if (!newF->empty()) { + cloneFunctionBody(origF); + return; + } auto *newEntryBB = newF->createBasicBlock(); @@ -861,23 +885,12 @@ template void SILCloner::cloneFunctionBody( SILFunction *F, SILBasicBlock *clonedEntryBB, ArrayRef entryArgs, llvm::function_ref entryArgIndexToOldArgIndex) { - assert(F != clonedEntryBB->getParent() && "Must clone into a new function."); - assert(BBMap.empty() && "This API does not allow clients to map blocks."); assert(ValueMap.empty() && "Stale ValueMap."); - assert(entryArgs.size() == F->getArguments().size()); for (unsigned i = 0, e = entryArgs.size(); i != e; ++i) { ValueMap[entryArgIndexToOldArgIndex(entryArgs[i])] = entryArgs[i]; } - - BBMap.insert(std::make_pair(&*F->begin(), clonedEntryBB)); - - Builder.setInsertionPoint(clonedEntryBB); - - // This will layout all newly cloned blocks immediate after clonedEntryBB. - visitBlocksDepthFirst(&*F->begin()); - - commonFixUp(F); + cloneFunctionBody(F); } template From ea6e3c9b4d7a5cdc42c9ae48e7904a361de64aca Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 19:41:59 +0200 Subject: [PATCH 06/10] ASTMangler: make sure to mangle canonical replacement types of substitution maps When mangling types, it's expected that the type is canonical. Except if mangling for debug info. Fixes a crash. --- lib/AST/ASTMangler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index fd2a4ad46e26d..909252e24ce90 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1968,7 +1968,11 @@ void ASTMangler::appendFlatGenericArgs(SubstitutionMap subs, for (auto replacement : subs.getReplacementTypes()) { if (replacement->hasArchetype()) replacement = replacement->mapTypeOutOfContext(); - appendType(replacement, sig, forDecl); + if (DWARFMangling) { + appendType(replacement, sig, forDecl); + } else { + appendType(replacement->getCanonicalType(), sig, forDecl); + } } } From 89bba668e23343a1cbf68cf1ece5da4dea8c862a Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 19:55:58 +0200 Subject: [PATCH 07/10] Mangling: add a closure specialization mangling for arguments which specialize for the same closure as a previous argument For example: ``` %1 = partial_apply %closure apply %f(%1, %1) // first argument: `.closure(%1)` // second argument: `.previousArgumentIndex(0)` ``` --- .../ClosureSpecialization.swift | 3 +- .../PassManager/FunctionPassContext.swift | 28 ++++++- docs/ABI/Mangling.rst | 1 + include/swift/Demangling/Demangle.h | 1 + .../swift/SILOptimizer/OptimizerBridging.h | 10 ++- .../Utils/SpecializationMangler.h | 25 ++++-- lib/Demangling/Demangler.cpp | 12 +++ lib/Demangling/NodePrinter.cpp | 26 ++++-- lib/Demangling/Remangler.cpp | 3 + lib/SILOptimizer/Utils/OptimizerBridging.cpp | 25 ++---- .../Utils/SpecializationMangler.cpp | 82 +++++++++---------- test/Demangle/Inputs/manglings.txt | 1 + 12 files changed, 138 insertions(+), 79 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index be811c64ebf6d..7584483e4888b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -1427,7 +1427,8 @@ private struct PullbackClosureInfo { func specializedCalleeName(_ context: FunctionPassContext) -> String { let closureArgs = Array(self.closureArgDescriptors.map { - (argumentIndex: $0.closureArgIndex, argumentValue: $0.closure) + (argumentIndex: $0.closureArgIndex, + argumentValue: FunctionPassContext.ClosureArgumentMangling.closure($0.closure)) }) return context.mangle(withClosureArguments: closureArgs, from: pullbackFn) } diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift index 027689b8af393..f2ec4f144b889 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift @@ -111,10 +111,34 @@ struct FunctionPassContext : MutatingContext { return String(taking: bridgedPassContext.mangleOutlinedVariable(function.bridged)) } - func mangle(withClosureArguments closureArgs: [(argumentIndex: Int, argumentValue: Value)], + enum ClosureArgumentMangling { + case closure(SingleValueInstruction) + + /// The argument specializes for the same closure as a previous argument, e.g. + /// ``` + /// %1 = partial_apply %closure + /// apply %f(%1, %1) // first argument: `.closure(%1)` + /// // second argument: `.previousArgumentIndex(0)` + case previousArgumentIndex(Int) + } + + func mangle(withClosureArguments closureArgs: [(argumentIndex: Int, argumentValue: ClosureArgumentMangling)], from applySiteCallee: Function ) -> String { - closureArgs.withBridgedArrayRef{ bridgedClosureArgs in + let bridgedArgManglings = closureArgs.map { + switch $0.argumentValue { + case .closure(let closure): + return BridgedPassContext.ClosureArgMangling(argIdx: $0.argumentIndex, + inst: Optional(closure).bridged, + otherArgIdx: -1) + case .previousArgumentIndex(let idx): + return BridgedPassContext.ClosureArgMangling(argIdx: $0.argumentIndex, + inst: OptionalBridgedInstruction(), + otherArgIdx: idx) + } + } + + return bridgedArgManglings.withBridgedArrayRef{ bridgedClosureArgs in String(taking: bridgedPassContext.mangleWithClosureArgs(bridgedClosureArgs, applySiteCallee.bridged)) } } diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index ab78fa267ca03..c4beec306e9cb 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1362,6 +1362,7 @@ Some kinds need arguments, which precede ``Tf``. ARG-SPEC-KIND ::= 'n' // Unmodified argument ARG-SPEC-KIND ::= 'c' // Consumes n 'type' arguments which are closed over types in argument order // and one 'identifier' argument which is the closure symbol name + ARG-SPEC-KIND ::= 'C' NATURAL-ZERO // the same closure as a previous argument ARG-SPEC-KIND ::= 'p' CONST-PROP // Constant propagated argument ARG-SPEC-KIND ::= 'e' 'D'? 'G'? 'X'? // Generic argument, with optional dead, owned=>guaranteed or exploded-specifier ARG-SPEC-KIND ::= 'd' 'G'? 'X'? // Dead argument, with optional owned=>guaranteed or exploded-specifier diff --git a/include/swift/Demangling/Demangle.h b/include/swift/Demangling/Demangle.h index a7997e5ac83b2..12606c6520c03 100644 --- a/include/swift/Demangling/Demangle.h +++ b/include/swift/Demangling/Demangle.h @@ -117,6 +117,7 @@ enum class FunctionSigSpecializationParamKind : unsigned { InOutToOut = 8, ConstantPropKeyPath = 9, ConstantPropStruct = 10, + ClosurePropPreviousArg = 11, // Option Set Flags use bits 6-31. This gives us 26 bits to use for option // flags. diff --git a/include/swift/SILOptimizer/OptimizerBridging.h b/include/swift/SILOptimizer/OptimizerBridging.h index 29a5c96067313..144a9a826eec2 100644 --- a/include/swift/SILOptimizer/OptimizerBridging.h +++ b/include/swift/SILOptimizer/OptimizerBridging.h @@ -187,9 +187,15 @@ struct BridgedPassContext { bool specializeAppliesInFunction(BridgedFunction function, bool isMandatory) const; BridgedOwnedString mangleOutlinedVariable(BridgedFunction function) const; BridgedOwnedString mangleAsyncRemoved(BridgedFunction function) const; + + struct ClosureArgMangling { + SwiftInt argIdx; + OptionalBridgedInstruction inst; + SwiftInt otherArgIdx; + }; + BridgedOwnedString mangleWithDeadArgs(BridgedArrayRef bridgedDeadArgIndices, BridgedFunction function) const; - BridgedOwnedString mangleWithClosureArgs(BridgedArrayRef closureArgIndices, - BridgedFunction applySiteCallee) const; + BridgedOwnedString mangleWithClosureArgs(BridgedArrayRef closureArgManglings, BridgedFunction applySiteCallee) const; BridgedOwnedString mangleWithConstCaptureArgs(BridgedArrayRef bridgedConstArgs, BridgedFunction applySiteCallee) const; BridgedOwnedString mangleWithBoxToStackPromotedArgs(BridgedArrayRef bridgedPromotedArgIndices, diff --git a/include/swift/SILOptimizer/Utils/SpecializationMangler.h b/include/swift/SILOptimizer/Utils/SpecializationMangler.h index 058c912e5a261..0ceaf6517d7f7 100644 --- a/include/swift/SILOptimizer/Utils/SpecializationMangler.h +++ b/include/swift/SILOptimizer/Utils/SpecializationMangler.h @@ -68,6 +68,7 @@ class FunctionSignatureSpecializationMangler : public SpecializationMangler { BoxToValue = 3, BoxToStack = 4, InOutToOut = 5, + ClosurePropPreviousArg = 6, // the same closure as a previous `ClosureProp` argument First_Option = 0, Last_Option = 31, @@ -82,8 +83,20 @@ class FunctionSignatureSpecializationMangler : public SpecializationMangler { LastOptionSetEntry = 32768, }; - using ArgInfo = std::pair>; + struct ArgInfo { + ArgumentModifier kind; + union { + SILInstruction *inst; + unsigned otherArgIdx; // only for `ClosurePropPreviousArg` + }; + + ArgInfo(ArgumentModifier kind) : kind(kind), inst(nullptr) {} + + void append(ArgumentModifier modifier) { + kind = ArgumentModifier(ArgumentModifierIntBase(kind) | ArgumentModifierIntBase(modifier)); + } + }; + // Information for each SIL argument in the original function before // specialization. This includes SIL indirect result argument required for // the original function type at the current stage of compilation. @@ -99,9 +112,8 @@ class FunctionSignatureSpecializationMangler : public SpecializationMangler { void setArgumentConstantProp(unsigned OrigArgIdx, SILInstruction *constInst); void appendStringAsIdentifier(StringRef str); - void setArgumentClosureProp(unsigned OrigArgIdx, PartialApplyInst *PAI); - void setArgumentClosureProp(unsigned OrigArgIdx, - ThinToThickFunctionInst *TTTFI); + void setArgumentClosureProp(unsigned OrigArgIdx, SILInstruction *closure); + void setArgumentClosurePropPreviousArg(unsigned OrigArgIdx, unsigned otherArgIdx); void setArgumentDead(unsigned OrigArgIdx); void setArgumentOwnedToGuaranteed(unsigned OrigArgIdx); void setArgumentGuaranteedToOwned(unsigned OrigArgIdx); @@ -120,8 +132,7 @@ class FunctionSignatureSpecializationMangler : public SpecializationMangler { private: void mangleConstantProp(SILInstruction *constInst); void mangleClosureProp(SILInstruction *Inst); - void mangleArgument(ArgumentModifierIntBase ArgMod, - NullablePtr Inst); + void mangleArgument(ArgInfo argInfo); void mangleReturnValue(ReturnValueModifierIntBase RetMod); }; diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 129639af517bb..062b0ee82bb75 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -3430,6 +3430,18 @@ NodePointer Demangler::demangleFuncSpecParam(Node::Kind Kind) { return addChild(Param, createNode( Node::Kind::FunctionSignatureSpecializationParamKind, uint64_t(FunctionSigSpecializationParamKind::ClosureProp))); + case 'C': { + // Consumes an identifier and multiple type parameters. + // The parameters will be added later. + addChild(Param, createNode( + Node::Kind::FunctionSignatureSpecializationParamKind, + uint64_t(FunctionSigSpecializationParamKind::ClosurePropPreviousArg))); + int prevArgIdx = demangleNatural(); + if (prevArgIdx < 0) + return nullptr; + return addChild(Param, createNode( + Node::Kind::FunctionSignatureSpecializationParamPayload, (Node::IndexType)prevArgIdx)); + } case 'p': { for (;;) { switch (nextChar()) { diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 8885f9a8494df..6762fadefa8a6 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -1247,6 +1247,15 @@ void NodePrinter::printFunctionSigSpecializationParams(NodePointer Node, } Printer << "]"; break; + case FunctionSigSpecializationParamKind::ClosurePropPreviousArg: + if (Idx + 2 > End) + return; + Printer << "["; + print(Node->getChild(Idx++), depth + 1); + Printer << " "; + print(Node->getChild(Idx++), depth + 1); + Printer << "]"; + break; default: assert( ((V & unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed)) || @@ -1889,11 +1898,15 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, case Node::Kind::FunctionSignatureSpecializationParam: printer_unreachable("should be handled in printSpecializationPrefix"); case Node::Kind::FunctionSignatureSpecializationParamPayload: { - std::string demangledName = demangleSymbolAsString(Node->getText()); - if (demangledName.empty()) { - Printer << Node->getText(); - } else { - Printer << demangledName; + if (Node->hasText()) { + std::string demangledName = demangleSymbolAsString(Node->getText()); + if (demangledName.empty()) { + Printer << Node->getText(); + } else { + Printer << demangledName; + } + } else if (Node->hasIndex()) { + Printer << Node->getIndex(); } return nullptr; } @@ -1971,6 +1984,9 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, case FunctionSigSpecializationParamKind::ClosureProp: Printer << "Closure Propagated"; return nullptr; + case FunctionSigSpecializationParamKind::ClosurePropPreviousArg: + Printer << "Same As Argument"; + return nullptr; case FunctionSigSpecializationParamKind::ExistentialToGeneric: case FunctionSigSpecializationParamKind::Dead: case FunctionSigSpecializationParamKind::OwnedToGuaranteed: diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 69b9e2980c402..f9a339eee25e8 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -1602,6 +1602,9 @@ Remangler::mangleFunctionSignatureSpecializationParam(Node *node, case FunctionSigSpecializationParamKind::ClosureProp: Buffer << 'c'; break; + case FunctionSigSpecializationParamKind::ClosurePropPreviousArg: + Buffer << 'C' << node->getChild(idx++)->getIndex(); + break; case FunctionSigSpecializationParamKind::BoxToValue: Buffer << 'i'; break; diff --git a/lib/SILOptimizer/Utils/OptimizerBridging.cpp b/lib/SILOptimizer/Utils/OptimizerBridging.cpp index 5b0cdef492b6a..a1bafbf8c65e2 100644 --- a/lib/SILOptimizer/Utils/OptimizerBridging.cpp +++ b/lib/SILOptimizer/Utils/OptimizerBridging.cpp @@ -274,32 +274,21 @@ BridgedOwnedString BridgedPassContext::mangleWithDeadArgs(BridgedArrayRef bridge } BridgedOwnedString BridgedPassContext::mangleWithClosureArgs( - BridgedArrayRef bridgedClosureArgs, BridgedFunction applySiteCallee + BridgedArrayRef closureArgManglings, BridgedFunction applySiteCallee ) const { - - struct ClosureArgElement { - SwiftInt argIdx; - BridgeValueExistential argValue; - }; - auto pass = Demangle::SpecializationPass::ClosureSpecializer; auto serializedKind = applySiteCallee.getFunction()->getSerializedKind(); Mangle::FunctionSignatureSpecializationMangler mangler(applySiteCallee.getFunction()->getASTContext(), pass, serializedKind, applySiteCallee.getFunction()); - auto closureArgs = bridgedClosureArgs.unbridged(); - - for (ClosureArgElement argElmt : closureArgs) { - auto closureArg = argElmt.argValue.value.getSILValue(); - auto closureArgIndex = argElmt.argIdx; + auto closureArgs = closureArgManglings.unbridged(); - if (auto *PAI = dyn_cast(closureArg)) { - mangler.setArgumentClosureProp(closureArgIndex, - const_cast(PAI)); + for (ClosureArgMangling argElmt : closureArgs) { + auto closureArgIndex = (unsigned)argElmt.argIdx; + if (SILInstruction *inst = argElmt.inst.unbridged()) { + mangler.setArgumentClosureProp(closureArgIndex, inst); } else { - auto *TTTFI = cast(closureArg); - mangler.setArgumentClosureProp(closureArgIndex, - const_cast(TTTFI)); + mangler.setArgumentClosurePropPreviousArg(closureArgIndex, argElmt.otherArgIdx); } } diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp index ecbcacef9a968..7362d76482e0e 100644 --- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp +++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp @@ -44,77 +44,71 @@ FunctionSignatureSpecializationMangler::FunctionSignatureSpecializationMangler(A for (unsigned i = 0, e = F->getConventions().getNumSILArguments(); i != e; ++i) { (void)i; - OrigArgs.push_back( - {ArgumentModifierIntBase(ArgumentModifier::Unmodified), nullptr}); + OrigArgs.push_back(ArgumentModifier::Unmodified); } ReturnValue = ReturnValueModifierIntBase(ReturnValueModifier::Unmodified); } void FunctionSignatureSpecializationMangler::setArgumentDead( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first |= ArgumentModifierIntBase(ArgumentModifier::Dead); + OrigArgs[OrigArgIdx].append(ArgumentModifier::Dead); } void FunctionSignatureSpecializationMangler::setArgumentClosureProp( - unsigned OrigArgIdx, PartialApplyInst *PAI) { + unsigned OrigArgIdx, SILInstruction *closure) { + ASSERT(isa(closure) || isa(closure)); auto &Info = OrigArgs[OrigArgIdx]; - Info.first = ArgumentModifierIntBase(ArgumentModifier::ClosureProp); - Info.second = PAI; + Info.kind = ArgumentModifier::ClosureProp; + Info.inst = closure; } -void FunctionSignatureSpecializationMangler::setArgumentClosureProp( - unsigned OrigArgIdx, ThinToThickFunctionInst *TTTFI) { +void FunctionSignatureSpecializationMangler::setArgumentClosurePropPreviousArg( + unsigned OrigArgIdx, unsigned otherArgIdx) { auto &Info = OrigArgs[OrigArgIdx]; - Info.first = ArgumentModifierIntBase(ArgumentModifier::ClosureProp); - Info.second = TTTFI; + Info.kind = ArgumentModifier::ClosurePropPreviousArg; + Info.otherArgIdx = otherArgIdx; } void FunctionSignatureSpecializationMangler::setArgumentConstantProp( unsigned OrigArgIdx, SILInstruction *constInst) { auto &Info = OrigArgs[OrigArgIdx]; - Info.first = ArgumentModifierIntBase(ArgumentModifier::ConstantProp); - Info.second = constInst; + Info.kind = ArgumentModifier::ConstantProp; + Info.inst = constInst; } void FunctionSignatureSpecializationMangler::setArgumentOwnedToGuaranteed( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first |= - ArgumentModifierIntBase(ArgumentModifier::OwnedToGuaranteed); + OrigArgs[OrigArgIdx].append(ArgumentModifier::OwnedToGuaranteed); } void FunctionSignatureSpecializationMangler::setArgumentSROA( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first |= ArgumentModifierIntBase(ArgumentModifier::SROA); + OrigArgs[OrigArgIdx].append(ArgumentModifier::SROA); } void FunctionSignatureSpecializationMangler::setArgumentGuaranteedToOwned( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first |= - ArgumentModifierIntBase(ArgumentModifier::GuaranteedToOwned); + OrigArgs[OrigArgIdx].append(ArgumentModifier::GuaranteedToOwned); } void FunctionSignatureSpecializationMangler::setArgumentExistentialToGeneric( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first |= - ArgumentModifierIntBase(ArgumentModifier::ExistentialToGeneric); + OrigArgs[OrigArgIdx].append(ArgumentModifier::ExistentialToGeneric); } void FunctionSignatureSpecializationMangler::setArgumentBoxToValue( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first = - ArgumentModifierIntBase(ArgumentModifier::BoxToValue); + OrigArgs[OrigArgIdx].kind = ArgumentModifier::BoxToValue; } void FunctionSignatureSpecializationMangler::setArgumentBoxToStack( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first = - ArgumentModifierIntBase(ArgumentModifier::BoxToStack); + OrigArgs[OrigArgIdx].kind = ArgumentModifier::BoxToStack; } void FunctionSignatureSpecializationMangler::setArgumentInOutToOut( unsigned OrigArgIdx) { - OrigArgs[OrigArgIdx].first = - ArgumentModifierIntBase(ArgumentModifier::InOutToOut); + OrigArgs[OrigArgIdx].kind = ArgumentModifier::InOutToOut; } void @@ -270,41 +264,44 @@ FunctionSignatureSpecializationMangler::mangleClosureProp(SILInstruction *Inst) } } -void FunctionSignatureSpecializationMangler::mangleArgument( - ArgumentModifierIntBase ArgMod, NullablePtr Inst) { - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ConstantProp)) { +void FunctionSignatureSpecializationMangler::mangleArgument(ArgInfo argInfo) { + switch (argInfo.kind) { + case ArgumentModifier::ConstantProp: // Append the prefix for constant propagation 'p'. ArgOpBuffer << 'p'; - mangleConstantProp(Inst.get()); + mangleConstantProp(argInfo.inst); return; - } - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::ClosureProp)) { - mangleClosureProp(Inst.get()); + case ArgumentModifier::ClosureProp: + mangleClosureProp(argInfo.inst); return; - } - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::Unmodified)) { + case ArgumentModifier::Unmodified: ArgOpBuffer << 'n'; return; - } - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToValue)) { + case ArgumentModifier::BoxToValue: ArgOpBuffer << 'i'; return; - } - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToStack)) { + case ArgumentModifier::BoxToStack: ArgOpBuffer << 's'; return; - } - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::InOutToOut)) { + case ArgumentModifier::InOutToOut: ArgOpBuffer << 'r'; return; + + case ArgumentModifier::ClosurePropPreviousArg: + ArgOpBuffer << 'C' << argInfo.otherArgIdx; + return; + + default: + break; } bool hasSomeMod = false; + ArgumentModifierIntBase ArgMod = ArgumentModifierIntBase(argInfo.kind); if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::ExistentialToGeneric)) { ArgOpBuffer << 'e'; hasSomeMod = true; @@ -356,10 +353,7 @@ std::string FunctionSignatureSpecializationMangler::mangle() { beginMangling(); for (unsigned i : indices(OrigArgs)) { - ArgumentModifierIntBase ArgMod; - NullablePtr Inst; - std::tie(ArgMod, Inst) = OrigArgs[i]; - mangleArgument(ArgMod, Inst); + mangleArgument(OrigArgs[i]); } ArgOpBuffer << '_'; mangleReturnValue(ReturnValue); diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 3e5d59b894a34..13f135910eed0 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -262,6 +262,7 @@ _$Ss17MutableCollectionP1asAARzs012RandomAccessB0RzsAA11SubSequences013Bidirecti _T03foo4_123ABTf3psbpsb_n ---> function signature specialization of foo _T04main5innerys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n ---> function signature specialization { var A } ]> of main.inner(inout Swift.Int32, (Swift.Int32) -> ()) -> () _$S4main5inneryys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n ---> function signature specialization { var A } ]> of main.inner(inout Swift.Int32, (Swift.Int32) -> ()) -> () +$s3foo7closureSSTf1cC0_n ---> function signature specialization of foo _T03foo6testityyyc_yyctF1a1bTf3pfpf_n ---> function signature specialization of foo.testit(() -> (), () -> ()) -> () _$S3foo6testityyyyc_yyctF1a1bTf3pfpf_n ---> function signature specialization of foo.testit(() -> (), () -> ()) -> () _SocketJoinOrLeaveMulticast ---> _SocketJoinOrLeaveMulticast From df20d362552dca4f4a8c123d438b313cbffb8fb3 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 20:39:17 +0200 Subject: [PATCH 08/10] ClosureSpecialization: support for OSSA and a big overhaul Beside supporting OSSA, this change significantly simplifies the pass. The main change is that instead of starting at a closure (e.g. `partial_apply`) and finding all call sites, we now start at a call site and look for closures for all arguments. This makes a lot of things much simpler, e.g. not so many intermediate data structures are required to track all the states. I needed to remove the 3 unit tests because the things those tests were testing are not there anymore. However, the pass is tested with a lot of sil tests (and I added quite a few), which should give good test coverage. The old ClosureSpecializer pass is still kept in place, because at that point in the pipeline we don't have OSSA, yet. Once we have that, we can replace the old pass withe the new one. However, the autodiff closure specializer already runs in the OSSA pipeline and there the new changes take effect. --- .../ClosureSpecialization.swift | 1708 +++++------------ .../PassManager/PassRegistration.swift | 2 +- .../Optimizer/Utilities/FunctionTest.swift | 3 - .../swift/SILOptimizer/PassManager/Passes.def | 5 +- lib/SILOptimizer/PassManager/PassPipeline.cpp | 4 +- .../closure_specialization/multi_bb_bte.sil | 226 +-- .../multi_bb_no_bte1.sil | 40 +- .../multi_bb_no_bte2.sil | 82 +- .../closure_specialization/single_bb.sil | 200 +- .../multi_bb_no_bte.swift | 3 + .../closure_specialization/single_bb2.swift | 3 + ...cialize.sil => closure_specialization.sil} | 756 ++++---- ...s.sil => closure_specialization_attrs.sil} | 37 +- ...> closure_specialization_consolidated.sil} | 457 ++--- ...sil => closure_specialization_fragile.sil} | 22 +- ....sil => closure_specialization_opaque.sil} | 24 +- .../closure_specialization_simple.sil | 387 ++++ .../closure_specialize_and_cfg.sil | 49 - .../closure_spec_and_inline.swift | 24 - .../closure_specialize_and_cfg.sil | 49 - .../closure_specialize_dynamic_self.swift | 23 - .../closure_specialize_loop.swift | 81 - .../closure_specialize_simple.sil | 292 --- 23 files changed, 1690 insertions(+), 2787 deletions(-) rename test/SILOptimizer/{experimental-swift-based-closure-specialization/closure_specialize.sil => closure_specialization.sil} (53%) rename test/SILOptimizer/{experimental-swift-based-closure-specialization/closure_specialize_attrs.sil => closure_specialization_attrs.sil} (70%) rename test/SILOptimizer/{experimental-swift-based-closure-specialization/closure_specialize_consolidated.sil => closure_specialization_consolidated.sil} (52%) rename test/SILOptimizer/{experimental-swift-based-closure-specialization/closure_specialize_fragile.sil => closure_specialization_fragile.sil} (61%) rename test/SILOptimizer/{experimental-swift-based-closure-specialization/closure_specialize_opaque.sil => closure_specialization_opaque.sil} (62%) create mode 100644 test/SILOptimizer/closure_specialization_simple.sil delete mode 100644 test/SILOptimizer/closure_specialize_and_cfg.sil delete mode 100644 test/SILOptimizer/experimental-swift-based-closure-specialization/closure_spec_and_inline.swift delete mode 100644 test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_and_cfg.sil delete mode 100644 test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_dynamic_self.swift delete mode 100644 test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_loop.swift delete mode 100644 test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_simple.sil diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index 7584483e4888b..b8dbafcb12afa 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -10,16 +10,64 @@ // //===-----------------------------------------------------------------------===// -/// This file contains the closure-specialization optimizations for general and differentiable Swift. +import AST +import SIL + +/// Closure Specialization +/// ---------------------- +/// Specializes functions which take a closure (a `partial_apply` or `thin_to_thick_function` as argument. +/// The closure is created directly in the specialized function whereas the captured arguments are passed +/// as additional arguments to the specialized function. As a heuristic, this is only done if the closure +/// is actually called in the function because after specialization, the closure and its call can be +/// further optimized, e.g. the closure can be inlined. +/// +/// ``` +/// %3 = function_ref @closure +/// %4 = partial_apply %3(%1, %2) : (Float, Int, Bool) -> () +/// %5 = function_ref @closure_user +/// apply %5(%4) +/// ... +/// +/// sil @closure_user : ((Float) -> (), Float) -> () { +/// bb0(%0 : $(Float) -> (), %1 : $Float): +/// apply %0(%1) +/// ... +/// ``` +/// -> +/// ``` +/// %5 = function_ref @specialized_closure_user +/// apply %5(%1, %2) +/// ... +/// +/// sil @specialized_closure_user : (Float, Int, Bool) -> () { +/// bb0(%0 : $Float, %1 : $Int, %2 : $Bool): +/// %3 = function_ref @closure +/// %4 = partial_apply %3(%1, %2) +/// apply %3(%0) +/// ... +/// ``` +/// +let closureSpecialization = FunctionPass(name: "closure-specialization") { + (function: Function, context: FunctionPassContext) in -/// General Closure Specialization -/// ------------------------------------ -/// TODO: Add description when the functionality is added. + guard function.hasOwnership else { + return + } + + for inst in function.instructions { + if let apply = inst as? FullApplySite { + _ = trySpecialize(apply: apply, context) + } + } + if context.needFixStackNesting { + context.fixStackNesting(in: function) + } +} /// AutoDiff Closure Specialization /// ------------------------------- /// This optimization performs closure specialization tailored for the patterns seen in Swift Autodiff. In principle, -/// the optimization does the same thing as the existing closure specialization pass. However, it is tailored to the +/// the optimization does the same thing as the general closure specialization pass. However, it is tailored to the /// patterns of Swift Autodiff. /// /// The compiler performs reverse-mode differentiation on functions marked with `@differentiable(reverse)`. In doing so, @@ -98,31 +146,14 @@ /// return %3: $Float /// } /// ``` - -import AST -import SIL -import SILBridging - -private let verbose = false - -private func log(prefix: Bool = true, _ message: @autoclosure () -> String) { - if verbose { - debugLog(prefix: prefix, message()) - } -} - -// =========== Entry point =========== // -let generalClosureSpecialization = FunctionPass( - name: "experimental-swift-based-closure-specialization" -) { - (function: Function, context: FunctionPassContext) in - // TODO: Implement general closure specialization optimization - print("NOT IMPLEMENTED") -} - +/// let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-specialization") { (function: Function, context: FunctionPassContext) in + guard function.hasOwnership else { + return + } + guard !function.isDefinedExternally, function.isAutodiffVJP else { @@ -132,1078 +163,591 @@ let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-special var remainingSpecializationRounds = 5 repeat { - guard let pullbackClosureInfo = getPullbackClosureInfo(in: function, context) else { - break - } - - var (specializedFunction, alreadyExists) = getOrCreateSpecializedFunction( - basedOn: pullbackClosureInfo, context) - - if !alreadyExists { - context.notifyNewFunction( - function: specializedFunction, derivedFrom: pullbackClosureInfo.pullbackFn) - } - - rewriteApplyInstruction( - using: specializedFunction, pullbackClosureInfo: pullbackClosureInfo, context) - - var deadClosures = InstructionWorklist(context) - pullbackClosureInfo.closureArgDescriptors - .map { $0.closure } - .forEach { deadClosures.pushIfNotVisited($0) } - - defer { - deadClosures.deinitialize() - } - - while let deadClosure = deadClosures.pop() { - let isDeleted = context.tryDeleteDeadClosure(closure: deadClosure as! SingleValueInstruction) - if isDeleted { - context.notifyInvalidatedStackNesting() + var changed = false + for inst in function.instructions { + if let partialApply = inst as? PartialApplyInst, + partialApply.isPullbackInResultOfAutodiffVJP + { + if trySpecialize(apply: partialApply, context) { + changed = true + } } } - if context.needFixStackNesting { context.fixStackNesting(in: function) } + if !changed { + break + } remainingSpecializationRounds -= 1 } while remainingSpecializationRounds > 0 } -// =========== Top-level functions ========== // - -private let specializationLevelLimit = 2 - -private func getPullbackClosureInfo(in caller: Function, _ context: FunctionPassContext) - -> PullbackClosureInfo? -{ - /// __Root__ closures created via `partial_apply` or `thin_to_thick_function` may be converted and reabstracted - /// before finally being used at an apply site. We do not want to handle these intermediate closures separately - /// as they are handled and cloned into the specialized function as part of the root closures. Therefore, we keep - /// track of these intermediate closures in a set. - /// - /// This set is populated via the `markConvertedAndReabstractedClosuresAsUsed` function which is called when we're - /// handling the different uses of our root closures. - /// - /// Below SIL example illustrates the above point. - /// ``` - /// // The below set of a "root" closure and its reabstractions/conversions - /// // will be handled as a unit and the entire set will be copied over - /// // in the specialized version of `takesClosure` if we determine that we - /// // can specialize `takesClosure` against its closure argument. - /// __ - /// %someFunction = function_ref @someFunction: $@convention(thin) (Int, Int) -> Int \ - /// %rootClosure = partial_apply [callee_guaranteed] %someFunction (%someInt): $(Int, Int) -> Int \ - /// %thunk = function_ref @reabstractionThunk : $@convention(thin) (@callee_guaranteed (Int) -> Int) -> @out Int / - /// %reabstractedClosure = partial_apply [callee_guaranteed] %thunk(%rootClosure) : / - /// $@convention(thin) (@callee_guaranteed (Int) -> Int) -> @out Int __/ - /// - /// %takesClosure = function_ref @takesClosure : $@convention(thin) (@owned @callee_guaranteed (Int) -> @out Int) -> Int - /// %result = partial_apply %takesClosure(%reabstractedClosure) : $@convention(thin) (@owned @callee_guaranteed () -> @out Int) -> Int - /// ret %result - /// ``` - var convertedAndReabstractedClosures = InstructionSet(context) - - defer { - convertedAndReabstractedClosures.deinitialize() - } - - var pullbackClosureInfoOpt = PullbackClosureInfo?(nil) - - for inst in caller.instructions { - if !convertedAndReabstractedClosures.contains(inst), - let rootClosure = inst.asSupportedClosure - { - updatePullbackClosureInfo( - for: rootClosure, in: &pullbackClosureInfoOpt, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures, context) - } - } - - return pullbackClosureInfoOpt -} - -private func getOrCreateSpecializedFunction( - basedOn pullbackClosureInfo: PullbackClosureInfo, _ context: FunctionPassContext -) - -> (function: Function, alreadyExists: Bool) -{ - let specializedFunctionName = pullbackClosureInfo.specializedCalleeName(context) - if let specializedFunction = context.lookupFunction(name: specializedFunctionName) { - return (specializedFunction, true) - } - - let pullbackFn = pullbackClosureInfo.pullbackFn - let specializedParameters = pullbackFn.convention.getSpecializedParameters( - basedOn: pullbackClosureInfo) - - let specializedFunction = - context.createSpecializedFunctionDeclaration( - from: pullbackFn, withName: specializedFunctionName, - withParams: specializedParameters, - makeThin: true, makeBare: true) - - context.buildSpecializedFunction( - specializedFunction: specializedFunction, - buildFn: { (emptySpecializedFunction, functionPassContext) in - var closureSpecCloner = Cloner( - cloneToEmptyFunction: emptySpecializedFunction, functionPassContext) - closureSpecCloner.cloneAndSpecializeFunctionBody(using: pullbackClosureInfo) - closureSpecCloner.deinitialize() - }) - - return (specializedFunction, false) -} - -private func rewriteApplyInstruction( - using specializedCallee: Function, pullbackClosureInfo: PullbackClosureInfo, - _ context: FunctionPassContext -) { - let newApplyArgs = pullbackClosureInfo.getArgumentsForSpecializedApply(of: specializedCallee) - - for newApplyArg in newApplyArgs { - if case let .PreviouslyCaptured(capturedArg, needsRetain, parentClosureArgIndex) = newApplyArg, - needsRetain - { - let closureArgDesc = pullbackClosureInfo.closureArgDesc(at: parentClosureArgIndex)! - var builder = Builder(before: closureArgDesc.closure, context) - - // TODO: Support only OSSA instructions once the OSSA elimination pass is moved after all function optimization - // passes. - if pullbackClosureInfo.paiOfPullback.parentBlock != closureArgDesc.closure.parentBlock { - // Emit the retain and release that keeps the argument live across the callee using the closure. - builder.createRetainValue(operand: capturedArg) - - for instr in closureArgDesc.lifetimeFrontier { - builder = Builder(before: instr, context) - builder.createReleaseValue(operand: capturedArg) - } - - // Emit the retain that matches the captured argument by the partial_apply in the callee that is consumed by - // the partial_apply. - builder = Builder(before: pullbackClosureInfo.paiOfPullback, context) - builder.createRetainValue(operand: capturedArg) - } else { - builder.createRetainValue(operand: capturedArg) - } - } - } - - // Rewrite apply instruction - var builder = Builder(before: pullbackClosureInfo.paiOfPullback, context) - let oldPartialApply = pullbackClosureInfo.paiOfPullback - let funcRef = builder.createFunctionRef(specializedCallee) - let capturedArgs = Array(newApplyArgs.map { $0.value }) - - let newPartialApply = builder.createPartialApply( - function: funcRef, substitutionMap: SubstitutionMap(), - capturedArguments: capturedArgs, calleeConvention: oldPartialApply.calleeConvention, - hasUnknownResultIsolation: oldPartialApply.hasUnknownResultIsolation, - isOnStack: oldPartialApply.isOnStack) - - builder = Builder(before: pullbackClosureInfo.paiOfPullback.next!, context) - // TODO: Support only OSSA instructions once the OSSA elimination pass is moved after all function optimization - // passes. - for closureArgDesc in pullbackClosureInfo.closureArgDescriptors { - if closureArgDesc.isClosureConsumed, - !closureArgDesc.isPartialApplyOnStack, - !closureArgDesc.parameterInfo.isTrivialNoescapeClosure - { - builder.createReleaseValue(operand: closureArgDesc.closure) - } - } - - oldPartialApply.replace(with: newPartialApply, context) -} - // ===================== Utility functions and extensions ===================== // -private func updatePullbackClosureInfo( - for rootClosure: SingleValueInstruction, in pullbackClosureInfoOpt: inout PullbackClosureInfo?, - convertedAndReabstractedClosures: inout InstructionSet, _ context: FunctionPassContext -) { - var rootClosurePossibleLiveRange = InstructionRange(begin: rootClosure, context) - defer { - rootClosurePossibleLiveRange.deinitialize() - } - - var rootClosureApplies = OperandWorklist(context) - defer { - rootClosureApplies.deinitialize() +private func trySpecialize(apply: ApplySite, _ context: FunctionPassContext) -> Bool { + guard isCalleeSpecializable(of: apply), + let specialization = analyzeArguments(of: apply, context) + else { + return false } - // A "root" closure undergoing conversions and/or reabstractions has additional restrictions placed upon it, in order - // for a pullback to be specialized against it. We handle conversion/reabstraction uses before we handle apply uses - // to gather the parameters required to evaluate these restrictions or to skip pullback's uses of "unsupported" - // closures altogether. + // We need to make each captured argument of all closures a unique Value. Otherwise the Cloner would + // wrongly map added capture arguments to the re-generated closure in the specialized function: + // + // %4 = partial_apply %3(%1, %1) : (Int, Int) -> () // %1 is captured twice // - // There are currently 2 restrictions that are evaluated prior to specializing a pullback against a converted and/or - // reabstracted closure - - // 1. A reabstracted root closure can only be specialized against, if the reabstracted closure is ultimately passed - // trivially (as a noescape+thick function) as captured argument of pullback's partial_apply. + // sil @specialized_closure_user : (Int, Int) -> () { + // bb0(%0 : $Int, %1 : $Int): + // %3 = function_ref @closure + // %4 = partial_apply %3(%0, %0) <- instead of an argument list of `(%0, %1)`! // - // 2. A root closure may be a partial_apply [stack], in which case we need to make sure that all mark_dependence - // bases for it will be available in the specialized callee in case the pullback is specialized against this root - // closure. + // This wouldn't be a problem per se - the code is correct. However, this is not reflected in the mangling. + // And the same specialized function could be re-used at a call-site where not two identical values are + // passed to the closure. + // + specialization.uniqueCaptureArguments(context) - let (foundUnexpectedUse, haveUsedReabstraction) = - handleNonApplies( - for: rootClosure, rootClosureApplies: &rootClosureApplies, - rootClosurePossibleLiveRange: &rootClosurePossibleLiveRange, context) + let specializedFunction = specialization.getOrCreateSpecializedFunction(context) - if foundUnexpectedUse { - return - } + specialization.unUniqueCaptureArguments(context) - let intermediateClosureArgDescriptorData = - handleApplies( - for: rootClosure, pullbackClosureInfoOpt: &pullbackClosureInfoOpt, - rootClosureApplies: &rootClosureApplies, - rootClosurePossibleLiveRange: &rootClosurePossibleLiveRange, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures, - haveUsedReabstraction: haveUsedReabstraction, context) + specialization.rewriteApply(for: specializedFunction, context) - if pullbackClosureInfoOpt == nil { - return - } + specialization.deleteDeadClosures(context) - finalizePullbackClosureInfo( - for: rootClosure, in: &pullbackClosureInfoOpt, - rootClosurePossibleLiveRange: rootClosurePossibleLiveRange, - intermediateClosureArgDescriptorData: intermediateClosureArgDescriptorData, context) + return true } -/// Handles all non-apply direct and transitive uses of `rootClosure`. -/// -/// Returns: -/// haveUsedReabstraction - whether the root closure is reabstracted via a thunk -/// foundUnexpectedUse - whether the root closure is directly or transitively used in an instruction that we don't know -/// how to handle. If true, then `rootClosure` should not be specialized against. -private func handleNonApplies( - for rootClosure: SingleValueInstruction, - rootClosureApplies: inout OperandWorklist, - rootClosurePossibleLiveRange: inout InstructionRange, - _ context: FunctionPassContext -) - -> (foundUnexpectedUse: Bool, haveUsedReabstraction: Bool) -{ - var foundUnexpectedUse = false - var haveUsedReabstraction = false - - /// The root closure or an intermediate closure created by reabstracting the root closure may be a `partial_apply - /// [stack]` and we need to make sure that all `mark_dependence` bases for this `onStack` closure will be available in - /// the specialized callee, in case the pullback is specialized against this root closure. - /// - /// `possibleMarkDependenceBases` keeps track of all potential values that may be used as bases for creating - /// `mark_dependence`s for our `onStack` root/reabstracted closures. For root closures these values are non-trivial - /// closure captures (which are always available as function arguments in the specialized callee). For reabstracted - /// closures these values may be the root closure or its conversions (below is a short SIL example representing this - /// case). - /// ``` - /// %someFunction = function_ref @someFunction : $@convention(thin) (Int) -> Int - /// %rootClosure = partial_apply [callee_guaranteed] %someFunction(%someInt) : $@convention(thin) (Int) -> Int - /// %noescapeRootClosure = convert_escape_to_noescape %rootClosure : $@callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> Int - /// %thunk = function_ref @reabstractionThunk : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int - /// %thunkedRootClosure = partial_apply [callee_guaranteed] [on_stack] %thunk(%noescapeRootClosure) : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int - /// %dependency = mark_dependence %thunkedRootClosure : $@noescape @callee_guaranteed () -> @out Int on %noescapeClosure : $@noescape @callee_guaranteed () -> Int - /// %takesClosure = function_ref @takesClosure : $@convention(thin) (@owned @noescape @callee_guaranteed () -> @out Int) - /// %ret = apply %takesClosure(%dependency) : $@convention(thin) (@owned @noescape @callee_guaranteed () -> @out Int) - /// ``` - /// - /// Any value outside of the aforementioned values is not going to be available in the specialized callee and a - /// `mark_dependence` of the root closure on such a value means that we cannot specialize the pullback against it. - var possibleMarkDependenceBases = ValueSet(context) - defer { - possibleMarkDependenceBases.deinitialize() - } +private func isCalleeSpecializable(of apply: ApplySite) -> Bool { + if let callee = apply.referencedFunction, + callee.isDefinition, - var rootClosureConversionsAndReabstractions = OperandWorklist(context) - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: rootClosure.uses) - defer { - rootClosureConversionsAndReabstractions.deinitialize() - } + // We don't support generic functions (yet) + !apply.hasSubstitutions, - if let pai = rootClosure as? PartialApplyInst { - for arg in pai.arguments { - possibleMarkDependenceBases.insert(arg) - } + // Don't specialize non-fragile (read as non-serialized) callees if the caller is fragile; the + // specialized callee will have shared linkage, and thus cannot be referenced from the fragile caller. + !(apply.parentFunction.isSerialized && !callee.isSerialized), + + // If the callee uses a dynamic Self, we cannot specialize it, since the resulting specialization + // might no longer have 'self' as the last parameter. + // + // TODO: Keep the self argument the last when appending arguments. + !callee.mayBindDynamicSelf + { + return true } + return false +} - while let use = rootClosureConversionsAndReabstractions.pop() { - switch use.instruction { - case let cfi as ConvertFunctionInst: - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: cfi.uses) - possibleMarkDependenceBases.insert(cfi) - rootClosurePossibleLiveRange.insert(use.instruction) - - case let cvt as ConvertEscapeToNoEscapeInst: - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: cvt.uses) - possibleMarkDependenceBases.insert(cvt) - rootClosurePossibleLiveRange.insert(use.instruction) - - case let pai as PartialApplyInst: - if !pai.isPullbackInResultOfAutodiffVJP, - pai.isSupportedClosure, - pai.isPartialApplyOfThunk, - // Argument must be a closure - pai.arguments[0].type.isThickFunction +private func analyzeArguments(of apply: ApplySite, _ context: FunctionPassContext) -> SpecializationInfo? { + var argumentsToSpecialize = [(Operand, Closure)]() + var rootClosures = [PartialApplyInst]() + var rootClosuresAdded = InstructionSet(context) + defer { rootClosuresAdded.deinitialize() } + + for argOp in apply.argumentOperands { + var visited = ValueSet(context) + defer { visited.deinitialize() } + if let closure = findSpecializableClosure(of: argOp.value, &visited), + // Ok, we know that we can perform the optimization but not whether or not the optimization + // is profitable. Check if the closure is actually called in the callee (or in a function + // called by the callee). This opens optimization opportunities, like inlining. + isClosureApplied(apply.calleeArgument(of: argOp, in: apply.referencedFunction!)!) + { + argumentsToSpecialize.append((argOp, closure)) + if let partialApply = closure as? PartialApplyInst, + rootClosuresAdded.insert(partialApply) { - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: pai.uses) - possibleMarkDependenceBases.insert(pai) - rootClosurePossibleLiveRange.insert(use.instruction) - haveUsedReabstraction = true - } else if pai.isPullbackInResultOfAutodiffVJP { - rootClosureApplies.pushIfNotVisited(use) + rootClosures.append(partialApply) } + } + } + if argumentsToSpecialize.isEmpty { + return nil + } + return SpecializationInfo(apply: apply, closureArguments: argumentsToSpecialize, rootClosures: rootClosures) +} - case let mv as MoveValueInst: - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: mv.uses) - possibleMarkDependenceBases.insert(mv) - rootClosurePossibleLiveRange.insert(use.instruction) +// Walks down the use-def chain of a function argument, recursively, to find a rootClosure. +private func findSpecializableClosure(of value: Value, _ visited: inout ValueSet) -> Closure? { + visited.insert(value) - case let mdi as MarkDependenceInst: - if possibleMarkDependenceBases.contains(mdi.base), - mdi.value == use.value, - mdi.value.type.isNoEscapeFunction, - mdi.value.type.isThickFunction - { - rootClosureConversionsAndReabstractions.pushIfNotVisited(contentsOf: mdi.uses) - rootClosurePossibleLiveRange.insert(use.instruction) - } + let specializationLevelLimit = 2 - case is CopyValueInst, - is DestroyValueInst, - is RetainValueInst, - is ReleaseValueInst, - is StrongRetainInst, - is StrongReleaseInst: - rootClosurePossibleLiveRange.insert(use.instruction) - - case let ti as TupleInst: - if ti.parentFunction.isAutodiffVJP, - let returnInst = ti.parentFunction.returnInstruction, - ti == returnInst.returnedValue - { - // This is the pullback closure returned from an Autodiff VJP and we don't need to handle it. - } else { - fallthrough - } + switch value { + case is ConvertFunctionInst, + is ConvertEscapeToNoEscapeInst, + is MoveValueInst, + is CopyValueInst: + return findSpecializableClosure(of: (value as! UnaryInstruction).operand.value, &visited) - default: - foundUnexpectedUse = true - log("Found unexpected direct or transitive user of root closure: \(use.instruction)") - return (foundUnexpectedUse, haveUsedReabstraction) + case let mdi as MarkDependenceInst: + guard mdi.value.type.isNoEscapeFunction, mdi.value.type.isThickFunction else { + return nil } - } - - return (foundUnexpectedUse, haveUsedReabstraction) -} - -private typealias IntermediateClosureArgDescriptorDatum = ( - applySite: SingleValueInstruction, closureArgIndex: Int, paramInfo: ParameterInfo -) - -private func handleApplies( - for rootClosure: SingleValueInstruction, pullbackClosureInfoOpt: inout PullbackClosureInfo?, - rootClosureApplies: inout OperandWorklist, - rootClosurePossibleLiveRange: inout InstructionRange, - convertedAndReabstractedClosures: inout InstructionSet, haveUsedReabstraction: Bool, - _ context: FunctionPassContext -) -> [IntermediateClosureArgDescriptorDatum] { - var intermediateClosureArgDescriptorData: [IntermediateClosureArgDescriptorDatum] = [] - - while let use = rootClosureApplies.pop() { - rootClosurePossibleLiveRange.insert(use.instruction) - - // TODO [extend to general swift]: Handle full apply sites - guard let pai = use.instruction as? PartialApplyInst else { - continue + guard let operandClosure = findSpecializableClosure(of: mdi.value, &visited) else { + return nil } - - // TODO: Handling generic closures may be possible but is not yet implemented - if pai.hasSubstitutions || !pai.calleeIsDynamicFunctionRef - || !pai.isPullbackInResultOfAutodiffVJP + // Make sure that the mark_dependence's base is part of the use-def chain and will therefore be cloned as well. + if !visited.contains(mdi.base) { + return nil + } + return operandClosure + + case let partialApply as PartialApplyInst: + // Don't specialize for re-abstractions via a partial_apply, but treat such re-abstractions like + // closure "conversions". E.g. + // ``` + // %1 = partial_apply // root closure + // %2 = function_ref @thunk + // %3 = partial_apply %2(%1) // re-abstraction + // apply %f(%3) + // ``` + if partialApply.isPartialApplyOfThunk, + let argumentClosure = findSpecializableClosure(of: partialApply.arguments[0], &visited) { - continue + return argumentClosure + } + guard let callee = partialApply.referencedFunction, + !partialApply.hasSubstitutions, + + // Avoid an infinite specialization loop caused by repeated runs of ClosureSpecialization and + // ConstantCapturePropagation. + // ConstantCapturePropagation propagates constant function-literals. Such function specializations + // can then be optimized again by ClosureSpecialization and so on. This happens if a closure argument + // is called _and_ referenced in another closure, which is passed to a recursive call. E.g. + // + // func foo(_ c: @escaping () -> ()) { + // c() foo({ c() }) + // } + // + // A limit of 2 is good enough and will not be exceed in "regular" optimization scenarios. + callee.specializationLevel <= specializationLevelLimit, + + // Functions with a readnone, readonly or releasenone effect and a consumed captures cannot be + // specialized because the captured arguments are passed as owned arguments to the specialized + // function. Destroy for such arguments in the specialized function violates the effect. + (partialApply.isOnStack || callee.effectAllowsSpecialization), + + // TODO: handle other kind of indirect arguments + partialApply.hasOnlyInoutIndirectArguments, + + (partialApply.isOnStack || partialApply.allArgumentsCanBeCopied) + else { + return nil } + return partialApply - guard let callee = pai.referencedFunction else { - continue + case let tttfi as ThinToThickFunctionInst: + guard let callee = tttfi.referencedFunction, + callee.specializationLevel <= specializationLevelLimit + else { + return nil } + return tttfi - if callee.isDefinedExternally { - continue - } + default: + return nil + } +} - // Don't specialize non-fragile (read as non-serialized) callees if the caller is fragile; the specialized callee - // will have shared linkage, and thus cannot be referenced from the fragile caller. - let caller = rootClosure.parentFunction - if caller.isSerialized && !callee.isSerialized { - continue - } +/// Either a `partial_apply` or a `thin_to_thick_function` +private typealias Closure = SingleValueInstruction - // If the callee uses a dynamic Self, we cannot specialize it, since the resulting specialization might no longer - // have 'self' as the last parameter. - // - // TODO: We could fix this by inserting new arguments more carefully, or changing how we model dynamic Self - // altogether. - if callee.mayBindDynamicSelf { - continue - } +/// Information about the function to be specialized and for which closure arguments. +private struct SpecializationInfo { - // Proceed if the closure is passed as an argument (and not called). If it is called we have nothing to do. - // - // `closureArgumentIndex` is the index of the closure in the callee's argument list. - guard let closureArgumentIndex = pai.calleeArgumentIndex(of: use) else { - continue - } + // The apply which we want to specialize + let apply: ApplySite - // Ok, we know that we can perform the optimization but not whether or not the optimization is profitable. Check if - // the closure is actually called in the callee (or in a function called by the callee). - if !isClosureApplied(in: callee, closureArgIndex: closureArgumentIndex) { - continue - } + // All closure arguments of the apply which we want to replace (usually there is one, but there can be + // multiple). + // Note that the `Closure` is not necessarily the value of the `Operand`. There can be function conventions + // and re-abstractions (via a thunk) in-between: + // + // %4 = partial_apply %3(%1) : (Int) -> () // %4 = rootClosure + // %5 = convert_function %4 + // %6 = copy_value %5 + // apply %5(%5) // %5 = closureArgument + // + let closureArguments: [(closureArgument: Operand, rootClosure: Closure)] - let onlyHaveThinToThickClosure = - rootClosure is ThinToThickFunctionInst && !haveUsedReabstraction + // All rootClosures of `closureArguments` which are `partial_apply`s, and uniqued: if a rootClosure + // appears multiple times in `closureArguments`, it's only added a single time here. + let rootClosures: [PartialApplyInst] - guard let closureParamInfo = pai.operandConventions[parameter: use.index] else { - fatalError("While handling apply uses, parameter info not found for operand: \(use)!") - } + // The function to specialize + var callee: Function { apply.referencedFunction! } - // If we are going to need to release the copied over closure, we must make sure that we understand all the exit - // blocks, i.e., they terminate with an instruction that clearly indicates whether to release the copied over - // closure or leak it. - if closureParamInfo.convention.isGuaranteed, - !onlyHaveThinToThickClosure, - !callee.blocks.allSatisfy({ $0.isReachableExitBlock || $0.terminator is UnreachableInst }) - { - continue - } + private typealias Cloner = SIL.Cloner - // Functions with a readnone, readonly or releasenone effect and a nontrivial context cannot be specialized. - // Inserting a release in such a function results in miscompilation after other optimizations. For now, the - // specialization is disabled. - // - // TODO: A @noescape closure should never be converted to an @owned argument regardless of the function's effect - // attribute. - if !callee.effectAllowsSpecialization && !onlyHaveThinToThickClosure { - continue - } + func getOrCreateSpecializedFunction(_ context: FunctionPassContext) -> Function { + let specializedFunctionName = getSpecializedFunctionName(context) - // Avoid an infinite specialization loop caused by repeated runs of ClosureSpecializer and CapturePropagation. - // CapturePropagation propagates constant function-literals. Such function specializations can then be optimized - // again by the ClosureSpecializer and so on. This happens if a closure argument is called _and_ referenced in - // another closure, which is passed to a recursive call. E.g. - // - // func foo(_ c: @escaping () -> ()) { - // c() foo({ c() }) - // } - // - // A limit of 2 is good enough and will not be exceed in "regular" optimization scenarios. - let closureCallee = - rootClosure is PartialApplyInst - ? (rootClosure as! PartialApplyInst).referencedFunction! - : (rootClosure as! ThinToThickFunctionInst).referencedFunction! - - if closureCallee.specializationLevel > specializationLevelLimit { - continue + if let existingSpecializedFunction = context.lookupFunction(name: specializedFunctionName) { + return existingSpecializedFunction } - if haveUsedReabstraction { - markConvertedAndReabstractedClosuresAsUsed( - rootClosure: rootClosure, convertedAndReabstractedClosure: use.value, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures) - } + let specializedParameters = getSpecializedParameters() - if pullbackClosureInfoOpt == nil { - pullbackClosureInfoOpt = PullbackClosureInfo(paiOfPullback: pai) - } else { - assert(pullbackClosureInfoOpt!.paiOfPullback == pai) - } + let specializedFunction = + context.createSpecializedFunctionDeclaration( + from: callee, withName: specializedFunctionName, + withParams: specializedParameters, + // The specialized function is always a thin function. This is important because we add additional + // parameters after the Self parameter of witness methods. In this case the new function is not a + // method anymore. + makeThin: true, makeBare: true) - intermediateClosureArgDescriptorData - .append((applySite: pai, closureArgIndex: closureArgumentIndex, paramInfo: closureParamInfo)) - } + context.buildSpecializedFunction( + specializedFunction: specializedFunction, + buildFn: { (specializedFunction, specializedContext) in + var cloner = Cloner(cloneToEmptyFunction: specializedFunction, specializedContext) + defer { cloner.deinitialize() } - return intermediateClosureArgDescriptorData -} + cloneAndSpecializeFunctionBody(using: &cloner) + }) -/// Finalizes the pullback closure info for a given root closure by adding a corresponding `ClosureArgDescriptor` -private func finalizePullbackClosureInfo( - for rootClosure: SingleValueInstruction, in pullbackClosureInfoOpt: inout PullbackClosureInfo?, - rootClosurePossibleLiveRange: InstructionRange, - intermediateClosureArgDescriptorData: [IntermediateClosureArgDescriptorDatum], - _ context: FunctionPassContext -) { - assert(pullbackClosureInfoOpt != nil) - - let closureInfo = ClosureInfo( - closure: rootClosure, lifetimeFrontier: Array(rootClosurePossibleLiveRange.ends)) - - for (applySite, closureArgumentIndex, parameterInfo) in intermediateClosureArgDescriptorData { - if pullbackClosureInfoOpt!.paiOfPullback != applySite { - fatalError( - "ClosureArgDescriptor's applySite field is not equal to pullback's partial_apply; got \(applySite)!" - ) - } - let closureArgDesc = ClosureArgDescriptor( - closureInfo: closureInfo, closureArgumentIndex: closureArgumentIndex, - parameterInfo: parameterInfo) - pullbackClosureInfoOpt!.appendClosureArgDescriptor(closureArgDesc) + context.notifyNewFunction(function: specializedFunction, derivedFrom: callee) + + return specializedFunction } -} -private func isClosureApplied(in callee: Function, closureArgIndex index: Int) -> Bool { - func inner(_ callee: Function, _ index: Int, _ handledFuncs: inout Set) -> Bool { - let closureArg = callee.argument(at: index) - for use in closureArg.uses { - if let fai = use.instruction as? ApplySite { - if fai.callee == closureArg { - return true - } + private func getSpecializedFunctionName(_ context: FunctionPassContext) -> String { + var visited = Dictionary() - if let faiCallee = fai.referencedFunction, - !faiCallee.blocks.isEmpty, - handledFuncs.insert(faiCallee).inserted, - handledFuncs.count <= recursionBudget - { - if inner(faiCallee, fai.calleeArgumentIndex(of: use)!, &handledFuncs) { - return true - } - } + let argumentManglings = closureArguments.map { (argOp, closure) in + let argIdx = apply.calleeArgumentIndex(of: argOp)! + if let prevArgIdx = visited[closure] { + + // If the same closure is passed multiple times to a function, we need to reflect this in the mangling: + // + // %3 = function_ref @closure + // %4 = partial_apply %3(%1) : (Int) -> () + // apply %6(%4, %4) + // + // sil @specialized_closure_user : (Int) -> () { + // + // is different than + // + // %3 = function_ref @closure + // %4 = partial_apply %3(%1) : (Int) -> () + // %5 = partial_apply %3(%1) : (Int) -> () + // apply %6(%4, %5) + // + // sil @specialized_closure_user : (Int, Int) -> () { + // + return (argIdx, FunctionPassContext.ClosureArgumentMangling.previousArgumentIndex(prevArgIdx)) + } else { + visited[closure] = argIdx + return (argIdx, FunctionPassContext.ClosureArgumentMangling.closure(closure)) } } - - return false + return context.mangle(withClosureArguments: argumentManglings, from: callee) } - // Limit the number of recursive calls to not go into exponential behavior in corner cases. - let recursionBudget = 8 - var handledFuncs: Set = [] - return inner(callee, index, &handledFuncs) -} + private func getSpecializedParameters() -> [ParameterInfo] { + var specializedParamInfoList: [ParameterInfo] = [] -/// Marks any converted/reabstracted closures, corresponding to a given root closure as used. We do not want to -/// look at such closures separately as during function specialization they will be handled as part of the root closure. -private func markConvertedAndReabstractedClosuresAsUsed( - rootClosure: Value, convertedAndReabstractedClosure: Value, - convertedAndReabstractedClosures: inout InstructionSet -) { - if convertedAndReabstractedClosure != rootClosure { - switch convertedAndReabstractedClosure { - case let pai as PartialApplyInst: - convertedAndReabstractedClosures.insert(pai) - return - markConvertedAndReabstractedClosuresAsUsed( - rootClosure: rootClosure, - convertedAndReabstractedClosure: pai.arguments[0], - convertedAndReabstractedClosures: &convertedAndReabstractedClosures) - case let cvt as ConvertFunctionInst: - convertedAndReabstractedClosures.insert(cvt) - return - markConvertedAndReabstractedClosuresAsUsed( - rootClosure: rootClosure, - convertedAndReabstractedClosure: cvt.fromFunction, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures) - case let cvt as ConvertEscapeToNoEscapeInst: - convertedAndReabstractedClosures.insert(cvt) - return - markConvertedAndReabstractedClosuresAsUsed( - rootClosure: rootClosure, - convertedAndReabstractedClosure: cvt.fromFunction, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures) - case let mdi as MarkDependenceInst: - convertedAndReabstractedClosures.insert(mdi) - return - markConvertedAndReabstractedClosuresAsUsed( - rootClosure: rootClosure, convertedAndReabstractedClosure: mdi.value, - convertedAndReabstractedClosures: &convertedAndReabstractedClosures) - default: - log("Parent function of pullbackClosureInfo: \(rootClosure.parentFunction)") - log("Root closure: \(rootClosure)") - log("Converted/reabstracted closure: \(convertedAndReabstractedClosure)") - fatalError( - "While marking converted/reabstracted closures as used, found unexpected instruction: \(convertedAndReabstractedClosure)" - ) + // Start by adding all original parameters except for the closure parameters. + let firstParamIndex = callee.argumentConventions.firstParameterIndex + for (index, paramInfo) in callee.convention.parameters.enumerated() { + let argIndex = index + firstParamIndex + if !closureArguments.contains(where: { apply.calleeArgumentIndex(of: $0.0) == argIndex}) { + specializedParamInfoList.append(paramInfo) + } } - } -} -extension Cloner where Context == FunctionPassContext { - fileprivate func cloneAndSpecializeFunctionBody(using pullbackClosureInfo: PullbackClosureInfo) { - self.cloneEntryBlockArgsWithoutOrigClosures(usingOrigCalleeAt: pullbackClosureInfo) + // Now, append parameters captured by each of the root closures. + for partialApply in rootClosures { + let closureConvention = partialApply.functionConvention + let unappliedArgumentCount = partialApply.unappliedArgumentCount - closureConvention.indirectSILResultCount - let (allSpecializedEntryBlockArgs, closureArgIndexToAllClonedReleasableClosures) = - cloneAllClosures(at: pullbackClosureInfo) - - self.cloneFunctionBody(from: pullbackClosureInfo.pullbackFn, entryBlockArguments: allSpecializedEntryBlockArgs) + for paramInfo in closureConvention.parameters[unappliedArgumentCount...] { + let newParamInfo = paramInfo.withSpecializedConvention(for: partialApply, in: callee) + specializedParamInfoList.append(newParamInfo) + } + } - self.insertCleanupCodeForClonedReleasableClosures( - from: pullbackClosureInfo, - closureArgIndexToAllClonedReleasableClosures: closureArgIndexToAllClonedReleasableClosures) + return specializedParamInfoList } - private func cloneEntryBlockArgsWithoutOrigClosures( - usingOrigCalleeAt pullbackClosureInfo: PullbackClosureInfo - ) { - let originalEntryBlock = pullbackClosureInfo.pullbackFn.entryBlock - let clonedFunction = self.targetFunction - let clonedEntryBlock = self.getOrCreateEntryBlock() - - originalEntryBlock.arguments - .enumerated() - .filter { index, _ in !pullbackClosureInfo.hasClosureArg(at: index) } - .forEach { _, arg in - let clonedEntryBlockArgType = arg.type.getLoweredType(in: clonedFunction) - let clonedEntryBlockArg = clonedEntryBlock.addFunctionArgument( - type: clonedEntryBlockArgType, self.context) - clonedEntryBlockArg.copyFlags(from: arg as! FunctionArgument, self.context) - } - } + private func cloneAndSpecializeFunctionBody(using cloner: inout Cloner) { + addFunctionArgumentsWithoutClosures(using: &cloner) - /// Clones all closures, originally passed to the callee at the given pullbackClosureInfo, into the specialized function. - /// - /// Returns the following - - /// - allSpecializedEntryBlockArgs: Complete list of entry block arguments for the specialized function. This includes - /// the original arguments to the function (minus the closure arguments) and the arguments representing the values - /// originally captured by the skipped closure arguments. - /// - /// - closureArgIndexToAllClonedReleasableClosures: Mapping from a closure's argument index at `pullbackClosureInfo` to the list - /// of corresponding releasable closures cloned into the specialized function. We have a "list" because we clone - /// "closure chains", which consist of a "root" closure and its conversions/reabstractions. This map is used to - /// generate cleanup code for the cloned closures in the specialized function. - private func cloneAllClosures(at pullbackClosureInfo: PullbackClosureInfo) - -> ( - allSpecializedEntryBlockArgs: [Value], - closureArgIndexToAllClonedReleasableClosures: [Int: [SingleValueInstruction]] - ) - { - func entryBlockArgsWithOrigClosuresSkipped() -> [Value?] { - let clonedEntryBlock = self.getOrCreateEntryBlock() - var clonedNonClosureEntryBlockArgs = clonedEntryBlock.arguments.makeIterator() - - return pullbackClosureInfo.pullbackFn - .entryBlock - .arguments - .enumerated() - .reduce(into: []) { result, origArgTuple in - let (index, _) = origArgTuple - if !pullbackClosureInfo.hasClosureArg(at: index) { - result.append(clonedNonClosureEntryBlockArgs.next()) - } else { - result.append(Optional.none) - } - } + for rootClosure in rootClosures { + addFunctionArgumentsForCaptures(of: rootClosure, using: &cloner) } - var entryBlockArgs: [Value?] = entryBlockArgsWithOrigClosuresSkipped() - var closureArgIndexToAllClonedReleasableClosures: [Int: [SingleValueInstruction]] = [:] + let clonedClosureArguments = cloneClosures(using: &cloner) - for closureArgDesc in pullbackClosureInfo.closureArgDescriptors { - let (finalClonedReabstractedClosure, allClonedReleasableClosures) = - self.cloneClosureChain(representedBy: closureArgDesc, at: pullbackClosureInfo) + cloner.cloneFunctionBody(from: callee) - entryBlockArgs[closureArgDesc.closureArgIndex] = finalClonedReabstractedClosure - closureArgIndexToAllClonedReleasableClosures[closureArgDesc.closureArgIndex] = - allClonedReleasableClosures - } + addMissingDestroysAtFunctionExits(for: clonedClosureArguments, cloner.context) + } + + private func addFunctionArgumentsWithoutClosures(using cloner: inout Cloner) { + let clonedEntryBlock = cloner.getOrCreateEntryBlock() - return (entryBlockArgs.map { $0! }, closureArgIndexToAllClonedReleasableClosures) + for originalArg in callee.arguments where !isClosureArgument(calleeArgument: originalArg) { + let argType = originalArg.type.getLoweredType(in: cloner.targetFunction) + let clonedArg = clonedEntryBlock.addFunctionArgument(type: argType, cloner.context) + clonedArg.copyFlags(from: originalArg, cloner.context) + cloner.recordFoldedValue(originalArg, mappedTo: clonedArg) + } } - private func cloneClosureChain( - representedBy closureArgDesc: ClosureArgDescriptor, at pullbackClosureInfo: PullbackClosureInfo - ) - -> ( - finalClonedReabstractedClosure: SingleValueInstruction, - allClonedReleasableClosures: [SingleValueInstruction] - ) - { - let (origToClonedValueMap, capturedArgRange) = self.addEntryBlockArgs( - forValuesCapturedBy: closureArgDesc) - let clonedFunction = self.targetFunction - let clonedEntryBlock = self.getOrCreateEntryBlock() - let clonedClosureArgs = Array(clonedEntryBlock.arguments[capturedArgRange]) - - let builder = - clonedEntryBlock.instructions.isEmpty - ? Builder(atStartOf: clonedFunction, self.context) - : Builder( - atEndOf: clonedEntryBlock, location: clonedEntryBlock.instructions.last!.location, - self.context) - - let clonedRootClosure = builder.cloneRootClosure( - representedBy: closureArgDesc, capturedArguments: clonedClosureArgs) - - let finalClonedReabstractedClosure = - builder.cloneRootClosureReabstractions( - rootClosure: closureArgDesc.closure, clonedRootClosure: clonedRootClosure, - reabstractedClosure: pullbackClosureInfo.appliedArgForClosure( - at: closureArgDesc.closureArgIndex)!, - origToClonedValueMap: origToClonedValueMap, - self.context) - - let allClonedReleasableClosures = [finalClonedReabstractedClosure] - return (finalClonedReabstractedClosure, allClonedReleasableClosures) + private func addFunctionArgumentsForCaptures(of closure: PartialApplyInst, using cloner: inout Cloner) { + for originalClosureArg in closure.arguments { + let capturedArg = cloner.targetFunction.entryBlock.addFunctionArgument( + type: originalClosureArg.type.getLoweredType(in: cloner.targetFunction), + cloner.context) + if !cloner.isCloned(value: originalClosureArg) { + cloner.recordFoldedValue(originalClosureArg, mappedTo: capturedArg) + } + } } - private func addEntryBlockArgs(forValuesCapturedBy closureArgDesc: ClosureArgDescriptor) - -> (origToClonedValueMap: [HashableValue: Value], capturedArgRange: Range) - { - var origToClonedValueMap: [HashableValue: Value] = [:] - let clonedFunction = self.targetFunction - let clonedEntryBlock = self.getOrCreateEntryBlock() + private func cloneClosures(using cloner: inout Cloner) -> [Value] { + return closureArguments.map { (closureArgOp, _) in + let clonedArg = cloner.cloneRecursively(value: closureArgOp.value) - let capturedArgRangeStart = clonedEntryBlock.arguments.count + let originalArg = apply.calleeArgument(of: closureArgOp, in: callee)! + cloner.recordFoldedValue(originalArg, mappedTo: clonedArg) - for arg in closureArgDesc.arguments { - let capturedArg = clonedEntryBlock.addFunctionArgument( - type: arg.type.getLoweredType(in: clonedFunction), - self.context) - origToClonedValueMap[arg] = capturedArg + return clonedArg } + } - let capturedArgRangeEnd = clonedEntryBlock.arguments.count - let capturedArgRange = - capturedArgRangeStart == capturedArgRangeEnd - ? 0..<0 - : capturedArgRangeStart.. Value? { - get { - self[key.hashable] - } - set { - self[key.hashable] = newValue + private func insertCompensatingDestroysForOwnedClosureArguments(_ context: FunctionPassContext) { + let builder = Builder(before: apply, context) + for (argOp, _) in closureArguments where argOp.endsLifetime { + builder.createDestroyValue(operand: argOp.value) } } -} -extension PullbackClosureInfo { - fileprivate enum NewApplyArg { - case Original(Value) - // TODO: This can be simplified in OSSA. We can just do a copy_value for everything - except for addresses??? - case PreviouslyCaptured( - value: Value, needsRetain: Bool, parentClosureArgIndex: Int) - - var value: Value { - switch self { - case let .Original(originalArg): - return originalArg - case let .PreviouslyCaptured(capturedArg, _, _): - return capturedArg + private func getNewApplyArguments(_ context: FunctionPassContext) -> [Value] { + let newCapturedArguments = rootClosures.flatMap { partialApply in + partialApply.arguments.map { capturedArg in + if partialApply.isOnStack || capturedArg.ownership == .none { + // Non-escaping closures don't consume their captures. Therefore we pass them also as "guaranteed" + // arguments to the specialized function. + // Note that because the non-escaping closure was passed to the original function, this guarantees + // that the lifetime of the captured arguments also extend to at least the apply of the function. + capturedArg + } else { + // Escaping closures consume their captures. Therefore we pass them as "owned" arguments to the + // specialized function. + capturedArg.copy(at: partialApply, andMakeAvailableIn: apply.parentBlock, context) + } } } + return nonClosureArguments.values + newCapturedArguments } - fileprivate func getArgumentsForSpecializedApply(of specializedCallee: Function) -> [NewApplyArg] - { - var newApplyArgs: [NewApplyArg] = [] + func uniqueCaptureArguments(_ context: FunctionPassContext) { + let builder = Builder(before: apply, context) - // Original arguments - for (applySiteIndex, arg) in self.paiOfPullback.arguments.enumerated() { - let calleeArgIndex = self.paiOfPullback.unappliedArgumentCount + applySiteIndex - if !self.hasClosureArg(at: calleeArgIndex) { - newApplyArgs.append(.Original(arg)) + // Insert identity cast instructions for all closure arguments to make them unique. We could use any kind + // of forwarding instruction - we'll delete them afterwards, anyway. + // + // %4 = partial_apply %3(%1, %1) : (Int, Int) -> () // %1 is captured twice + // -> + // %2 = unchecked_value_cast %1 + // %3 = unchecked_value_cast %1 + // %4 = partial_apply %3(%2, %3) : (Int, Int) -> () // all arguments are unique values now! + // + for closure in rootClosures { + for argOp in closure.argumentOperands { + let cast = builder.createUncheckedValueCast(from: argOp.value, to: argOp.value.type) + argOp.set(to: cast, context) } } + } - // Previously captured arguments - for closureArgDesc in self.closureArgDescriptors { - for (applySiteIndex, capturedArg) in closureArgDesc.arguments.enumerated() { - let needsRetain = closureArgDesc.isCapturedArgNonTrivialObjectType( - applySiteIndex: applySiteIndex, - specializedCallee: specializedCallee) - - newApplyArgs.append( - .PreviouslyCaptured( - value: capturedArg, needsRetain: needsRetain, - parentClosureArgIndex: closureArgDesc.closureArgIndex)) + func unUniqueCaptureArguments(_ context: FunctionPassContext) { + // Remove the inserted identity casts again. + for closure in rootClosures { + for argOp in closure.argumentOperands { + let cast = argOp.value as! UncheckedValueCastInst + cast.replace(with: cast.fromValue, context) } } - - return newApplyArgs } -} -extension ClosureArgDescriptor { - fileprivate func isCapturedArgNonTrivialObjectType( - applySiteIndex: Int, specializedCallee: Function - ) -> Bool { - precondition( - self.closure is PartialApplyInst, "ClosureArgDescriptor is not for a partial_apply closure!") + func deleteDeadClosures(_ context: FunctionPassContext) { + for (_, closure) in closureArguments where !closure.isDeleted { + if context.tryDeleteDeadClosure(closure: closure) { + context.notifyInvalidatedStackNesting() + } + } + } - let capturedArg = self.arguments[applySiteIndex] - let pai = self.closure as! PartialApplyInst - let capturedArgIndexInCallee = applySiteIndex + pai.unappliedArgumentCount - let capturedArgConvention = self.callee.argumentConventions[capturedArgIndexInCallee] + private var nonClosureArguments: LazyFilterSequence { + apply.argumentOperands.lazy.filter{ argOp in !closureArguments.contains{ $0.0 == argOp } } + } - return !capturedArg.type.isTrivial(in: specializedCallee) - && !capturedArgConvention.isAllowedIndirectConvForClosureSpec + private func isClosureArgument(calleeArgument: FunctionArgument) -> Bool { + closureArguments.contains { apply.calleeArgument(of: $0.0, in: callee) == calleeArgument } } } -extension Builder { - fileprivate func cloneRootClosure( - representedBy closureArgDesc: ClosureArgDescriptor, capturedArguments: [Value] - ) - -> SingleValueInstruction - { - let function = self.createFunctionRef(closureArgDesc.callee) - - if let pai = closureArgDesc.closure as? PartialApplyInst { - return self.createPartialApply( - function: function, substitutionMap: SubstitutionMap(), - capturedArguments: capturedArguments, calleeConvention: pai.calleeConvention, - hasUnknownResultIsolation: pai.hasUnknownResultIsolation, - isOnStack: pai.isOnStack) - } else { - return self.createThinToThickFunction( - thinFunction: function, resultType: closureArgDesc.closure.type) - } - } +private func isClosureApplied(_ closure: Value) -> Bool { + var handledFuncs: Set = [] + return checkRecursivelyIfClosureIsApplied(closure, &handledFuncs) +} - fileprivate func cloneRootClosureReabstractions( - rootClosure: Value, clonedRootClosure: Value, reabstractedClosure: Value, - origToClonedValueMap: [HashableValue: Value], _ context: FunctionPassContext - ) - -> SingleValueInstruction - { - func inner( - _ rootClosure: Value, _ clonedRootClosure: Value, _ reabstractedClosure: Value, - _ origToClonedValueMap: inout [HashableValue: Value] - ) -> Value { - switch reabstractedClosure { - case let reabstractedClosure where reabstractedClosure == rootClosure: - origToClonedValueMap[reabstractedClosure] = clonedRootClosure - return clonedRootClosure - - case let cvt as ConvertFunctionInst: - let toBeReabstracted = inner( - rootClosure, clonedRootClosure, cvt.fromFunction, - &origToClonedValueMap) - let reabstracted = self.createConvertFunction( - originalFunction: toBeReabstracted, resultType: cvt.type, - withoutActuallyEscaping: cvt.withoutActuallyEscaping) - origToClonedValueMap[cvt] = reabstracted - return reabstracted - - case let cvt as ConvertEscapeToNoEscapeInst: - let toBeReabstracted = inner( - rootClosure, clonedRootClosure, cvt.fromFunction, - &origToClonedValueMap) - let reabstracted = self.createConvertEscapeToNoEscape( - originalFunction: toBeReabstracted, resultType: cvt.type, - isLifetimeGuaranteed: true) - origToClonedValueMap[cvt] = reabstracted - return reabstracted - - case let pai as PartialApplyInst: - let toBeReabstracted = inner( - rootClosure, clonedRootClosure, pai.arguments[0], - &origToClonedValueMap) - - guard let function = pai.referencedFunction else { - log("Parent function of pullbackClosureInfo: \(rootClosure.parentFunction)") - log("Root closure: \(rootClosure)") - log("Unsupported reabstraction closure: \(pai)") - fatalError("Encountered unsupported reabstraction (via partial_apply) of root closure!") - } +private func checkRecursivelyIfClosureIsApplied(_ closure: Value, _ handledFuncs: inout Set) -> Bool { + for use in closure.uses { + switch use.instruction { - let fri = self.createFunctionRef(function) - let reabstracted = self.createPartialApply( - function: fri, substitutionMap: SubstitutionMap(), - capturedArguments: [toBeReabstracted], - calleeConvention: pai.calleeConvention, - hasUnknownResultIsolation: pai.hasUnknownResultIsolation, - isOnStack: pai.isOnStack) - origToClonedValueMap[pai] = reabstracted - return reabstracted - - case let mdi as MarkDependenceInst: - let toBeReabstracted = inner( - rootClosure, clonedRootClosure, mdi.value, &origToClonedValueMap) - let base = origToClonedValueMap[mdi.base]! - let reabstracted = self.createMarkDependence( - value: toBeReabstracted, base: base, kind: .Escaping) - origToClonedValueMap[mdi] = reabstracted - return reabstracted - - default: - log("Parent function of pullbackClosureInfo: \(rootClosure.parentFunction)") - log("Root closure: \(rootClosure)") - log("Converted/reabstracted closure: \(reabstractedClosure)") - fatalError("Encountered unsupported reabstraction of root closure: \(reabstractedClosure)") + case let apply as FullApplySite: + if apply.callee == closure { + return true } - } - - var origToClonedValueMap = origToClonedValueMap - let finalClonedReabstractedClosure = inner( - rootClosure, clonedRootClosure, reabstractedClosure, - &origToClonedValueMap) - return (finalClonedReabstractedClosure as! SingleValueInstruction) - } - - fileprivate func destroyPartialApply(pai: PartialApplyInst, _ context: FunctionPassContext) { - // TODO: Support only OSSA instructions once the OSSA elimination pass is moved after all function optimization - // passes. - - if pai.isOnStack { - // for arg in pai.arguments { - // self.createDestroyValue(operand: arg) - // } - // self.createDestroyValue(operand: pai) - - if pai.parentFunction.hasOwnership { - // Under OSSA, the closure acts as an owned value whose lifetime is a borrow scope for the captures, so we need to - // end the borrow scope before ending the lifetimes of the captures themselves. - self.createDestroyValue(operand: pai) - self.destroyCapturedArgs(for: pai) - } else { - self.destroyCapturedArgs(for: pai) - self.createDeallocStack(pai) - context.notifyInvalidatedStackNesting() + let recursionBudget = 8 + + // Recurse into called function + if let callee = apply.referencedFunction, + callee.isDefinition, + handledFuncs.insert(callee).inserted, + handledFuncs.count <= recursionBudget, + let calleeArg = apply.calleeArgument(of: use, in: callee) + { + if checkRecursivelyIfClosureIsApplied(calleeArg, &handledFuncs) { + return true + } } - } else { - if pai.parentFunction.hasOwnership { - self.createDestroyValue(operand: pai) - } else { - self.createReleaseValue(operand: pai) + + case is CopyValueInst, is MoveValueInst: + if checkRecursivelyIfClosureIsApplied(use.instruction as! SingleValueInstruction, &handledFuncs) { + return true } + + default: + break } } + + return false } -extension FunctionConvention { - fileprivate func getSpecializedParameters(basedOn pullbackClosureInfo: PullbackClosureInfo) - -> [ParameterInfo] - { - let pullbackFn = pullbackClosureInfo.pullbackFn - var specializedParamInfoList: [ParameterInfo] = [] +/// Add destroys for values which are not consumed, yet. +/// There are two cases of values for which we need this: +/// 1. guaranteed closure arguments +/// 2. operands of copies at the call site +/// +/// ``` +/// %1 = partial_apply %closure // is cloned to the specialized function +/// %2 = copy_value %1 // is cloned to the specialized function +/// apply %function(%2) : (@guaranteed () -> ()) -> () +/// destroy_value %1 +/// +/// sil @specializedFunction() -> () { +/// bb0: +/// %1 = partial_apply %closure +/// %2 = copy_value %1 +/// ... // body +/// destroy_value %2 // case 1: destroy for the guaranteed closure argument +/// destroy_value %1 // case 2: destroy for the operand of the copy +/// return +/// ``` +private func addMissingDestroysAtFunctionExits(for clonedArguments: [Value], _ context: FunctionPassContext) { + var needDestroy = ValueWorklist(context) + defer { needDestroy.deinitialize() } - // Start by adding all original parameters except for the closure parameters. - let firstParamIndex = pullbackFn.argumentConventions.firstParameterIndex - for (index, paramInfo) in pullbackFn.convention.parameters.enumerated() { - let argIndex = index + firstParamIndex - if !pullbackClosureInfo.hasClosureArg(at: argIndex) { - specializedParamInfoList.append(paramInfo) - } - } + for clonedArg in clonedArguments { + findValuesWhichNeedDestroyRecursively(value: clonedArg, needDestroy: &needDestroy) + } - // Now, append parameters captured by each of the original closure parameter. - // - // Captured parameters are always appended to the function signature. If the argument type of the captured - // parameter in the callee is: - // - direct and trivial, pass the new parameter as Direct_Unowned. - // - direct and non-trivial, pass the new parameter as Direct_Owned. - // - indirect, pass the new parameter using the same parameter convention as in - // the original closure. - for closureArgDesc in pullbackClosureInfo.closureArgDescriptors { - if let closure = closureArgDesc.closure as? PartialApplyInst { - let closureCallee = closureArgDesc.callee - let closureCalleeConvention = closureCallee.convention - let unappliedArgumentCount = - closure.unappliedArgumentCount - closureCalleeConvention.indirectSILResultCount - - let prevCapturedParameters = - closureCalleeConvention - .parameters[unappliedArgumentCount...] - .enumerated() - .map { index, paramInfo in - let argIndexOfParam = - closureCallee.argumentConventions.firstParameterIndex + unappliedArgumentCount + index - let argType = closureCallee.argumentTypes[argIndexOfParam] - return paramInfo.withSpecializedConvention( - isArgTypeTrivial: argType.isTrivial(in: closureCallee)) - } - - specializedParamInfoList.append(contentsOf: prevCapturedParameters) - } + while let valueToDestroy = needDestroy.pop() { + Builder.insertCleanupAtFunctionExits(of: valueToDestroy.parentFunction, context) { builder in + builder.createDestroyValue(operand: valueToDestroy) } - - return specializedParamInfoList } } -extension ParameterInfo { - fileprivate func withSpecializedConvention(isArgTypeTrivial: Bool) -> Self { - let specializedParamConvention = - self.convention.isAllowedIndirectConvForClosureSpec - ? self.convention - : isArgTypeTrivial ? ArgumentConvention.directUnowned : ArgumentConvention.directOwned - - return ParameterInfo( - type: self.type, convention: specializedParamConvention, options: self.options, - hasLoweredAddresses: self.hasLoweredAddresses) +private func findValuesWhichNeedDestroyRecursively(value: Value, needDestroy: inout ValueWorklist) { + if let svi = value as? SingleValueInstruction { + for op in svi.operands { + findValuesWhichNeedDestroyRecursively(value: op.value, needDestroy: &needDestroy) + } } - - fileprivate var isTrivialNoescapeClosure: Bool { - SILFunctionType_isTrivialNoescape(type.bridged) + if value.ownership == .owned && value.uses.endingLifetime.isEmpty { + needDestroy.pushIfNotVisited(value) } } -extension ArgumentConvention { - fileprivate var isAllowedIndirectConvForClosureSpec: Bool { - switch self { - case .indirectInout, .indirectInoutAliasable: - return true - default: - return false +private extension ParameterInfo { + func withSpecializedConvention(for partialApply: PartialApplyInst, in callee: Function) -> Self { + let argType = type.loweredType(in: partialApply.parentFunction) + let specializedParamConvention = if self.convention.isIndirect { + self.convention + } else { + if argType.isTrivial(in: callee) { + ArgumentConvention.directUnowned + } else { + if partialApply.isOnStack { + ArgumentConvention.directGuaranteed + } else { + ArgumentConvention.directOwned + } + } } + + return ParameterInfo( + type: self.type, convention: specializedParamConvention, options: self.options, + hasLoweredAddresses: self.hasLoweredAddresses) } } -extension PartialApplyInst { +private extension PartialApplyInst { /// True, if the closure obtained from this partial_apply is the /// pullback returned from an autodiff VJP - fileprivate var isPullbackInResultOfAutodiffVJP: Bool { + var isPullbackInResultOfAutodiffVJP: Bool { if self.parentFunction.isAutodiffVJP, let use = self.uses.singleUse, let tupleInst = use.instruction as? TupleInst, @@ -1216,262 +760,34 @@ extension PartialApplyInst { return false } - fileprivate var isPartialApplyOfThunk: Bool { + var isPartialApplyOfThunk: Bool { if self.numArguments == 1, let fun = self.referencedFunction, fun.thunkKind == .reabstractionThunk || fun.thunkKind == .thunk, self.arguments[0].type.isLoweredFunction, - self.arguments[0].type.isReferenceCounted(in: self.parentFunction) - || self.callee.type.isThickFunction + self.arguments[0].type.isReferenceCounted(in: self.parentFunction) || self.callee.type.isThickFunction { return true } - return false } - fileprivate var hasOnlyInoutIndirectArguments: Bool { + var hasOnlyInoutIndirectArguments: Bool { self.argumentOperands .filter { !$0.value.type.isObject } .allSatisfy { self.convention(of: $0)!.isInout } } -} - -extension Instruction { - fileprivate var asSupportedClosure: SingleValueInstruction? { - switch self { - case let tttf as ThinToThickFunctionInst where tttf.callee is FunctionRefInst: - return tttf - // TODO: figure out what to do with non-inout indirect arguments - // https://forums.swift.org/t/non-inout-indirect-types-not-supported-in-closure-specialization-optimization/70826 - case let pai as PartialApplyInst - where pai.callee is FunctionRefInst && pai.hasOnlyInoutIndirectArguments: - return pai - default: - return nil - } - } - - fileprivate var isSupportedClosure: Bool { - asSupportedClosure != nil - } -} -extension ApplySite { - fileprivate var calleeIsDynamicFunctionRef: Bool { - return !(callee is DynamicFunctionRefInst || callee is PreviousDynamicFunctionRefInst) + var allArgumentsCanBeCopied: Bool { + arguments.allSatisfy { !$0.type.isMoveOnly } } } -extension Function { - fileprivate var effectAllowsSpecialization: Bool { +private extension Function { + var effectAllowsSpecialization: Bool { switch self.effectAttribute { case .readNone, .readOnly, .releaseNone: return false default: return true } } } - -// ===================== Utility Types ===================== // -private struct OrderedDict { - private var valueIndexDict: [Key: Int] = [:] - private var entryList: [(Key, Value)] = [] - - subscript(key: Key) -> Value? { - if let index = valueIndexDict[key] { - return entryList[index].1 - } - return nil - } - - mutating func insert(key: Key, value: Value) { - if valueIndexDict[key] == nil { - valueIndexDict[key] = entryList.count - entryList.append((key, value)) - } - } - - mutating func update(key: Key, value: Value) { - if let index = valueIndexDict[key] { - entryList[index].1 = value - } - } - - var keys: LazyMapSequence<[(Key, Value)], Key> { - entryList.lazy.map { $0.0 } - } - - var values: LazyMapSequence<[(Key, Value)], Value> { - entryList.lazy.map { $0.1 } - } -} - -/// Represents all the information required to represent a closure in isolation, i.e., outside of a pullback's partial_apply context -/// where the closure may be getting captured as an argument. -/// -/// Composed with other information inside a `ClosureArgDescriptor` to represent a closure as a captured argument of a pullback's partial_apply. -private struct ClosureInfo { - let closure: SingleValueInstruction - let lifetimeFrontier: [Instruction] - - init(closure: SingleValueInstruction, lifetimeFrontier: [Instruction]) { - self.closure = closure - self.lifetimeFrontier = lifetimeFrontier - } - -} - -/// Represents a closure as a captured argument of a pullback's partial_apply. -private struct ClosureArgDescriptor { - let closureInfo: ClosureInfo - /// The index of the closure in the pullback's partial_apply argument list. - let closureArgumentIndex: Int - let parameterInfo: ParameterInfo - - var closure: SingleValueInstruction { - closureInfo.closure - } - var lifetimeFrontier: [Instruction] { - closureInfo.lifetimeFrontier - } - - var isPartialApplyOnStack: Bool { - if let pai = closure as? PartialApplyInst { - return pai.isOnStack - } - return false - } - - var callee: Function { - if let pai = closure as? PartialApplyInst { - return pai.referencedFunction! - } else { - return (closure as! ThinToThickFunctionInst).referencedFunction! - } - } - - var location: Location { - closure.location - } - - var closureArgIndex: Int { - closureArgumentIndex - } - - var closureParamInfo: ParameterInfo { - parameterInfo - } - - var numArguments: Int { - if let pai = closure as? PartialApplyInst { - return pai.numArguments - } else { - return 0 - } - } - - var arguments: LazyMapSequence { - if let pai = closure as? PartialApplyInst { - return pai.arguments - } - - return OperandArray.empty.lazy.map { $0.value } as LazyMapSequence - } - - var isClosureGuaranteed: Bool { - closureParamInfo.convention.isGuaranteed - } - - var isClosureConsumed: Bool { - closureParamInfo.convention.isConsumed - } -} - -/// Represents a partial_apply of pullback capturing one or more closure arguments. -private struct PullbackClosureInfo { - let paiOfPullback: PartialApplyInst - var closureArgDescriptors: [ClosureArgDescriptor] = [] - - init(paiOfPullback: PartialApplyInst) { - self.paiOfPullback = paiOfPullback - } - - mutating func appendClosureArgDescriptor(_ descriptor: ClosureArgDescriptor) { - self.closureArgDescriptors.append(descriptor) - } - - var pullbackFn: Function { - paiOfPullback.referencedFunction! - } - - var reachableExitBBsInCallee: [BasicBlock] { - pullbackFn.blocks.filter { $0.isReachableExitBlock } - } - - func hasClosureArg(at index: Int) -> Bool { - closureArgDescriptors.contains { $0.closureArgumentIndex == index } - } - - func closureArgDesc(at index: Int) -> ClosureArgDescriptor? { - closureArgDescriptors.first { $0.closureArgumentIndex == index } - } - - func appliedArgForClosure(at index: Int) -> Value? { - if let closureArgDesc = closureArgDesc(at: index) { - return paiOfPullback.arguments[ - closureArgDesc.closureArgIndex - paiOfPullback.unappliedArgumentCount] - } - - return nil - } - - func specializedCalleeName(_ context: FunctionPassContext) -> String { - let closureArgs = Array(self.closureArgDescriptors.map { - (argumentIndex: $0.closureArgIndex, - argumentValue: FunctionPassContext.ClosureArgumentMangling.closure($0.closure)) - }) - return context.mangle(withClosureArguments: closureArgs, from: pullbackFn) - } -} - -// ===================== Unit tests ===================== // - -let getPullbackClosureInfoTest = FunctionTest( - "autodiff_closure_specialize_get_pullback_closure_info" -) { function, arguments, context in - print("Specializing closures in function: \(function.name)") - print("===============================================") - let pullbackClosureInfo = getPullbackClosureInfo(in: function, context)! - print("PartialApply of pullback: \(pullbackClosureInfo.paiOfPullback)") - print("Passed in closures: ") - for index in pullbackClosureInfo.closureArgDescriptors.indices { - var closureArgDescriptor = pullbackClosureInfo.closureArgDescriptors[index] - print("\(index+1). \(closureArgDescriptor.closureInfo.closure)") - } - print("\n") -} - -let specializedFunctionSignatureAndBodyTest = FunctionTest( - "autodiff_closure_specialize_specialized_function_signature_and_body" -) { function, arguments, context in - - let pullbackClosureInfo = getPullbackClosureInfo(in: function, context)! - - let (specializedFunction, _) = getOrCreateSpecializedFunction( - basedOn: pullbackClosureInfo, context) - print("Generated specialized function: \(specializedFunction.name)") - print("\(specializedFunction)\n") -} - -let rewrittenCallerBodyTest = FunctionTest("autodiff_closure_specialize_rewritten_caller_body") { - function, arguments, context in - let pullbackClosureInfo = getPullbackClosureInfo(in: function, context)! - - let (specializedFunction, _) = getOrCreateSpecializedFunction( - basedOn: pullbackClosureInfo, context) - rewriteApplyInstruction( - using: specializedFunction, pullbackClosureInfo: pullbackClosureInfo, context) - - print("Rewritten caller body for: \(function.name):") - print("\(function)\n") -} diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift index fa478ddce641f..af7f48d73c00c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift @@ -105,7 +105,7 @@ private func registerSwiftPasses() { registerPass(tempRValueElimination, { tempRValueElimination.run($0) }) registerPass(mandatoryTempRValueElimination, { mandatoryTempRValueElimination.run($0) }) registerPass(tempLValueElimination, { tempLValueElimination.run($0) }) - registerPass(generalClosureSpecialization, { generalClosureSpecialization.run($0) }) + registerPass(closureSpecialization, { closureSpecialization.run($0) }) registerPass(autodiffClosureSpecialization, { autodiffClosureSpecialization.run($0) }) registerPass(loopInvariantCodeMotionPass, { loopInvariantCodeMotionPass.run($0) }) diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift index 984d9609e4eda..701fe2819e86d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift @@ -43,7 +43,6 @@ public func registerOptimizerTests() { registerFunctionTests( addressOwnershipLiveRangeTest, argumentConventionsTest, - getPullbackClosureInfoTest, interiorLivenessTest, lifetimeDependenceRootTest, lifetimeDependenceScopeTest, @@ -52,8 +51,6 @@ public func registerOptimizerTests() { localVariableReachableUsesTest, localVariableReachingAssignmentsTest, rangeOverlapsPathTest, - rewrittenCallerBodyTest, - specializedFunctionSignatureAndBodyTest, variableIntroducerTest ) diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index b10044121c8c6..062a3f1b9dc5d 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -153,9 +153,8 @@ PASS(TempLValueElimination, "temp-lvalue-elimination", PASS(LoopInvariantCodeMotion, "loop-invariant-code-motion", "New Loop Invariant Code Motion") -// NOTE - ExperimentalSwiftBasedClosureSpecialization and AutodiffClosureSpecialization are a WIP -PASS(ExperimentalSwiftBasedClosureSpecialization, "experimental-swift-based-closure-specialization", - "General closure-specialization pass written in Swift") +PASS(ClosureSpecialization, "closure-specialization", + "Specialize functions with closure arguments") PASS(AutodiffClosureSpecialization, "autodiff-closure-specialization", "Autodiff specific closure-specialization pass") diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index b7d857433be29..10ff5814b79a1 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -1034,10 +1034,10 @@ SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) { if (SILPrintFinalOSSAModule) { addModulePrinterPipeline(P, "SIL Print Final OSSA Module"); } - P.addOwnershipModelEliminator(); - P.addAutodiffClosureSpecialization(); + P.addOwnershipModelEliminator(); + // After serialization run the function pass pipeline to iteratively lower // high-level constructs like @_semantics calls. addMidLevelFunctionPipeline(P); diff --git a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_bte.sil b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_bte.sil index ea361e96a6832..7d705d7eaf4b8 100644 --- a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_bte.sil +++ b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_bte.sil @@ -1,6 +1,5 @@ /// Multi basic block VJP, pullback accepting branch tracing enum argument. -// RUN: %target-sil-opt -sil-print-types -test-runner %s -o /dev/null 2>&1 | %FileCheck %s --check-prefixes=TRUNNER,CHECK // RUN: %target-sil-opt -sil-print-types -autodiff-closure-specialization -sil-combine %s -o - | %FileCheck %s --check-prefixes=COMBINE,CHECK // REQUIRES: swift_in_compiler @@ -33,59 +32,36 @@ sil @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf sil [transparent] [thunk] @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // pullback of mul42(_:) -sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test5mul42yS2fSgFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector { -bb0(%0 : $Float, %1 : $_AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, %2 : $@callee_guaranteed (Float) -> Float): +sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test5mul42yS2fSgFTJpSpSr : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector { +bb0(%0 : $Float, %1 : $_AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, %2 : @owned $@callee_guaranteed (Float) -> Float): %4 = apply %2(%0) : $@callee_guaranteed (Float) -> Float - strong_release %2 + destroy_value %2 %6 = enum $Optional, #Optional.some!enumelt, %4 %7 = struct $Optional.TangentVector (%6) return %7 } // end sil function '$s4test5mul42yS2fSgFTJpSpSr' // reverse-mode derivative of mul42(_:) -sil hidden @$s4test5mul42yS2fSgFTJrSpSr : $@convention(thin) (Optional) -> (Float, @owned @callee_guaranteed (Float) -> Optional.TangentVector) { +sil hidden [ossa] @$s4test5mul42yS2fSgFTJrSpSr : $@convention(thin) (Optional) -> (Float, @owned @callee_guaranteed (Float) -> Optional.TangentVector) { bb0(%0 : $Optional): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test5mul42yS2fSgFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]]) : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s4test5mul42yS2fSgFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktj1_k5FZSf_K6SfcfU_S2fTf1nnc_n - // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test5mul42yS2fSgFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktj1_k5FZSf_K6SfcfU_S2fTf1nnc_n : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector { + // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test5mul42yS2fSgFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktj1_k5FZSf_K6SfcfU_S2fTf1nnc_n : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector { // CHECK: bb0(%0 : $Float, %1 : $_AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, %2 : $Float, %3 : $Float): + // CHECK: %[[#A6:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // CHECK: %[[#A4:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) // CHECK: %[[#A5:]] = partial_apply [callee_guaranteed] %[[#A4]](%2, %3) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // CHECK: %[[#A6:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#A7:]] = partial_apply [callee_guaranteed] %[[#A6]](%[[#A5]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#A8:]] = apply %[[#A7]](%0) : $@callee_guaranteed (Float) -> Float // COMBINE-NOT: = partial_apply // COMBINE: %[[#A8:]] = apply %[[#A6]](%0, %[[#A5]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: strong_release %[[#A7]] : $@callee_guaranteed (Float) -> Float // CHECK: %[[#A10:]] = enum $Optional, #Optional.some!enumelt, %[[#A8]] : $Float // CHECK: %[[#A11:]] = struct $Optional.TangentVector (%[[#A10]] : $Optional) // CHECK: return %[[#A11]] : $Optional.TangentVector - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test5mul42yS2fSgFTJrSpSr: - // CHECK: sil hidden @$s4test5mul42yS2fSgFTJrSpSr : $@convention(thin) (Optional) -> (Float, @owned @callee_guaranteed (Float) -> Optional.TangentVector) { + // CHECK: sil hidden [ossa] @$s4test5mul42yS2fSgFTJrSpSr : $@convention(thin) (Optional) -> (Float, @owned @callee_guaranteed (Float) -> Optional.TangentVector) { // CHECK: bb1(%2 : $Float): // CHECK: %[[#B4:]] = struct $Float (%[[#]] : $Builtin.FPIEEE32) - // TRUNNER: %[[#B10:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#B11:]] = partial_apply [callee_guaranteed] %[[#B10]](%2, %[[#B4]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#B12:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#B13:]] = partial_apply [callee_guaranteed] %[[#B12]](%[[#B11]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#B14:]] = function_ref @$s4test5mul42yS2fSgFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector // COMBINE-NOT: = partial_apply // COMBINE-NOT: = function_ref - // CHECK: %[[#B15:]] = function_ref @$s4test5mul42yS2fSgFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktj1_k5FZSf_K6SfcfU_S2fTf1nnc_n : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector - // CHECK: %[[#B16:]] = partial_apply [callee_guaranteed] %[[#B15]](%[[#]], %2, %[[#B4]]) : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector - // TRUNNER: release_value %[[#B11]] : $@callee_guaranteed (Float) -> (Float, Float) + // CHECK: %[[#B15:]] = function_ref @$s4test5mul42yS2fSgFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktj1_k5FZSf_K6SfcfU_S2fTf1nnc_n : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector + // CHECK: %[[#B16:]] = partial_apply [callee_guaranteed] %[[#B15]](%[[#]], %2, %[[#B4]]) : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, Float, Float) -> Optional.TangentVector // CHECK: %[[#B18:]] = tuple (%[[#]] : $Float, %[[#B16]] : $@callee_guaranteed (Float) -> Optional.TangentVector) // CHECK: return %[[#B18]] @@ -106,8 +82,8 @@ bb1(%3 : $Float): %13 = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float %14 = partial_apply [callee_guaranteed] %13(%12) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // function_ref pullback of mul42(_:) - %16 = function_ref @$s4test5mul42yS2fSgFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector - %17 = partial_apply [callee_guaranteed] %16(%7, %14) : $@convention(thin) (Float, @owned _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector + %16 = function_ref @$s4test5mul42yS2fSgFTJpSpSr : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector + %17 = partial_apply [callee_guaranteed] %16(%7, %14) : $@convention(thin) (Float, _AD__$s4test5mul42yS2fSgF_bb2__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float) -> Optional.TangentVector %18 = tuple (%10, %17) return %18 @@ -192,43 +168,40 @@ enum _AD__$s4test5ClassV6stored8optionalACSf_SfSgtcfC_bb0__Pred__src_0_wrt_0_1 { sil @$s4test5ClassV6stored8optionalACSf_SfSgtcfCTJpSSUpSr : $@convention(thin) (Class.TangentVector) -> (Float, Optional.TangentVector) // pullback of Class.method() -sil private @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Class.TangentVector { -bb0(%0 : $Float, %1 : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %2 : $@callee_guaranteed (Float) -> Float, %3 : $@callee_guaranteed (Float) -> (Float, Float)): +sil private [ossa] @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Class.TangentVector { +bb0(%0 : $Float, %1 : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %2 : @owned $@callee_guaranteed (Float) -> Float, %3 : @owned $@callee_guaranteed (Float) -> (Float, Float)): %4 = float_literal $Builtin.FPIEEE32, 0x0 // 0 %8 = apply %3(%0) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %3 + destroy_value %3 %10 = tuple_extract %8, 0 %11 = tuple_extract %8, 1 %12 = struct_extract %11, #Float._value %13 = builtin "fadd_FPIEEE32"(%4, %12) : $Builtin.FPIEEE32 %15 = apply %2(%10) : $@callee_guaranteed (Float) -> Float - strong_release %2 + destroy_value %2 %17 = struct_extract %15, #Float._value %18 = builtin "fadd_FPIEEE32"(%13, %17) : $Builtin.FPIEEE32 switch_enum %1, case #_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb2 -bb1(%37 : $(predecessor: _AD__$s4test5ClassV6methodSfyF_bb2__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> Float)): - %38 = tuple_extract %37, 0 - %39 = tuple_extract %37, 1 +bb1(%37 : @owned $(predecessor: _AD__$s4test5ClassV6methodSfyF_bb2__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> Float)): + (%38, %39) = destructure_tuple %37 %40 = builtin "fadd_FPIEEE32"(%18, %4) : $Builtin.FPIEEE32 %41 = struct $Float (%40) %42 = apply %39(%41) : $@callee_guaranteed (Float) -> Float - strong_release %39 + destroy_value %39 %44 = struct_extract %42, #Float._value %45 = builtin "fadd_FPIEEE32"(%44, %4) : $Builtin.FPIEEE32 %46 = builtin "fadd_FPIEEE32"(%4, %45) : $Builtin.FPIEEE32 %50 = unchecked_enum_data %38, #_AD__$s4test5ClassV6methodSfyF_bb2__Pred__src_0_wrt_0.bb0!enumelt - %51 = tuple_extract %50, 1 - %52 = tuple_extract %50, 0 - br bb3(%4, %46, %52, %51) + (%51, %52) = destructure_tuple %50 + br bb3(%4, %46, %51, %52) -bb2(%54 : $(predecessor: _AD__$s4test5ClassV6methodSfyF_bb1__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> (Float, Float))): - %55 = tuple_extract %54, 0 - %56 = tuple_extract %54, 1 +bb2(%54 : @owned $(predecessor: _AD__$s4test5ClassV6methodSfyF_bb1__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> (Float, Float))): + (%55, %56) = destructure_tuple %54 %57 = builtin "fadd_FPIEEE32"(%18, %4) : $Builtin.FPIEEE32 %58 = struct $Float (%57) %59 = apply %56(%58) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %56 + destroy_value %56 %61 = tuple_extract %59, 0 %62 = tuple_extract %59, 1 %63 = struct_extract %61, #Float._value @@ -239,11 +212,10 @@ bb2(%54 : $(predecessor: _AD__$s4test5ClassV6methodSfyF_bb1__Pred__src_0_wrt_0, %69 = builtin "fadd_FPIEEE32"(%64, %4) : $Builtin.FPIEEE32 %70 = builtin "fadd_FPIEEE32"(%69, %4) : $Builtin.FPIEEE32 %73 = unchecked_enum_data %55, #_AD__$s4test5ClassV6methodSfyF_bb1__Pred__src_0_wrt_0.bb0!enumelt - %74 = tuple_extract %73, 1 - %75 = tuple_extract %73, 0 - br bb3(%70, %67, %75, %74) + (%74, %75) = destructure_tuple %73 + br bb3(%70, %67, %74, %75) -bb3(%77 : $Builtin.FPIEEE32, %78 : $Builtin.FPIEEE32, %79 : $@callee_guaranteed (Float) -> Float, %80 : $@callee_guaranteed (Class.TangentVector) -> (Float, Optional.TangentVector)): +bb3(%77 : $Builtin.FPIEEE32, %78 : $Builtin.FPIEEE32, %79 : @owned $@callee_guaranteed (Float) -> Float, %80 : @owned $@callee_guaranteed (Class.TangentVector) -> (Float, Optional.TangentVector)): %81 = builtin "fadd_FPIEEE32"(%4, %77) : $Builtin.FPIEEE32 %85 = builtin "fadd_FPIEEE32"(%78, %4) : $Builtin.FPIEEE32 %87 = builtin "fadd_FPIEEE32"(%81, %4) : $Builtin.FPIEEE32 @@ -263,7 +235,7 @@ bb3(%77 : $Builtin.FPIEEE32, %78 : $Builtin.FPIEEE32, %79 : $@callee_guaranteed %109 = struct $Optional.TangentVector (%108) %110 = struct $Class.TangentVector (%105, %109) %111 = apply %80(%110) : $@callee_guaranteed (Class.TangentVector) -> (Float, Optional.TangentVector) - strong_release %80 + destroy_value %80 %113 = tuple_extract %111, 1 %114 = struct_extract %113, #Optional.TangentVector.value switch_enum %114, case #Optional.none!enumelt: bb4, case #Optional.some!enumelt: bb5 @@ -283,7 +255,7 @@ bb6(%122 : $Builtin.FPIEEE32): %125 = builtin "fadd_FPIEEE32"(%124, %4) : $Builtin.FPIEEE32 %126 = struct $Float (%125) %127 = apply %79(%126) : $@callee_guaranteed (Float) -> Float - strong_release %79 + destroy_value %79 %129 = struct_extract %127, #Float._value %130 = builtin "fadd_FPIEEE32"(%129, %4) : $Builtin.FPIEEE32 %131 = builtin "fadd_FPIEEE32"(%4, %130) : $Builtin.FPIEEE32 @@ -297,63 +269,34 @@ bb6(%122 : $Builtin.FPIEEE32): } // end sil function '$s4test5ClassV6methodSfyFTJpSpSr' // reverse-mode derivative of Class.method() -sil hidden @$s4test5ClassV6methodSfyFTJrSpSr : $@convention(method) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { +sil hidden [ossa] @$s4test5ClassV6methodSfyFTJrSpSr : $@convention(method) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { bb0(%0 : $Class): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test5ClassV6methodSfyFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]], %[[#C42:]]) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Class.TangentVector - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#]] = partial_apply [callee_guaranteed] %[[#C7:]](%[[#C34:]], %[[#]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-NEXT: 2. %[[#C42]] = partial_apply [callee_guaranteed] %[[#C7]](%[[#C34]], %[[#]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s4test5ClassV6methodSfyFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktk1_l5FZSf_L6SfcfU_S2fAES2fTf1nncc_n - // CHECK: sil private @$s4test5ClassV6methodSfyFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktk1_l5FZSf_L6SfcfU_S2fAES2fTf1nncc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, Float, Float, Float, Float) -> Class.TangentVector { - // CHECK: bb0(%0 : $Float, %1 : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %2 : $Float, %3 : $Float, %4 : $Float, %5 : $Float): + // CHECK: sil private [ossa] @$s4test5ClassV6methodSfyFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktk1_l5FZSf_L6SfcfU_S2fAES2fTf1nncc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, Float, Float, Float, Float) -> Class.TangentVector { + // CHECK: bb0(%0 : $Float, %1 : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %2 : $Float, %3 : $Float, %4 : $Float, %5 : $Float): + // CHECK: %[[#D8:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // CHECK: %[[#D6:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) // CHECK: %[[#D7:]] = partial_apply [callee_guaranteed] %[[#D6]](%2, %3) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // CHECK: %[[#D8:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#D9:]] = partial_apply [callee_guaranteed] %[[#D8]](%[[#D7]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // COMBINE-NOT: = partial_apply - // CHECK: %[[#D10:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#D11:]] = partial_apply [callee_guaranteed] %[[#D10]](%4, %5) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // COMBINE-NOT: = partial_apply - // TRUNNER: %[[#D13:]] = apply %[[#D11]](%0) : $@callee_guaranteed (Float) -> (Float, Float) - // COMBINE: %[[#D13:]] = apply %[[#D10]](%0, %4, %5) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: strong_release %[[#D11]] : $@callee_guaranteed (Float) -> (Float, Float) + // COMBINE: %[[#D13:]] = apply %[[#D6]](%0, %4, %5) : $@convention(thin) (Float, Float, Float) -> (Float, Float) // CHECK: %[[#D15:]] = tuple_extract %[[#D13]] : $(Float, Float), 0 - // TRUNNER: %[[#]] = apply %[[#D9]](%[[#D15]]) : $@callee_guaranteed (Float) -> Float // COMBINE: %[[#]] = apply %[[#D8]](%[[#D15]], %[[#D7]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: strong_release %[[#D9]] : $@callee_guaranteed (Float) -> Float - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test5ClassV6methodSfyFTJrSpSr: - // CHECK: sil hidden @$s4test5ClassV6methodSfyFTJrSpSr : $@convention(method) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { + // CHECK: sil hidden [ossa] @$s4test5ClassV6methodSfyFTJrSpSr : $@convention(method) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { // CHECK: bb0(%0 : $Class): // CHECK: %[[#E2:]] = struct $Float // CHECK: %[[#E7:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) // CHECK: %[[#E9:]] = function_ref @$sS3fIegydd_TJSpSSUpSrUSUP : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float // CHECK: bb1(%[[#]] : $Float): // CHECK: bb2: - // CHECK: bb3(%[[#E33:]] : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %[[#E34:]] : $Float): + // CHECK: bb3(%[[#E33:]] : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %[[#E34:]] : $Float): // CHECK: %[[#E37:]] = struct $Float - // TRUNNER: %[[#E38:]] = partial_apply [callee_guaranteed] %[[#E7]](%[[#E34]], %[[#E2]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#]] = partial_apply [callee_guaranteed] %[[#E9]](%[[#E38]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: %[[#E42:]] = partial_apply [callee_guaranteed] %[[#E7]](%[[#E34]], %[[#E37]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#]] = function_ref @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Class.TangentVector // COMBINE-NOT: = partial_apply // COMBINE-NOT: = function_ref @$s4test5ClassV6methodSfyFTJpSpSr // CHECK: %[[#E44:]] = function_ref @$s4test5ClassV6methodSfyFTJpSpSr073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktk1_l5FZSf_L6SfcfU_S2fAES2fTf1nncc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, Float, Float, Float, Float) -> Class.TangentVector // CHECK: %[[#E45:]] = partial_apply [callee_guaranteed] %[[#E44]](%[[#E33]], %[[#E34]], %[[#E2]], %[[#E34]], %[[#E37]]) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, Float, Float, Float, Float) -> Class.TangentVector - // TRUNNER: release_value %[[#E38]] : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: release_value %[[#E42]] : $@callee_guaranteed (Float) -> (Float, Float) // CHECK: %[[#E48:]] = tuple (%[[#]] : $Float, %[[#E45]] : $@callee_guaranteed (Float) -> Class.TangentVector) // CHECK: return %[[#E48]] @@ -396,7 +339,7 @@ bb2: %45 = enum $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, #_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0.bb2!enumelt, %44 br bb3(%45, %41) -bb3(%47 : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %48 : $Float): +bb3(%47 : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, %48 : $Float): %49 = struct_extract %48, #Float._value %50 = builtin "fmul_FPIEEE32"(%2, %49) : $Builtin.FPIEEE32 %51 = struct $Float (%50) @@ -456,23 +399,23 @@ sil @$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZ sil @$sSf16_DifferentiationE12_vjpSubtract3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) // pullback of cond_tuple_var(_:) -sil private @$s4test14cond_tuple_varyS2fFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { -bb0(%0 : $Float, %1 : $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %2 : $@callee_guaranteed (Float) -> (Float, Float), %3 : $@callee_guaranteed (Float) -> (Float, Float), %4 : $@callee_guaranteed (Float) -> (Float, Float)): +sil private [ossa] @$s4test14cond_tuple_varyS2fFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { +bb0(%0 : $Float, %1 : @owned $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %2 : @owned $@callee_guaranteed (Float) -> (Float, Float), %3 : @owned $@callee_guaranteed (Float) -> (Float, Float), %4 : @owned $@callee_guaranteed (Float) -> (Float, Float)): %5 = float_literal $Builtin.FPIEEE32, 0x0 // 0 %10 = apply %4(%0) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %4 + destroy_value %4 %12 = tuple_extract %10, 0 %13 = tuple_extract %10, 1 %14 = struct_extract %13, #Float._value %15 = builtin "fadd_FPIEEE32"(%5, %14) : $Builtin.FPIEEE32 %17 = apply %3(%12) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %3 + destroy_value %3 %19 = tuple_extract %17, 0 %20 = tuple_extract %17, 1 %21 = struct_extract %20, #Float._value %22 = builtin "fadd_FPIEEE32"(%5, %21) : $Builtin.FPIEEE32 %24 = apply %2(%19) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %2 + destroy_value %2 %26 = tuple_extract %24, 0 %27 = tuple_extract %24, 1 %28 = struct_extract %27, #Float._value @@ -481,29 +424,25 @@ bb0(%0 : $Float, %1 : $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %32 = builtin "fadd_FPIEEE32"(%5, %31) : $Builtin.FPIEEE32 switch_enum %1, case #_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0.bb2!enumelt: bb1, case #_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0.bb1!enumelt: bb2 -bb1(%44 : $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb2__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> Float)): - %45 = tuple_extract %44, 0 - %46 = tuple_extract %44, 1 +bb1(%44 : @owned $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb2__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> Float)): + (%45, %46) = destructure_tuple %44 %47 = builtin "fadd_FPIEEE32"(%15, %5) : $Builtin.FPIEEE32 %49 = builtin "fadd_FPIEEE32"(%22, %5) : $Builtin.FPIEEE32 %50 = struct $Float (%49) %52 = apply %46(%50) : $@callee_guaranteed (Float) -> Float - strong_release %46 + destroy_value %46 %54 = struct_extract %52, #Float._value %55 = builtin "fadd_FPIEEE32"(%54, %47) : $Builtin.FPIEEE32 %61 = unchecked_enum_data %45, #_AD__$s4test14cond_tuple_varyS2fF_bb2__Pred__src_0_wrt_0.bb0!enumelt - %62 = tuple_extract %61, 1 - %63 = tuple_extract %61, 0 - br bb3(%55, %32, %29, %5, %5, %63, %62) - -bb2(%65 : $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb1__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> (Float, Float), @callee_guaranteed (Float) -> (Float, Float))): - %66 = tuple_extract %65, 0 - %67 = tuple_extract %65, 1 - %68 = tuple_extract %65, 2 + (%62, %63) = destructure_tuple %61 + br bb3(%55, %32, %29, %5, %5, %62, %63) + +bb2(%65 : @owned $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb1__Pred__src_0_wrt_0, @callee_guaranteed (Float) -> (Float, Float), @callee_guaranteed (Float) -> (Float, Float))): + (%66, %67, %68) = destructure_tuple %65 %69 = builtin "fadd_FPIEEE32"(%15, %5) : $Builtin.FPIEEE32 %70 = struct $Float (%69) %72 = apply %68(%70) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %68 + destroy_value %68 %74 = tuple_extract %72, 0 %75 = tuple_extract %72, 1 %76 = struct_extract %74, #Float._value @@ -515,7 +454,7 @@ bb2(%65 : $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb1__Pred__src_0_wrt_ %84 = builtin "fadd_FPIEEE32"(%22, %5) : $Builtin.FPIEEE32 %85 = struct $Float (%84) %87 = apply %67(%85) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %67 + destroy_value %67 %89 = tuple_extract %87, 0 %90 = tuple_extract %87, 1 %91 = struct_extract %89, #Float._value @@ -533,15 +472,14 @@ bb2(%65 : $(predecessor: _AD__$s4test14cond_tuple_varyS2fF_bb1__Pred__src_0_wrt_ %107 = builtin "fadd_FPIEEE32"(%105, %5) : $Builtin.FPIEEE32 %108 = builtin "fadd_FPIEEE32"(%106, %107) : $Builtin.FPIEEE32 %114 = unchecked_enum_data %66, #_AD__$s4test14cond_tuple_varyS2fF_bb1__Pred__src_0_wrt_0.bb0!enumelt - %115 = tuple_extract %114, 1 - %116 = tuple_extract %114, 0 - br bb3(%108, %5, %5, %97, %82, %116, %115) + (%115, %116) = destructure_tuple %114 + br bb3(%108, %5, %5, %97, %82, %115, %116) -bb3(%118 : $Builtin.FPIEEE32, %119 : $Builtin.FPIEEE32, %120 : $Builtin.FPIEEE32, %121 : $Builtin.FPIEEE32, %122 : $Builtin.FPIEEE32, %123 : $@callee_guaranteed (Float) -> (Float, Float), %124 : $@callee_guaranteed (Float) -> (Float, Float)): +bb3(%118 : $Builtin.FPIEEE32, %119 : $Builtin.FPIEEE32, %120 : $Builtin.FPIEEE32, %121 : $Builtin.FPIEEE32, %122 : $Builtin.FPIEEE32, %123 : @owned $@callee_guaranteed (Float) -> (Float, Float), %124 : @owned $@callee_guaranteed (Float) -> (Float, Float)): %125 = builtin "fadd_FPIEEE32"(%122, %5) : $Builtin.FPIEEE32 %126 = struct $Float (%125) %127 = apply %124(%126) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %124 + destroy_value %124 %129 = tuple_extract %127, 0 %130 = tuple_extract %127, 1 %131 = struct_extract %129, #Float._value @@ -551,7 +489,7 @@ bb3(%118 : $Builtin.FPIEEE32, %119 : $Builtin.FPIEEE32, %120 : $Builtin.FPIEEE32 %135 = builtin "fadd_FPIEEE32"(%121, %5) : $Builtin.FPIEEE32 %136 = struct $Float (%135) %137 = apply %123(%136) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %123 + destroy_value %123 %139 = tuple_extract %137, 0 %140 = tuple_extract %137, 1 %141 = struct_extract %139, #Float._value @@ -565,73 +503,39 @@ bb3(%118 : $Builtin.FPIEEE32, %119 : $Builtin.FPIEEE32, %120 : $Builtin.FPIEEE32 } // end sil function '$s4test14cond_tuple_varyS2fFTJpSpSr' // reverse-mode derivative of cond_tuple_var(_:) -sil hidden @$s4test14cond_tuple_varyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s4test14cond_tuple_varyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { [global: ] bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test14cond_tuple_varyS2fFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#F1:]], %[[#F2:]], %[[#F3:]]) : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#F1]] = thin_to_thick_function %[[#]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER-NEXT: 2. %[[#F2]] = thin_to_thick_function %[[#]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER-NEXT: 3. %[[#F3]] = thin_to_thick_function %[[#]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s4test14cond_tuple_varyS2fFTJpSpSr067$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktl1_m5FZSf_M6SfcfU_0ef1_g4E12_i16Subtract3lhs3rhsk1_l1_mnl1_mo1_mP2U_ACTf1nnccc_n - // CHECK: sil private @$s4test14cond_tuple_varyS2fFTJpSpSr067$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktl1_m5FZSf_M6SfcfU_0ef1_g4E12_i16Subtract3lhs3rhsk1_l1_mnl1_mo1_mP2U_ACTf1nnccc_n : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0) -> Float { - // CHECK: bb0(%0 : $Float, %1 : $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0): + // CHECK: sil private [ossa] @$s4test14cond_tuple_varyS2fFTJpSpSr067$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktl1_m5FZSf_M6SfcfU_0ef1_g4E12_i16Subtract3lhs3rhsk1_l1_mnl1_mo1_mP2U_ACTf1nnccc_n : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0) -> Float { + // CHECK: bb0(%0 : $Float, %1 : @owned $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0): // CHECK: %[[#F2:]] = function_ref @$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) - // TRUNNER: %[[#F3:]] = thin_to_thick_function %[[#F2]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) // COMBINE-NOT: = thin_to_thick_function // CHECK: %[[#F4:]] = function_ref @$sSf16_DifferentiationE12_vjpSubtract3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) - // TRUNNER: %[[#F5:]] = thin_to_thick_function %[[#F4]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // COMBINE-NOT: = thin_to_thick_function - // CHECK: %[[#F6:]] = function_ref @$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) - // TRUNNER: %[[#F7:]] = thin_to_thick_function %[[#F6]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) // COMBINE-NOT: = thin_to_thick_function // CHECK: %[[#F8:]] = float_literal $Builtin.FPIEEE32, 0x0 // 0 - // TRUNNER: %[[#F9:]] = apply %[[#F7]](%0) : $@callee_guaranteed (Float) -> (Float, Float) - // COMBINE: %[[#F9:]] = apply %[[#F6]](%0) : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: strong_release %[[#F7]] : $@callee_guaranteed (Float) -> (Float, Float) + // COMBINE: %[[#F9:]] = apply %[[#F2]](%0) : $@convention(thin) (Float) -> (Float, Float) // CHECK: %[[#F11:]] = tuple_extract %[[#F9]] : $(Float, Float), 0 - // TRUNNER: %[[#F15:]] = apply %[[#F5]](%[[#F11]]) : $@callee_guaranteed (Float) -> (Float, Float) - // COMBINE: %[[#F15:]] = apply %[[#F4]](%[[#F11]]) : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: strong_release %[[#F5]] : $@callee_guaranteed (Float) -> (Float, Float) + // COMBINE: %[[#F15:]] = apply %[[#F4]](%[[#F11]]) : $@convention(thin) (Float) -> (Float, Float) // CHECK: %[[#F17:]] = tuple_extract %[[#F15]] : $(Float, Float), 0 - // TRUNNER: %[[#]] = apply %[[#F3]](%[[#F17]]) : $@callee_guaranteed (Float) -> (Float, Float) - // COMBINE: %[[#]] = apply %[[#F2]](%[[#F17]]) : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: strong_release %[[#F3]] : $@callee_guaranteed (Float) -> (Float, Float) + // COMBINE: %[[#]] = apply %[[#F2]](%[[#F17]]) : $@convention(thin) (Float) -> (Float, Float) // CHECK: {{^}}bb1{{.*}}: // CHECK: {{^}}bb2{{.*}}: // CHECK: {{^}}bb3{{.*}}: - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test14cond_tuple_varyS2fFTJrSpSr: - // CHECK: sil hidden @$s4test14cond_tuple_varyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s4test14cond_tuple_varyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // CHECK: %[[#G7:]] = function_ref @$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) // CHECK: %[[#G11:]] = function_ref @$sSf16_DifferentiationE12_vjpSubtract3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float) -> (Float, Float) // CHECK: bb1: // CHECK: bb2: - // CHECK: bb3(%[[#G31:]] : $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %[[#]] : $Builtin.FPIEEE32, %[[#]] : $Builtin.FPIEEE32): + // CHECK: bb3(%[[#G31:]] : @owned $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %[[#]] : $Builtin.FPIEEE32, %[[#]] : $Builtin.FPIEEE32): // COMBINE-NOT: = thin_to_thick_function // COMBINE-NOT: = function_ref @$s4test14cond_tuple_varyS2fFTJpSpSr - // TRUNNER: %[[#G33:]] = thin_to_thick_function %[[#G7]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: %[[#G34:]] = thin_to_thick_function %[[#G11]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: %[[#G35:]] = thin_to_thick_function %[[#G7]] : $@convention(thin) (Float) -> (Float, Float) to $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: %[[#]] = function_ref @$s4test14cond_tuple_varyS2fFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float), @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float // CHECK: %[[#G41:]] = function_ref @$s4test14cond_tuple_varyS2fFTJpSpSr067$sSf16_DifferentiationE7_vjpAdd3lhs3rhsSf5value_Sf_SftSfc8pullbacktl1_m5FZSf_M6SfcfU_0ef1_g4E12_i16Subtract3lhs3rhsk1_l1_mnl1_mo1_mP2U_ACTf1nnccc_n : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0) -> Float // CHECK: %[[#G42:]] = partial_apply [callee_guaranteed] %[[#G41]](%[[#G31]]) : $@convention(thin) (Float, @owned _AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0) -> Float - // TRUNNER: release_value %[[#G33]] : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: release_value %[[#G34]] : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: release_value %[[#G35]] : $@callee_guaranteed (Float) -> (Float, Float) // CHECK: %[[#G46:]] = tuple (%[[#]] : $Float, %[[#G42]] : $@callee_guaranteed (Float) -> Float) // CHECK: return %[[#G46]] @@ -674,7 +578,7 @@ bb2: %42 = enum $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, #_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0.bb2!enumelt, %41 br bb3(%42, %4, %34) -bb3(%44 : $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %45 : $Builtin.FPIEEE32, %46 : $Builtin.FPIEEE32): +bb3(%44 : @owned $_AD__$s4test14cond_tuple_varyS2fF_bb3__Pred__src_0_wrt_0, %45 : $Builtin.FPIEEE32, %46 : $Builtin.FPIEEE32): %47 = thin_to_thick_function %7 to $@callee_guaranteed (Float) -> (Float, Float) %48 = builtin "fsub_FPIEEE32"(%5, %46) : $Builtin.FPIEEE32 %49 = thin_to_thick_function %11 to $@callee_guaranteed (Float) -> (Float, Float) diff --git a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte1.sil b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte1.sil index 1df1b94421d86..86124d0e29aab 100644 --- a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte1.sil +++ b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte1.sil @@ -1,6 +1,5 @@ /// Multi basic block VJP, pullback not accepting branch tracing enum argument. -// RUN: %target-sil-opt -sil-print-types -test-runner %s -o /dev/null 2>&1 | %FileCheck %s --check-prefixes=TRUNNER,CHECK // RUN: %target-sil-opt -sil-print-types -autodiff-closure-specialization -sil-combine %s -o - | %FileCheck %s --check-prefixes=COMBINE,CHECK // REQUIRES: swift_in_compiler @@ -82,51 +81,30 @@ sil @$s4test5ClassV6stored8optionalACSf_SfSgtcfCTJpSSUpSr : $@convention(thin) ( sil @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector // pullback of methodWrapper(_:) -sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test13methodWrapperySfAA5ClassVFTJpSpSr : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) -> Class.TangentVector { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> Class.TangentVector): +sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test13methodWrapperySfAA5ClassVFTJpSpSr : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) -> Class.TangentVector { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Class.TangentVector): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> Class.TangentVector - strong_release %1 + destroy_value %1 return %2 } // end sil function '$s4test13methodWrapperySfAA5ClassVFTJpSpSr' // reverse-mode derivative of methodWrapper(_:) -sil hidden @$s4test13methodWrapperySfAA5ClassVFTJrSpSr : $@convention(thin) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { +sil hidden [ossa] @$s4test13methodWrapperySfAA5ClassVFTJrSpSr : $@convention(thin) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { bb0(%0 : $Class): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test13methodWrapperySfAA5ClassVFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#A36:]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) -> Class.TangentVector - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#A36]] = partial_apply [callee_guaranteed] %[[#]](%[[#]]) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s4test13methodWrapperySfAA5ClassVFTJpSpSr08$s4test5D19V6methodSfyFTJpSpSr4main05_AD__edfG24F_bb3__Pred__src_0_wrt_0OTf1nc_n - // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test13methodWrapperySfAA5ClassVFTJpSpSr08$s4test5D19V6methodSfyFTJpSpSr4main05_AD__edfG24F_bb3__Pred__src_0_wrt_0OTf1nc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector { - // CHECK: bb0(%0 : $Float, %1 : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): + // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test13methodWrapperySfAA5ClassVFTJpSpSr08$s4test5D19V6methodSfyFTJpSpSr4main05_AD__edfG24F_bb3__Pred__src_0_wrt_0OTf1nc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector { + // CHECK: bb0(%0 : $Float, %1 : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): // CHECK: %[[#B2:]] = function_ref @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: %[[#B3:]] = partial_apply [callee_guaranteed] %[[#B2]](%1) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: %[[#B4:]] = apply %[[#B3]](%0) : $@callee_guaranteed (Float) -> Class.TangentVector // COMBINE-NOT: partial_apply // COMBINE: %[[#B4:]] = apply %[[#B2]](%0, %1) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: strong_release %[[#B3]] : $@callee_guaranteed (Float) -> Class.TangentVector // CHECK: return %[[#B4]] - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test13methodWrapperySfAA5ClassVFTJrSpSr: - // CHECK: sil hidden @$s4test13methodWrapperySfAA5ClassVFTJrSpSr : $@convention(thin) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { - // CHECK: bb3(%[[#C33:]] : $Float, %[[#C34:]] : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): - // TRUNNER: %[[#C35:]] = function_ref @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: %[[#C37:]] = partial_apply [callee_guaranteed] %[[#C35]](%[[#C34]]) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: %[[#C38:]] = function_ref @$s4test13methodWrapperySfAA5ClassVFTJpSpSr : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) -> Class.TangentVector + // CHECK: sil hidden [ossa] @$s4test13methodWrapperySfAA5ClassVFTJrSpSr : $@convention(thin) (Class) -> (Float, @owned @callee_guaranteed (Float) -> Class.TangentVector) { + // CHECK: bb3(%[[#C33:]] : $Float, %[[#C34:]] : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): // COMBINE-NOT: function_ref @$s4test5ClassV6methodSfyFTJpSpSr // COMBINE-NOT: partial_apply // COMBINE-NOT: function_ref @$s4test13methodWrapperySfAA5ClassVFTJpSpSr // CHECK: %[[#C39:]] = function_ref @$s4test13methodWrapperySfAA5ClassVFTJpSpSr08$s4test5D19V6methodSfyFTJpSpSr4main05_AD__edfG24F_bb3__Pred__src_0_wrt_0OTf1nc_n : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector // CHECK: %[[#C40:]] = partial_apply [callee_guaranteed] %[[#C39]](%[[#C34]]) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector - // TRUNNER: release_value %[[#C37]] : $@callee_guaranteed (Float) -> Class.TangentVector // CHECK: %[[#C42:]] = tuple (%[[#C33]] : $Float, %[[#C40]] : $@callee_guaranteed (Float) -> Class.TangentVector) // CHECK: return %[[#C42]] @@ -169,7 +147,7 @@ bb2: %46 = enum $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0, #_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0.bb2!enumelt, %45 br bb3(%42, %46) -bb3(%48 : $Float, %49 : $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): +bb3(%48 : $Float, %49 : @owned $_AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0): // function_ref pullback of Class.method() %50 = function_ref @$s4test5ClassV6methodSfyFTJpSpSr : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector %51 = partial_apply [callee_guaranteed] %50(%49) : $@convention(thin) (Float, @owned _AD__$s4test5ClassV6methodSfyF_bb3__Pred__src_0_wrt_0) -> Class.TangentVector diff --git a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte2.sil b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte2.sil index 794f752a65651..3316e069465fd 100644 --- a/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte2.sil +++ b/test/AutoDiff/SILOptimizer/closure_specialization/multi_bb_no_bte2.sil @@ -1,6 +1,5 @@ /// Multi basic block VJP, pullback not accepting branch tracing enum argument. -// RUN: %target-sil-opt -sil-print-types -test-runner %s -o /dev/null 2>&1 | %FileCheck %s --check-prefixes=TRUNNER,CHECK // RUN: %target-sil-opt -sil-print-types -autodiff-closure-specialization -sil-combine %s -o - | %FileCheck %s --check-prefixes=COMBINE,CHECK // REQUIRES: swift_in_compiler @@ -30,63 +29,41 @@ sil [transparent] [thunk] @$sSa16_DifferentiationAA14DifferentiableRzlE13_vjpSub sil [transparent] [thunk] @$s13TangentVector16_Differentiation14DifferentiablePQzSaA2bCRzlE0D4ViewVyAE_GIegno_AeHIegno_AbCRzlTRSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView // specialized pullback of sum1(_:_:) -sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) { -bb0(%0 : $Float, %1 : $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), %2 : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView): +sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), %2 : @owned $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView): %3 = float_literal $Builtin.FPIEEE32, 0x0 // 0 %4 = struct_extract %0, #Float._value %5 = builtin "fadd_FPIEEE32"(%3, %4) : $Builtin.FPIEEE32 %6 = struct $Float (%5) %7 = alloc_stack $Float - store %6 to %7 + store %6 to [trivial] %7 %9 = apply %2(%7) : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView - strong_release %2 + destroy_value %2 dealloc_stack %7 %13 = apply %1(%9) : $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) - release_value %9 - strong_release %1 + destroy_value %9 + destroy_value %1 return %13 } // end sil function '$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n' // reverse-mode derivative of sum1(_:_:) -sil hidden @$s4test4sum1ySfSaySfG_ACtFTJrSSpSr : $@convention(thin) (@guaranteed Array, @guaranteed Array) -> (Float, @owned @callee_guaranteed (Float) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) { -bb0(%0 : $Array, %1 : $Array): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test4sum1ySfSaySfG_ACtFTJrSSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]]) : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n0ce1_fghi39E13_vjpSubscript5indexx5value_SaA2aBRzljkl48Vy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaV7FSf_TG5ACSiTf1nnc_n - // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n0ce1_fghi39E13_vjpSubscript5indexx5value_SaA2aBRzljkl48Vy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaV7FSf_TG5ACSiTf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned Array, Int) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) { - // CHECK: bb0(%0 : $Float, %1 : $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), %2 : $Array, %3 : $Int): +sil hidden [ossa] @$s4test4sum1ySfSaySfG_ACtFTJrSSpSr : $@convention(thin) (@guaranteed Array, @guaranteed Array) -> (Float, @owned @callee_guaranteed (Float) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) { +bb0(%0 : @guaranteed $Array, %1 : @guaranteed $Array): + // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n0ce1_fghi39E13_vjpSubscript5indexx5value_SaA2aBRzljkl48Vy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaV7FSf_TG5ACSiTf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned Array, Int) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) { + // CHECK: bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), %2 : @owned $Array, %3 : $Int): + // CHECK: %[[#D6:]] = function_ref @$s13TangentVector16_Differentiation14DifferentiablePQzSaA2bCRzlE0D4ViewVyAE_GIegno_AeHIegno_AbCRzlTRSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView // CHECK: %[[#D4:]] = function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE13_vjpSubscript5indexx5value_SaA2aBRzlE0B4ViewVy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaBRzlFSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView // CHECK: %[[#D5:]] = partial_apply [callee_guaranteed] %[[#D4]](%2, %3) : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView - // CHECK: %[[#D6:]] = function_ref @$s13TangentVector16_Differentiation14DifferentiablePQzSaA2bCRzlE0D4ViewVyAE_GIegno_AeHIegno_AbCRzlTRSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView - // TRUNNER: %[[#D7:]] = partial_apply [callee_guaranteed] %[[#D6]](%[[#D5]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView - // CHECK: store %[[#D11:]] to %[[#D12:]] : $*Float - // TRUNNER: %[[#D14:]] = apply %[[#D7]](%[[#D12]]) : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView + // CHECK: store %[[#D11:]] to [trivial] %[[#D12:]] : $*Float // COMBINE: %[[#D14:]] = apply %[[#D6]](%[[#D12]], %[[#D5]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView - // TRUNNER: strong_release %[[#D7]] : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView - // COMBINE: strong_release %[[#D5]] : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView + // COMBINE: destroy_value %[[#D5]] : $@callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView // CHECK: %[[#D17:]] = apply %1(%[[#D14]]) : $@callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) // CHECK: return %[[#D17]] : $(Array.DifferentiableView, Array.DifferentiableView) - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test4sum1ySfSaySfG_ACtFTJrSSpSr: - // CHECK: sil hidden @$s4test4sum1ySfSaySfG_ACtFTJrSSpSr : $@convention(thin) (@guaranteed Array, @guaranteed Array) -> (Float, @owned @callee_guaranteed (Float) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) { + // CHECK: sil hidden [ossa] @$s4test4sum1ySfSaySfG_ACtFTJrSSpSr : $@convention(thin) (@guaranteed Array, @guaranteed Array) -> (Float, @owned @callee_guaranteed (Float) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) { + // CHECK: (%[[#]], %[[#E42:]]) = destructure_tuple %[[#]] : $(Array, @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) // CHECK: bb8: - // CHECK: %[[#E42:]] = tuple_extract %[[#]] : $(Array, @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)), 1 - // TRUNNER: %[[#E44:]] = function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE13_vjpSubscript5indexx5value_SaA2aBRzlE0B4ViewVy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaBRzlFSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView - // TRUNNER: %[[#E45:]] = partial_apply [callee_guaranteed] %[[#E44]](%[[#]], %[[#]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView - // TRUNNER: %[[#E46:]] = function_ref @$s13TangentVector16_Differentiation14DifferentiablePQzSaA2bCRzlE0D4ViewVyAE_GIegno_AeHIegno_AbCRzlTRSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView - // TRUNNER: %[[#E47:]] = partial_apply [callee_guaranteed] %[[#E46]](%[[#E45]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> @owned Array.DifferentiableView - // TRUNNER: %[[#]] = function_ref @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) // COMBINE-NOT: function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE13_vjpSubscript5indexx5value_SaA2aBRzlE0B4ViewVy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaBRzlFSf_TG5 // COMBINE-NOT: partial_apply @@ -100,24 +77,26 @@ bb0(%0 : $Array, %1 : $Array): // CHECK: return %[[#E55]] %4 = alloc_stack [var_decl] $Array - store %0 to %4 + %5 = copy_value %0 + store %5 to [init] %4 // function_ref specialized Array.append(contentsOf:) %6 = function_ref @$sSa6append10contentsOfyqd__n_t7ElementQyd__RszSTRd__lFSf_SaySfGTg5 : $@convention(method) (@owned Array, @inout Array) -> () - retain_value %0 - retain_value %1 - %9 = apply %6(%1, %4) : $@convention(method) (@owned Array, @inout Array) -> () - %10 = load %4 + %7 = copy_value %1 + %9 = apply %6(%7, %4) : $@convention(method) (@owned Array, @inout Array) -> () + %10 = load [take] %4 dealloc_stack %4 // function_ref specialized pullback #1 (_:) in static Array._vjpConcatenate(_:_:) %12 = function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE15_vjpConcatenateySayxG5value_SaA2aBRzlE0B4ViewVy13TangentVectorQz_G_AJtAJc8pullbacktAD_ADtFZAKL_yAJ_AJtAjaBRzlFSf_Tg5 : $@convention(thin) (@guaranteed Array.DifferentiableView, @guaranteed Array, @guaranteed Array) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) - %13 = partial_apply [callee_guaranteed] %12(%0, %1) : $@convention(thin) (@guaranteed Array.DifferentiableView, @guaranteed Array, @guaranteed Array) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) + %12a = copy_value %0 + %12b = copy_value %1 + %13 = partial_apply [callee_guaranteed] %12(%12a, %12b) : $@convention(thin) (@guaranteed Array.DifferentiableView, @guaranteed Array, @guaranteed Array) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) // function_ref specialized thunk for @escaping @callee_guaranteed (@guaranteed [A.Differentiable.TangentVector].DifferentiableView) -> (@owned [A.Differentiable.TangentVector].DifferentiableView, @owned [A.Differentiable.TangentVector].DifferentiableView) %14 = function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVy13TangentVectorAaBPQz_GA2HIeggoo_A3HIeggoo_AaBRzlTRSf_Tg5 : $@convention(thin) (@guaranteed Array.DifferentiableView, @guaranteed @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) %15 = partial_apply [callee_guaranteed] %14(%13) : $@convention(thin) (@guaranteed Array.DifferentiableView, @guaranteed @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) %16 = convert_function %15 to $@callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@guaranteed τ_0_0) -> (@owned τ_0_1, @owned τ_0_2) for .DifferentiableView, Array.DifferentiableView, Array.DifferentiableView> %17 = tuple (%10, %16) - %18 = unchecked_bitwise_cast %17 to $(Array, @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) - %19 = tuple_extract %18, 0 + %18 = unchecked_value_cast %17 to $(Array, @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView)) + (%19, %121) = destructure_tuple %18 %21 = integer_literal $Builtin.Int64, 0 %22 = struct $Int (%21) %23 = integer_literal $Builtin.Int1, -1 @@ -125,7 +104,8 @@ bb0(%0 : $Array, %1 : $Array): // function_ref specialized Array._checkSubscript(_:wasNativeTypeChecked:) %25 = function_ref @$sSa15_checkSubscript_20wasNativeTypeCheckeds16_DependenceTokenVSi_SbtFSf_Tg5 : $@convention(method) (Int, Bool, @guaranteed Array) -> _DependenceToken %26 = apply %25(%22, %24, %19) : $@convention(method) (Int, Bool, @guaranteed Array) -> _DependenceToken - %27 = struct_extract %19, #Array._buffer + %b = begin_borrow %19 + %27 = struct_extract %b, #Array._buffer %28 = struct_extract %27, #_ArrayBuffer._storage %29 = string_literal utf8 "Swift/BridgeStorage.swift" %30 = integer_literal $Builtin.Word, 25 @@ -167,7 +147,7 @@ bb4: %78 = struct_element_addr %77, #_ArrayBody._storage %79 = struct_element_addr %78, #_SwiftArrayBodyStorage.count %80 = struct_element_addr %79, #Int._value - %81 = load %80 + %81 = load [trivial] %80 %82 = builtin "cmp_slt_Int64"(%81, %21) : $Builtin.Int1 %83 = builtin "int_expect_Int1"(%82, %43) : $Builtin.Int1 cond_br %83, bb6, bb7 @@ -185,9 +165,9 @@ bb7: cond_br %119, bb8, bb5 bb8: - %121 = tuple_extract %18, 1 %122 = ref_tail_addr [immutable] %75, $Float - %123 = load %122 + %123 = load [trivial] %122 + end_borrow %b // function_ref specialized pullback #1 (_:) in Array._vjpSubscript(index:) %124 = function_ref @$sSa16_DifferentiationAA14DifferentiableRzlE13_vjpSubscript5indexx5value_SaA2aBRzlE0B4ViewVy13TangentVectorQz_GAIc8pullbacktSi_tFAKL_yAjiaBRzlFSf_TG5 : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView %125 = partial_apply [callee_guaranteed] %124(%19, %22) : $@convention(thin) (@in_guaranteed Float, @guaranteed Array, Int) -> @owned Array.DifferentiableView @@ -198,7 +178,5 @@ bb8: %128 = function_ref @$s4test4sum1ySfSaySfG_ACtFTJpSSpSr055$sSfSa16_DifferentiationAA14DifferentiableRzlE0B4ViewVyd8_GIegno_D10AEIegyo_TRSfSa01_F0AE0H0RzlE0hL0VySf_GIegno_Tf1nnc_n : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) %129 = partial_apply [callee_guaranteed] %128(%121, %127) : $@convention(thin) (Float, @owned @callee_guaranteed (@guaranteed Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView), @owned @callee_guaranteed (@in_guaranteed Float) -> @owned Array.DifferentiableView) -> (@owned Array.DifferentiableView, @owned Array.DifferentiableView) %130 = tuple (%123, %129) - retain_value %0 - retain_value %1 return %130 } // end sil function '$s4test4sum1ySfSaySfG_ACtFTJrSSpSr' diff --git a/test/AutoDiff/SILOptimizer/closure_specialization/single_bb.sil b/test/AutoDiff/SILOptimizer/closure_specialization/single_bb.sil index 951e213fc53c3..cc31016a187bb 100644 --- a/test/AutoDiff/SILOptimizer/closure_specialization/single_bb.sil +++ b/test/AutoDiff/SILOptimizer/closure_specialization/single_bb.sil @@ -1,4 +1,3 @@ -// RUN: %target-sil-opt -sil-print-types -test-runner %s -o /dev/null 2>&1 | %FileCheck %s --check-prefixes=TRUNNER,CHECK // RUN: %target-sil-opt -sil-print-types -autodiff-closure-specialization -sil-combine %s -o - | %FileCheck %s --check-prefixes=COMBINE,CHECK // REQUIRES: swift_in_compiler @@ -16,10 +15,10 @@ import _Differentiation //////////////////////////////////////////////////////////////// sil @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float) -sil private @$pullback_f : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> (Float, Float)): +sil private [ossa] @$pullback_f : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> (Float, Float)): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %1 : $@callee_guaranteed (Float) -> (Float, Float) + destroy_value %1 %4 = tuple_extract %2 : $(Float, Float), 0 %5 = tuple_extract %2 : $(Float, Float), 1 %6 = struct_extract %5 : $Float, #Float._value @@ -30,31 +29,14 @@ bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> (Float, Float)): } // reverse-mode derivative of f(_:) -sil hidden @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test1fyS2fFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#A1:]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER-NEXT: Passed in closures: - // TRUNNER-NEXT: 1. %[[#A1]] = partial_apply [callee_guaranteed] %[[#]](%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s11$pullback_f12$vjpMultiplyS2fTf1nc_n - // CHECK: sil private @$s11$pullback_f12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { + // CHECK: sil private [ossa] @$s11$pullback_f12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { // CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float): // CHECK: %[[#A2:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#A3:]] = partial_apply [callee_guaranteed] %[[#A2]](%1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#]] = apply %[[#A3]](%0) : $@callee_guaranteed (Float) -> (Float, Float) // COMBINE: %[[#]] = apply %[[#A2]](%0, %1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: strong_release %[[#A3]] : $@callee_guaranteed (Float) -> (Float, Float) - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test1fyS2fFTJrSpSr - // CHECK: sil hidden @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s4test1fyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // CHECK: %[[#A4:]] = struct_extract %0 : $Float, #Float._value // CHECK: %[[#A5:]] = builtin "fmul_FPIEEE32"(%[[#A4]] : $Builtin.FPIEEE32, %[[#A4]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 @@ -81,8 +63,8 @@ bb0(%0 : $Float): ///////////////////////////////////////////////////////////////////// // Single closure call site where closure is passed as @guaranteed // ///////////////////////////////////////////////////////////////////// -sil private @$pullback_k : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> (Float, Float)): +sil private [ossa] @$pullback_k : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float { +bb0(%0 : $Float, %1 : @guaranteed $@callee_guaranteed (Float) -> (Float, Float)): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> (Float, Float) %3 = tuple_extract %2 : $(Float, Float), 0 %4 = tuple_extract %2 : $(Float, Float), 1 @@ -94,31 +76,14 @@ bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> (Float, Float)): } // end sil function '$pullback_k' // reverse-mode derivative of k(_:) -sil hidden @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test1kyS2fFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#B1:]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: Passed in closures: - // TRUNNER: 1. %[[#B1]] = partial_apply [callee_guaranteed] %[[#]](%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s11$pullback_k12$vjpMultiplyS2fTf1nc_n - // CHECK: sil private @$s11$pullback_k12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { + // CHECK: sil private [ossa] @$s11$pullback_k12$vjpMultiplyS2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { // CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float): // CHECK: %[[#B2:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#B3:]] = partial_apply [callee_guaranteed] %[[#B2]](%1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#]] = apply %[[#B3]](%0) : $@callee_guaranteed (Float) -> (Float, Float) // COMBINE: %[[#]] = apply %[[#B2]](%0, %1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: release_value %[[#B3]] : $@callee_guaranteed (Float) -> (Float, Float) - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test1kyS2fFTJrSpSr - // CHECK: sil hidden @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s4test1kyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // CHECK: %[[#B4:]] = struct_extract %0 : $Float, #Float._value // CHECK: %[[#B5:]] = builtin "fmul_FPIEEE32"(%[[#B4]] : $Builtin.FPIEEE32, %[[#B4]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 @@ -138,7 +103,6 @@ bb0(%0 : $Float): // function_ref $pullback_k %7 = function_ref @$pullback_k : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float %8 = partial_apply [callee_guaranteed] %7(%6) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> Float - strong_release %6 : $@callee_guaranteed (Float) -> (Float, Float) %10 = tuple (%4 : $Float, %8 : $@callee_guaranteed (Float) -> Float) return %10 : $(Float, @callee_guaranteed (Float) -> Float) } // end sil function '$s4test1kyS2fFTJrSpSr' @@ -150,16 +114,16 @@ sil @$vjpSin : $@convention(thin) (Float, Float) -> Float sil @$vjpCos : $@convention(thin) (Float, Float) -> Float // pullback of g(_:) -sil private @$pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> Float, %2 : $@callee_guaranteed (Float) -> Float, %3 : $@callee_guaranteed (Float) -> (Float, Float)): +sil private [ossa] @$pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float, %2 : @owned $@callee_guaranteed (Float) -> Float, %3 : @owned $@callee_guaranteed (Float) -> (Float, Float)): %4 = apply %3(%0) : $@callee_guaranteed (Float) -> (Float, Float) - strong_release %3 : $@callee_guaranteed (Float) -> (Float, Float) + destroy_value %3 : $@callee_guaranteed (Float) -> (Float, Float) %6 = tuple_extract %4 : $(Float, Float), 0 %7 = tuple_extract %4 : $(Float, Float), 1 %8 = apply %2(%7) : $@callee_guaranteed (Float) -> Float - strong_release %2 : $@callee_guaranteed (Float) -> Float + destroy_value %2 : $@callee_guaranteed (Float) -> Float %10 = apply %1(%6) : $@callee_guaranteed (Float) -> Float - strong_release %1 : $@callee_guaranteed (Float) -> Float + destroy_value %1 : $@callee_guaranteed (Float) -> Float %12 = struct_extract %8 : $Float, #Float._value %13 = struct_extract %10 : $Float, #Float._value %14 = builtin "fadd_FPIEEE32"(%13 : $Builtin.FPIEEE32, %12 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 @@ -168,43 +132,18 @@ bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> Float, %2 : $@callee_guaran } // reverse-mode derivative of g(_:) -sil hidden @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s4test1gyS2fFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#C1:]], %[[#C2:]], %[[#C3:]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> Float, @owned @callee_guaranteed (Float) -> (Float, Float)) -> Float - // TRUNNER: Passed in closures: - // TRUNNER: 1. %[[#C1]] = partial_apply [callee_guaranteed] %[[#]](%0) : $@convention(thin) (Float, Float) -> Float - // TRUNNER: 2. %[[#C2]] = partial_apply [callee_guaranteed] %[[#]](%0) : $@convention(thin) (Float, Float) -> Float - // TRUNNER: 3. %[[#C3]] = partial_apply [callee_guaranteed] %[[#]](%[[#]], %[[#]]) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s11$pullback_g7$vjpSinSf0B3CosSf0B8MultiplyS2fTf1nccc_n - // CHECK: sil private @$s11$pullback_g7$vjpSinSf0B3CosSf0B8MultiplyS2fTf1nccc_n : $@convention(thin) (Float, Float, Float, Float, Float) -> Float { + // CHECK: sil private [ossa] @$s11$pullback_g7$vjpSinSf0B3CosSf0B8MultiplyS2fTf1nccc_n : $@convention(thin) (Float, Float, Float, Float, Float) -> Float { // CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float, %3 : $Float, %4 : $Float): // CHECK: %[[#C4:]] = function_ref @$vjpSin : $@convention(thin) (Float, Float) -> Float - // TRUNNER: %[[#C5:]] = partial_apply [callee_guaranteed] %[[#C4]](%1) : $@convention(thin) (Float, Float) -> Float // CHECK: %[[#C6:]] = function_ref @$vjpCos : $@convention(thin) (Float, Float) -> Float - // TRUNNER: %[[#C7:]] = partial_apply [callee_guaranteed] %[[#C6]](%2) : $@convention(thin) (Float, Float) -> Float // CHECK: %[[#C8:]] = function_ref @$vjpMultiply : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#C9:]] = partial_apply [callee_guaranteed] %[[#C8]](%3, %4) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: %[[#]] = apply %[[#C9]](%0) : $@callee_guaranteed (Float) -> (Float, Float) // COMBINE: %[[#]] = apply %[[#C8]](%0, %3, %4) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER: strong_release %[[#C9]] : $@callee_guaranteed (Float) -> (Float, Float) - // TRUNNER: %[[#]] = apply %[[#C7]](%[[#]]) : $@callee_guaranteed (Float) -> Float // COMBINE: %[[#]] = apply %[[#C6]](%[[#]], %2) : $@convention(thin) (Float, Float) -> Float - // TRUNNER: strong_release %[[#C7]] : $@callee_guaranteed (Float) -> Float - // TRUNNER: %[[#]] = apply %[[#C5]](%[[#]]) : $@callee_guaranteed (Float) -> Float // COMBINE: %[[#]] = apply %[[#C4]](%[[#]], %1) : $@convention(thin) (Float, Float) -> Float - // TRUNNER: strong_release %[[#C5]] : $@callee_guaranteed (Float) -> Float - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s4test1gyS2fFTJrSpSr - // CHECK: sil hidden @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s4test1gyS2fFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // CHECK: %[[#C10:]] = struct_extract %0 : $Float, #Float._value // CHECK: %[[#C11:]] = builtin "int_sin_FPIEEE32"(%[[#C10]] : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 @@ -266,47 +205,29 @@ sil [transparent] [thunk] @subset_parameter_thunk : $@convention(thin) (Float, @ sil @pullback_f : $@convention(thin) (Float, Double) -> X.TangentVector -sil shared @pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> X.TangentVector): +sil shared [ossa] @pullback_g : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> X.TangentVector): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> X.TangentVector - strong_release %1 : $@callee_guaranteed (Float) -> X.TangentVector + destroy_value %1 : $@callee_guaranteed (Float) -> X.TangentVector return %2 : $X.TangentVector } -sil hidden @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) { +sil hidden [ossa] @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) { bb0(%0 : $X): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s5test21g1xSfAA1XV_tFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) -> X.TangentVector - // TRUNNER: Passed in closures: - // TRUNNER: 1. %[[#]] = thin_to_thick_function %[[#]] : $@convention(thin) (Float, Double) -> X.TangentVector to $@callee_guaranteed (Float, Double) -> X.TangentVector - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s10pullback_g0A2_fTf1nc_n - // CHECK: sil shared @$s10pullback_g0A2_fTf1nc_n : $@convention(thin) (Float) -> X.TangentVector { + // CHECK: sil shared [ossa] @$s10pullback_g0A2_fTf1nc_n : $@convention(thin) (Float) -> X.TangentVector { // CHECK: bb0(%0 : $Float): + // CHECK: %[[#D3:]] = function_ref @subset_parameter_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector // CHECK: %[[#D1:]] = function_ref @pullback_f : $@convention(thin) (Float, Double) -> X.TangentVector // CHECK: %[[#D2:]] = thin_to_thick_function %[[#D1]] : $@convention(thin) (Float, Double) -> X.TangentVector to $@callee_guaranteed (Float, Double) -> X.TangentVector - // CHECK: %[[#D3:]] = function_ref @subset_parameter_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector - // TRUNNER: %[[#D4:]] = partial_apply [callee_guaranteed] %[[#D3]](%[[#D2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector - // TRUNNER: %[[#D5:]] = apply %[[#D4]](%0) : $@callee_guaranteed (Float) -> X.TangentVector // COMBINE: %[[#D5:]] = apply %[[#D3]](%0, %[[#D2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (Float, Double) -> X.TangentVector) -> X.TangentVector - // TRUNNER: strong_release %[[#D4]] : $@callee_guaranteed (Float) -> X.TangentVector // CHECK: return %[[#D5]] - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s5test21g1xSfAA1XV_tFTJrSpSr - // CHECK: sil hidden @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) { + // CHECK: sil hidden [ossa] @$s5test21g1xSfAA1XV_tFTJrSpSr : $@convention(thin) (X) -> (Float, @owned @callee_guaranteed (Float) -> X.TangentVector) { // CHECK: bb0(%0 : $X): // CHECK: %[[#D6:]] = struct_extract %0 : $X, #X.a // COMBINE-NOT: function_ref @pullback_f // COMBINE-NOT: function_ref @subset_parameter_thunk // CHECK: %[[#D7:]] = function_ref @$s10pullback_g0A2_fTf1nc_n : $@convention(thin) (Float) -> X.TangentVector - // TRUNNER: %[[#D8:]] = partial_apply [callee_guaranteed] %[[#D7]]() : $@convention(thin) (Float) -> X.TangentVector // COMBINE: %[[#D8:]] = thin_to_thick_function %[[#D7]] : $@convention(thin) (Float) -> X.TangentVector to $@callee_guaranteed (Float) -> X.TangentVector // CHECK: %[[#D9:]] = tuple (%[[#D6]] : $Float, %[[#D8]] : $@callee_guaranteed (Float) -> X.TangentVector) // CHECK: return %[[#D9]] @@ -341,48 +262,31 @@ sil [transparent] [thunk] @pullback_f_specialized : $@convention(thin) (@in_guar // thunk for @escaping @callee_guaranteed (@in_guaranteed Float) -> (@out Float) sil [transparent] [reabstraction_thunk] @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float -sil private [signature_optimized_thunk] [heuristic_always_inline] @pullback_h : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> Float): +sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @pullback_h : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> Float - strong_release %1 : $@callee_guaranteed (Float) -> Float + destroy_value %1 : $@callee_guaranteed (Float) -> Float return %2 : $Float } // reverse-mode derivative of h(x:) -sil hidden @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s5test21h1xS2f_tFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float - // TRUNNER: Passed in closures: - // TRUNNER: 1. %[[#]] = partial_apply [callee_guaranteed] %[[#]](%0, %0) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s10pullback_h073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbackti1_j5FZSf_J6SfcfU_S2fTf1nc_n - // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] @$s10pullback_h073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbackti1_j5FZSf_J6SfcfU_S2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { + // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s10pullback_h073$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbackti1_j5FZSf_J6SfcfU_S2fTf1nc_n : $@convention(thin) (Float, Float, Float) -> Float { // CHECK: bb0(%0 : $Float, %1 : $Float, %2 : $Float): + // CHECK: %[[#E8:]] = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float + // CHECK: %[[#E6:]] = function_ref @pullback_f_specialized : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ) -> @out Float + // CHECK: %[[#E3:]] = function_ref @$sS3fIegydd_S3fIegnrr_TR : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float) // CHECK: %[[#E1:]] = function_ref @$sSf16_DifferentiationE12_vjpMultiply3lhs3rhsSf5value_Sf_SftSfc8pullbacktSf_SftFZSf_SftSfcfU_ : $@convention(thin) (Float, Float, Float) -> (Float, Float) // CHECK: %[[#E2:]] = partial_apply [callee_guaranteed] %[[#E1]](%1, %2) : $@convention(thin) (Float, Float, Float) -> (Float, Float) - // CHECK: %[[#E3:]] = function_ref @$sS3fIegydd_S3fIegnrr_TR : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float) // CHECK: %[[#E4:]] = partial_apply [callee_guaranteed] %[[#E3]](%[[#E2]]) : $@convention(thin) (@in_guaranteed Float, @guaranteed @callee_guaranteed (Float) -> (Float, Float)) -> (@out Float, @out Float) // CHECK: %[[#E5:]] = convert_function %[[#E4]] : $@callee_guaranteed (@in_guaranteed Float) -> (@out Float, @out Float) to $@callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for - // CHECK: %[[#E6:]] = function_ref @pullback_f_specialized : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ) -> @out Float // CHECK: %[[#E7:]] = partial_apply [callee_guaranteed] %[[#E6]](%[[#E5]]) : $@convention(thin) (@in_guaranteed Float, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_1, @out τ_0_2) for ) -> @out Float - // CHECK: %[[#E8:]] = function_ref @$sS2fIegnr_S2fIegyd_TR : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: %[[#E9:]] = partial_apply [callee_guaranteed] %[[#E8]](%[[#E7]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: %[[#E10:]] = apply %[[#E9]](%0) : $@callee_guaranteed (Float) -> Float // COMBINE: %[[#E10:]] = apply %[[#E8]](%0, %[[#E7]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: strong_release %[[#E9]] : $@callee_guaranteed (Float) -> Float - // COMBINE: strong_release %[[#E7]] : $@callee_guaranteed (@in_guaranteed Float) -> @out Float + // COMBINE: destroy_value %[[#E7]] : $@callee_guaranteed (@in_guaranteed Float) -> @out Float // CHECK: return %[[#E10]] - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s5test21h1xS2f_tFTJrSpSr - // CHECK: sil hidden @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s5test21h1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // CHECK: %[[#E11:]] = struct_extract %0 : $Float, #Float._value // CHECK: %[[#E12:]] = builtin "fmul_FPIEEE32"(%[[#E11]] : $Builtin.FPIEEE32, %1 : $Builtin.FPIEEE32) : $Builtin.FPIEEE32 @@ -432,46 +336,28 @@ sil [transparent] [thunk] @pullback_y_specialized : $@convention(thin) (@in_guar sil [transparent] [reabstraction_thunk] @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float -sil private [signature_optimized_thunk] [heuristic_always_inline] @pullback_z : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float { -bb0(%0 : $Float, %1 : $@callee_guaranteed (Float) -> Float): +sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @pullback_z : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float { +bb0(%0 : $Float, %1 : @owned $@callee_guaranteed (Float) -> Float): %2 = apply %1(%0) : $@callee_guaranteed (Float) -> Float - strong_release %1 : $@callee_guaranteed (Float) -> Float + destroy_value %1 : $@callee_guaranteed (Float) -> Float return %2 : $Float } -sil hidden @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +sil hidden [ossa] @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { bb0(%0 : $Float): - //=========== Test callsite and closure gathering logic ===========// - specify_test "autodiff_closure_specialize_get_pullback_closure_info" - // TRUNNER-LABEL: Specializing closures in function: $s5test21z1xS2f_tFTJrSpSr - // TRUNNER: PartialApply of pullback: %[[#]] = partial_apply [callee_guaranteed] %[[#]](%[[#]]) : $@convention(thin) (Float, @owned @callee_guaranteed (Float) -> Float) -> Float - // TRUNNER: Passed in closures: - // TRUNNER: 1. %[[#]] = thin_to_thick_function %[[#]] : $@convention(thin) (@in_guaranteed Float) -> @out Float to $@callee_guaranteed (@in_guaranteed Float) -> @out Float - // TRUNNER-EMPTY: - - //=========== Test specialized function signature and body ===========// - specify_test "autodiff_closure_specialize_specialized_function_signature_and_body" - // TRUNNER-LABEL: Generated specialized function: $s10pullback_z0A14_y_specializedTf1nc_n - // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] @$s10pullback_z0A14_y_specializedTf1nc_n : $@convention(thin) (Float) -> Float { + // CHECK: sil private [signature_optimized_thunk] [heuristic_always_inline] [ossa] @$s10pullback_z0A14_y_specializedTf1nc_n : $@convention(thin) (Float) -> Float { // CHECK: bb0(%0 : $Float): + // CHECK: %[[#F3:]] = function_ref @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float // CHECK: %[[#F1:]] = function_ref @pullback_y_specialized : $@convention(thin) (@in_guaranteed Float) -> @out Float // CHECK: %[[#F2:]] = thin_to_thick_function %[[#F1]] : $@convention(thin) (@in_guaranteed Float) -> @out Float to $@callee_guaranteed (@in_guaranteed Float) -> @out Float - // CHECK: %[[#F3:]] = function_ref @reabstraction_thunk : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: %[[#F4:]] = partial_apply [callee_guaranteed] %[[#F3]](%[[#F2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: %[[#F5:]] = apply %[[#F4]](%0) : $@callee_guaranteed (Float) -> Float // COMBINE: %[[#F5:]] = apply %[[#F3]](%0, %[[#F2]]) : $@convention(thin) (Float, @guaranteed @callee_guaranteed (@in_guaranteed Float) -> @out Float) -> Float - // TRUNNER: strong_release %[[#F4]] : $@callee_guaranteed (Float) -> Float // CHECK: return %[[#F5]] - //=========== Test rewritten body ===========// - specify_test "autodiff_closure_specialize_rewritten_caller_body" - // TRUNNER-LABEL: Rewritten caller body for: $s5test21z1xS2f_tFTJrSpSr - // CHECK: sil hidden @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { + // CHECK: sil hidden [ossa] @$s5test21z1xS2f_tFTJrSpSr : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK: bb0(%0 : $Float): // COMBINE-NOT: function_ref @pullback_y_specialized // COMBINE-NOT: function_ref @reabstraction_thunk // CHECK: %[[#F6:]] = function_ref @$s10pullback_z0A14_y_specializedTf1nc_n : $@convention(thin) (Float) -> Float - // TRUNNER: %[[#F7:]] = partial_apply [callee_guaranteed] %[[#F6]]() : $@convention(thin) (Float) -> Float // COMBINE: %[[#F7:]] = thin_to_thick_function %[[#F6]] : $@convention(thin) (Float) -> Float to $@callee_guaranteed (Float) -> Float // CHECK: %[[#F8:]] = tuple (%0 : $Float, %[[#F7]] : $@callee_guaranteed (Float) -> Float) // CHECK: return %[[#F8]] diff --git a/test/AutoDiff/validation-test/closure_specialization/multi_bb_no_bte.swift b/test/AutoDiff/validation-test/closure_specialization/multi_bb_no_bte.swift index c9ca9aa640840..9cca3225d3a38 100644 --- a/test/AutoDiff/validation-test/closure_specialization/multi_bb_no_bte.swift +++ b/test/AutoDiff/validation-test/closure_specialization/multi_bb_no_bte.swift @@ -16,6 +16,9 @@ // RUN: cat %t/out.sil | %FileCheck %s --check-prefix=CHECK3 // RUN: cat %t/out.sil | %FileCheck %s --check-prefix=CHECK4 +// TODO: re-enable this test once we have OSSA throughout the pipeline +// XFAIL: * + import DifferentiationUnittest import StdlibUnittest diff --git a/test/AutoDiff/validation-test/closure_specialization/single_bb2.swift b/test/AutoDiff/validation-test/closure_specialization/single_bb2.swift index 8376d619b03bb..2989dec84f31a 100644 --- a/test/AutoDiff/validation-test/closure_specialization/single_bb2.swift +++ b/test/AutoDiff/validation-test/closure_specialization/single_bb2.swift @@ -14,6 +14,9 @@ // RUN: cat %t/out.sil | %FileCheck %s --check-prefix=CHECK4 // RUN: cat %t/out.sil | %FileCheck %s --check-prefix=CHECK5 +// TODO: re-enable this test once we have OSSA throughout the pipeline +// XFAIL: * + import DifferentiationUnittest import StdlibUnittest diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize.sil b/test/SILOptimizer/closure_specialization.sil similarity index 53% rename from test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize.sil rename to test/SILOptimizer/closure_specialization.sil index 116c527a6273a..5c3d776b2d01d 100644 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize.sil +++ b/test/SILOptimizer/closure_specialization.sil @@ -1,98 +1,95 @@ -// RUN: %target-sil-opt -enable-sil-verify-all -experimental-swift-based-closure-specialization %s | %FileCheck %s -// XFAIL: * +// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -closure-specialization %s | %FileCheck %s + +sil_stage canonical import Builtin import Swift -// CHECK-LABEL: sil shared [noinline] @$s7specgen12take_closureyyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () { +// CHECK-LABEL: sil shared [noinline] [ossa] @$s7specgen12take_closureyyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () { // CHECK: bb0(%0 : $Int) // CHECK: function_ref @$s7specgen6calleryySiFySi_SitcfU_ // CHECK: partial_apply -// CHECK-LABEL: sil shared [noinline] @$s7specgen12take_closureyyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () { +// CHECK-LABEL: sil shared [noinline] [ossa] @$s7specgen12take_closureyyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () { // CHECK-NEXT: bb0: // CHECK: [[FUN:%.*]] = function_ref @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () // CHECK: thin_to_thick_function [[FUN]] : $@convention(thin) (Int, Int) -> () to $@callee_owned (Int, Int) -> () -// CHECK-LABEL: sil [noinline] @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { -sil [noinline] @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { -bb0(%0 : $@callee_owned (Int, Int) -> ()): - %1 = alloc_stack $Int - %2 = load %1 : $*Int +// CHECK-LABEL: sil [noinline] [ossa] @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { +sil [ossa] [noinline] @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { +bb0(%0 : @owned $@callee_owned (Int, Int) -> ()): + %2 = load [trivial] undef : $*Int %3 = apply %0(%2, %2) : $@callee_owned (Int, Int) -> () - dealloc_stack %1 : $*Int %9999 = tuple() return %9999 : $() } -// CHECK-LABEL: sil shared [noinline] @$s7specgen13take_closure2yyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () { +// CHECK-LABEL: sil shared [noinline] [ossa] @$s7specgen13take_closure2yyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () { // CHECK: bb0(%0 : $Int) // CHECK: [[FUN:%.*]] = function_ref @$s7specgen6calleryySiFySi_SitcfU_ // CHECK: partial_apply [[FUN]]( -// CHECK-LABEL: sil shared [noinline] @$s7specgen13take_closure2yyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () { +// CHECK-LABEL: sil shared [noinline] [ossa] @$s7specgen13take_closure2yyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () { // CHECK-NEXT: bb0: // CHECK: [[FUN:%.*]] = function_ref @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () // CHECK: thin_to_thick_function [[FUN]] : $@convention(thin) (Int, Int) -> () to $@callee_owned (Int, Int) -> () -// CHECK-LABEL: sil [noinline] @$s7specgen13take_closure2yyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { -sil [noinline] @$s7specgen13take_closure2yyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { -bb0(%0 : $@callee_owned (Int, Int) -> ()): - %1 = alloc_stack $Int - %2 = load %1 : $*Int +// CHECK-LABEL: sil [noinline] [ossa] @$s7specgen13take_closure2yyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { +sil [ossa] [noinline] @$s7specgen13take_closure2yyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () { +bb0(%0 : @owned $@callee_owned (Int, Int) -> ()): + %2 = load [trivial] undef : $*Int %3 = apply %0(%2, %2) : $@callee_owned (Int, Int) -> () - dealloc_stack %1 : $*Int %9999 = tuple() return %9999 : $() } -// CHECK-LABEL: sil [noinline] @$s7specgen6calleeyySi_S2itF : $@convention(thin) (Int, Int, Int) -> () { +// CHECK-LABEL: sil [noinline] [ossa] @$s7specgen6calleeyySi_S2itF : $@convention(thin) (Int, Int, Int) -> () { // specgen.callee (Swift.Int, Swift.Int, Swift.Int) -> () -sil [noinline] @$s7specgen6calleeyySi_S2itF : $@convention(thin) (Int, Int, Int) -> () { +sil [ossa] [noinline] @$s7specgen6calleeyySi_S2itF : $@convention(thin) (Int, Int, Int) -> () { bb0(%0 : $Int, %1 : $Int, %2 : $Int): %6 = tuple () // user: %7 return %6 : $() // id: %7 } -// CHECK-LABEL: sil @$s7specgen6calleryySiF : $@convention(thin) (Int) -> () { -// CHECK: [[ID1:%[0-9]+]] = function_ref @$s7specgen13take_closure2yyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () +// CHECK-LABEL: sil [ossa] @$s7specgen6calleryySiF : $@convention(thin) (Int) -> () { // CHECK: [[ID2:%[0-9]+]] = function_ref @$s7specgen12take_closureyyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () // CHECK: apply [[ID2]](%0) : $@convention(thin) (Int) -> () +// CHECK: [[ID1:%[0-9]+]] = function_ref @$s7specgen13take_closure2yyySi_SitcF023$s7specgen6calleryySiFyE8_SitcfU_SiTf1c_n : $@convention(thin) (Int) -> () // CHECK: apply [[ID1]](%0) : $@convention(thin) (Int) -> () -sil @$s7specgen6calleryySiF : $@convention(thin) (Int) -> () { +sil [ossa] @$s7specgen6calleryySiF : $@convention(thin) (Int) -> () { bb0(%0 : $Int): // function_ref specgen.take_closure ((Swift.Int, Swift.Int) -> ()) -> () %2 = function_ref @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () // user: %5 // function_ref specgen.(caller (Swift.Int) -> ()).(closure #1) %3 = function_ref @$s7specgen6calleryySiFySi_SitcfU_ : $@convention(thin) (Int, Int, Int) -> () // user: %4 %4 = partial_apply %3(%0) : $@convention(thin) (Int, Int, Int) -> () // user: %5 - strong_retain %4 : $@callee_owned (Int, Int) -> () - %5 = apply %2(%4) : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () + %4a = copy_value %4 + %5 = apply %2(%4a) : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () %6 = function_ref @$s7specgen13take_closure2yyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () // user: %5 - strong_retain %4 : $@callee_owned (Int, Int) -> () - %7 = apply %6(%4) : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () - strong_release %4 : $@callee_owned (Int, Int) -> () + %4b = copy_value %4 + %7 = apply %6(%4b) : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () + destroy_value %4 %9999 = tuple() return %9999 : $() } -// CHECK-LABEL: sil shared @$s7specgen6calleryySiFySi_SitcfU_ : $@convention(thin) (Int, Int, Int) -> () { -sil shared @$s7specgen6calleryySiFySi_SitcfU_ : $@convention(thin) (Int, Int, Int) -> () { +// CHECK-LABEL: sil shared [ossa] @$s7specgen6calleryySiFySi_SitcfU_ : $@convention(thin) (Int, Int, Int) -> () { +sil shared [ossa] @$s7specgen6calleryySiFySi_SitcfU_ : $@convention(thin) (Int, Int, Int) -> () { bb0(%0 : $Int, %1 : $Int, %2 : $Int): %5 = alloc_box $<τ_0_0> { var τ_0_0 } , var, name "p" // users: %6, %10, %14 %5a = project_box %5 : $<τ_0_0> { var τ_0_0 } , 0 - store %0 to %5a : $*Int // id: %6 + store %0 to [trivial] %5a : $*Int // id: %6 %7 = alloc_box $<τ_0_0> { var τ_0_0 } , var, name "q" // users: %8, %11, %13 %7a = project_box %7 : $<τ_0_0> { var τ_0_0 } , 0 - store %1 to %7a : $*Int // id: %8 + store %1 to [trivial] %7a : $*Int // id: %8 // function_ref specgen.callee (Swift.Int, Swift.Int, Swift.Int) -> () %9 = function_ref @$s7specgen6calleeyySi_S2itF : $@convention(thin) (Int, Int, Int) -> () // user: %12 - %10 = load %5a : $*Int // user: %12 - %11 = load %7a : $*Int // user: %12 + %10 = load [trivial] %5a : $*Int // user: %12 + %11 = load [trivial] %7a : $*Int // user: %12 %12 = apply %9(%10, %11, %2) : $@convention(thin) (Int, Int, Int) -> () - strong_release %7 : $<τ_0_0> { var τ_0_0 } - strong_release %5 : $<τ_0_0> { var τ_0_0 } + destroy_value %7 + destroy_value %5 %15 = tuple () // user: %16 return %15 : $() // id: %16 } @@ -101,20 +98,20 @@ bb0(%0 : $Int, %1 : $Int, %2 : $Int): // Thin To Thick Function Tests // ////////////////////////////////// -// CHECK-LABEL: sil [noinline] @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () { +// CHECK-LABEL: sil [noinline] [ossa] @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () { // specgen.callee (Swift.Int, Swift.Int) -> () -sil [noinline] @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () { +sil [noinline] [ossa] @$s7specgen6calleeyySi_SitF : $@convention(thin) (Int, Int) -> () { bb0(%0 : $Int, %1 : $Int): %6 = tuple () // user: %7 return %6 : $() // id: %7 } -// CHECK-LABEL: sil @$s7specgen11tttficalleryySiF : $@convention(thin) (Int) -> () { -// CHECK: [[ID1:%[0-9]+]] = function_ref @$s7specgen13take_closure2yyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () +// CHECK-LABEL: sil [ossa] @$s7specgen11tttficalleryySiF : $@convention(thin) (Int) -> () { // CHECK: [[ID2:%[0-9]+]] = function_ref @$s7specgen12take_closureyyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () // CHECK: apply [[ID2]]() : $@convention(thin) () -> () +// CHECK: [[ID1:%[0-9]+]] = function_ref @$s7specgen13take_closure2yyySi_SitcF26$s7specgen6calleeyySi_SitFTf1c_n : $@convention(thin) () -> () // CHECK: apply [[ID1]]() : $@convention(thin) () -> () -sil @$s7specgen11tttficalleryySiF : $@convention(thin) (Int) -> () { +sil [ossa] @$s7specgen11tttficalleryySiF : $@convention(thin) (Int) -> () { bb0(%0 : $Int): // function_ref specgen.take_closure ((Swift.Int, Swift.Int) -> ()) -> () %2 = function_ref @$s7specgen12take_closureyyySi_SitcF : $@convention(thin) (@owned @callee_owned (Int, Int) -> ()) -> () // user: %5 @@ -132,26 +129,24 @@ bb0(%0 : $Int): // address and non-address only types) taken as @in or @in_guaranteed. // This is a temporary limitation. -// TODO: figure out what to do with non-inout indirect arguments -// https://forums.swift.org/t/non-inout-indirect-types-not-supported-in-closure-specialization-optimization/70826 -// CHECK-LABEL: sil @address_closure : $@convention(thin) (@in Int) -> () { -sil @address_closure : $@convention(thin) (@in Int) -> () { +// CHECK-LABEL: sil [ossa] @address_closure : $@convention(thin) (@in Int) -> () { +sil [ossa] @address_closure : $@convention(thin) (@in Int) -> () { bb0(%0 : $*Int): %6 = tuple() return %6 : $() } -// CHECK-LABEL: sil @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { -sil @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> ()): +// CHECK-LABEL: sil [ossa] @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +sil [ossa] @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +bb0(%0 : @owned $@callee_owned () -> ()): %1 = apply %0() : $@callee_owned () -> () %9999 = tuple() return %9999 : $() } -// CHECK-LABEL: sil @address_caller : $@convention(thin) (@in Int) -> () { +// CHECK-LABEL: sil [ossa] @address_caller : $@convention(thin) (@in Int) -> () { // CHECK-NOT: _TTSf1cl15address_closureSi__address_closure_user -sil @address_caller : $@convention(thin) (@in Int) -> () { +sil [ossa] @address_caller : $@convention(thin) (@in Int) -> () { bb0(%0 : $*Int): %1 = function_ref @address_closure : $@convention(thin) (@in Int) -> () %2 = partial_apply %1(%0) : $@convention(thin) (@in Int) -> () @@ -163,17 +158,17 @@ bb0(%0 : $*Int): class A {} -sil hidden [noinline] @closure : $@convention(thin) (@owned A, @owned A) -> () { -bb0(%0 : $A, %1 : $A): - strong_release %1 : $A - strong_release %0 : $A +sil hidden [ossa] [noinline] @closure : $@convention(thin) (@owned A, @owned A) -> () { +bb0(%0 : @owned $A, %1 : @owned $A): + destroy_value %1 + destroy_value %0 %4 = tuple () return %4 : $() } // CHECK-LABEL: sil shared {{.*}} @$s11use_closure{{.*}}Tf{{.*}} : $@convention(thin) (@owned A) -> () { -sil hidden [noinline] @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () { -bb0(%0 : $@callee_owned (@owned A) -> ()): +sil hidden [ossa] [noinline] @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () { +bb0(%0 : @owned $@callee_owned (@owned A) -> ()): %1 = alloc_ref $A %2 = apply %0(%1) : $@callee_owned (@owned A) -> () %3 = tuple () @@ -181,8 +176,8 @@ bb0(%0 : $@callee_owned (@owned A) -> ()): } // CHECK-LABEL: sil shared {{.*}} @$s17use_closure_throw{{.*}}Tf{{.*}} : $@convention(thin) (@owned A) -> @error any Error { -sil hidden [noinline] @use_closure_throw : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> @error any Error { -bb0(%0 : $@callee_owned (@owned A) -> ()): +sil hidden [ossa] [noinline] @use_closure_throw : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> @error any Error { +bb0(%0 : @owned $@callee_owned (@owned A) -> ()): %1 = alloc_ref $A %2 = apply %0(%1) : $@callee_owned (@owned A) -> () %3 = tuple () @@ -190,31 +185,31 @@ bb0(%0 : $@callee_owned (@owned A) -> ()): } // CHECK-LABEL: sil {{.*}} @different_execution_counts -// CHECK: bb0([[ARG:%.*]] : $A -// CHECK: strong_retain [[ARG]] +// CHECK: bb0([[ARG:%.*]] : @guaranteed $A +// CHECK: %1 = copy_value %0 // CHECK-NOT: partial_apply -// CHECK: [[SPECIALIZED_CLOSURE_USER:%.*]] = function_ref @$s11use_closure{{.*}}Tf -// CHECK: retain_value [[ARG]] +// CHECK: [[C:%.*]] = copy_value %1 // CHECK-NOT: partial_apply // CHECK: integer_literal $Builtin.Int64, 0 -// CHECK: br bb2 +// CHECK: br bb2 // CHECK: bb1: -// CHECK: strong_release [[ARG]] -// CHECK: release_value [[ARG]] -// CHECK: return +// CHECK: destroy_value [[C]] +// CHECK: destroy_value %1 +// CHECK: return // CHECK: bb2({{.*}}): // Match the partial_apply consume of arg. -// CHECK: retain_value [[ARG]] -// CHECK: apply [[SPECIALIZED_CLOSURE_USER]]([[ARG]]) -// CHECK: cond_br {{.*}}, bb1, bb3 - -sil hidden [noinline] @different_execution_counts : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): - strong_retain %0 : $A +// CHECK: [[C2:%.*]] = copy_value [[C]] +// CHECK: [[SPECIALIZED_CLOSURE_USER:%.*]] = function_ref @$s11use_closure{{.*}}Tf +// CHECK: apply [[SPECIALIZED_CLOSURE_USER]]([[C2]]) +// CHECK: cond_br {{.*}}, bb1, bb3 + +sil hidden [ossa] [noinline] @different_execution_counts : $@convention(thin) (@guaranteed A) -> () { +bb0(%0 : @guaranteed $A): + %1 = copy_value %0 %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () + %3 = partial_apply %2(%1) : $@convention(thin) (@owned A, @owned A) -> () %4 = integer_literal $Builtin.Int64, 0 %5 = integer_literal $Builtin.Int64, 5 %6 = integer_literal $Builtin.Int64, 1 @@ -223,15 +218,15 @@ bb0(%0 : $A): br bb2(%4 : $Builtin.Int64) bb1: - strong_release %3 : $@callee_owned (@owned A) -> () + destroy_value %3 %11 = tuple () return %11 : $() bb2(%13 : $Builtin.Int64): %14 = builtin "sadd_with_overflow_Int64"(%13 : $Builtin.Int64, %6 : $Builtin.Int64, %7 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) %15 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 0 - strong_retain %3 : $@callee_owned (@owned A) -> () - %17 = apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () + %16 = copy_value %3 + %17 = apply %8(%16) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () %18 = builtin "cmp_eq_Int64"(%15 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1 cond_br %18, bb1, bb3 @@ -239,181 +234,116 @@ bb3: br bb2(%15 : $Builtin.Int64) } -// CHECK-LABEL: sil @insert_release_in_liferange_exit_block -// CHECK: bb0(%0 : $A): -// CHECK: retain_value %0 -// CHECK: bb1: -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb3 -// CHECK: bb2: -// CHECK: retain_value %0 -// CHECK: apply %{{[0-9]+}}(%0) -// CHECK: release_value %0 -// CHECK: bb3: -// CHECK-NOT: %0 -// CHECK: return -sil @insert_release_in_liferange_exit_block : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): - strong_retain %0 : $A +// CHECK-LABEL: sil [ossa] @insert_release_in_liverange_exit_block +// CHECK: bb0(%0 : @guaranteed $A): +// CHECK: %1 = copy_value %0 +// CHECK: [[C:%.*]] = copy_value %1 +// CHECK: bb1: +// CHECK-NEXT: destroy_value [[C]] +// CHECK-NEXT: destroy_value +// CHECK-NEXT: br bb3 +// CHECK: bb2: +// CHECK: apply %{{[0-9]+}}([[C]]) +// CHECK: bb3: +// CHECK-NOT: %0 +// CHECK: return +sil [ossa] @insert_release_in_liverange_exit_block : $@convention(thin) (@guaranteed A) -> () { +bb0(%0 : @guaranteed $A): + %1 = copy_value %0 %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () + %3 = partial_apply %2(%1) : $@convention(thin) (@owned A, @owned A) -> () %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () + %4 = copy_value %3 %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () cond_br undef, bb1, bb2 bb1: + destroy_value %4 br bb3 bb2: - strong_retain %3 : $@callee_owned (@owned A) -> () - %17 = apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () + %17 = apply %8(%4) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () br bb3 bb3: - strong_release %5 : $@callee_owned () -> () - %11 = tuple () - return %11 : $() -} - -// CHECK-LABEL: sil @insert_release_at_critical_edge -// CHECK: bb0(%0 : $A): -// CHECK: retain_value %0 -// CHECK: bb1: -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb3 -// CHECK: bb2: -// CHECK: retain_value %0 -// CHECK: apply %{{[0-9]+}}(%0) -// CHECK: release_value %0 -// CHECK: bb3: -// CHECK-NOT: %0 -// CHECK: return -sil @insert_release_at_critical_edge : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): - strong_retain %0 : $A - %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () - %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - cond_br undef, bb1, bb2 - -bb1: - strong_retain %3 : $@callee_owned (@owned A) -> () - %17 = apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - br bb2 - -bb2: - strong_release %5 : $@callee_owned () -> () + destroy_value %5 %11 = tuple () return %11 : $() } -// CHECK-LABEL: sil @insert_release_at_critical_loop_exit_edge -// CHECK: bb0(%0 : $A): -// CHECK: retain_value %0 +// CHECK-LABEL: sil [ossa] @insert_release_in_loop_exit_block +// CHECK: bb0(%0 : @guaranteed $A): +// CHECK: %1 = copy_value %0 +// CHECK: [[C:%.*]] = copy_value %1 // CHECK: bb1: // CHECK-NEXT: br bb2 // CHECK: bb2: -// CHECK: retain_value %0 -// CHECK: apply %{{[0-9]+}}(%0) +// CHECK: [[C2:%.*]] = copy_value [[C]] +// CHECK: apply %{{[0-9]+}}([[C2]]) // CHECK-NOT: %0 -// CHECK: bb3: -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb5 // CHECK: bb4: -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb5 -// CHECK: bb5: +// CHECK-NEXT: destroy_value [[C]] +// CHECK-NEXT: destroy_value // CHECK-NOT: %0 // CHECK: return -sil @insert_release_at_critical_loop_exit_edge : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): - strong_retain %0 : $A +sil [ossa] @insert_release_in_loop_exit_block : $@convention(thin) (@guaranteed A) -> () { +bb0(%0 : @guaranteed $A): + %1 = copy_value %0 %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () + %3 = partial_apply %2(%1) : $@convention(thin) (@owned A, @owned A) -> () %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () + %4 = copy_value %3 %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - cond_br undef, bb3, bb1 + cond_br undef, bb4, bb1 bb1: br bb2 bb2: - strong_retain %3 : $@callee_owned (@owned A) -> () - %17 = apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - cond_br undef, bb2, bb4 + %16 = copy_value %4 + %17 = apply %8(%16) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () + cond_br undef, bb3, bb5 bb3: - br bb4 + br bb2 bb4: - strong_release %5 : $@callee_owned () -> () - %11 = tuple () - return %11 : $() -} - -// CHECK-LABEL: sil @insert_release_in_loop_exit_block -// CHECK: bb0(%0 : $A): -// CHECK: retain_value %0 -// CHECK: bb1: -// CHECK-NEXT: br bb2 -// CHECK: bb2: -// CHECK: retain_value %0 -// CHECK: apply %{{[0-9]+}}(%0) -// CHECK-NOT: %0 -// CHECK: bb3: -// CHECK-NEXT: release_value %0 -// CHECK-NOT: %0 -// CHECK: return -sil @insert_release_in_loop_exit_block : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): - strong_retain %0 : $A - %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () - %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - cond_br undef, bb3, bb1 - -bb1: - br bb2 + destroy_value %4 + br bb6 -bb2: - strong_retain %3 : $@callee_owned (@owned A) -> () - %17 = apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> () - cond_br undef, bb2, bb3 +bb5: + destroy_value %4 + br bb6 -bb3: - strong_release %5 : $@callee_owned () -> () +bb6: + destroy_value %5 %11 = tuple () return %11 : $() } -// CHECK-LABEL: sil @insert_release_after_try_apply -// CHECK: bb0(%0 : $A): -// CHECK: retain_value %0 -// CHECK: bb1: -// CHECK: retain_value %0 -// CHECK-NEXT: try_apply -// CHECK: bb2(%{{[0-9]+}} : $()): -// CHECK-NEXT: strong_release %0 -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb4 -// CHECK: bb3(%{{[0-9]+}} : $any Error): -// CHECK-NEXT: strong_release %0 -// CHECK-NEXT: release_value %0 -// CHECK-NEXT: br bb4 -// CHECK: bb4: -// CHECK-NOT: %0 +// CHECK-LABEL: sil [ossa] @insert_release_after_try_apply +// CHECK: bb0(%0 : @guaranteed $A): +// CHECK: %1 = copy_value %0 +// CHECK: [[C:%.*]] = copy_value %1 +// CHECK: bb1: +// CHECK-NEXT: destroy_value %1 +// CHECK: try_apply %{{[0-9]+}}([[C]]) +// CHECK: bb2(%{{[0-9]+}} : $()): +// CHECK-NEXT: br bb4 +// CHECK: bb3(%{{[0-9]+}} : $any Error): +// CHECK-NEXT: br bb4 +// CHECK: bb4: +// CHECK-NOT: %0 // CHECK: return -sil @insert_release_after_try_apply : $@convention(thin) (@guaranteed A) -> () { -bb0(%0 : $A): +sil [ossa] @insert_release_after_try_apply : $@convention(thin) (@guaranteed A) -> () { +bb0(%0 : @guaranteed $A): + %1 = copy_value %0 %2 = function_ref @closure : $@convention(thin) (@owned A, @owned A) -> () - %3 = partial_apply %2(%0) : $@convention(thin) (@owned A, @owned A) -> () + %3 = partial_apply %2(%1) : $@convention(thin) (@owned A, @owned A) -> () %8 = function_ref @use_closure_throw : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> @error Error br bb1 bb1: - strong_retain %3 : $@callee_owned (@owned A) -> () try_apply %8(%3) : $@convention(thin) (@owned @callee_owned (@owned A) -> ()) -> @error Error, normal bb2, error bb3 bb2(%n : $()): @@ -430,92 +360,92 @@ bb4: // Ensure that we can specialize and properly mangle functions that take closures with <τ_0_0> { var τ_0_0 } . -// CHECK-LABEL: sil shared [noinline] @$s4main5inneryys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n : $@convention(thin) (@inout Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () +// CHECK-LABEL: sil shared [noinline] [ossa] @$s4main5inneryys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n : $@convention(thin) (@inout Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () // CHECK: bb0 // CHECK: [[FN:%.*]] = function_ref @closure_with_box_argument // CHECK: [[PARTIAL:%.*]] = partial_apply [[FN]](%1) -// CHECK: [[ARG:%.*]] = load %0 -// CHECK: apply [[PARTIAL]]([[ARG]]) +// CHECK: [[C:%.*]] = copy_value [[PARTIAL]] +// CHECK: [[ARG:%.*]] = load [trivial] %0 +// CHECK: apply [[C]]([[ARG]]) // CHECK-LABEL: {{.*}} @$s4main5inneryys5Int32Vz_yADctF -sil hidden [noinline] @$s4main5inneryys5Int32Vz_yADctF : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () { -bb0(%0 : $*Builtin.Int32, %1 : $@callee_owned (Builtin.Int32) -> ()): - strong_retain %1 : $@callee_owned (Builtin.Int32) -> () - %5 = load %0 : $*Builtin.Int32 +sil hidden [ossa] [noinline] @$s4main5inneryys5Int32Vz_yADctF : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () { +bb0(%0 : $*Builtin.Int32, %1 : @owned $@callee_owned (Builtin.Int32) -> ()): + %5 = load [trivial] %0 : $*Builtin.Int32 %6 = apply %1(%5) : $@callee_owned (Builtin.Int32) -> () %11 = tuple () return %11 : $() } -// CHECK-LABEL: sil @pass_a_closure -sil @pass_a_closure: $@convention(thin) () -> Builtin.Int32 { +// CHECK-LABEL: sil [ossa] @pass_a_closure +sil [ossa] @pass_a_closure: $@convention(thin) () -> Builtin.Int32 { bb0: %0 = alloc_box $<τ_0_0> { var τ_0_0 } , var, name "i" %0a = project_box %0 : $<τ_0_0> { var τ_0_0 } , 0 %1 = integer_literal $Builtin.Int32, 0 - store %1 to %0a : $*Builtin.Int32 + store %1 to [trivial] %0a : $*Builtin.Int32 %4 = function_ref @closure_with_box_argument : $@convention(thin) (Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () - strong_retain %0 : $<τ_0_0> { var τ_0_0 } - %6 = partial_apply %4(%0) : $@convention(thin) (Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () + %5 = copy_value %0 + %6 = partial_apply %4(%5) : $@convention(thin) (Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () %7 = alloc_stack $Builtin.Int32 %9 = integer_literal $Builtin.Int32, 1 - store %9 to %7 : $*Builtin.Int32 + store %9 to [trivial] %7 : $*Builtin.Int32 %12 = function_ref @$s4main5inneryys5Int32Vz_yADctF: $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () - strong_retain %6 : $@callee_owned (Builtin.Int32) -> () - %14 = apply %12(%7, %6) : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () - strong_release %6 : $@callee_owned (Builtin.Int32) -> () + %13 = copy_value %6 + %14 = apply %12(%7, %13) : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () + destroy_value %6 %16 = tuple () dealloc_stack %7 : $*Builtin.Int32 - %18 = load %0a : $*Builtin.Int32 - strong_release %0 : $<τ_0_0> { var τ_0_0 } + %18 = load [trivial] %0a : $*Builtin.Int32 + destroy_value %0 return %18 : $Builtin.Int32 } -// CHECK-LABEL: sil shared @closure_with_box_argument -sil shared @closure_with_box_argument : $@convention(thin) (Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () { -bb0(%0 : $Builtin.Int32, %1 : $<τ_0_0> { var τ_0_0 } ): +// CHECK-LABEL: sil shared [ossa] @closure_with_box_argument +sil shared [ossa] @closure_with_box_argument : $@convention(thin) (Builtin.Int32, @owned <τ_0_0> { var τ_0_0 } ) -> () { +bb0(%0 : $Builtin.Int32, %1 : @owned $<τ_0_0> { var τ_0_0 } ): %3 = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 - store %0 to %3 : $*Builtin.Int32 - strong_release %1 : $<τ_0_0> { var τ_0_0 } + store %0 to [trivial] %3 : $*Builtin.Int32 + destroy_value %1 %7 = tuple () return %7 : $() } // Check that we don't crash with this: -// CHECK-LABEL: sil @test_box_with_named_elements_tuple -sil @test_box_with_named_elements_tuple: $@convention(thin) () -> Builtin.Int32 { +// CHECK-LABEL: sil [ossa] @test_box_with_named_elements_tuple +sil [ossa] @test_box_with_named_elements_tuple: $@convention(thin) () -> Builtin.Int32 { bb0: %0 = alloc_box ${ let (first: Builtin.Int32, second: Builtin.Int32) } %0p = project_box %0 : ${ let (first: Builtin.Int32, second: Builtin.Int32) }, 0 %0a = tuple_element_addr %0p : $*(first: Builtin.Int32, second: Builtin.Int32), 0 %0b = tuple_element_addr %0p : $*(first: Builtin.Int32, second: Builtin.Int32), 1 %1 = integer_literal $Builtin.Int32, 0 - store %1 to %0a : $*Builtin.Int32 - store %1 to %0b : $*Builtin.Int32 + store %1 to [trivial] %0a : $*Builtin.Int32 + store %1 to [trivial] %0b : $*Builtin.Int32 %4 = function_ref @closure_with_named_elements_tuple : $@convention(thin) (Builtin.Int32, @owned { let (first: Builtin.Int32, second: Builtin.Int32) }) -> () - strong_retain %0 : ${ let (first: Builtin.Int32, second: Builtin.Int32) } - %6 = partial_apply %4(%0) : $@convention(thin) (Builtin.Int32, @owned { let (first: Builtin.Int32, second: Builtin.Int32) }) -> () + %5 = copy_value %0 + %6 = partial_apply %4(%5) : $@convention(thin) (Builtin.Int32, @owned { let (first: Builtin.Int32, second: Builtin.Int32) }) -> () %7 = alloc_stack $Builtin.Int32 %9 = integer_literal $Builtin.Int32, 1 - store %9 to %7 : $*Builtin.Int32 + store %9 to [trivial] %7 : $*Builtin.Int32 %12 = function_ref @$s4main5inneryys5Int32Vz_yADctF: $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () - strong_retain %6 : $@callee_owned (Builtin.Int32) -> () - %14 = apply %12(%7, %6) : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () - strong_release %6 : $@callee_owned (Builtin.Int32) -> () + %13 = copy_value %6 + %14 = apply %12(%7, %13) : $@convention(thin) (@inout Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> ()) -> () + destroy_value %6 %16 = tuple () dealloc_stack %7 : $*Builtin.Int32 - %18 = load %0a : $*Builtin.Int32 - strong_release %0 : ${ let (first: Builtin.Int32, second: Builtin.Int32) } + %18 = load [trivial] %0a : $*Builtin.Int32 + destroy_value %0 return %18 : $Builtin.Int32 } -// CHECK-LABEL: sil shared @closure_with_named_elements_tuple -sil shared @closure_with_named_elements_tuple : $@convention(thin) (Builtin.Int32, @owned { let (first: Builtin.Int32, second: Builtin.Int32) }) -> () { -bb0(%0 : $Builtin.Int32, %1 : ${ let (first: Builtin.Int32, second: Builtin.Int32) }): +// CHECK-LABEL: sil shared [ossa] @closure_with_named_elements_tuple +sil shared [ossa] @closure_with_named_elements_tuple : $@convention(thin) (Builtin.Int32, @owned { let (first: Builtin.Int32, second: Builtin.Int32) }) -> () { +bb0(%0 : $Builtin.Int32, %1 : @owned ${ let (first: Builtin.Int32, second: Builtin.Int32) }): %3 = project_box %1 : ${ let (first: Builtin.Int32, second: Builtin.Int32) }, 0 %4 = tuple_element_addr %3 : $*(first: Builtin.Int32, second: Builtin.Int32), 0 - store %0 to %4 : $*Builtin.Int32 - strong_release %1 : ${ let (first: Builtin.Int32, second: Builtin.Int32) } + store %0 to [trivial] %4 : $*Builtin.Int32 + destroy_value %1 %7 = tuple () return %7 : $() } @@ -533,25 +463,28 @@ public struct S : P { init() } -// CHECK-LABEL: sil shared @$s4test1SVAA1PA2aDP3fooyS2iycFZTW8closure2SiTf1cn_n : $@convention(thin) (@thick S.Type, Int) -> Int -sil @$s4test1SVAA1PA2aDP3fooyS2iycFZTW : $@convention(witness_method: P) (@owned @callee_owned () -> Int, @thick S.Type) -> Int { -bb0(%0 : $@callee_owned () -> Int, %1 : $@thick S.Type): - %3 = apply %0() : $@callee_owned () -> Int +// CHECK-LABEL: sil shared [ossa] @$s4test1SVAA1PA2aDP3fooyS2iycFZTW8closure2SiTf1cn_n : $@convention(thin) (@thick S.Type, Int) -> Int +sil [ossa] @$s4test1SVAA1PA2aDP3fooyS2iycFZTW : $@convention(witness_method: P) (@guaranteed @noescape @callee_guaranteed () -> Int, @thick S.Type) -> Int { +bb0(%0 : @guaranteed $@noescape @callee_guaranteed () -> Int, %1 : $@thick S.Type): + %3 = apply %0() : $@noescape @callee_guaranteed () -> Int return %3 : $Int } -sil shared @closure2 : $@convention(thin) (Int) -> Int { +sil shared [ossa] @closure2 : $@convention(thin) (Int) -> Int { bb0(%0 : $Int): return %0 : $Int } -sil @call_witness_method : $@convention(thin) (Int, S) -> Int { +sil [ossa] @call_witness_method : $@convention(thin) (Int, S) -> Int { bb0(%0 : $Int, %1 : $S): %3 = function_ref @closure2 : $@convention(thin) (Int) -> Int - %4 = partial_apply %3(%0) : $@convention(thin) (Int) -> Int + %4 = partial_apply [callee_guaranteed] %3(%0) : $@convention(thin) (Int) -> Int + %4a = convert_escape_to_noescape %4 : $@callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> Int %5 = metatype $@thick S.Type - %6 = function_ref @$s4test1SVAA1PA2aDP3fooyS2iycFZTW : $@convention(witness_method: P) (@owned @callee_owned () -> Int, @thick S.Type) -> Int - %7 = apply %6(%4, %5) : $@convention(witness_method: P) (@owned @callee_owned () -> Int, @thick S.Type) -> Int + %6 = function_ref @$s4test1SVAA1PA2aDP3fooyS2iycFZTW : $@convention(witness_method: P) (@guaranteed @noescape @callee_guaranteed () -> Int, @thick S.Type) -> Int + %7 = apply %6(%4a, %5) : $@convention(witness_method: P) (@guaranteed @noescape @callee_guaranteed () -> Int, @thick S.Type) -> Int + destroy_value %4a + destroy_value %4 return %7 : $Int } @@ -560,27 +493,31 @@ sil_witness_table S: P module test { } // Test partial_apply -> convert_function -> convert_function -> try_apply. -sil @testClosureConvertHelper : $(Int) -> () +sil [ossa] @testClosureConvertHelper : $(Int) -> () // specialized testClosureConvertThunk // FIXME: Need to handle closures with multiple exceptional exits. -// CHECK-LABEL: sil shared @$s23testClosureConvertThunk0abC6HelperSiTf1nc_n : $@convention(thin) (Int) -> (@out (), @error any Error) { -// CHECK: bb0(%0 : $*(), %1 : $Int): -// CHECK: [[F:%.*]] = function_ref @testClosureConvertHelper : $@convention(thin) (Int) -> () -// CHECK: [[PA:%.*]] = partial_apply [[F]](%1) : $@convention(thin) (Int) -> () -// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_owned () -> () to $@noescape @callee_owned () -> () -// CHECK: [[CVT2:%.*]] = convert_function [[CVT1]] : $@noescape @callee_owned () -> () to $@noescape @callee_owned () -> @error any Error -// CHECK: try_apply [[CVT2]]() : $@noescape @callee_owned () -> @error any Error, normal bb1, error bb2 -// CHECK: bb1 -// CHECK: release_value [[PA]] -// CHECK: return -// CHECK: bb2 -// CHECK: release_value [[PA]] -// CHECK: throw +// CHECK-LABEL: sil shared [ossa] @$s23testClosureConvertThunk0abC6HelperSiTf1nc_n : $@convention(thin) (Int) -> (@out (), @error any Error) { +// CHECK: bb0(%0 : $*(), %1 : $Int): +// CHECK: [[F:%.*]] = function_ref @testClosureConvertHelper : $@convention(thin) (Int) -> () +// CHECK: [[PA:%.*]] = partial_apply [[F]](%1) : $@convention(thin) (Int) -> () +// CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_owned () -> () to $@noescape @callee_owned () -> () +// CHECK: [[CVT2:%.*]] = convert_function [[CVT1]] : $@noescape @callee_owned () -> () to $@noescape @callee_owned () -> @error any Error +// CHECK: [[C:%.*]] = copy_value [[CVT2]] +// CHECK: try_apply [[C]]() : $@noescape @callee_owned () -> @error any Error, normal bb1, error bb2 +// CHECK: bb1 +// CHECK: destroy_value [[CVT2]] +// CHECK: destroy_value [[PA]] +// CHECK: return +// CHECK: bb2 +// CHECK: destroy_value [[CVT2]] +// CHECK: destroy_value [[PA]] +// CHECK: throw // CHECK-LABEL: } // end sil function '$s23testClosureConvertThunk0abC6HelperSiTf1nc_n' -sil @testClosureConvertThunk : $@convention(thin) (@noescape @callee_owned () -> @error Error) -> (@out (), @error Error) { -bb0(%0 : $*(), %1 : $@noescape @callee_owned () -> @error Error): - try_apply %1() : $@noescape @callee_owned () -> @error Error, normal bb1, error bb2 +sil [ossa] @testClosureConvertThunk : $@convention(thin) (@guaranteed @noescape @callee_owned () -> @error Error) -> (@out (), @error Error) { +bb0(%0 : $*(), %1 : @guaranteed $@noescape @callee_owned () -> @error Error): + %2 = copy_value %1 + try_apply %2() : $@noescape @callee_owned () -> @error Error, normal bb1, error bb2 bb1(%7 : $()): %8 = tuple () @@ -591,15 +528,15 @@ bb2(%10 : $Error): } // Test closure specialization when the closure type is converted before application. -sil @testClosureConvert : $(Int) -> () { +sil [ossa] @testClosureConvert : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $() %49 = function_ref @testClosureConvertHelper : $@convention(thin) (Int) -> () %50 = partial_apply %49(%0) : $@convention(thin) (Int) -> () %51 = convert_escape_to_noescape %50 : $@callee_owned () -> () to $@noescape @callee_owned () -> () %52 = convert_function %51 : $@noescape @callee_owned () -> () to $@noescape @callee_owned () -> @error Error - %53 = function_ref @testClosureConvertThunk : $@convention(thin) (@noescape @callee_owned () -> @error Error) -> (@out (), @error Error) - try_apply %53(%48, %52) : $@convention(thin) (@noescape @callee_owned () -> @error Error) -> (@out (), @error Error), normal bb7, error bb11 + %53 = function_ref @testClosureConvertThunk : $@convention(thin) (@guaranteed @noescape @callee_owned () -> @error Error) -> (@out (), @error Error) + try_apply %53(%48, %52) : $@convention(thin) (@guaranteed @noescape @callee_owned () -> @error Error) -> (@out (), @error Error), normal bb7, error bb11 bb7(%callret : $()): br bb99 @@ -608,28 +545,31 @@ bb11(%128 : $Error): br bb99 bb99: + destroy_value %52 + destroy_value %50 dealloc_stack %48 : $*() %empty = tuple () return %empty : $() } -sil @testClosureThunkNoEscape : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () { -bb0(%0 : $@noescape @callee_guaranteed () -> ()): +sil [ossa] @testClosureThunkNoEscape : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () { +bb0(%0 : @guaranteed $@noescape @callee_guaranteed () -> ()): apply %0() : $@noescape @callee_guaranteed () -> () %8 = tuple () return %8 : $() } -// CHECK-LABEL: sil shared @$s24testClosureThunkNoEscape0aB13ConvertHelperSiTf1c_n : $@convention(thin) (Int) -> () { +// CHECK-LABEL: sil shared [ossa] @$s24testClosureThunkNoEscape0aB13ConvertHelperSiTf1c_n : $@convention(thin) (Int) -> () { // CHECK: bb0([[ARG:%.*]] : $Int): // CHECK: [[F:%.*]] = function_ref @testClosureConvertHelper : $@convention(thin) (Int) -> () // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[F]]([[ARG]]) : $@convention(thin) (Int) -> () // CHECK: [[E:%.*]] = convert_escape_to_noescape [[PA]] : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> () // CHECK: apply [[E]]() : $@noescape @callee_guaranteed () -> () -// CHECK: release_value [[PA]] +// CHECK: destroy_value [[E]] +// CHECK: destroy_value [[PA]] // CHECK: return // CHECK: } -// CHECK-LABEL: sil @testClosureNoEscape : $@convention(thin) (Int) -> () { +// CHECK-LABEL: sil [ossa] @testClosureNoEscape : $@convention(thin) (Int) -> () { // CHECK-NOT: partial_apply // CHECK: [[FN:%.*]] = function_ref @$s24testClosureThunkNoEscape0aB13ConvertHelperSiTf1c_n : $@convention(thin) (Int) -> () // CHECK-NOT: partial_apply @@ -638,25 +578,26 @@ bb0(%0 : $@noescape @callee_guaranteed () -> ()): // CHECK: return // CHECK: } -sil @testClosureNoEscape : $(Int) -> () { +sil [ossa] @testClosureNoEscape : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $() %49 = function_ref @testClosureConvertHelper : $@convention(thin) (Int) -> () %50 = partial_apply [callee_guaranteed] %49(%0) : $@convention(thin) (Int) -> () %51 = convert_escape_to_noescape %50 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> () - %53 = function_ref @testClosureThunkNoEscape : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () - apply %53(%51) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () - release_value %50: $@callee_guaranteed () ->() + %53 = function_ref @testClosureThunkNoEscape : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + apply %53(%51) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + destroy_value %50 + destroy_value %51 dealloc_stack %48 : $*() %empty = tuple () return %empty : $() } -sil @testClosureConvertHelper2 : $(Int) -> Int +sil [ossa] @testClosureConvertHelper2 : $(Int) -> Int -sil @testClosureThunkNoEscape2 : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int { -bb0(%0 : $*Int, %1 : $@noescape @callee_guaranteed () -> @out Int): +sil [ossa] @testClosureThunkNoEscape2 : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int { +bb0(%0 : $*Int, %1 : @guaranteed $@noescape @callee_guaranteed () -> @out Int): apply %1(%0) : $@noescape @callee_guaranteed () -> @out Int %8 = tuple () return %8 : $() @@ -664,30 +605,22 @@ bb0(%0 : $*Int, %1 : $@noescape @callee_guaranteed () -> @out Int): sil [reabstraction_thunk] @reabstractionThunk : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int -// CHECK-LABEL: sil shared @$s25testClosureThunkNoEscape20aB14ConvertHelper2SiTf1nc_n : $@convention(thin) (Int) -> @out Int +// CHECK-LABEL: sil shared [ossa] @$s25testClosureThunkNoEscape20aB14ConvertHelper2SiTf1nc_n : $@convention(thin) (Int) -> @out Int // CHECK: [[PA1:%.*]] = partial_apply // CHECK: convert_escape_to_noescape // CHECK: [[PA2:%.*]] = partial_apply -// CHECK: convert_escape_to_noescape +// CHECK: [[CE:%.*]] = convert_escape_to_noescape // CHECK: apply -// CHECK: release_value [[PA1]] -// CHECK: release_value [[PA2]] +// CHECK: destroy_value [[CE]] +// CHECK: destroy_value [[PA2]] +// CHECK: destroy_value [[PA1]] // CHECK: return -// CHECK-LABEL: sil shared @$s25testClosureThunkNoEscape219reabstractionThunk2SiIegd_Tf1nc_n : $@convention(thin) (@owned @callee_guaranteed () -> Int) -> @out Int { -// CHECK: bb0(%0 : $*Int, %1 : $@callee_guaranteed () -> Int): -// CHECK: [[F:%.*]] = function_ref @reabstractionThunk2 -// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[F]](%1) -// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA]] -// CHECK: apply [[CVT]](%0) : $@noescape @callee_guaranteed () -> @out Int -// CHECK: release_value [[PA]] : $@callee_guaranteed () -> @out Int -// CHECK: return - -// CHECK-LABEL: sil @reabstractionTest : $@convention(thin) (Int) -> () +// CHECK-LABEL: sil [ossa] @reabstractionTest : $@convention(thin) (Int) -> () // CHECK: [[F:%.*]] = function_ref @$s25testClosureThunkNoEscape20aB14ConvertHelper2SiTf1nc_n // CHECK: apply [[F]] // CHECK: return -sil @reabstractionTest : $(Int) -> () { +sil [ossa] @reabstractionTest : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $Int %49 = function_ref @testClosureConvertHelper2 : $@convention(thin) (Int) -> Int @@ -696,39 +629,40 @@ bb0(%0 : $Int): %52 = function_ref @reabstractionThunk : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int %53 = partial_apply [callee_guaranteed] %52(%51) : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int %54 = convert_escape_to_noescape %53 : $@callee_guaranteed () -> @out Int to $@noescape @callee_guaranteed () -> @out Int - %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - apply %55(%48, %54) : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - release_value %50: $@callee_guaranteed () -> Int - release_value %53: $@callee_guaranteed () -> @out Int + %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + apply %55(%48, %54) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + destroy_value %50 + destroy_value %53 + destroy_value %54 dealloc_stack %48 : $*Int %empty = tuple () return %empty : $() } -sil @testClosureConvertHelper3 : $@convention(thin) (Int) -> Int +sil [ossa] @testClosureConvertHelper3 : $@convention(thin) (Int) -> Int sil [reabstraction_thunk] @reabstractionThunk3 : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int -sil @testClosureThunkNoEscape3 : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @out () { -entry(%empty : $*(), %closure : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ): +sil [ossa] @testClosureThunkNoEscape3 : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @out () { +entry(%empty : $*(), %closure : @owned $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ): %out = alloc_stack $Int %ret = apply %closure(%out) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for dealloc_stack %out : $*Int - store %ret to %empty : $*() + store %ret to [trivial] %empty : $*() + destroy_value %closure %retval = tuple () return %retval : $() } -// CHECK-LABEL: sil @reabstractionTest4 {{.*}} { +// CHECK-LABEL: sil [ossa] @reabstractionTest4 {{.*}} { // CHECK: [[HELPER:%[^,]+]] = function_ref @testClosureConvertHelper3 -// CHECK: [[SPECIALIZATION:%[^,]+]] = function_ref @$s25testClosureThunkNoEscape30aB14ConvertHelper3SiTf1nc_n // CHECK: [[CLOSURE:%[^,]+]] = partial_apply [callee_guaranteed] [[HELPER]] // CHECK: [[NOESCAPE_CLOSURE:%[^,]+]] = convert_escape_to_noescape [[CLOSURE]] +// CHECK: [[SPECIALIZATION:%[^,]+]] = function_ref @$s25testClosureThunkNoEscape30aB14ConvertHelper3SiTf1nc_n // CHECK: apply [[SPECIALIZATION]]{{.*}} -// CHECK: release_value [[CLOSURE]] -// CHECK-NOT: release_value [[CLOSURE]] -// CHECK: strong_release [[NOESCAPE_CLOSURE]] +// CHECK: destroy_value [[CLOSURE]] +// CHECK: destroy_value [[NOESCAPE_CLOSURE]] // CHECK-LABEL: } // end sil function 'reabstractionTest4' -sil @reabstractionTest4 : $(Int) -> () { +sil [ossa] @reabstractionTest4 : $(Int) -> () { bb0(%value : $Int): %testThrowingClosureConvertHelper = function_ref @testClosureConvertHelper3 : $@convention(thin) (Int) -> Int %closure = partial_apply [callee_guaranteed] %testThrowingClosureConvertHelper(%value) : $@convention(thin) (Int) -> Int @@ -739,52 +673,50 @@ bb0(%value : $Int): %dependency = mark_dependence %appliedThunk : $@noescape @callee_guaranteed () -> @out Int on %noescapeClosure : $@noescape @callee_guaranteed () -> Int %generified = convert_function %dependency : $@noescape @callee_guaranteed () -> @out Int to $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for %test = function_ref @testClosureThunkNoEscape3 : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @out () - strong_retain %generified : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for %out = alloc_stack $() %ret = apply %test(%out, %generified) : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for ) -> @out () dealloc_stack %out : $*() - release_value %closure : $@callee_guaranteed () -> Int - strong_release %noescapeClosure : $@noescape @callee_guaranteed () -> Int - dealloc_stack %appliedThunk : $@noescape @callee_guaranteed () -> @out Int + destroy_value %closure + destroy_value %noescapeClosure %empty = tuple () return %empty : $() } -sil @testThrowingClosureConvertHelper : $@convention(thin) (Int) -> (Int, @error any Error) +sil [ossa] @testThrowingClosureConvertHelper : $@convention(thin) (Int) -> (Int, @error any Error) sil [reabstraction_thunk] @reabstractionThunkThrowing : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error any Error)) -> (@out Int, @error any Error) -sil @testClosureThunkNoEscapeThrowing : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) -> (@out (), @error any Error) { -entry(%empty : $*(), %closure : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ): +sil [ossa] @testClosureThunkNoEscapeThrowing : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) -> (@out (), @error any Error) { +entry(%empty : $*(), %closure : @owned $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ): %out = alloc_stack $Int try_apply %closure(%out) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for , normal bb1, error bb2 bb1(%ret : $()): + destroy_value %closure dealloc_stack %out : $*Int - store %ret to %empty : $*() + store %ret to [trivial] %empty : $*() %retval = tuple () return %retval : $() bb2(%error : $any Error): + destroy_value %closure dealloc_stack %out : $*Int throw %error : $any Error } -// CHECK-LABEL: sil @reabstractionThrowing : $@convention(thin) (Int) -> ((), @error any Error) { +// CHECK-LABEL: sil [ossa] @reabstractionThrowing : $@convention(thin) (Int) -> ((), @error any Error) { // CHECK: [[HELPER:%[^,]+]] = function_ref @testThrowingClosureConvertHelper -// CHECK: [[SPECIALIZATION:%[^,]+]] = function_ref @$s32testClosureThunkNoEscapeThrowing0afB13ConvertHelperSiTf1nc_n // CHECK: [[CLOSURE:%[^,]+]] = partial_apply [callee_guaranteed] [[HELPER]] // CHECK: [[NOESCAPE_CLOSURE:%[^,]+]] = convert_escape_to_noescape [[CLOSURE]] +// CHECK: [[SPECIALIZATION:%[^,]+]] = function_ref @$s32testClosureThunkNoEscapeThrowing0afB13ConvertHelperSiTf1nc_n // CHECK: try_apply [[SPECIALIZATION]]{{.*}}normal [[NORMAL_BLOCK:bb[0-9]+]], error [[ERROR_BLOCK:bb[0-9]+]] // CHECK: [[NORMAL_BLOCK]] -// CHECK: release_value [[CLOSURE]] -// CHECK-NOT: release_value [[CLOSURE]] -// CHECK: strong_release [[NOESCAPE_CLOSURE]] +// CHECK: destroy_value [[NOESCAPE_CLOSURE]] +// CHECK: destroy_value [[CLOSURE]] // CHECK: [[ERROR_BLOCK]] -// CHECK: release_value [[CLOSURE]] -// CHECK-NOT: release_value [[CLOSURE]] -// CHECK: strong_release [[NOESCAPE_CLOSURE]] +// CHECK: destroy_value [[NOESCAPE_CLOSURE]] +// CHECK: destroy_value [[CLOSURE]] // CHECK-LABEL: } // end sil function 'reabstractionThrowing' -sil @reabstractionThrowing : $(Int) -> ((), @error any Error) { +sil [ossa] @reabstractionThrowing : $(Int) -> ((), @error any Error) { bb0(%value : $Int): %testThrowingClosureConvertHelper = function_ref @testThrowingClosureConvertHelper : $@convention(thin) (Int) -> (Int, @error any Error) %closure = partial_apply [callee_guaranteed] %testThrowingClosureConvertHelper(%value) : $@convention(thin) (Int) -> (Int, @error any Error) @@ -795,36 +727,33 @@ bb0(%value : $Int): %dependency = mark_dependence %appliedThunk : $@noescape @callee_guaranteed () -> (@out Int, @error any Error) on %noescapeClosure : $@noescape @callee_guaranteed () -> (Int, @error any Error) %generified = convert_function %dependency : $@noescape @callee_guaranteed () -> (@out Int, @error any Error) to $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for %test = function_ref @testClosureThunkNoEscapeThrowing : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) -> (@out (), @error any Error) - strong_retain %generified : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for %out = alloc_stack $() try_apply %test(%out, %generified) : $@convention(thin) (@owned @noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ) -> (@out (), @error any Error), normal bb1, error bb2 bb1(%ret : $()): dealloc_stack %out : $*() - release_value %closure : $@callee_guaranteed () -> (Int, @error any Error) - strong_release %noescapeClosure : $@noescape @callee_guaranteed () -> (Int, @error any Error) - dealloc_stack %appliedThunk : $@noescape @callee_guaranteed () -> (@out Int, @error any Error) + destroy_value %noescapeClosure + destroy_value %closure %empty = tuple () return %empty : $() bb2(%error : $any Error): dealloc_stack %out : $*() - release_value %closure : $@callee_guaranteed () -> (Int, @error any Error) - strong_release %noescapeClosure : $@noescape @callee_guaranteed () -> (Int, @error any Error) - dealloc_stack %appliedThunk : $@noescape @callee_guaranteed () -> (@out Int, @error any Error) + destroy_value %noescapeClosure + destroy_value %closure throw %error : $any Error } // Currently not supported cases. -sil @testClosureThunk4 : $@convention(thin) (@owned @callee_guaranteed () -> @out Int) -> @out Int { -bb0(%0 : $*Int, %1 : $@callee_guaranteed () -> @out Int): +sil [ossa] @testClosureThunk4 : $@convention(thin) (@owned @callee_guaranteed () -> @out Int) -> @out Int { +bb0(%0 : $*Int, %1 : @owned $@callee_guaranteed () -> @out Int): apply %1(%0) : $@callee_guaranteed () -> @out Int - release_value %1: $@callee_guaranteed () -> @out Int + destroy_value %1 %8 = tuple () return %8 : $() } -// CHECK-LABEL: sil @reabstractionTest2 +// CHECK-LABEL: sil [ossa] @reabstractionTest2 // CHECK: bb0(%0 : $Int): // CHECK: [[STK:%.*]] = alloc_stack $Int // CHECK: [[F:%.*]] = function_ref @testClosureConvertHelper2 @@ -832,13 +761,13 @@ bb0(%0 : $*Int, %1 : $@callee_guaranteed () -> @out Int): // CHECK: [[CVT:%.*]] = convert_escape_to_noescape [[PA]] // CHECK: [[F2:%.*]] = function_ref @reabstractionThunk // CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed] [[F2]]([[CVT]]) -// CHECK: [[F3:%.*]] = function_ref @testClosureThunk4 -// CHECK: apply [[F3]]([[STK]], [[PA2]]) -// CHECK: release_value [[PA]] +// CHECK: [[F3:%.*]] = function_ref @$s17testClosureThunk40aB14ConvertHelper2SiTf1nc_n : $@convention(thin) (Int) -> @out Int +// CHECK: apply [[F3]]([[STK]], %0) +// CHECK: destroy_value [[PA]] // CHECK: dealloc_stack [[STK]] // CHECK: return -sil @reabstractionTest2 : $(Int) -> () { +sil [ossa] @reabstractionTest2 : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $Int %49 = function_ref @testClosureConvertHelper2 : $@convention(thin) (Int) -> Int @@ -848,7 +777,7 @@ bb0(%0 : $Int): %53 = partial_apply [callee_guaranteed] %52(%51) : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int %55 = function_ref @testClosureThunk4 : $@convention(thin) (@owned @callee_guaranteed () -> @out Int) -> @out Int apply %55(%48, %53) : $@convention(thin) (@owned @callee_guaranteed () -> @out Int) -> @out Int - release_value %50: $@callee_guaranteed () -> Int + destroy_value %50 dealloc_stack %48 : $*Int %empty = tuple () return %empty : $() @@ -857,20 +786,15 @@ bb0(%0 : $Int): // Only support the ultimate partial_apply. sil [reabstraction_thunk] @reabstractionThunk2 : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int -// CHECK-LABEL: sil @reabstractionTest3 : $@convention(thin) (Int) -> () { +// CHECK-LABEL: sil [ossa] @reabstractionTest3 : $@convention(thin) (Int) -> () { // CHECK: bb0(%0 : $Int): // CHECK: [[STK:%.*]] = alloc_stack $Int -// CHECK: [[F:%.*]] = function_ref @testClosureConvertHelper2 -// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[F]](%0) -// CHECK: [[F2:%.*]] = function_ref @reabstractionThunk2 -// CHECK: [[SPEC:%.*]] = function_ref @$s25testClosureThunkNoEscape219reabstractionThunk2SiIegd_Tf1nc_n : $@convention(thin) (@owned @callee_guaranteed () -> Int) -> @out Int -// CHECK: retain_value [[PA]] : $@callee_guaranteed () -> Int -// CHECK: %8 = apply [[SPEC]]([[STK]], [[PA]]) : $@convention(thin) (@owned @callee_guaranteed () -> Int) -> @out Int -// CHECK: strong_release [[PA]] : $@callee_guaranteed () -> Int +// CHECK: [[SPEC:%.*]] = function_ref @$s25testClosureThunkNoEscape20aB14ConvertHelper2SiTf1nc_n : $@convention(thin) (Int) -> @out Int // user: %9 +// CHECK: = apply [[SPEC]]([[STK]], %0) : $@convention(thin) (Int) -> @out Int // CHECK: dealloc_stack [[STK]] : $*Int // CHECK: return -sil @reabstractionTest3 : $(Int) -> () { +sil [ossa] @reabstractionTest3 : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $Int %49 = function_ref @testClosureConvertHelper2 : $@convention(thin) (Int) -> Int @@ -878,9 +802,10 @@ bb0(%0 : $Int): %52 = function_ref @reabstractionThunk2 : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int %53 = partial_apply [callee_guaranteed] %52(%50) : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int %54 = convert_escape_to_noescape %53 : $@callee_guaranteed () -> @out Int to $@noescape @callee_guaranteed () -> @out Int - %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - apply %55(%48, %54) : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - release_value %53: $@callee_guaranteed () -> @out Int + %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + apply %55(%48, %54) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + destroy_value %54 + destroy_value %53 dealloc_stack %48 : $*Int %empty = tuple () return %empty : $() @@ -890,54 +815,135 @@ bb0(%0 : $Int): // Begin Apply Test // ////////////////////// -sil @coroutine_user : $@yield_once @convention(thin) (@noescape @callee_guaranteed () -> Int) -> @yields Int { -bb0(%0 : $@noescape @callee_guaranteed () -> Int): +sil [ossa] @coroutine_user : $@yield_once @convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> @yields Int { +bb0(%0 : @guaranteed $@noescape @callee_guaranteed () -> Int): %1 = apply %0() : $@noescape @callee_guaranteed () -> Int unreachable } -// CHECK-LABEL: sil @test_coroutine_user : $@convention(thin) (Int) -> Int { -// CHECK: [[COROUTINE_USER:%.*]] = function_ref @coroutine_user -// CHECK: begin_apply [[COROUTINE_USER]]( +// CHECK-LABEL: sil shared [ossa] @$s14coroutine_user25testClosureConvertHelper2SiTf1c_n : $@yield_once @convention(thin) (Int) -> @yields Int { + +// CHECK-LABEL: sil [ossa] @test_coroutine_user : $@convention(thin) (Int) -> Int { +// CHECK: [[C:%.*]] = function_ref @$s14coroutine_user25testClosureConvertHelper2SiTf1c_n : $@yield_once @convention(thin) (Int) -> @yields Int +// CHECK: = begin_apply [[C]](%0) // CHECK: } // end sil function 'test_coroutine_user' -sil @test_coroutine_user : $@convention(thin) (Int) -> Int { +sil [ossa] @test_coroutine_user : $@convention(thin) (Int) -> Int { bb0(%0 : $Int): %1 = function_ref @testClosureConvertHelper2 : $@convention(thin) (Int) -> Int %2 = partial_apply [callee_guaranteed] %1(%0) : $@convention(thin) (Int) -> Int %3 = convert_escape_to_noescape %2 : $@callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> Int - %4 = function_ref @coroutine_user : $@yield_once @convention(thin) (@noescape @callee_guaranteed () -> Int) -> @yields Int - (%value, %token) = begin_apply %4(%3) : $@yield_once @convention(thin) (@noescape @callee_guaranteed () -> Int) -> @yields Int + %4 = function_ref @coroutine_user : $@yield_once @convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> @yields Int + (%value, %token) = begin_apply %4(%3) : $@yield_once @convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Int) -> @yields Int cond_br undef, bb1, bb2 bb1: end_apply %token as $() + destroy_value %3 br bb3 bb2: abort_apply %token + destroy_value %3 br bb3 bb3: - release_value %2 : $@callee_guaranteed () -> Int + destroy_value %2 return %value : $Int } -// CHECK-LABEL: sil @reabstractionTest_on_stack + +// CHECK-LABEL: sil [ossa] @reabstractionTest_on_stack // CHECK: bb0([[A:%.*]] : $Int): // CHECK: [[R:%.*]] = alloc_stack $Int // CHECK: [[F:%.*]] = function_ref @$s25testClosureThunkNoEscape20aB14ConvertHelper2SiTf1nc_n // CHECK: apply [[F]]([[R]], [[A]]) -sil @reabstractionTest_on_stack : $(Int) -> () { +sil [ossa] @reabstractionTest_on_stack : $(Int) -> () { bb0(%0 : $Int): %48 = alloc_stack $Int %49 = function_ref @testClosureConvertHelper2 : $@convention(thin) (Int) -> Int %50 = partial_apply [callee_guaranteed] [on_stack] %49(%0) : $@convention(thin) (Int) -> Int %52 = function_ref @reabstractionThunk : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int %53 = partial_apply [callee_guaranteed] [on_stack] %52(%50) : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int - %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - apply %55(%48, %53) : $@convention(thin) (@noescape @callee_guaranteed () -> @out Int) -> @out Int - dealloc_stack %53 : $@noescape @callee_guaranteed () -> @out Int - dealloc_stack %50 : $@noescape @callee_guaranteed () -> Int + %55 = function_ref @testClosureThunkNoEscape2 : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + apply %55(%48, %53) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Int) -> @out Int + destroy_value %53 : $@noescape @callee_guaranteed () -> @out Int + destroy_value %50 : $@noescape @callee_guaranteed () -> Int dealloc_stack %48 : $*Int %empty = tuple () return %empty : $() } + +sil [ossa] @closure_with_string : $@convention(thin) (@guaranteed String) -> () + +sil [ossa] @use_non_escaping_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () { +bb0(%0 : @guaranteed $@noescape @callee_guaranteed () -> ()): + %2 = apply %0() : $@noescape @callee_guaranteed () -> () + %3 = tuple () + return %3 : $() +} + +// CHECK-LABEL: sil [ossa] @non_trivial_arg_capture : {{.*}} { +// CHECK-NOT: retain_value {{%.*}} : $String +// CHECK-LABEL: } // end sil function 'non_trivial_arg_capture' +sil [ossa] @non_trivial_arg_capture : $@convention(thin) (@guaranteed String) -> () { +bb0(%nc : @guaranteed $String): + %closure_fn = function_ref @closure_with_string : $@convention(thin) (@guaranteed String) -> () + %closure = partial_apply [callee_guaranteed] [on_stack] %closure_fn(%nc) : $@convention(thin) (@guaranteed String) -> () + %use = function_ref @use_non_escaping_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + apply %use(%closure) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + destroy_value %closure + %11 = tuple () + return %11 : $() +} + +struct NC : ~Copyable { + deinit {} +} + +sil hidden [ossa] [noinline] @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () { +bb0(%0 : @guaranteed $NC): + %retval = tuple () + return %retval : $() +} + +sil hidden [ossa] [noinline] @use_noncopyable_arg_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () { +bb0(%0 : @guaranteed $@noescape @callee_guaranteed () -> ()): + %2 = apply %0() : $@noescape @callee_guaranteed () -> () + %3 = tuple () + return %3 : $() +} + +// CHECK-LABEL: sil [ossa] @specialize_noncopyable_arg_closure : {{.*}} { +// CHECK: = function_ref @$s27use_noncopyable_arg_closure0b1_c1_D04main2NCVTf1c_n : $@convention(thin) (@guaranteed NC) -> () +// CHECK-LABEL: } // end sil function 'specialize_noncopyable_arg_closure' +sil [ossa] @specialize_noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () { +bb0(%nc : @guaranteed $NC): + %closure_fn = function_ref @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () + %closure = partial_apply [callee_guaranteed] [on_stack] %closure_fn(%nc) : $@convention(thin) (@guaranteed NC) -> () + %use = function_ref @use_noncopyable_arg_closure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + apply %use(%closure) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> ()) -> () + destroy_value %closure + %11 = tuple () + return %11 : $() +} + +sil hidden [ossa] [noinline] @use_escaping_noncopyable_arg_closure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () { +bb0(%0 : @guaranteed $@callee_guaranteed () -> ()): + %2 = apply %0() : $@callee_guaranteed () -> () + %3 = tuple () + return %3 : $() +} + +// CHECK-LABEL: sil [ossa] @dont_specialize_noncopyable_arg_closure : {{.*}} { +// CHECK: [[C:%.*]] = partial_apply +// CHECK: apply {{%[0-9]+}}([[C]]) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () +// CHECK-LABEL: } // end sil function 'dont_specialize_noncopyable_arg_closure' +sil [ossa] @dont_specialize_noncopyable_arg_closure : $@convention(thin) (@owned NC) -> () { +bb0(%nc : @owned $NC): + %closure_fn = function_ref @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () + %closure = partial_apply [callee_guaranteed] %closure_fn(%nc) : $@convention(thin) (@guaranteed NC) -> () + %use = function_ref @use_escaping_noncopyable_arg_closure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () + apply %use(%closure) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () + destroy_value %closure + %11 = tuple () + return %11 : $() +} diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_attrs.sil b/test/SILOptimizer/closure_specialization_attrs.sil similarity index 70% rename from test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_attrs.sil rename to test/SILOptimizer/closure_specialization_attrs.sil index 34222394140be..7d18fd013789d 100644 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_attrs.sil +++ b/test/SILOptimizer/closure_specialization_attrs.sil @@ -1,5 +1,4 @@ -// RUN: %target-sil-opt -enable-sil-verify-all -experimental-swift-based-closure-specialization %s | %FileCheck %s -// XFAIL: * +// RUN: %target-sil-opt -enable-sil-verify-all -closure-specialization %s | %FileCheck %s import Builtin @@ -36,15 +35,15 @@ bb0(%0 : @guaranteed $C, %1 : @guaranteed $C, %2 : @guaranteed $C): return %15 : $() } -sil @caller : $@convention(thin) (@owned C) -> () { -bb0(%0 : $C): +sil [ossa] @caller : $@convention(thin) (@owned C) -> () { +bb0(%0 : @owned $C): %3 = function_ref @closure : $@convention(thin) (@guaranteed C, @guaranteed C, @guaranteed C) -> () %4 = partial_apply [callee_guaranteed] [on_stack] %3(%0) : $@convention(thin) (@guaranteed C, @guaranteed C, @guaranteed C) -> () %take_closure = function_ref @take_closure : $@convention(thin) (@owned C, @guaranteed @noescape @callee_guaranteed (@guaranteed C, @guaranteed C) -> ()) -> () - strong_retain %0 : $C - %5 = apply %take_closure(%0, %4) : $@convention(thin) (@owned C, @guaranteed @noescape @callee_guaranteed (@guaranteed C, @guaranteed C) -> ()) -> () - strong_release %0 : $C - dealloc_stack %4 : $@noescape @callee_guaranteed (@guaranteed C, @guaranteed C) -> () + %5 = copy_value %0 + %6 = apply %take_closure(%5, %4) : $@convention(thin) (@owned C, @guaranteed @noescape @callee_guaranteed (@guaranteed C, @guaranteed C) -> ()) -> () + destroy_value %4 + destroy_value %0 %retval = tuple() return %retval : $() } @@ -58,30 +57,30 @@ bb0(%0 : $C): // This should not be specialized until we support guaranteed arguments. // CHECK-NOT: @$s20takesReadOnlyClosure -sil private [readonly] @takesReadOnlyClosure : $@convention(thin) (@noescape @callee_guaranteed (Val) -> Val) -> Val { -bb0(%2 : $@noescape @callee_guaranteed (Val) -> Val): +sil private [readonly] [ossa] @takesReadOnlyClosure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Val) -> Val) -> Val { +bb0(%2 : @guaranteed $@noescape @callee_guaranteed (Val) -> Val): %46 = struct $Val () %261 = apply %2(%46) : $@noescape @callee_guaranteed (Val) -> Val return %261 : $Val } -sil private @readOnlyClosure : $@convention(thin) (Val, @guaranteed Storage) -> Val { -bb0(%0 : $Val, %1 : @closureCapture $Storage): +sil private [ossa] @readOnlyClosure : $@convention(thin) (Val, @guaranteed Storage) -> Val { +bb0(%0 : $Val, %1 : @closureCapture @guaranteed $Storage): %46 = struct $Val () return %46 : $Val } -// CHECK-LABEL: sil @testPassReadOnlyClosure : $@convention(method) (@guaranteed Storage) -> Val { +// CHECK-LABEL: sil [ossa] @testPassReadOnlyClosure : $@convention(method) (@guaranteed Storage) -> Val { // CHECK-NOT: @owned Storage -// CHECK: apply %{{.*}} : $@convention(thin) (@noescape @callee_guaranteed (Val) -> Val) -> Val +// CHECK: apply %{{.*}} : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Val) -> Val) -> Val // CHECK-LABEL: } // end sil function 'testPassReadOnlyClosure' -sil @testPassReadOnlyClosure : $@convention(method) (@guaranteed Storage) -> Val { -bb0(%0 : $Storage): +sil [ossa] @testPassReadOnlyClosure : $@convention(method) (@guaranteed Storage) -> Val { +bb0(%0 : @guaranteed $Storage): %176 = function_ref @readOnlyClosure : $@convention(thin) (Val, @guaranteed Storage) -> Val %177 = partial_apply [callee_guaranteed] [on_stack] %176(%0) : $@convention(thin) (Val, @guaranteed Storage) -> Val %178 = mark_dependence %177 : $@noescape @callee_guaranteed (Val) -> Val on %0 : $Storage - %188 = function_ref @takesReadOnlyClosure : $@convention(thin) (@noescape @callee_guaranteed (Val) -> Val) -> Val - %189 = apply %188(%178) : $@convention(thin) (@noescape @callee_guaranteed (Val) -> Val) -> Val - dealloc_stack %177 : $@noescape @callee_guaranteed (Val) -> Val + %188 = function_ref @takesReadOnlyClosure : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Val) -> Val) -> Val + %189 = apply %188(%178) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Val) -> Val) -> Val + destroy_value %178 return %189 : $Val } diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_consolidated.sil b/test/SILOptimizer/closure_specialization_consolidated.sil similarity index 52% rename from test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_consolidated.sil rename to test/SILOptimizer/closure_specialization_consolidated.sil index e90d6518408b9..bbc1af7e09b57 100644 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_consolidated.sil +++ b/test/SILOptimizer/closure_specialization_consolidated.sil @@ -1,6 +1,4 @@ -// RUN: %target-sil-opt -enable-sil-verify-all -experimental-swift-based-closure-specialization %s | %FileCheck %s -check-prefix=REMOVECLOSURES -// RUN: %target-sil-opt -enable-sil-verify-all -closure-specialize-eliminate-dead-closures=0 -experimental-swift-based-closure-specialization %s | %FileCheck %s -// XFAIL: * +// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -closure-specialization %s | %FileCheck %s import Builtin import Swift @@ -49,22 +47,22 @@ public struct S: Q { // @in_guaranteed. // (*NOTE* this includes address and non-address only types). // This is a temporary limitation. -// CHECK-LABEL: sil @address_closure : $@convention(thin) (@in Int32) -> () { -sil @address_closure : $@convention(thin) (@in Int32) -> () { +// CHECK-LABEL: sil [ossa] @address_closure : $@convention(thin) (@in Int32) -> () { +sil [ossa] @address_closure : $@convention(thin) (@in Int32) -> () { bb0(%0 : $*Int32): %6 = tuple() return %6 : $() } -sil @address_closure_struct_complex : $@convention(thin) (@in S) -> () { +sil [ossa] @address_closure_struct_complex : $@convention(thin) (@in_guaranteed S) -> () { bb0(%0 : $*S): %6 = tuple() return %6 : $() } -// CHECK-LABEL: sil @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { -sil @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> ()): +// CHECK-LABEL: sil [ossa] @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +sil [ossa] @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +bb0(%0 : @owned $@callee_owned () -> ()): %1 = apply %0() : $@callee_owned () -> () %9999 = tuple() return %9999 : $() @@ -72,7 +70,7 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_noescape_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (Int32, @inout_aliasable Int32) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (Int32, @inout_aliasable Int32) -> () // CHECK: function_ref @address_closure_trivial : $@convention(thin) (Int32, @inout_aliasable Int32) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (Int32, @inout_aliasable Int32) -> () // CHECK: apply @@ -80,7 +78,7 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_noescape_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable Int32) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable Int32) -> () // CHECK: function_ref @address_closure_trivial_mutating : $@convention(thin) (@inout_aliasable Int32) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (@inout_aliasable Int32) -> () // CHECK: apply @@ -88,7 +86,7 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_noescape_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: function_ref @address_closure_existential : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: apply @@ -96,7 +94,7 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_noescape_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: function_ref @address_closure_struct1 : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: apply @@ -104,7 +102,7 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: function_ref @address_closure_struct2 : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: apply @@ -112,23 +110,23 @@ bb0(%0 : $@callee_owned () -> ()): // Check that a specialization of address_closure_user was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: function_ref @address_closure_class1 : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: partial_apply %{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: apply // CHECK: return -// CHECK-LABEL: sil @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () { -sil @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () { -bb0(%0 : $@noescape @callee_owned () -> ()): +// CHECK-LABEL: sil [ossa] @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () { +sil [ossa] @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () { +bb0(%0 : @owned $@noescape @callee_owned () -> ()): %1 = apply %0() : $@noescape @callee_owned () -> () %9999 = tuple() return %9999 : $() } -// CHECK-LABEL: sil @address_caller : $@convention(thin) (@in Int32) -> () { +// CHECK-LABEL: sil [ossa] @address_caller : $@convention(thin) (@in Int32) -> () { // CHECK-NOT: _TTSf1cl15address_closureSi__address_closure_user -sil @address_caller : $@convention(thin) (@in Int32) -> () { +sil [ossa] @address_caller : $@convention(thin) (@in Int32) -> () { bb0(%0 : $*Int32): %1 = function_ref @address_closure : $@convention(thin) (@in Int32) -> () %2 = partial_apply %1(%0) : $@convention(thin) (@in Int32) -> () @@ -143,20 +141,21 @@ bb0(%0 : $*Int32): // (*NOTE* this includes address and non-address only types). // This is a temporary limitation. // -// CHECK-LABEL: sil @address_caller_complex : $@convention(thin) (@in Int32) -> () +// CHECK-LABEL: sil [ossa] @address_caller_complex : $@convention(thin) (@in Int32) -> () // CHECK-NOT: function_ref @{{.*}}address_closure_user{{.*}} : $@convention(thin) (@in Int32) -> () // CHECK: partial_apply // CHECK-NOT: function_ref @{{.*}}address_closure_user{{.*}} : $@convention(thin) (@in Int32) -> () // CHECK: return -sil @address_caller_complex : $@convention(thin) (@in Int32) -> () { +sil [ossa] @address_caller_complex : $@convention(thin) (@in Int32) -> () { bb0(%0 : $*Int32): %00 = alloc_stack $Int32 - %01 = load %0 : $*Int32 - store %01 to %00 : $*Int32 + %01 = load [trivial] %0 : $*Int32 + store %01 to [trivial] %00 : $*Int32 %1 = function_ref @address_closure : $@convention(thin) (@in Int32) -> () %2 = partial_apply %1(%00) : $@convention(thin) (@in Int32) -> () %3 = function_ref @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () - %4 = apply %3(%2) : $@convention(thin) (@owned @callee_owned () -> ()) -> () + %2c = copy_value %2 + %4 = apply %3(%2c) : $@convention(thin) (@owned @callee_owned () -> ()) -> () dealloc_stack %00 : $*Int32 br bb1 @@ -171,23 +170,21 @@ bb1: // (*NOTE* this includes address and non-address only types). // This is a temporary limitation. // -// CHECK-LABEL: sil @address_caller_struct_complex : $@convention(thin) (@in S) -> () +// CHECK-LABEL: sil [ossa] @address_caller_struct_complex : $@convention(thin) (@in S) -> () // CHECK-NOT: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_user{{.*}} : $@convention(thin) (@in S) -> () // CHECK: partial_apply // CHECK-NOT: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_user{{.*}} : $@convention(thin) (@in S) -> () // CHECK: return -sil @address_caller_struct_complex : $@convention(thin) (@in S) -> () { +sil [ossa] @address_caller_struct_complex : $@convention(thin) (@in S) -> () { bb0(%0 : $*S): %00 = alloc_stack $S - %01 = load %0 : $*S - retain_value %01 : $S - store %01 to %00 : $*S - %1 = function_ref @address_closure_struct_complex : $@convention(thin) (@in S) -> () - %2 = partial_apply %1(%00) : $@convention(thin) (@in S) -> () + %01 = load [take] %0 : $*S + store %01 to [init] %00 : $*S + %1 = function_ref @address_closure_struct_complex : $@convention(thin) (@in_guaranteed S) -> () + %2 = partial_apply %1(%00) : $@convention(thin) (@in_guaranteed S) -> () %3 = function_ref @address_closure_user : $@convention(thin) (@owned @callee_owned () -> ()) -> () - %4 = apply %3(%2) : $@convention(thin) (@owned @callee_owned () -> ()) -> () - %5 = load %00 : $*S - release_value %5 : $S + %2c = copy_value %2 + %4 = apply %3(%2c) : $@convention(thin) (@owned @callee_owned () -> ()) -> () dealloc_stack %00 : $*S br bb1 @@ -199,41 +196,42 @@ bb1: // More complex tests involving address arguments. -sil @address_closure_trivial : $@convention(thin) (Int32, @inout_aliasable Int32) -> () { +sil [ossa] @address_closure_trivial : $@convention(thin) (Int32, @inout_aliasable Int32) -> () { bb0(%0 : $Int32, %1 : $*Int32): %9 = integer_literal $Builtin.Int32, 42 %10 = struct $Int32 (%9 : $Builtin.Int32) - store %10 to %1 : $*Int32 + store %10 to [trivial] %1 : $*Int32 %12 = tuple () return %12 : $() } -// CHECK-LABEL: sil @address_caller_trivial +// CHECK-LABEL: sil [ossa] @address_caller_trivial // CHECK-NOT: partial_apply // CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (Int32, @inout_aliasable Int32) -> () // CHECK: apply [[SPECIALIZED_FN1]]{{.*}} // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_trivial: $@convention(thin) (Int32) -> Int32 { +sil [ossa] @address_caller_trivial: $@convention(thin) (Int32) -> Int32 { bb0(%0 : $Int32): %2 = alloc_stack $Int32, var, name "xx" - store %0 to %2 : $*Int32 + store %0 to [trivial] %2 : $*Int32 // function_ref address_closure_noescape_user(f:) - %4 = function_ref @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () + %4 = function_ref @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () // function_ref address_closure_trivial(x:) %5 = function_ref @address_closure_trivial : $@convention(thin) (Int32, @inout_aliasable Int32) -> () %6 = partial_apply %5(%0, %2) : $@convention(thin) (Int32, @inout_aliasable Int32) -> () %6b = convert_escape_to_noescape %6 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - %7 = apply %4(%6b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - %8 = load %2 : $*Int32 + %7 = apply %4(%6b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + destroy_value %6 + %8 = load [trivial] %2 : $*Int32 dealloc_stack %2 : $*Int32 return %8 : $Int32 } -sil @address_closure_trivial_mutating : $@convention(thin) (@inout_aliasable Int32) -> () { +sil [ossa] @address_closure_trivial_mutating : $@convention(thin) (@inout_aliasable Int32) -> () { bb0(%0 : $*Int32): %2 = struct_element_addr %0 : $*Int32, #Int32._value - %3 = load %2 : $*Builtin.Int32 + %3 = load [trivial] %2 : $*Builtin.Int32 %4 = integer_literal $Builtin.Int32, 1 %5 = integer_literal $Builtin.Int1, -1 %6 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %4 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) @@ -241,48 +239,49 @@ bb0(%0 : $*Int32): %8 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 1 cond_fail %8 : $Builtin.Int1 %10 = struct $Int32 (%7 : $Builtin.Int32) - store %10 to %0 : $*Int32 + store %10 to [trivial] %0 : $*Int32 %12 = tuple () return %12 : $() } -// CHECK-LABEL: sil @address_caller_trivial_mutating +// CHECK-LABEL: sil [ossa] @address_caller_trivial_mutating // CHECK-NOT: partial_apply // CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable Int32) -> () // CHECK: apply [[SPECIALIZED_FN1]]{{.*}} // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_trivial_mutating: $@convention(thin) (Int32) -> Int32 { +sil [ossa] @address_caller_trivial_mutating: $@convention(thin) (Int32) -> Int32 { bb0(%0 : $Int32): %2 = alloc_stack $Int32, var, name "xx" - store %0 to %2 : $*Int32 - %4 = function_ref @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () + store %0 to [trivial] %2 : $*Int32 + %4 = function_ref @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () %5 = function_ref @address_closure_trivial_mutating : $@convention(thin) (@inout_aliasable Int32) -> () %6 = partial_apply %5(%2) : $@convention(thin) (@inout_aliasable Int32) -> () %6b = convert_escape_to_noescape %6 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - %7 = apply %4(%6b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - %8 = load %2 : $*Int32 + %7 = apply %4(%6b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + destroy_value %6 + %8 = load [trivial] %2 : $*Int32 dealloc_stack %2 : $*Int32 return %8 : $Int32 } -sil @S_init : $@convention(method) (@thin S.Type) -> @owned S +sil [ossa] @S_init : $@convention(method) (@thin S.Type) -> @owned S -sil hidden @address_closure_body_out_result : $@convention(thin) (@in Q, @in Q) -> @out Q { +sil hidden [ossa] @address_closure_body_out_result : $@convention(thin) (@in Q, @in Q) -> @out Q { bb0(%0 : $*Q, %1 : $*Q, %2 : $*Q): %5 = init_existential_addr %0 : $*Q, $S // function_ref S.init() %6 = function_ref @S_init : $@convention(method) (@thin S.Type) -> @owned S %7 = metatype $@thin S.Type %8 = apply %6(%7) : $@convention(method) (@thin S.Type) -> @owned S - store %8 to %5 : $*S + store %8 to [init] %5 : $*S destroy_addr %2 : $*Q destroy_addr %1 : $*Q %12 = tuple () return %12 : $() } -sil @address_closure_out_result : $@convention(thin) (@in Q, @inout_aliasable Q, @inout_aliasable Q) -> @out Q { +sil [ossa] @address_closure_out_result : $@convention(thin) (@in Q, @inout_aliasable Q, @inout_aliasable Q) -> @out Q { bb0(%0 : $*Q, %1 : $*Q, %2 : $*Q, %3 : $*Q): %7 = function_ref @address_closure_body_out_result : $@convention(thin) (@in Q, @in Q) -> @out Q %8 = alloc_stack $Q @@ -299,20 +298,20 @@ bb0(%0 : $*Q, %1 : $*Q, %2 : $*Q, %3 : $*Q): // Check that a specialization of address_closure_user_out_result was generated which does not // take a closure as a parameter anymore. -// CHECK-LABEL: sil shared @{{.*}}address_closure_user_out_result{{.*}} : $@convention(thin) (@inout_aliasable any Q, @inout_aliasable any Q) -> @out any Q +// CHECK-LABEL: sil shared [ossa] @{{.*}}address_closure_user_out_result{{.*}} : $@convention(thin) (@inout_aliasable any Q, @inout_aliasable any Q) -> @out any Q // CHECK: function_ref @address_closure_out_result : $@convention(thin) (@in any Q, @inout_aliasable any Q, @inout_aliasable any Q) -> @out any Q // CHECK: [[PARTIAL_APPLY:%.*]] = partial_apply %{{.*}} : $@convention(thin) (@in any Q, @inout_aliasable any Q, @inout_aliasable any Q) -> @out any Q // CHECK: apply [[PARTIAL_APPLY]] // CHECK: return -sil @address_closure_user_out_result : $@convention(thin) (@noescape @callee_owned (@in Q) -> @out Q) -> @out Q { -bb0(%0 : $*Q, %1 : $@noescape @callee_owned (@in Q) -> @out Q): +sil [ossa] @address_closure_user_out_result : $@convention(thin) (@owned @noescape @callee_owned (@in Q) -> @out Q) -> @out Q { +bb0(%0 : $*Q, %1 : @owned $@noescape @callee_owned (@in Q) -> @out Q): %4 = alloc_stack $Q %5 = init_existential_addr %4 : $*Q, $S %6 = function_ref @S_init : $@convention(method) (@thin S.Type) -> @owned S %7 = metatype $@thin S.Type %8 = apply %6(%7) : $@convention(method) (@thin S.Type) -> @owned S - store %8 to %5 : $*S + store %8 to [init] %5 : $*S %10 = apply %1(%0, %4) : $@noescape @callee_owned (@in Q) -> @out Q dealloc_stack %4 : $*Q %13 = tuple () @@ -323,45 +322,45 @@ bb0(%0 : $*Q, %1 : $@noescape @callee_owned (@in Q) -> @out Q): // unsupported address type arguments (e.g. @in or @out), but the partial_apply has only // supported address type arguments, i.e. @inout or @inout_aliasable. // -// CHECK-LABEL: sil @address_caller_out_result : $@convention(thin) (@in any Q, @in any Q) -> @out any Q +// CHECK-LABEL: sil [ossa] @address_caller_out_result : $@convention(thin) (@in any Q, @in any Q) -> @out any Q // CHECK-NOT: partial_apply // CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_user_out_result{{.*}} : $@convention(thin) (@inout_aliasable any Q, @inout_aliasable any Q) -> @out any Q // CHECK: apply [[SPECIALIZED_FN1]]{{.*}} // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_out_result: $@convention(thin) (@in Q, @in Q) -> @out Q { +sil [ossa] @address_caller_out_result: $@convention(thin) (@in Q, @in Q) -> @out Q { bb0(%0 : $*Q, %1 : $*Q, %2 : $*Q): - %5 = function_ref @address_closure_user_out_result : $@convention(thin) (@noescape @callee_owned (@in Q) -> @out Q) -> @out Q + %5 = function_ref @address_closure_user_out_result : $@convention(thin) (@owned @noescape @callee_owned (@in Q) -> @out Q) -> @out Q %6 = function_ref @address_closure_out_result : $@convention(thin) (@in Q, @inout_aliasable Q, @inout_aliasable Q) -> @out Q %7 = partial_apply %6(%1, %2) : $@convention(thin) (@in Q, @inout_aliasable Q, @inout_aliasable Q) -> @out Q %7b = convert_escape_to_noescape %7 : $@callee_owned (@in Q) -> @out Q to $@noescape @callee_owned (@in Q) -> @out Q - %8 = apply %5(%0, %7b) : $@convention(thin) (@noescape @callee_owned (@in Q) -> @out Q) -> @out Q + %8 = apply %5(%0, %7b) : $@convention(thin) (@owned @noescape @callee_owned (@in Q) -> @out Q) -> @out Q + destroy_value %7 destroy_addr %2 : $*Q destroy_addr %1 : $*Q %11 = tuple () return %11 : $() } -// CHECK-LABEL: sil @address_caller_existential +// CHECK-LABEL: sil [ossa] @address_caller_existential // CHECK-NOT: partial_apply -// CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: [[SPECIALIZED_FN2:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: apply [[SPECIALIZED_FN2]]{{.*}} +// CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable any P) -> () // CHECK: apply [[SPECIALIZED_FN1]]{{.*}} // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_existential : $@convention(thin) (@in P, @in P, Int32) -> @out P { +sil [ossa] @address_caller_existential : $@convention(thin) (@in P, @in P, Int32) -> @out P { bb0(%0 : $*P, %1 : $*P, %2 : $*P, %3 : $Int32): %7 = alloc_stack $P copy_addr %1 to [init] %7 : $*P %9 = function_ref @address_closure_existential : $@convention(thin) (@inout_aliasable P) -> () %10 = partial_apply %9(%7) : $@convention(thin) (@inout_aliasable P) -> () %10b = convert_escape_to_noescape %10 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - %12 = function_ref @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - strong_retain %10 : $@callee_owned () -> () - %14 = apply %12(%10b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - strong_retain %10 : $@callee_owned () -> () - %16 = apply %12(%10b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () + %12 = function_ref @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %14 = apply %12(%10b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %10c = convert_escape_to_noescape %10 : $@callee_owned () -> () to $@noescape @callee_owned () -> () + %16 = apply %12(%10c) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () %17 = integer_literal $Builtin.Int32, 10 %18 = struct_extract %3 : $Int32, #Int32._value %19 = builtin "cmp_slt_Int32"(%17 : $Builtin.Int32, %18 : $Builtin.Int32) : $Builtin.Int1 @@ -371,14 +370,14 @@ bb1: destroy_addr %2 : $*P copy_addr %1 to [init] %0 : $*P destroy_addr %1 : $*P - strong_release %10 : $@callee_owned () -> () + destroy_value %10 br bb3 bb2: destroy_addr %1 : $*P copy_addr %2 to [init] %0 : $*P destroy_addr %2 : $*P - strong_release %10 : $@callee_owned () -> () + destroy_value %10 br bb3 bb3: @@ -388,33 +387,33 @@ bb3: return %33 : $() } -sil shared @address_closure_existential : $@convention(thin) (@inout_aliasable P) -> () { +sil shared [ossa] @address_closure_existential : $@convention(thin) (@inout_aliasable P) -> () { bb0(%0 : $*P): %7 = tuple () return %7 : $() } -sil @address_closure_struct1 : $@convention(thin) (@inout_aliasable S, @owned S) -> () { -bb0(%0 : $*S, %1 : $S): +sil [ossa] @address_closure_struct1 : $@convention(thin) (@inout_aliasable S, @owned S) -> () { +bb0(%0 : $*S, %1 : @owned $S): %4 = struct_element_addr %0 : $*S, #S.c - %5 = load %4 : $*Optional - store %1 to %0 : $*S - release_value %5 : $Optional + %5 = load [copy] %4 : $*Optional + store %1 to [assign] %0 : $*S + destroy_value %5 %8 = tuple () return %8 : $() } -sil @address_closure_struct2 : $@convention(thin) (@inout_aliasable S, @owned S) -> () { -bb0(%0 : $*S, %1 : $S): +sil [ossa] @address_closure_struct2 : $@convention(thin) (@inout_aliasable S, @owned S) -> () { +bb0(%0 : $*S, %1 : @owned $S): %4 = struct_element_addr %0 : $*S, #S.c - %5 = load %4 : $*Optional - store %1 to %0 : $*S - release_value %5 : $Optional + %5 = load [copy] %4 : $*Optional + store %1 to [assign] %0 : $*S + destroy_value %5 %8 = tuple () return %8 : $() } -// CHECK-LABEL: sil @address_caller_struct +// CHECK-LABEL: sil [ossa] @address_caller_struct // CHECK-NOT: partial_apply // CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable S, @owned S) -> () // CHECK: apply [[SPECIALIZED_FN1]] @@ -422,64 +421,62 @@ bb0(%0 : $*S, %1 : $S): // CHECK: apply [[SPECIALIZED_FN2]] // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_struct : $@convention(thin) (@guaranteed S, @guaranteed S) -> @owned S { -bb0(%0 : $S, %1 : $S): +sil [ossa] @address_caller_struct : $@convention(thin) (@owned S, @guaranteed S) -> @owned S { +bb0(%0 : @owned $S, %1 : @guaranteed $S): + %2 = copy_value %0 + %3 = copy_value %1 %4 = alloc_stack $S, var, name "xx" - %5 = struct_extract %0 : $S, #S.c - store %0 to %4 : $*S - %7 = function_ref @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () + store %0 to [init] %4 : $*S + %7 = function_ref @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () %8 = function_ref @address_closure_struct1 : $@convention(thin) (@inout_aliasable S, @owned S) -> () - %9 = partial_apply %8(%4, %1) : $@convention(thin) (@inout_aliasable S, @owned S) -> () + %9 = partial_apply %8(%4, %3) : $@convention(thin) (@inout_aliasable S, @owned S) -> () %9b = convert_escape_to_noescape %9 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - retain_value %0 : $S - retain_value %1 : $S - %12 = apply %7(%9b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () + %12 = apply %7(%9b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () %13 = function_ref @address_closure_struct2 : $@convention(thin) (@inout_aliasable S, @owned S) -> () - %14 = partial_apply %13(%4, %0) : $@convention(thin) (@inout_aliasable S, @owned S) -> () + %14 = partial_apply %13(%4, %2) : $@convention(thin) (@inout_aliasable S, @owned S) -> () %14b = convert_escape_to_noescape %14 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - retain_value %5 : $Optional - %16 = apply %7(%14b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - %17 = load %4 : $*S + %16 = apply %7(%14b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %17 = load [take] %4 : $*S + destroy_value %9 + destroy_value %14 dealloc_stack %4 : $*S return %17 : $S } -sil shared @address_closure_class1 : $@convention(thin) (@inout_aliasable C, @owned C) -> () { -bb0(%0 : $*C, %1 : $C): - %4 = load %0 : $*C - store %1 to %0 : $*C - strong_release %4 : $C +sil shared [ossa] @address_closure_class1 : $@convention(thin) (@inout_aliasable C, @owned C) -> () { +bb0(%0 : $*C, %1 : @owned $C): + %4 = load [copy] %0 : $*C + store %1 to [assign] %0 : $*C + destroy_value %4 %7 = tuple () return %7 : $() } -// CHECK-LABEL: sil @address_caller_class1 +// CHECK-LABEL: sil [ossa] @address_caller_class1 // CHECK-NOT: partial_apply -// CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: [[SPECIALIZED_FN2:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: apply [[SPECIALIZED_FN2]]{{.*}} +// CHECK: [[SPECIALIZED_FN1:%.*]] = function_ref @{{.*}}address_closure_noescape_user{{.*}} : $@convention(thin) (@inout_aliasable C, @owned C) -> () // CHECK: apply [[SPECIALIZED_FN1]]{{.*}} // CHECK-NOT: partial_apply // CHECK: return -sil @address_caller_class1 : $@convention(thin) (@guaranteed C, @guaranteed C) -> @owned C { -bb0(%0 : $C, %1 : $C): +sil [ossa] @address_caller_class1 : $@convention(thin) (@guaranteed C, @guaranteed C) -> @owned C { +bb0(%0 : @guaranteed $C, %1 : @guaranteed $C): + %2 = copy_value %0 + %3 = copy_value %1 %4 = alloc_stack $C, var, name "xx" - store %0 to %4 : $*C + store %2 to [init] %4 : $*C %7 = function_ref @address_closure_class1 : $@convention(thin) (@inout_aliasable C, @owned C) -> () - %8 = partial_apply %7(%4, %1) : $@convention(thin) (@inout_aliasable C, @owned C) -> () + %8 = partial_apply %7(%4, %3) : $@convention(thin) (@inout_aliasable C, @owned C) -> () %8b = convert_escape_to_noescape %8 : $@callee_owned () -> () to $@noescape @callee_owned () -> () - %10 = function_ref @address_closure_noescape_user : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - strong_retain %0 : $C - strong_retain %1 : $C - strong_retain %8 : $@callee_owned () -> () - %14 = apply %10(%8b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - strong_retain %8 : $@callee_owned () -> () - %16 = apply %10(%8b) : $@convention(thin) (@noescape @callee_owned () -> ()) -> () - %17 = load %4 : $*C - strong_retain %17 : $C - strong_release %8 : $@callee_owned () -> () - %20 = load %4 : $*C - strong_release %20 : $C + %10 = function_ref @address_closure_noescape_user : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %14 = apply %10(%8b) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %8c = convert_escape_to_noescape %8 : $@callee_owned () -> () to $@noescape @callee_owned () -> () + %16 = apply %10(%8c) : $@convention(thin) (@owned @noescape @callee_owned () -> ()) -> () + %17 = load [copy] %4 : $*C + %20 = load [take] %4 : $*C + destroy_value %8 + destroy_value %20 dealloc_stack %4 : $*C return %17 : $C } @@ -492,164 +489,134 @@ bb0(%0 : $C, %1 : $C): // closure and @owned and @guaranteed. // -// CHECK-LABEL: sil @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -sil @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject, %4 : $Builtin.NativeObject, %5 : $Builtin.Int32, %6 : $Builtin.NativeObject, %7 : $Builtin.NativeObject): +// CHECK-LABEL: sil [ossa] @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +sil [ossa] @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0 : @unowned $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : @owned $Builtin.NativeObject, %3 : @guaranteed $Builtin.NativeObject, %4 : @unowned $Builtin.NativeObject, %5 : $Builtin.Int32, %6 : @owned $Builtin.NativeObject, %7 : @guaranteed $Builtin.NativeObject): %9999 = tuple () - release_value %2 : $Builtin.NativeObject - release_value %6 : $Builtin.NativeObject + destroy_value %2 + destroy_value %6 return %9999 : $() } -// CHECK-LABEL: sil @small_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -sil @small_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject): +// CHECK-LABEL: sil [ossa] @small_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +sil [ossa] @small_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0 : @unowned $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : @owned $Builtin.NativeObject, %3 : @guaranteed $Builtin.NativeObject): %9999 = tuple () - release_value %2 : $Builtin.NativeObject + destroy_value %2 return %9999 : $() } -// CHECK-LABEL: sil shared @$s18owned_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK-LABEL: sil shared [ossa] @$s18owned_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { // CHECK: bb0 // CHECK: [[FUN:%.*]] = function_ref @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () // CHECK: [[CLOSURE:%.*]] = partial_apply [[FUN]]( -// CHECK: apply [[CLOSURE]]( -// CHECK: release_value [[CLOSURE]] +// CHECK: [[C:%.*]] = copy_value [[CLOSURE]] +// CHECK: apply [[C]]( -// CHECK-LABEL: sil shared @$s18owned_apply_callee014small_closure_C0Tf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-LABEL: sil shared [ossa] @$s18owned_apply_callee014small_closure_C0Tf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { // CHECK: bb0 // CHECK: [[FUN:%.*]] = function_ref @small_closure_callee // CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[FUN]] : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () to $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () // CHECK: apply [[CLOSURE]]( -// CHECK: release_value [[CLOSURE]] - -// CHECK-LABEL: sil @owned_apply_callee : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -sil @owned_apply_callee : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -bb0(%0 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : $Builtin.NativeObject, %4 : $Builtin.NativeObject): - retain_value %3 : $Builtin.NativeObject - apply %0(%1, %2, %3, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - release_value %3 : $Builtin.NativeObject - release_value %0 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + +// CHECK-LABEL: sil [ossa] @owned_apply_callee : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +sil [ossa] @owned_apply_callee : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0 : @owned $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : @unowned $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : @owned $Builtin.NativeObject, %4 : @guaranteed $Builtin.NativeObject): + %5 = copy_value %3 + apply %0(%1, %2, %5, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + destroy_value %3 %9999 = tuple () return %9999 : $() } -// CHECK-LABEL: sil shared @$s23guaranteed_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { -// CHECK: bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject, %4 : $Builtin.NativeObject, %5 : $Builtin.Int32, %6 : $Builtin.NativeObject, %7 : $Builtin.NativeObject): +// CHECK-LABEL: sil shared [ossa] @$s23guaranteed_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK: bb0(%0 : @unowned $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : @owned $Builtin.NativeObject, %3 : @guaranteed $Builtin.NativeObject, %4 : @owned $Builtin.NativeObject, %5 : $Builtin.Int32, %6 : @owned $Builtin.NativeObject, %7 : @owned $Builtin.NativeObject): // CHECK: [[FUN:%.*]] = function_ref @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () // CHECK: [[CLOSURE:%.*]] = partial_apply [[FUN]]( -// CHECK: apply [[CLOSURE]]( -// CHECK: release_value [[CLOSURE]] +// CHECK: [[C:%.*]] = copy_value [[CLOSURE]] +// CHECK: apply [[C]]( +// CHECK: destroy_value [[CLOSURE]] -// CHECK-LABEL: sil shared @$s23guaranteed_apply_callee014small_closure_C0Tf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -// CHECK: bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject): +// CHECK-LABEL: sil shared [ossa] @$s23guaranteed_apply_callee014small_closure_C0Tf1cnnnn_n : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK: bb0(%0 : @unowned $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : @owned $Builtin.NativeObject, %3 : @guaranteed $Builtin.NativeObject): // CHECK: [[FUN:%.*]] = function_ref @small_closure_callee // CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[FUN]] : -// CHECK: apply [[CLOSURE]]( -// CHECK-NOT: release_value [[CLOSURE]] - -// CHECK-LABEL: sil @guaranteed_apply_callee : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -sil @guaranteed_apply_callee : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { -bb0(%0 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : $Builtin.NativeObject, %4 : $Builtin.NativeObject): - retain_value %3 : $Builtin.NativeObject - apply %0(%1, %2, %3, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - release_value %3 : $Builtin.NativeObject +// CHECK: [[C:%.*]] = copy_value [[CLOSURE]] +// CHECK: apply [[C]]( + +// CHECK-LABEL: sil [ossa] @guaranteed_apply_callee : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +sil [ossa] @guaranteed_apply_callee : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0 : @guaranteed $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : @unowned $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : @owned $Builtin.NativeObject, %4 : @guaranteed $Builtin.NativeObject): + %5 = copy_value %3 + %6 = copy_value %0 + apply %6(%1, %2, %5, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + destroy_value %3 %9999 = tuple () return %9999 : $() } -sil @guaranteed_apply_callee_throw : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> @error Error { -bb0(%0 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : $Builtin.NativeObject, %4 : $Builtin.NativeObject, %5: $Error): - retain_value %3 : $Builtin.NativeObject - apply %0(%1, %2, %3, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - release_value %3 : $Builtin.NativeObject +sil [ossa] @guaranteed_apply_callee_throw : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> @error Error { +bb0(%0 : @guaranteed $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), %1 : @unowned $Builtin.NativeObject, %2 : $Builtin.Int32, %3 : @owned $Builtin.NativeObject, %4 : @guaranteed $Builtin.NativeObject, %5: @owned $Error): + %6 = copy_value %3 + %7 = copy_value %0 + apply %7(%1, %2, %6, %4) : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + destroy_value %3 throw %5 : $Error } -// CHECK-LABEL: sil @thin_thick_and_partial_apply_test : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned any Error) -> () { -// CHECK: bb0([[ARG0:%.*]] : $Builtin.NativeObject, [[ARG1:%.*]] : $Builtin.Int32, [[ARG2:%.*]] : $Builtin.NativeObject, [[ARG3:%.*]] : $Builtin.NativeObject, [[ARG4:%.*]] : $any Error): + +// CHECK-LABEL: sil [ossa] @thin_thick_and_partial_apply_test : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned any Error) -> () { +// CHECK: bb0([[ARG0:%.*]] : @unowned $Builtin.NativeObject, [[ARG1:%.*]] : $Builtin.Int32, [[ARG2:%.*]] : @owned $Builtin.NativeObject, [[ARG3:%.*]] : @guaranteed $Builtin.NativeObject, [[ARG4:%.*]] : @owned $any Error): // CHECK: [[OLD_CLOSURE_CALLEE1:%.*]] = function_ref @large_closure_callee // CHECK: [[OLD_CLOSURE_CALLEE2:%.*]] = function_ref @small_closure_callee -// CHECK: retain_value [[ARG0]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject -// CHECK: [[SPECFUN0:%.*]] = function_ref @$s23guaranteed_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n -// CHECK: retain_value [[ARG0]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject +// CHECK: [[C0:%.*]] = copy_value [[ARG0]] +// CHECK-NEXT: [[C2:%.*]] = copy_value [[ARG2]] +// CHECK-NEXT: [[C3:%.*]] = copy_value [[ARG3]] +// CHECK: [[D0:%.*]] = copy_value [[C0]] +// CHECK-NEXT: [[D2:%.*]] = copy_value [[C2]] +// CHECK-NEXT: [[D3:%.*]] = copy_value [[C3]] +// CHECK: [[E0:%.*]] = copy_value [[C0]] +// CHECK-NEXT: [[E2:%.*]] = copy_value [[C2]] +// CHECK-NEXT: [[E3:%.*]] = copy_value [[C3]] +// CHECK-NOT: partial_apply [[OLD_CLOSURE_CALLEE1]] +// CHECK-NOT: thin_to_thick_function [[OLD_CLOSURE_CALLEE2]] // CHECK: [[SPECFUN1:%.*]] = function_ref @$s18owned_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n -// CHECK: retain_value [[ARG0]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// CHECK-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject -// CHECK: [[DEAD_CLOSURE_1:%.*]] = partial_apply [[OLD_CLOSURE_CALLEE1]] -// CHECK: [[SPECFUN2:%.*]] = function_ref @$s23guaranteed_apply_callee014small_closure_C0Tf1cnnnn_n -// CHECK: [[SPECFUN3:%.*]] = function_ref @$s18owned_apply_callee014small_closure_C0Tf1cnnnn_n -// CHECK: [[DEAD_CLOSURE_2:%.*]] = thin_to_thick_function [[OLD_CLOSURE_CALLEE2]] -// CHECK: retain_value [[DEAD_CLOSURE_1]] -// CHECK-NOT: retain_value [[DEAD_CLOSURE_2]] -// CHECK-NOT: apply [[DEAD_CLOSURE_1]] -// CHECK-NOT: apply [[DEAD_CLOSURE_2]] // CHECK: apply [[SPECFUN1]]( -// CHECK-NEXT: release_value [[DEAD_CLOSURE_1]] -// CHECK-NOT: release_value [[DEAD_CLOSURE_2]] +// CHECK: [[SPECFUN3:%.*]] = function_ref @$s18owned_apply_callee014small_closure_C0Tf1cnnnn_n // CHECK: apply [[SPECFUN3]]( -// CHECK-NOT: release_value [[DEAD_CLOSURE_1]] -// CHECK-NOT: release_value [[DEAD_CLOSURE_2]] +// CHECK: [[SPECFUN0:%.*]] = function_ref @$s23guaranteed_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n // CHECK: apply [[SPECFUN0]]( -// CHECK-NOT: release_value [[DEAD_CLOSURE_1]] -// CHECK-NOT: release_value [[DEAD_CLOSURE_2]] +// CHECK: [[SPECFUN2:%.*]] = function_ref @$s23guaranteed_apply_callee014small_closure_C0Tf1cnnnn_n // CHECK: apply [[SPECFUN2]]( -// CHECK-NEXT: release_value [[DEAD_CLOSURE_1]] -// CHECK-NOT: release_value [[DEAD_CLOSURE_2]] - -// REMOVECLOSURES-LABEL: sil @thin_thick_and_partial_apply_test : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned any Error) -> () { -// REMOVECLOSURES: bb0([[ARG0:%.*]] : $Builtin.NativeObject, [[ARG1:%.*]] : $Builtin.Int32, [[ARG2:%.*]] : $Builtin.NativeObject, [[ARG3:%.*]] : $Builtin.NativeObject, [[ARG4:%.*]] : $any Error): -// REMOVECLOSURES: [[OLD_CLOSURE_CALLEE1:%.*]] = function_ref @large_closure_callee -// REMOVECLOSURES: [[OLD_CLOSURE_CALLEE2:%.*]] = function_ref @small_closure_callee -// REMOVECLOSURES: retain_value [[ARG0]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject -// REMOVECLOSURES: [[SPECFUN0:%.*]] = function_ref @$s23guaranteed_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n -// REMOVECLOSURES: retain_value [[ARG0]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject -// REMOVECLOSURES: [[SPECFUN1:%.*]] = function_ref @$s18owned_apply_callee014large_closure_C0BoBi32_BoBoTf1cnnnn_n -// REMOVECLOSURES: retain_value [[ARG0]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG2]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: retain_value [[ARG3]] : $Builtin.NativeObject -// REMOVECLOSURES-NOT: partial_apply [[OLD_CLOSURE_CALLEE1]] -// REMOVECLOSURES: [[SPECFUN4:%.*]] = function_ref @$s29guaranteed_apply_callee_throw014small_closure_C0Tf1cnnnnn_n -// REMOVECLOSURES: [[SPECFUN2:%.*]] = function_ref @$s23guaranteed_apply_callee014small_closure_C0Tf1cnnnn_n -// REMOVECLOSURES: [[SPECFUN3:%.*]] = function_ref @$s18owned_apply_callee014small_closure_C0Tf1cnnnn_n -// REMOVECLOSURES-NOT: thin_to_thick_function [[OLD_CLOSURE_CALLEE2]] -// REMOVECLOSURES: apply [[SPECFUN1]]( -// REMOVECLOSURES-NEXT: apply [[SPECFUN3]]( -// REMOVECLOSURES-NEXT: apply [[SPECFUN0]]( -// REMOVECLOSURES-NEXT: apply [[SPECFUN2]]( -// REMOVECLOSURES-NEXT: strong_release [[ARG0]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: strong_release [[ARG2]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: strong_release [[ARG3]] : $Builtin.NativeObject -// REMOVECLOSURES-NEXT: try_apply [[SPECFUN4]]( -sil @thin_thick_and_partial_apply_test : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> () { -bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject, %11: $Error): +// CHECK-NEXT: destroy_value [[C0]] +// CHECK-NEXT: destroy_value [[C2]] +// CHECK-NEXT: destroy_value [[C3]] +// CHECK: [[SPECFUN4:%.*]] = function_ref @$s29guaranteed_apply_callee_throw014small_closure_C0Tf1cnnnnn_n +// CHECK-NEXT: try_apply [[SPECFUN4]]( +sil [ossa] @thin_thick_and_partial_apply_test : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> () { +bb0(%0 : @unowned $Builtin.NativeObject, %1 : $Builtin.Int32, %2 : @owned $Builtin.NativeObject, %3 : @guaranteed $Builtin.NativeObject, %11: @owned $Error): %4 = function_ref @owned_apply_callee : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () %5 = function_ref @guaranteed_apply_callee : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () %6 = function_ref @large_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () %7 = function_ref @small_closure_callee : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () %10 = function_ref @guaranteed_apply_callee_throw : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> @error Error - retain_value %0 : $Builtin.NativeObject - retain_value %2 : $Builtin.NativeObject - retain_value %3 : $Builtin.NativeObject - %8 = partial_apply %6(%0, %1, %2, %3) : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + %0c = copy_value %0 + %2c = copy_value %2 + %3c = copy_value %3 + %8 = partial_apply %6(%0c, %1, %2c, %3c) : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () %9 = thin_to_thick_function %7 : $@convention(thin) (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () to $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - retain_value %8 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - apply %4(%8, %0, %1, %2, %3) : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - apply %4(%9, %0, %1, %2, %3) : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - apply %5(%8, %0, %1, %2, %3) : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - apply %5(%9, %0, %1, %2, %3) : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () - - release_value %8 : $@callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + %2d = copy_value %2 + %8c = copy_value %8 + apply %4(%8c, %0, %1, %2d, %3) : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + %2e = copy_value %2 + apply %4(%9, %0, %1, %2e, %3) : $@convention(thin) (@owned @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + %2f = copy_value %2 + apply %5(%8, %0, %1, %2f, %3) : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + %2g = copy_value %2 + apply %5(%9, %0, %1, %2g, %3) : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () + + destroy_value %8 try_apply %10(%9, %0, %1, %2, %3, %11) : $@convention(thin) (@guaranteed @callee_owned (Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> (), Builtin.NativeObject, Builtin.Int32, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject, @owned Error) -> @error Error, normal bb2, error bb3 bb2(%n : $()): @@ -673,7 +640,7 @@ bb4: // CHECK-LABEL: @$s4test3barSiAA1P_p_SitF : $@convention(thin) (@in any P, Int32) -> Int32 { // CHECK: partial_apply // CHECK: apply -sil [noinline] @$s4test3barSiAA1P_p_SitF : $@convention(thin) (@in P, Int32) -> Int32 { +sil [noinline] [ossa] @$s4test3barSiAA1P_p_SitF : $@convention(thin) (@in P, Int32) -> Int32 { bb0(%0 : $*P, %1 : $Int32): %2 = open_existential_addr mutable_access %0 : $*P to $*@opened("01234567-89ab-cdef-0123-000000000000", P) Self %3 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000", P) Self, #P.foo, %2 : $*@opened("01234567-89ab-cdef-0123-000000000000", P) Self : $@convention(witness_method: P) @callee_owned (@callee_owned (Int32) -> Int32, Int32, @inout T) -> Int32 @@ -683,11 +650,12 @@ bb0(%0 : $*P, %1 : $Int32): %6 = function_ref @$s4test3bazSiSi1m_tcSiF : $@convention(thin) (Int32, Int32) -> Int32 %7 = partial_apply %6(%5) : $@convention(thin) (Int32, Int32) -> Int32 %8 = apply %3<@opened("01234567-89ab-cdef-0123-000000000000", P) Self>(%7, %1, %2) : $@convention(witness_method: P) @callee_owned (@callee_owned (Int32) -> Int32, Int32, @inout T) -> Int32 + destroy_value %7 destroy_addr %0 : $*P return %8 : $Int32 } -sil @$s4test3bazSiSi1m_tcSiF : $@convention(thin) (Int32, Int32) -> Int32 +sil [ossa] @$s4test3bazSiSi1m_tcSiF : $@convention(thin) (Int32, Int32) -> Int32 ////////////////////////////////////////////////////////////////////////////////// // Make sure that we properly set a specialized closure's indirect return type. // @@ -696,30 +664,29 @@ sil @$s4test3bazSiSi1m_tcSiF : $@convention(thin) (Int32, Int32) -> Int32 // SIL verification should catch the incorrect type. // rdar:://19321284 -// CHECK-LABEL: sil [serialized] @callee : $@convention(thin) (Builtin.Int32) -> () { -sil [serialized] @callee : $@convention(thin) (Builtin.Int32) -> () { +// CHECK-LABEL: sil [serialized] [ossa] @callee : $@convention(thin) (Builtin.Int32) -> () { +sil [serialized] [ossa] @callee : $@convention(thin) (Builtin.Int32) -> () { bb0(%0 : $Builtin.Int32): unreachable } -sil shared [serialized] @thunk : $@convention(thin) (@callee_owned () -> ()) -> @out () { -bb0(%0 : $*(), %1 : $@callee_owned () -> ()): +sil shared [serialized] [ossa] @thunk : $@convention(thin) (@owned @callee_owned () -> ()) -> @out () { +bb0(%0 : $*(), %1 : @owned $@callee_owned () -> ()): apply %1() : $@callee_owned () -> () %9999 = tuple() return %9999 : $() } // CHECK-LABEL: @test_closure_propagation : $@convention(thin) () -> () { -// REMOVECLOSURES-LABEL: @test_closure_propagation : $@convention(thin) () -> () { -// REMOVECLOSURES-NOT: partial_apply -sil [serialized] @test_closure_propagation : $@convention(thin) () -> () { +// CHECK-NOT: partial_apply +sil [serialized] [ossa] @test_closure_propagation : $@convention(thin) () -> () { bb0: %f1 = function_ref @callee : $@convention(thin) (Builtin.Int32) -> () %i1 = integer_literal $Builtin.Int32, 24 %p1 = partial_apply %f1(%i1) : $@convention(thin) (Builtin.Int32) -> () - %f2 = function_ref @thunk : $@convention(thin) (@callee_owned () -> ()) -> @out () + %f2 = function_ref @thunk : $@convention(thin) (@owned @callee_owned () -> ()) -> @out () %s1 = alloc_stack $() - %a1 = apply %f2(%s1, %p1) : $@convention(thin) (@callee_owned () -> ()) -> @out () + %a1 = apply %f2(%s1, %p1) : $@convention(thin) (@owned @callee_owned () -> ()) -> @out () dealloc_stack %s1 : $*() unreachable } diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_fragile.sil b/test/SILOptimizer/closure_specialization_fragile.sil similarity index 61% rename from test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_fragile.sil rename to test/SILOptimizer/closure_specialization_fragile.sil index db078cfbf9558..72c67f758bf03 100644 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_fragile.sil +++ b/test/SILOptimizer/closure_specialization_fragile.sil @@ -1,4 +1,4 @@ -// RUN: %target-sil-opt %s -verify -experimental-swift-based-closure-specialization -o - | %FileCheck %s +// RUN: %target-sil-opt %s -verify -closure-specialization -o - | %FileCheck %s // Make sure we do not specialize resilientCallee. @@ -15,17 +15,17 @@ import SwiftShims public func resilientCallee(fn: () -> ()) // action() -sil [Onone] @$s26closure_specialize_fragile6actionyyF : $@convention(thin) () -> () { +sil [Onone] [ossa] @$s26closure_specialize_fragile6actionyyF : $@convention(thin) () -> () { bb0: %0 = tuple () return %0 : $() } // end sil function '$s26closure_specialize_fragile6actionyyF' -// CHECK-LABEL: sil [serialized] [heuristic_always_inline] @$s26closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> () +// CHECK-LABEL: sil [serialized] [heuristic_always_inline] [ossa] @$s26closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> () // CHECK: function_ref @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () // CHECK: return // fragileCaller() -sil [serialized] [heuristic_always_inline] @$s26closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> () { +sil [serialized] [heuristic_always_inline] [ossa] @$s26closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> () { bb0: // function_ref resilientCallee(fn:) %0 = function_ref @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () @@ -37,20 +37,20 @@ bb0: return %4 : $() } // end sil function '$s26closure_specialize_fragile0C6CalleryyF' -// CHECK-LABEL: sil @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () +// CHECK-LABEL: sil [ossa] @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () // resilientCallee(fn:) -sil @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> ()): - strong_retain %0 : $@callee_owned () -> () - %3 = apply %0() : $@callee_owned () -> () - strong_release %0 : $@callee_owned () -> () +sil [ossa] @$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +bb0(%0 : @owned $@callee_owned () -> ()): + %1 = copy_value %0 + %3 = apply %1() : $@callee_owned () -> () + destroy_value %0 %5 = tuple () return %5 : $() } // end sil function '$s26closure_specialize_fragile15resilientCalleeyyyc2fn_tF' // closure #1 in fragileCaller() -sil shared [serialized] @$s26closure_specialize_fragile0C6CalleryyFyycfU_ : $@convention(thin) () -> () { +sil shared [serialized] [ossa] @$s26closure_specialize_fragile0C6CalleryyFyycfU_ : $@convention(thin) () -> () { bb0: // function_ref action() %0 = function_ref @$s26closure_specialize_fragile6actionyyF : $@convention(thin) () -> () diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_opaque.sil b/test/SILOptimizer/closure_specialization_opaque.sil similarity index 62% rename from test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_opaque.sil rename to test/SILOptimizer/closure_specialization_opaque.sil index 149e7c3044711..c788b76a27b39 100644 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_opaque.sil +++ b/test/SILOptimizer/closure_specialization_opaque.sil @@ -1,20 +1,19 @@ -// RUN: %target-sil-opt -enable-sil-opaque-values -enable-sil-verify-all -experimental-swift-based-closure-specialization %s | %FileCheck %s -// XFAIL: * +// RUN: %target-sil-opt -sil-print-types -enable-sil-opaque-values -enable-sil-verify-all -closure-specialization %s | %FileCheck %s struct TestView {} struct TestRange {} struct TestSlice {} // helper -sil @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { +sil [ossa] @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice): %1284 = tuple () return %1284 : $() } // helper -sil @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out () { -bb0(%0 : $*TestView, %1 : $@callee_owned (@inout TestView) ->()): +sil [ossa] @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> () { +bb0(%0 : $*TestView, %1 : @owned $@callee_owned (@inout TestView) ->()): %call = apply %1(%0) : $@callee_owned (@inout TestView) -> () %1284 = tuple () return %1284 : $() @@ -22,22 +21,21 @@ bb0(%0 : $*TestView, %1 : $@callee_owned (@inout TestView) ->()): // Test that ClosureSpecializer can handle captured @in args, in addition to direct args. // -// CHECK-LABEL: sil @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { +// CHECK-LABEL: sil [ossa] @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { // CHECK: bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice): // CHECK: [[CLOSURE:%.*]] = function_ref @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () -// CHECK: [[SPECIALIZED:%.*]] = function_ref @$s5thunk7closure4main9TestRangeVAC0D5SliceVTf1nc_n : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> @out () // user: %6 -// CHECK: [[THUNK:%.*]] = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out () -// CHECK: [[CALL:%.*]] = apply [[SPECIALIZED]](%0, %1, %2) : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> @out () +// CHECK: [[THUNK:%.*]] = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> () +// CHECK: [[SPECIALIZED:%.*]] = function_ref @$s5thunk7closure4main9TestRangeVAC0D5SliceVTf1nc_n : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () +// CHECK: [[CALL:%.*]] = apply [[SPECIALIZED]](%0, %1, %2) : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () // CHECK: %{{.*}} = tuple () // CHECK: return %{{.*}} : $() // CHECK-LABEL: } // end sil function 'testSpecializeThunk' -sil @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { +sil [ossa] @testSpecializeThunk : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () { bb0(%0 : $*TestView, %1 : $TestRange, %2 : $TestSlice): %closurefn = function_ref @closure : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () %pa = partial_apply %closurefn(%1, %2) : $@convention(thin) (@inout TestView, TestRange, @in TestSlice) -> () - %thunk = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out () - strong_retain %pa : $@callee_owned (@inout TestView) -> () - %call = apply %thunk(%0, %pa) : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> @out () + %thunk = function_ref @thunk : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> () + %call = apply %thunk(%0, %pa) : $@convention(thin) (@inout TestView, @owned @callee_owned (@inout TestView) -> ()) -> () %1284 = tuple () return %1284 : $() } diff --git a/test/SILOptimizer/closure_specialization_simple.sil b/test/SILOptimizer/closure_specialization_simple.sil new file mode 100644 index 0000000000000..d969a39d0017a --- /dev/null +++ b/test/SILOptimizer/closure_specialization_simple.sil @@ -0,0 +1,387 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -closure-specialization %s | %FileCheck %s + +import Builtin +import Swift + +sil @simple_partial_apply_fun : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + +// CHECK-LABEL: sil shared [ossa] @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 { +// CHECK: bb0([[CAPTURED_ARG:%.*]] : $Builtin.Int1): +// CHECK: [[CLOSED_OVER_FUN:%.*]] = function_ref @simple_partial_apply_fun : +// CHECK: [[NEW_PAI:%.*]] = partial_apply [[CLOSED_OVER_FUN]] +// CHECK: destroy_value [[NEW_PAI]] +sil [ossa] @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { +bb0(%0 : @owned $@callee_owned (Builtin.Int1) -> Builtin.Int1): + br bb1 + +bb1: + %1 = integer_literal $Builtin.Int1, 0 + // We cannot do anything here for now but in the future I think we should try + // to handle this in closure specialization potentially. + %0c = copy_value %0 + %2 = apply %0c(%1) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + return %2 : $Builtin.Int1 +} + +// CHECK-LABEL: sil shared [ossa] @$s37simple_partial_apply_2nd_level_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 { +// CHECK: bb0([[CAPTURED_ARG:%.*]] : $Builtin.Int1): +// CHECK: [[SPECIALIZED_CALLEE:%.*]] = function_ref @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : +// CHECK: [[RET:%.*]]= apply [[SPECIALIZED_CALLEE]]([[CAPTURED_ARG]]) +// CHECK: return [[RET]] +sil [ossa] @simple_partial_apply_2nd_level_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { +bb0(%0 : @owned $@callee_owned (Builtin.Int1) -> Builtin.Int1): + br bb1 + +bb1: + %1 = function_ref @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %0c = copy_value %0 + %2 = apply %1(%0c) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + return %2 : $Builtin.Int1 +} +sil @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + +// CHECK-LABEL: sil shared [ossa] @$s36simple_multiple_partial_apply_caller0a1_c1_D4_funBi1_ABBi1_Tf1cc_n : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 { +// CHECK: [[C:%.*]] = function_ref @simple_partial_apply_fun : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 +// CHECK: = partial_apply [[C]](%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 +// CHECK: = partial_apply [[C]](%1) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 +// CHECK: } // end sil function '$s36simple_multiple_partial_apply_caller0a1_c1_D4_funBi1_ABBi1_Tf1cc_n' + +// CHECK-LABEL: sil shared [ossa] @$s36simple_multiple_partial_apply_caller19closure_with_stringSSTf1cC0_n : $@convention(thin) (@owned String) -> Builtin.Int1 { +// %0 // user: %2 +// CHECK: %1 = function_ref @closure_with_string : $@convention(thin) (Builtin.Int1, @guaranteed String) -> Builtin.Int1 +// CHECK: %2 = partial_apply %1(%0) : $@convention(thin) (Builtin.Int1, @guaranteed String) -> Builtin.Int1 +// CHECK: %3 = copy_value %2 +// CHECK: br bb1 +// CHECK: } // end sil function '$s36simple_multiple_partial_apply_caller19closure_with_stringSSTf1cC0_n' +sil [ossa] @simple_multiple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { +bb0(%0 : @owned $@callee_owned (Builtin.Int1) -> Builtin.Int1, %1 : @owned $@callee_owned (Builtin.Int1) -> Builtin.Int1): + br bb1 + +bb1: + %2 = integer_literal $Builtin.Int1, 0 + // We cannot do anything here for now but in the future I think we should try + // to handle this in closure specialization potentially. + %0c = copy_value %0 + apply %0c(%2) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 + %1c = copy_value %1 + apply %1c(%2) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + destroy_value %1 + return %2 : $Builtin.Int1 +} + +sil @simple_partial_apply_fun2 : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 +sil [ossa] @simple_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { +bb0(%0 : @owned $@callee_owned (Builtin.Int1) -> Builtin.Int1): + br bb1 + +bb1: + %1 = integer_literal $Builtin.Int1, 0 + // We cannot do anything here for now but in the future I think we should try + // to handle this in closure specialization potentially. + %0c = copy_value %0 + %2 = apply %0c(%1) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + return %2 : $Builtin.Int1 +} + + +sil @indirect_parameter_partial_apply_fun : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + +sil [ossa] @indirect_parameter_partial_apply_caller1 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () { +bb0(%0 : @owned $@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1): + br bb1 + +bb1: + %1 = alloc_stack $Builtin.Int1 + %2 = alloc_stack $Builtin.Int1 + %3 = alloc_stack $Builtin.Int1 + %4 = integer_literal $Builtin.Int1, 0 + store %4 to [trivial] %1 + store %4 to [trivial] %2 + %0c = copy_value %0 + apply %0c(%3, %1, %4, %2) : $@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + dealloc_stack %3 + dealloc_stack %2 + dealloc_stack %1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () { +bb0(%0 : @owned $@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1): + br bb1 + +bb1: + %1 = alloc_stack $Builtin.Int1 + %2 = integer_literal $Builtin.Int1, 0 + %0c = copy_value %0 + apply %0c(%1, %1, %2) : $@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1 + dealloc_stack %1 : $*Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller3 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () { +bb0(%0 : @owned $@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1): + br bb1 + +bb1: + %1 = alloc_stack $Builtin.Int1 + %0c = copy_value %0 + apply %0c(%1, %1) : $@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1 + dealloc_stack %1 : $*Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller4 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> () { +bb0(%0 : @owned $@callee_owned () -> @out Builtin.Int1): + br bb1 + +bb1: + %1 = alloc_stack $Builtin.Int1 + %0c = copy_value %0 + apply %0c(%1) : $@callee_owned () -> @out Builtin.Int1 + dealloc_stack %1 : $*Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller5 : $@convention(thin) (@owned @callee_owned () -> ()) -> () { +bb0(%0 : @owned $@callee_owned () -> ()): + br bb1 + +bb1: + %0c = copy_value %0 + apply %0c() : $@callee_owned () -> () + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller6 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 { +bb0(%1 : $*Builtin.Int1, %0 : @owned $@callee_owned () -> @out Builtin.Int1): + br bb1 + +bb1: + %0c = copy_value %0 + apply %0c(%1) : $@callee_owned () -> @out Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +sil [ossa] @indirect_parameter_partial_apply_caller7 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) { +bb0(%1 : $*(Builtin.Int1, Builtin.Int1), %0 : @owned $@callee_owned () -> @out Builtin.Int1): + br bb1 + +bb1: + %2 = alloc_stack $Builtin.Int1 + %3 = alloc_stack $Builtin.Int1 + %0c = copy_value %0 + %0d = copy_value %0 + apply %0c(%2) : $@callee_owned () -> @out Builtin.Int1 + apply %0d(%3) : $@callee_owned () -> @out Builtin.Int1 + %4 = load [trivial] %2: $*Builtin.Int1 + %5 = load [trivial] %3: $*Builtin.Int1 + %6 = tuple(%4 : $Builtin.Int1, %5: $Builtin.Int1) + store %6 to [trivial] %1 : $*(Builtin.Int1, Builtin.Int1) + dealloc_stack %3: $*Builtin.Int1 + dealloc_stack %2: $*Builtin.Int1 + cond_br undef, bb2, bb3 + +bb2: + br bb1 + +bb3: + destroy_value %0 + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @loop_driver : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +// CHECK-DAG: [[SPECIALIZED_FUN:%.*]] = function_ref @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 +// CHECK: apply [[SPECIALIZED_FUN]] +// CHECK-DAG: [[SPECIALIZED_FUN2:%.*]] = function_ref @$s37simple_partial_apply_2nd_level_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 +// CHECK: apply [[SPECIALIZED_FUN2]] + +// We can't call this one b/c it is just a declaration. +// CHECK: [[UNSPECIALIZED_FUN_DECL:%.*]] = function_ref @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 +// CHECK: apply [[UNSPECIALIZED_FUN_DECL]] + +// We handle closures with indirect results. +// CHECK: [[CLOSUREFUN:%.*]] = function_ref @indirect_parameter_partial_apply_fun +// CHECK-NOT: partial_apply [[CLOSUREFUN]]() +// CHECK-NOT: partial_apply [[CLOSUREFUN]]() + +// We don't handle captured indirect @in and @in_guaranteed parameters yet. +// CHECK: [[CLOSURE2:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) +// CHECK: [[CLOSURE3:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) +// CHECK: [[CLOSURE4:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) + +// CHECK: [[CALLER1:%.*]] = function_ref @indirect_parameter_partial_apply_caller1 +// CHECK: [[CALLER2:%.*]] = function_ref @indirect_parameter_partial_apply_caller2 +// CHECK: [[CALLER3:%.*]] = function_ref @indirect_parameter_partial_apply_caller3 +// CHECK: [[CALLER4:%.*]] = function_ref @indirect_parameter_partial_apply_caller4 + +// Closure with indirect result but no captured indirect parameter. +// CHECK-NOT: apply [[CALLER1]] +// CHECK: [[INLINEDCLOSURE_CALLER1:%.*]] = function_ref @$s40indirect_parameter_partial_apply_caller10a1_b1_c1_D4_funTf1c_n +// CHECK: apply [[INLINEDCLOSURE_CALLER1]]() +// CHECK-NOT: apply [[CALLER1]] + +// Closures with captured indirect parameters. +// CHECK: apply [[CALLER2]]([[CLOSURE2]]) +// CHECK: apply [[CALLER3]]([[CLOSURE3]]) +// CHECK: apply [[CALLER4]]([[CLOSURE4]]) + +// CHECK: [[SM:%.*]] = function_ref @$s36simple_multiple_partial_apply_caller0a1_c1_D4_funBi1_ABBi1_Tf1cc_n : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 +// CHECK: apply [[SM]](%0, %0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + +// CHECK: } // end sil function 'loop_driver' +sil [ossa] @loop_driver : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { +bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1): + %2 = function_ref @simple_partial_apply_fun : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %3 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %4 = function_ref @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %3c = copy_value %3 + %5 = apply %4(%3c) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + + %51 = function_ref @simple_partial_apply_2nd_level_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %52 = apply %51(%3) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + + %6 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %7 = function_ref @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %8 = apply %7(%6) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + + %9 = alloc_stack $Builtin.Int1 + + %10 = function_ref @indirect_parameter_partial_apply_fun : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + %11 = partial_apply %10() : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + %12 = partial_apply %10(%9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + %13 = partial_apply %10(%1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + %14 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + + %16 = function_ref @indirect_parameter_partial_apply_caller1 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () + %17 = function_ref @indirect_parameter_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () + %18 = function_ref @indirect_parameter_partial_apply_caller3 : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () + %19 = function_ref @indirect_parameter_partial_apply_caller4 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> () + %20 = function_ref @indirect_parameter_partial_apply_caller5 : $@convention(thin) (@owned @callee_owned () -> ()) -> () + + apply %16(%11) : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () + apply %17(%12) : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () + apply %18(%13) : $@convention(thin) (@owned @callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () + apply %19(%14) : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> () + + // Make sure we handle when we already have an out parameter correctly. + %21 = alloc_stack $(Builtin.Int1, Builtin.Int1) + %22 = function_ref @indirect_parameter_partial_apply_caller6 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 + %23 = function_ref @indirect_parameter_partial_apply_caller7 : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) + %24 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + %25 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 + apply %22(%9, %24) : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 + apply %23(%21, %25) : $@convention(thin) (@owned @callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) + + dealloc_stack %21 : $*(Builtin.Int1, Builtin.Int1) + dealloc_stack %9 : $*Builtin.Int1 + + %26 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %27 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %28 = function_ref @simple_multiple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %29 = apply %28(%26, %27) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + + %30 = function_ref @simple_partial_apply_fun2 : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %31 = partial_apply %30(%1) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 + %32 = function_ref @simple_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %33 = apply %32(%31) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + + + %9999 = tuple() + return %9999 : $() +} + +sil @closure_with_string : $@convention(thin) (Builtin.Int1, @guaranteed String) -> Builtin.Int1 + +// CHECK-LABEL: sil [ossa] @test_multi_closure_with_string : +// CHECK: [[C:%.*]] = copy_value %0 +// CHECK: [[F:%.*]] = function_ref @$s36simple_multiple_partial_apply_caller19closure_with_stringSSTf1cC0_n : $@convention(thin) (@owned String) -> Builtin.Int1 +// CHECK: = apply [[F]]([[C]]) : $@convention(thin) (@owned String) -> Builtin.Int1 +// CHECK: } // end sil function 'test_multi_closure_with_string' +sil [ossa] @test_multi_closure_with_string : $@convention(thin) (@owned String) -> () { +bb0(%0 : @owned $String): + %2 = function_ref @closure_with_string : $@convention(thin) (Builtin.Int1, @guaranteed String) -> Builtin.Int1 + %26 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, @guaranteed String) -> Builtin.Int1 + %27 = copy_value %26 + %28 = function_ref @simple_multiple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %29 = apply %28(%26, %27) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 + %9999 = tuple() + return %9999 : $() +} + diff --git a/test/SILOptimizer/closure_specialize_and_cfg.sil b/test/SILOptimizer/closure_specialize_and_cfg.sil deleted file mode 100644 index 57ea03a553085..0000000000000 --- a/test/SILOptimizer/closure_specialize_and_cfg.sil +++ /dev/null @@ -1,49 +0,0 @@ -// RUN: %target-sil-opt -sil-verify-without-invalidation -enable-sil-verify-all -simplify-cfg -closure-specialize %s - -// Test if the ClosureSpecializer correctly invalidates the dominator tree -// even if there are no functions specialized. -// The test just checks if the compiler does not crash. -// First running SimplifyCFG creates the dominator tree, which should then be -// invalidated by the ClosureSpecializer. -// If this is not done correctly the verification will complain that the -// dominator tree is not up to date. - -import Builtin -import Swift - -sil @closure : $@convention(thin) () -> () - -sil @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> () - -sil hidden [noinline] @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> (), %1 : $@callee_owned () -> ()): - %2 = apply %0() : $@callee_owned () -> () - %3 = apply %1() : $@callee_owned () -> () - %4 = tuple () - return %3 : $() -} - -sil @insert_release_in_liverange_exit_block : $@convention(thin) () -> () { -bb0: - %2 = function_ref @closure : $@convention(thin) () -> () - %3 = partial_apply %2() : $@convention(thin) () -> () - %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> () - %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned () -> ()) -> () - - // There is a critical edge from bb0 to bb2 which is broken by ValueLifetimeAnalysis. - cond_br undef, bb2, bb1 - -bb1: - strong_retain %3 : $@callee_owned () -> () - strong_retain %3 : $@callee_owned () -> () - %10 = function_ref @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () - - // Passing two closures actually prevents closure specialization. - %17 = apply %10(%3, %3) : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () - br bb2 - -bb2: - strong_release %5 : $@callee_owned () -> () - %11 = tuple () - return %11 : $() -} diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_spec_and_inline.swift b/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_spec_and_inline.swift deleted file mode 100644 index de0c3b87511f3..0000000000000 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_spec_and_inline.swift +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %target-swift-frontend -parse-as-library -O -module-name=test -experimental-swift-based-closure-specialization %s -emit-sil | %FileCheck %s -// XFAIL: * - -func closure(_ a: Int, b: Int) -> Bool { - return a < b -} - -// Check that closure() is inlined into call_closure after call_closure is -// specialized for it. - -// CHECK-LABEL: sil shared [noinline] @$s4test12call_closureySbSi_SiSbSi_SitXEtF27$s4test7closure_1bSbSi_SitFTf1nnc_n -// CHECK-NOT: apply -// CHECK: builtin "cmp_slt_Int -// CHECK-NOT: apply -// CHECK: return -@inline(never) -func call_closure(_ a: Int, _ b: Int, _ f: (Int , Int) -> Bool) -> Bool { - return f(a, b) -} - -public func testit() -> Bool { - return call_closure(0, 1, closure) -} - diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_and_cfg.sil b/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_and_cfg.sil deleted file mode 100644 index b54d53662ced8..0000000000000 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_and_cfg.sil +++ /dev/null @@ -1,49 +0,0 @@ -// RUN: %target-sil-opt -sil-verify-without-invalidation -enable-sil-verify-all -simplify-cfg -experimental-swift-based-closure-specialization %s - -// Test if the ClosureSpecializer correctly invalidates the dominator tree -// even if there are no functions specialized. -// The test just checks if the compiler does not crash. -// First running SimplifyCFG creates the dominator tree, which should then be -// invalidated by the ClosureSpecializer. -// If this is not done correctly the verification will complain that the -// dominator tree is not up to date. - -import Builtin -import Swift - -sil @closure : $@convention(thin) () -> () - -sil @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> () - -sil hidden [noinline] @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> (), %1 : $@callee_owned () -> ()): - %2 = apply %0() : $@callee_owned () -> () - %3 = apply %1() : $@callee_owned () -> () - %4 = tuple () - return %3 : $() -} - -sil @insert_release_in_liferange_exit_block : $@convention(thin) () -> () { -bb0: - %2 = function_ref @closure : $@convention(thin) () -> () - %3 = partial_apply %2() : $@convention(thin) () -> () - %8 = function_ref @use_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> () - %5 = partial_apply %8(%3) : $@convention(thin) (@owned @callee_owned () -> ()) -> () - - // There is a critical edge from bb0 to bb2 which is broken by ValueLifetimeAnalysis. - cond_br undef, bb2, bb1 - -bb1: - strong_retain %3 : $@callee_owned () -> () - strong_retain %3 : $@callee_owned () -> () - %10 = function_ref @use_closure2 : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () - - // Passing two closures actually prevents closure specialization. - %17 = apply %10(%3, %3) : $@convention(thin) (@owned @callee_owned () -> (), @owned @callee_owned () -> ()) -> () - br bb2 - -bb2: - strong_release %5 : $@callee_owned () -> () - %11 = tuple () - return %11 : $() -} diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_dynamic_self.swift b/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_dynamic_self.swift deleted file mode 100644 index 4e304127aa1f6..0000000000000 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_dynamic_self.swift +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %target-swift-frontend -emit-sil -O -experimental-swift-based-closure-specialization -primary-file %s - -// Just make sure we skip the optimization and not crash here. -// -// Eventually, we can make this work. -// -// - -class Foo { - required init() {} - - static func foo(_ f: () -> ()) -> Self { - f() - return self.init() - } -} - -class Bar: Foo {} - -func closures(_ x: String) { - print(Foo.foo { _ = x }) - print(Bar.foo { _ = x }) -} diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_loop.swift b/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_loop.swift deleted file mode 100644 index a5eb9a228e660..0000000000000 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_loop.swift +++ /dev/null @@ -1,81 +0,0 @@ -// RUN: %{python} %S/../Inputs/timeout.py 10 %target-swift-frontend -O -parse-as-library -experimental-swift-based-closure-specialization %s -emit-sil | %FileCheck %s -// XFAIL: * -public func callit() { - testit { false } -} - -// Check if the compiler terminates and does not full into an infinite optimization -// loop between the ClosureSpecializer and CapturePropagation. - -// CHECK-LABEL: sil @$s23closure_specialize_loop6testit1cySbyc_tF -public func testit(c: @escaping () -> Bool) { - if c() { - testit { !c() } - } -} - -// PR: https://github.com/apple/swift/pull/61956 -// Optimizing Expression.contains(where:) should not timeout. -// -// Repeated capture propagation leads to: -// func contains$termPred@arg0$[termPred$falsePred@arg1]@arg1(expr) { -// closure = termPred$[termPred$falsePred@arg1]@arg1 -// falsePred(expr) -// contains$termPred@arg0$termPred$[termPred$falsePred@arg1]@arg1(expr) -// } -// -// func contains$termPred@arg0$termPred$[termPred$falsePred@arg1]@arg1(expr) { -// closure = [termPred(termPred$[termPred$falsePred@arg1]@arg1)] -// closure(expr) -// contains$termPred@arg0(expr, closure) -// } -// The Demangled type tree looks like: -// kind=FunctionSignatureSpecialization -// kind=SpecializationPassID, index=3 -// kind=FunctionSignatureSpecializationParam -// kind=FunctionSignatureSpecializationParam -// kind=FunctionSignatureSpecializationParamKind, index=0 -// kind=FunctionSignatureSpecializationParamPayload, text="$s4test10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_36$s4test12IndirectEnumVACycfcS2bXEfU_Tf3npf_n" -// -// CHECK-LABEL: $s23closure_specialize_loop10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_012$s23closure_b7_loop10d44O8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_012g13_b7_loop10d44ijk2_tlm2U_no52U_012g30_B34_loop12IndirectEnumVACycfcnO10U_Tf3npf_nY2_nTf3npf_n -// ---> function signature specialization -// Swift.Bool -// in closure_specialize_loop.IndirectEnum.init() -> closure_specialize_loop.IndirectEnum]> -// of closure #1 (Swift.Bool) -> Swift.Bool -// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool -// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool]> -// of closure #1 (Swift.Bool) -> Swift.Bool -// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool -// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool]> -// of closure #1 (Swift.Bool) -> Swift.Bool -// in closure #1 (closure_specialize_loop.Expression) -> Swift.Bool -// in closure_specialize_loop.Expression.contains(where: (Swift.Bool) -> Swift.Bool) -> Swift.Bool -// -public indirect enum Expression { - case term(Bool) - case list(_ expressions: [Expression]) - - public func contains(where predicate: (Bool) -> Bool) -> Bool { - switch self { - case let .term(term): - return predicate(term) - case let .list(expressions): - return expressions.contains { expression in - expression.contains { term in - predicate(term) - } - } - } - } -} - -public struct IndirectEnum { - public init() { - let containsFalse = Expression.list([.list([.term(true), .term(false)]), .term(true)]).contains { term in - term == false - } - print(containsFalse) - } -} diff --git a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_simple.sil b/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_simple.sil deleted file mode 100644 index 42d91710ae3db..0000000000000 --- a/test/SILOptimizer/experimental-swift-based-closure-specialization/closure_specialize_simple.sil +++ /dev/null @@ -1,292 +0,0 @@ -// RUN: %target-sil-opt -enable-sil-verify-all -experimental-swift-based-closure-specialization %s | %FileCheck %s -// XFAIL: * - -import Builtin -import Swift - -sil @simple_partial_apply_fun : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - -// CHECK-LABEL: sil shared @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 { -// CHECK: bb0([[CAPTURED_ARG:%.*]] : $Builtin.Int1): -// CHECK: [[CLOSED_OVER_FUN:%.*]] = function_ref @simple_partial_apply_fun : -// CHECK: [[NEW_PAI:%.*]] = partial_apply [[CLOSED_OVER_FUN]] -// CHECK: strong_release [[NEW_PAI]] -sil @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { -bb0(%0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1): - br bb1 - -bb1: - %1 = integer_literal $Builtin.Int1, 0 - // We cannot do anything here for now but in the future I think we should try - // to handle this in closure specialization potentially. - %2 = apply %0(%1) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - strong_release %0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - return %2 : $Builtin.Int1 -} - -// CHECK-LABEL: sil shared @$s37simple_partial_apply_2nd_level_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 { -// CHECK: bb0([[CAPTURED_ARG:%.*]] : $Builtin.Int1): -// CHECK: [[SPECIALIZED_CALLEE:%.*]] = function_ref @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : -// CHECK: [[RET:%.*]]= apply [[SPECIALIZED_CALLEE]]([[CAPTURED_ARG]]) -// CHECK: return [[RET]] -sil @simple_partial_apply_2nd_level_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { -bb0(%0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1): - br bb1 - -bb1: - %1 = function_ref @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %2 = apply %1(%0) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - return %2 : $Builtin.Int1 -} -sil @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - -sil @simple_multiple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { -bb0(%0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1, %1 : $@callee_owned (Builtin.Int1) -> Builtin.Int1): - br bb1 - -bb1: - %2 = integer_literal $Builtin.Int1, 0 - // We cannot do anything here for now but in the future I think we should try - // to handle this in closure specialization potentially. - apply %0(%2) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - strong_release %0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - apply %1(%2) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - strong_release %1 : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - return %2 : $Builtin.Int1 -} - -sil @simple_partial_apply_fun2 : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 -sil @simple_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 { -bb0(%0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1): - br bb1 - -bb1: - %1 = integer_literal $Builtin.Int1, 0 - // We cannot do anything here for now but in the future I think we should try - // to handle this in closure specialization potentially. - %2 = apply %0(%1) : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - strong_release %0 : $@callee_owned (Builtin.Int1) -> Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - return %2 : $Builtin.Int1 -} - - -sil @indirect_parameter_partial_apply_fun : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - -sil @indirect_parameter_partial_apply_caller1 : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () { -bb0(%0 : $@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1): - br bb1 - -bb1: - %1 = alloc_stack $Builtin.Int1 - %2 = integer_literal $Builtin.Int1, 0 - apply %0(%1, %1, %2, %1) : $@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - dealloc_stack %1 : $*Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller2 : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () { -bb0(%0 : $@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1): - br bb1 - -bb1: - %1 = alloc_stack $Builtin.Int1 - %2 = integer_literal $Builtin.Int1, 0 - apply %0(%1, %1, %2) : $@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1 - dealloc_stack %1 : $*Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller3 : $@convention(thin) (@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () { -bb0(%0 : $@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1): - br bb1 - -bb1: - %1 = alloc_stack $Builtin.Int1 - apply %0(%1, %1) : $@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1 - dealloc_stack %1 : $*Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller4 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> () { -bb0(%0 : $@callee_owned () -> @out Builtin.Int1): - br bb1 - -bb1: - %1 = alloc_stack $Builtin.Int1 - apply %0(%1) : $@callee_owned () -> @out Builtin.Int1 - dealloc_stack %1 : $*Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller5 : $@convention(thin) (@callee_owned () -> ()) -> () { -bb0(%0 : $@callee_owned () -> ()): - br bb1 - -bb1: - apply %0() : $@callee_owned () -> () - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller6 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 { -bb0(%1 : $*Builtin.Int1, %0 : $@callee_owned () -> @out Builtin.Int1): - br bb1 - -bb1: - apply %0(%1) : $@callee_owned () -> @out Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -sil @indirect_parameter_partial_apply_caller7 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) { -bb0(%1 : $*(Builtin.Int1, Builtin.Int1), %0 : $@callee_owned () -> @out Builtin.Int1): - br bb1 - -bb1: - %2 = alloc_stack $Builtin.Int1 - %3 = alloc_stack $Builtin.Int1 - apply %0(%2) : $@callee_owned () -> @out Builtin.Int1 - apply %0(%3) : $@callee_owned () -> @out Builtin.Int1 - %4 = load %2: $*Builtin.Int1 - %5 = load %3: $*Builtin.Int1 - %6 = tuple(%4 : $Builtin.Int1, %5: $Builtin.Int1) - store %6 to %1 : $*(Builtin.Int1, Builtin.Int1) - dealloc_stack %3: $*Builtin.Int1 - dealloc_stack %2: $*Builtin.Int1 - cond_br undef, bb1, bb2 - -bb2: - %9999 = tuple() - return %9999 : $() -} - -// CHECK-LABEL: sil @loop_driver : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { -// CHECK-DAG: [[SPECIALIZED_FUN:%.*]] = function_ref @$s27simple_partial_apply_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 -// CHECK-DAG: [[SPECIALIZED_FUN2:%.*]] = function_ref @$s37simple_partial_apply_2nd_level_caller0a1_b1_C4_funBi1_Tf1c_n : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 -// CHECK: apply [[SPECIALIZED_FUN]] -// CHECK: apply [[SPECIALIZED_FUN2]] - -// We can't call this one b/c it is just a declaration. -// CHECK: [[UNSPECIALIZED_FUN_DECL:%.*]] = function_ref @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 -// CHECK: apply [[UNSPECIALIZED_FUN_DECL]] - -// We handle closures with indirect results. -// CHECK: [[CLOSUREFUN:%.*]] = function_ref @indirect_parameter_partial_apply_fun -// CHECK-NOT: partial_apply [[CLOSUREFUN]]() -// CHECK: [[INLINEDCLOSURE_CALLER1:%.*]] = function_ref @$s40indirect_parameter_partial_apply_caller10a1_b1_c1_D4_funTf1c_n -// CHECK-NOT: partial_apply [[CLOSUREFUN]]() - -// We don't handle captured indirect @in and @in_guaranteed parameters yet. -// CHECK: [[CLOSURE2:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) -// CHECK: [[CLOSURE3:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) -// CHECK: [[CLOSURE4:%.*]] = partial_apply [[CLOSUREFUN]](%{{.*}}) - -// CHECK: [[CALLER1:%.*]] = function_ref @indirect_parameter_partial_apply_caller1 -// CHECK: [[CALLER2:%.*]] = function_ref @indirect_parameter_partial_apply_caller2 -// CHECK: [[CALLER3:%.*]] = function_ref @indirect_parameter_partial_apply_caller3 -// CHECK: [[CALLER4:%.*]] = function_ref @indirect_parameter_partial_apply_caller4 - -// Closure with indirect result but no captured indirect parameter. -// CHECK-NOT: apply [[CALLER1]] -// apply [[INLINEDCLOSURE_CALLER1]]() -// CHECK-NOT: apply [[CALLER1]] - -// Closures with captured indirect parameters. -// apply [[CALLER2]]([[CLOSURE2]]) -// apply [[CALLER3]]([[CLOSURE3]]) -// apply [[CALLER4]]([[CLOSURE4]]) - -// CHECK: return -sil @loop_driver : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () { -bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1): - %2 = function_ref @simple_partial_apply_fun : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %3 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %4 = function_ref @simple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %5 = apply %4(%3) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - - %51 = function_ref @simple_partial_apply_2nd_level_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %52 = apply %51(%3) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - - %6 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %7 = function_ref @simple_partial_apply_caller_decl : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %8 = apply %7(%6) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - - %9 = alloc_stack $Builtin.Int1 - - %10 = function_ref @indirect_parameter_partial_apply_fun : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - %11 = partial_apply %10() : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - %12 = partial_apply %10(%9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - %13 = partial_apply %10(%1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - %14 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - - %16 = function_ref @indirect_parameter_partial_apply_caller1 : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () - %17 = function_ref @indirect_parameter_partial_apply_caller2 : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () - %18 = function_ref @indirect_parameter_partial_apply_caller3 : $@convention(thin) (@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () - %19 = function_ref @indirect_parameter_partial_apply_caller4 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> () - %20 = function_ref @indirect_parameter_partial_apply_caller5 : $@convention(thin) (@callee_owned () -> ()) -> () - - apply %16(%11) : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1) -> () - apply %17(%12) : $@convention(thin) (@callee_owned (@in Builtin.Int1, Builtin.Int1) -> @out Builtin.Int1) -> () - apply %18(%13) : $@convention(thin) (@callee_owned (@in Builtin.Int1) -> @out Builtin.Int1) -> () - apply %19(%14) : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> () - - // Make sure we handle when we already have an out parameter correctly. - %21 = alloc_stack $(Builtin.Int1, Builtin.Int1) - %22 = function_ref @indirect_parameter_partial_apply_caller6 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 - %23 = function_ref @indirect_parameter_partial_apply_caller7 : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) - %24 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - %25 = partial_apply %10(%9, %1, %9) : $@convention(thin) (@in Builtin.Int1, Builtin.Int1, @in Builtin.Int1) -> @out Builtin.Int1 - apply %22(%9, %24) : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out Builtin.Int1 - apply %23(%21, %25) : $@convention(thin) (@callee_owned () -> @out Builtin.Int1) -> @out (Builtin.Int1, Builtin.Int1) - - dealloc_stack %21 : $*(Builtin.Int1, Builtin.Int1) - dealloc_stack %9 : $*Builtin.Int1 - - %26 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %27 = partial_apply %2(%0) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %28 = function_ref @simple_multiple_partial_apply_caller : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %29 = apply %28(%26, %27) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1, @owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - - %30 = function_ref @simple_partial_apply_fun2 : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %31 = partial_apply %30(%1) : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 - %32 = function_ref @simple_partial_apply_caller2 : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - %33 = apply %32(%31) : $@convention(thin) (@owned @callee_owned (Builtin.Int1) -> Builtin.Int1) -> Builtin.Int1 - - - %9999 = tuple() - return %9999 : $() -} \ No newline at end of file From 259bf65fc95348317fe7f4034d79521bb1a8ee47 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 20:44:53 +0200 Subject: [PATCH 09/10] SIL: remove the now unused `SILFunctionType_isTrivialNoescape` bridging function --- include/swift/SIL/SILBridging.h | 2 -- include/swift/SIL/SILBridgingImpl.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index e2a75e09139df..e162787a5bf2f 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -243,8 +243,6 @@ BridgedParameterInfoArray SILFunctionType_getParameters(BridgedCanType); BRIDGED_INLINE bool SILFunctionType_hasSelfParam(BridgedCanType); -BRIDGED_INLINE bool SILFunctionType_isTrivialNoescape(BridgedCanType); - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedYieldInfoArray SILFunctionType_getYields(BridgedCanType); diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index 6eb30038e1ea0..a7e64961f5942 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -260,10 +260,6 @@ bool SILFunctionType_hasSelfParam(BridgedCanType funcTy) { return funcTy.unbridged()->castTo()->hasSelfParam(); } -bool SILFunctionType_isTrivialNoescape(BridgedCanType funcTy) { - return funcTy.unbridged()->castTo()->isTrivialNoEscape(); -} - BridgedYieldInfoArray SILFunctionType_getYields(BridgedCanType funcTy) { return {funcTy.unbridged()->castTo()->getYields()}; } From 8efafc7e3b3fef094788c4b748a53722420c7741 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Sun, 5 Oct 2025 20:45:38 +0200 Subject: [PATCH 10/10] Optimizer: remove the `-experimental-swift-based-closure-specialization` option --- include/swift/AST/SILOptions.h | 4 ---- include/swift/Option/FrontendOptions.td | 4 ---- lib/Frontend/CompilerInvocation.cpp | 3 --- lib/SILOptimizer/PassManager/PassPipeline.cpp | 8 ++------ 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 0d365e66fdeaf..da8e88772a59d 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -303,10 +303,6 @@ class SILOptions { /// Are we building in embedded Swift + -no-allocations? bool NoAllocations = false; - /// Should we use the experimental Swift based closure-specialization - /// optimization pass instead of the existing C++ one. - bool EnableExperimentalSwiftBasedClosureSpecialization = false; - /// The name of the file to which the backend should save optimization /// records. std::string OptRecordFile; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 3d034ee45263c..fd89aa7ccc436 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -393,10 +393,6 @@ def public_autolink_library : // HIDDEN FLAGS let Flags = [FrontendOption, NoDriverOption, HelpHidden] in { -def enable_experimental_swift_based_closure_specialization : - Flag<["-"], "experimental-swift-based-closure-specialization">, - HelpText<"Use the experimental Swift based closure-specialization optimization pass instead of the existing C++ one">; - def checked_async_objc_bridging : Joined<["-"], "checked-async-objc-bridging=">, HelpText<"Control whether checked continuations are used when bridging " "async calls from Swift to ObjC: 'on', 'off' ">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index ab67d57abfda6..cbe2ba40e579a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -3226,9 +3226,6 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.NoAllocations = Args.hasArg(OPT_no_allocations); - Opts.EnableExperimentalSwiftBasedClosureSpecialization = - Args.hasArg(OPT_enable_experimental_swift_based_closure_specialization); - // If these optimizations are enabled never preserve functions for the // debugger. Opts.ShouldFunctionsBePreservedToDebugger = diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 10ff5814b79a1..3d08efc8bf489 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -789,12 +789,8 @@ static void addClosureSpecializePassPipeline(SILPassPipelinePlan &P) { // take advantage of static dispatch. P.addConstantCapturePropagation(); - // Specialize closure. - if (P.getOptions().EnableExperimentalSwiftBasedClosureSpecialization) { - P.addExperimentalSwiftBasedClosureSpecialization(); - } else { - P.addClosureSpecializer(); - } + // TODO: replace this with the new ClosureSpecialization pass once we have OSSA at this point in the pipeline + P.addClosureSpecializer(); // Do the second stack promotion on low-level SIL. P.addStackPromotion();