From 86b599b007dff62e7de13f23c4033132754b10ea Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Thu, 16 Oct 2025 10:52:49 +0300 Subject: [PATCH 1/2] [AutoDiff] Run closure spec only if ownership info is present in pullback Calling `cloneRecursively` from `SpecializationInfo.cloneClosures` requires the pullback having ownership info. Otherwise, the cloner uses `recordFoldedValue` instead of `recordClonedInstruction`, and `postProcess` hook is not called, which leads to an assertion failure in `BridgedClonerImpl::cloneInst`. TODO: investigate why the assertion fails only on Linux. See: * https://github.com/swiftlang/swift/pull/84800#issuecomment-3398200989 * https://github.com/swiftlang/swift/issues/84955 --- .../FunctionPasses/ClosureSpecialization.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index b8dbafcb12afa..de07fbfba2101 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -166,7 +166,16 @@ let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-special var changed = false for inst in function.instructions { if let partialApply = inst as? PartialApplyInst, - partialApply.isPullbackInResultOfAutodiffVJP + partialApply.isPullbackInResultOfAutodiffVJP, + // Calling `cloneRecursively` from `SpecializationInfo.cloneClosures` + // requires the pullback having ownership info. Otherwise, the cloner + // uses `recordFoldedValue` instead of `recordClonedInstruction`, and + // `postProcess` hook is not called, which leads to an assertion + // failure in `BridgedClonerImpl::cloneInst`. + // TODO: investigate why the assertion fails only on Linux. See + // * https://github.com/swiftlang/swift/pull/84800#issuecomment-3398200989 + // * https://github.com/swiftlang/swift/issues/84955 + partialApply.referencedFunction?.hasOwnership == true { if trySpecialize(apply: partialApply, context) { changed = true From 93169c183e0f4dfca8b6f8df365087198028bcc1 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Thu, 16 Oct 2025 13:40:41 +0300 Subject: [PATCH 2/2] Address review comments --- .../FunctionPasses/ClosureSpecialization.swift | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index de07fbfba2101..aabfc62369030 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -166,16 +166,7 @@ let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-special var changed = false for inst in function.instructions { if let partialApply = inst as? PartialApplyInst, - partialApply.isPullbackInResultOfAutodiffVJP, - // Calling `cloneRecursively` from `SpecializationInfo.cloneClosures` - // requires the pullback having ownership info. Otherwise, the cloner - // uses `recordFoldedValue` instead of `recordClonedInstruction`, and - // `postProcess` hook is not called, which leads to an assertion - // failure in `BridgedClonerImpl::cloneInst`. - // TODO: investigate why the assertion fails only on Linux. See - // * https://github.com/swiftlang/swift/pull/84800#issuecomment-3398200989 - // * https://github.com/swiftlang/swift/issues/84955 - partialApply.referencedFunction?.hasOwnership == true + partialApply.isPullbackInResultOfAutodiffVJP { if trySpecialize(apply: partialApply, context) { changed = true @@ -233,6 +224,13 @@ private func isCalleeSpecializable(of apply: ApplySite) -> Bool { if let callee = apply.referencedFunction, callee.isDefinition, + // Calling `cloneRecursively` from `SpecializationInfo.cloneClosures` + // requires the callee having ownership info. Otherwise, the cloner + // uses `recordFoldedValue` instead of `recordClonedInstruction`, and + // `postProcess` hook is not called, which leads to an assertion + // failure in `BridgedClonerImpl::cloneInst`. + callee.hasOwnership, + // We don't support generic functions (yet) !apply.hasSubstitutions,