Skip to content

Commit 9a1a2c3

Browse files
authored
Merge pull request #64644 from tshortli/strip-unavailable-code
Introduce `-unavailable-decl-optimization`
2 parents d9b7ddc + 98b4e79 commit 9a1a2c3

File tree

14 files changed

+512
-4
lines changed

14 files changed

+512
-4
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ namespace swift {
105105
TaskToThread,
106106
};
107107

108+
/// Describes the code size optimization behavior for code associated with
109+
/// declarations that are marked unavailable.
110+
enum class UnavailableDeclOptimization : uint8_t {
111+
/// No optimization. Unavailable declarations will contribute to the
112+
/// resulting binary by default in this mode.
113+
None,
114+
115+
/// Avoid generating any code for unavailable declarations.
116+
///
117+
/// NOTE: This optimization can be ABI breaking for a library evolution
118+
/// enabled module because existing client binaries built with a
119+
/// pre-Swift 5.9 compiler may depend on linkable symbols associated with
120+
/// unavailable declarations.
121+
Complete,
122+
};
123+
108124
/// A collection of options that affect the language dialect and
109125
/// provide compiler debugging facilities.
110126
class LangOptions final {
@@ -171,6 +187,10 @@ namespace swift {
171187
/// Disable API availability checking.
172188
bool DisableAvailabilityChecking = false;
173189

190+
/// Optimization mode for unavailable declarations.
191+
UnavailableDeclOptimization UnavailableDeclOptimizationMode =
192+
UnavailableDeclOptimization::None;
193+
174194
/// Causes the compiler to use weak linkage for symbols belonging to
175195
/// declarations introduced at the deployment target.
176196
bool WeakLinkAtTarget = false;

include/swift/Option/Options.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,13 @@ def check_api_availability_only : Flag<["-"], "check-api-availability-only">,
490490
Flags<[HelpHidden, FrontendOption, NoInteractiveOption]>,
491491
HelpText<"Deprecated, has no effect">;
492492

493+
def unavailable_decl_optimization_EQ : Joined<["-"], "unavailable-decl-optimization=">,
494+
MetaVarName<"<complete,none>">,
495+
Flags<[FrontendOption, NoInteractiveOption]>,
496+
HelpText<"Specify the optimization mode for unavailable declarations. The "
497+
"value may be 'none' (no optimization) or 'complete' (code is not "
498+
"generated at all unavailable declarations)">;
499+
493500
def library_level : Separate<["-"], "library-level">,
494501
MetaVarName<"<level>">,
495502
Flags<[HelpHidden, FrontendOption, ModuleInterfaceOption]>,

include/swift/SIL/SILModule.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,22 @@ namespace Lowering {
10781078
/// Determine whether the given class will be allocated/deallocated using the
10791079
/// Objective-C runtime, i.e., +alloc and -dealloc.
10801080
LLVM_LIBRARY_VISIBILITY bool usesObjCAllocator(ClassDecl *theClass);
1081+
1082+
/// Returns true if SIL/IR lowering for the given declaration should be skipped.
1083+
/// A declaration may not require lowering if, for example, it is annotated as
1084+
/// unavailable and optimization settings allow it to be omitted.
1085+
LLVM_LIBRARY_VISIBILITY bool shouldSkipLowering(Decl *D);
10811086
} // namespace Lowering
10821087

1088+
/// Apply the given function to each ABI member of \c D skipping the members
1089+
/// that should be skipped according to \c shouldSkipLowering()
1090+
template <typename F>
1091+
void forEachMemberToLower(IterableDeclContext *D, F &&f) {
1092+
for (auto *member : D->getABIMembers()) {
1093+
if (!Lowering::shouldSkipLowering(member))
1094+
f(member);
1095+
}
1096+
}
10831097
} // namespace swift
10841098

10851099
#endif

include/swift/SIL/SILVTableVisitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,9 @@ template <class T> class SILVTableVisitor {
141141
if (!theClass->hasKnownSwiftImplementation())
142142
return;
143143

144-
for (auto member : theClass->getABIMembers())
144+
forEachMemberToLower(theClass, [&](Decl *member) {
145145
maybeAddMember(member);
146+
});
146147
}
147148
};
148149

lib/AST/Availability.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ AvailabilityInference::parentDeclForInferredAvailability(const Decl *D) {
181181
return NTD;
182182
}
183183

184+
if (auto *PBD = dyn_cast<PatternBindingDecl>(D))
185+
return PBD->getAnchoringVarDecl(0);
186+
184187
// Clang decls may be inaccurately parented rdar://53956555
185188
if (D->hasClangNode())
186189
return nullptr;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,20 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
552552
Diags.diagnose(SourceLoc(), diag::warn_flag_deprecated,
553553
"-check-api-availability-only");
554554

555+
if (const Arg *A = Args.getLastArg(OPT_unavailable_decl_optimization_EQ)) {
556+
auto value =
557+
llvm::StringSwitch<Optional<UnavailableDeclOptimization>>(A->getValue())
558+
.Case("none", UnavailableDeclOptimization::None)
559+
.Case("complete", UnavailableDeclOptimization::Complete)
560+
.Default(None);
561+
562+
if (value)
563+
Opts.UnavailableDeclOptimizationMode = *value;
564+
else
565+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
566+
A->getAsString(Args), A->getValue());
567+
}
568+
555569
Opts.WeakLinkAtTarget |= Args.hasArg(OPT_weak_link_at_target);
556570

557571
if (auto A = Args.getLastArg(OPT_enable_conformance_availability_errors,

lib/IRGen/GenDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,9 +2458,13 @@ void swift::irgen::disableAddressSanitizer(IRGenModule &IGM, llvm::GlobalVariabl
24582458

24592459
/// Emit a global declaration.
24602460
void IRGenModule::emitGlobalDecl(Decl *D) {
2461+
if (Lowering::shouldSkipLowering(D))
2462+
return;
2463+
24612464
D->visitAuxiliaryDecls([&](Decl *decl) {
24622465
emitGlobalDecl(decl);
24632466
});
2467+
24642468
switch (D->getKind()) {
24652469
case DeclKind::Extension:
24662470
return emitExtension(cast<ExtensionDecl>(D));

lib/IRGen/TBDGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source,
414414
}
415415

416416
bool TBDGenVisitor::willVisitDecl(Decl *D) {
417+
if (Lowering::shouldSkipLowering(D))
418+
return false;
419+
417420
// A @_silgen_name("...") function without a body only exists to
418421
// forward-declare a symbol from another library.
419422
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D))

lib/SIL/IR/SILModule.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,3 +955,13 @@ bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
955955
// allocation methods because they may have been overridden.
956956
return theClass->getObjectModel() == ReferenceCounting::ObjC;
957957
}
958+
959+
bool Lowering::shouldSkipLowering(Decl *D) {
960+
if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode !=
961+
UnavailableDeclOptimization::Complete)
962+
return false;
963+
964+
// Unavailable declarations should be skipped if
965+
// -unavailable-decl-optimization=complete is specified.
966+
return D->getSemanticUnavailableAttr() != None;
967+
}

lib/SILGen/SILGen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,13 @@ bool SILGenModule::hasFunction(SILDeclRef constant) {
770770
return emittedFunctions.count(constant);
771771
}
772772

773+
void SILGenModule::visit(Decl *D) {
774+
if (Lowering::shouldSkipLowering(D))
775+
return;
776+
777+
ASTVisitor::visit(D);
778+
}
779+
773780
void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); }
774781

775782
void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {

0 commit comments

Comments
 (0)