diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index be811c64ebf6d..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,261 +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: $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/FunctionPasses/ConstantCapturePropagation.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ConstantCapturePropagation.swift index 30173df36a0f1..1f3abb6e6b1f1 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) } @@ -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/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/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/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/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/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 1dcedbd60049a..801c0fbf2ce9a 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 @@ -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) 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/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/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) 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/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/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/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/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/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 4384c1132fcff..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); @@ -816,6 +814,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 +1229,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, @@ -1545,6 +1547,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/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index e5c031d7fbf45..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()}; } @@ -1349,6 +1345,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 +2305,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())}; 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 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/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/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/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); + } } } 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/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/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()) }; } diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index b7d857433be29..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(); @@ -1034,10 +1030,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/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/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/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 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