From 6f0f9db7fe7d3520a97b51bc0147d4fc678df1fa Mon Sep 17 00:00:00 2001 From: Dario Rexin Date: Thu, 11 Dec 2025 13:40:18 -0800 Subject: [PATCH] [SILOpt] Don't apply `@_specialize` attribute to ObjC methods rdar://164200332 The specialization should only apply to the Swift version of the method, which gets called by the ObjC version anyway, so the specialization is still in effect. --- lib/SIL/IR/SILFunctionBuilder.cpp | 82 ++++++++++--------- .../Inputs/NoObjCSpecialization.h | 14 ++++ .../SILOptimizer/no_objc_specialization.swift | 25 ++++++ 3 files changed, 82 insertions(+), 39 deletions(-) create mode 100644 test/SILOptimizer/Inputs/NoObjCSpecialization.h create mode 100644 test/SILOptimizer/no_objc_specialization.swift diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index f261d44280406..c8f9a1fbe4941 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -66,46 +66,50 @@ void SILFunctionBuilder::addFunctionAttributes( M.getOptions().EnableGlobalAssemblyVision) F->addSemanticsAttr(semantics::FORCE_EMIT_OPT_REMARK_PREFIX); - // Propagate @_specialize. - for (auto *A : Attrs.getAttributes()) { - auto *SA = cast(A); - auto kind = - SA->getSpecializationKind() == SpecializeAttr::SpecializationKind::Full - ? SILSpecializeAttr::SpecializationKind::Full - : SILSpecializeAttr::SpecializationKind::Partial; - assert(!constant.isNull()); - SILFunction *targetFunction = nullptr; - auto *attributedFuncDecl = constant.getAbstractFunctionDecl(); - auto *targetFunctionDecl = SA->getTargetFunctionDecl(attributedFuncDecl); - // Filter out _spi. - auto spiGroups = SA->getSPIGroups(); - bool hasSPI = !spiGroups.empty(); - if (hasSPI) { - if (attributedFuncDecl->getModuleContext() != M.getSwiftModule() && - !M.getSwiftModule()->isImportedAsSPI(SA, attributedFuncDecl)) { - continue; + if (F->getRepresentation() != SILFunctionTypeRepresentation::ObjCMethod) { + // Propagate @_specialize. + for (auto *A : Attrs.getAttributes()) { + auto *SA = cast(A); + auto kind = SA->getSpecializationKind() == + SpecializeAttr::SpecializationKind::Full + ? SILSpecializeAttr::SpecializationKind::Full + : SILSpecializeAttr::SpecializationKind::Partial; + assert(!constant.isNull()); + SILFunction *targetFunction = nullptr; + auto *attributedFuncDecl = constant.getAbstractFunctionDecl(); + auto *targetFunctionDecl = SA->getTargetFunctionDecl(attributedFuncDecl); + // Filter out _spi. + auto spiGroups = SA->getSPIGroups(); + bool hasSPI = !spiGroups.empty(); + if (hasSPI) { + if (attributedFuncDecl->getModuleContext() != M.getSwiftModule() && + !M.getSwiftModule()->isImportedAsSPI(SA, attributedFuncDecl)) { + continue; + } + } + assert(spiGroups.size() <= 1 && + "SIL does not support multiple SPI groups"); + Identifier spiGroupIdent; + if (hasSPI) { + spiGroupIdent = spiGroups[0]; + } + auto availability = AvailabilityInference::annotatedAvailableRangeForAttr( + attributedFuncDecl, SA, M.getSwiftModule()->getASTContext()); + auto specializedSignature = + SA->getSpecializedSignature(attributedFuncDecl); + if (targetFunctionDecl) { + SILDeclRef declRef(targetFunctionDecl, constant.kind, false); + targetFunction = getOrCreateDeclaration(targetFunctionDecl, declRef); + F->addSpecializeAttr(SILSpecializeAttr::create( + M, specializedSignature, SA->getTypeErasedParams(), + SA->isExported(), kind, targetFunction, spiGroupIdent, + attributedFuncDecl->getModuleContext(), availability)); + } else { + F->addSpecializeAttr(SILSpecializeAttr::create( + M, specializedSignature, SA->getTypeErasedParams(), + SA->isExported(), kind, nullptr, spiGroupIdent, + attributedFuncDecl->getModuleContext(), availability)); } - } - assert(spiGroups.size() <= 1 && "SIL does not support multiple SPI groups"); - Identifier spiGroupIdent; - if (hasSPI) { - spiGroupIdent = spiGroups[0]; - } - auto availability = AvailabilityInference::annotatedAvailableRangeForAttr( - attributedFuncDecl, SA, M.getSwiftModule()->getASTContext()); - auto specializedSignature = SA->getSpecializedSignature(attributedFuncDecl); - if (targetFunctionDecl) { - SILDeclRef declRef(targetFunctionDecl, constant.kind, false); - targetFunction = getOrCreateDeclaration(targetFunctionDecl, declRef); - F->addSpecializeAttr(SILSpecializeAttr::create( - M, specializedSignature, SA->getTypeErasedParams(), - SA->isExported(), kind, targetFunction, spiGroupIdent, - attributedFuncDecl->getModuleContext(), availability)); - } else { - F->addSpecializeAttr(SILSpecializeAttr::create( - M, specializedSignature, SA->getTypeErasedParams(), - SA->isExported(), kind, nullptr, spiGroupIdent, - attributedFuncDecl->getModuleContext(), availability)); } } diff --git a/test/SILOptimizer/Inputs/NoObjCSpecialization.h b/test/SILOptimizer/Inputs/NoObjCSpecialization.h new file mode 100644 index 0000000000000..7aa6f00111cfe --- /dev/null +++ b/test/SILOptimizer/Inputs/NoObjCSpecialization.h @@ -0,0 +1,14 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +extern __attribute__((visibility("default"))) +@protocol NoObjCSpecialization + +- (BOOL)fooWithValue:(id)value + andBool:(BOOL)boolValue + error:(NSError *_Nullable *)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/test/SILOptimizer/no_objc_specialization.swift b/test/SILOptimizer/no_objc_specialization.swift new file mode 100644 index 0000000000000..92722fc381bc0 --- /dev/null +++ b/test/SILOptimizer/no_objc_specialization.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-frontend -import-objc-header %S/Inputs/NoObjCSpecialization.h -O -emit-sil %s | %FileCheck %s + +// REQUIRES: objc_interop + +import Foundation + +final class NoObjCSpecializationImpl: NSObject, NoObjCSpecialization { + + // CHECK-NOT: @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFToyt_Tg5 : $@convention(objc_method) + // CHECK-LABEL: sil private [thunk] @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFTo : $@convention(objc_method) + // CHECK: [[FUNC:%.*]] = function_ref @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFTf4nnd_n : $@convention(thin) <τ_0_0> (@in_guaranteed Any, Bool) -> @error any Error + // CHECK: try_apply [[FUNC]]({{%.*}}, {{%.*}}) : $@convention(thin) <τ_0_0> (@in_guaranteed Any, Bool) -> @error any Error + // CHECK-LABEL: sil shared @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFyt_Tg5Tf4nnd_n : $@convention(thin) (@in_guaranteed Any, Bool) -> @error any Error { + // CHECK-LABEL: sil shared @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFTf4nnd_n : $@convention(thin) (@in_guaranteed Any, Bool) -> @error any Error { + // CHECK: [[FUNC:%.*]] = function_ref @$s22no_objc_specialization24NoObjCSpecializationImplC3foo9withValue7andBoolyyp_SbtKFyt_Tg5Tf4nnd_n : $@convention(thin) (@in_guaranteed Any, Bool) -> @error any Error + // CHECK: apply [nothrow] [[FUNC]]({{%.*}}, {{%.*}}) : $@convention(thin) (@in_guaranteed Any, Bool) -> @error any Error + @_specialize(where Value == Void) + func foo(withValue value: Any, andBool bool: Bool) throws { + if Value.self == Void.self { + print("Is Void with \(bool)") + } else { + print("Is \(value) with \(bool)") + } + } +}