From ca8bf981a49c45b991652825b7456aae1b646398 Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Fri, 4 Aug 2023 16:40:45 -0700 Subject: [PATCH] NFC: Hoist queries for unavailable decl optimizations into the AST library. Moving the query implementation up to the AST library from SIL will allow conveniences to be written on specific AST element classes. For instance, this will allow `EnumDecl` to expose a convenience that enumerates element decls that are available during lowering. Also, improve naming and documentation for these queries. --- include/swift/AST/Decl.h | 12 ++++++++++++ include/swift/SIL/SILModule.h | 11 +---------- lib/AST/Availability.cpp | 27 +++++++++++++++++++++++++++ lib/IRGen/GenClass.cpp | 2 +- lib/IRGen/GenDecl.cpp | 10 +++++----- lib/IRGen/GenEnum.cpp | 4 ++-- lib/IRGen/GenReflection.cpp | 6 +++--- lib/IRGen/GenStruct.cpp | 2 +- lib/IRGen/IRGenModule.h | 4 ++-- lib/IRGen/TBDGen.cpp | 2 +- lib/SIL/IR/SILModule.cpp | 27 --------------------------- lib/SILGen/SILGen.cpp | 2 +- lib/SILGen/SILGenBridging.cpp | 4 ++-- lib/SILGen/SILGenConstructor.cpp | 10 +++++----- lib/SILGen/SILGenDestructor.cpp | 8 ++++---- lib/SILGen/SILGenFunction.cpp | 2 +- lib/SILGen/SILGenGlobalVariable.cpp | 4 ++-- lib/SILGen/SILGenPoly.cpp | 2 +- 18 files changed, 71 insertions(+), 68 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 794f5801bf2..7acb9e7892f 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1234,6 +1234,18 @@ public: llvm::Optional> getSemanticUnavailableAttr() const; + /// Returns true if this declaration should be considered available during + /// SIL/IR lowering. A declaration would not be available during lowering if, + /// for example, it is annotated as unavailable with \c @available and + /// optimization settings require that it be omitted. + bool isAvailableDuringLowering() const; + + /// Returns true if ABI compatibility stubs must be emitted for the given + /// declaration. Decls marked unavailable with \c @available require these + /// stubs if the compiler flags have enabled unavailable declaration ABI + /// compatibility mode. + bool requiresUnavailableDeclABICompatibilityStubs() const; + // List the SPI groups declared with @_spi or inherited by this decl. // // SPI groups are inherited from the parent contexts only if the local decl diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 2f3aed40cbc..590c5c38440 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -1078,15 +1078,6 @@ namespace Lowering { /// Determine whether the given class will be allocated/deallocated using the /// Objective-C runtime, i.e., +alloc and -dealloc. LLVM_LIBRARY_VISIBILITY bool usesObjCAllocator(ClassDecl *theClass); - -/// Returns true if SIL/IR lowering for the given declaration should be skipped. -/// A declaration may not require lowering if, for example, it is annotated as -/// unavailable and optimization settings allow it to be omitted. -LLVM_LIBRARY_VISIBILITY bool shouldSkipLowering(const Decl *D); - -/// Returns true if SIL/IR lowering for the given declaration should produce -/// a stub that traps at runtime because the code ought to be unreachable. -LLVM_LIBRARY_VISIBILITY bool shouldLowerToUnavailableCodeStub(const Decl *D); } // namespace Lowering /// Apply the given function to each ABI member of \c D skipping the members @@ -1094,7 +1085,7 @@ LLVM_LIBRARY_VISIBILITY bool shouldLowerToUnavailableCodeStub(const Decl *D); template void forEachMemberToLower(IterableDeclContext *D, F &&f) { for (auto *member : D->getABIMembers()) { - if (!Lowering::shouldSkipLowering(member)) + if (member->isAvailableDuringLowering()) f(member); } } diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 38a0732da61..7db4aee6cc6 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -298,6 +298,33 @@ llvm::Optional Decl::getSemanticUnavailableAttr() const { llvm::None); } +static bool isUnconditionallyUnavailable(const Decl *D) { + if (auto unavailableAttrAndDecl = D->getSemanticUnavailableAttr()) + return unavailableAttrAndDecl->first->isUnconditionallyUnavailable(); + + return false; +} + +bool Decl::isAvailableDuringLowering() const { + // Unconditionally unavailable declarations should be skipped during lowering + // when -unavailable-decl-optimization=complete is specified. + if (getASTContext().LangOpts.UnavailableDeclOptimizationMode != + UnavailableDeclOptimization::Complete) + return true; + + return !isUnconditionallyUnavailable(this); +} + +bool Decl::requiresUnavailableDeclABICompatibilityStubs() const { + // Code associated with unavailable declarations should trap at runtime if + // -unavailable-decl-optimization=stub is specified. + if (getASTContext().LangOpts.UnavailableDeclOptimizationMode != + UnavailableDeclOptimization::Stub) + return false; + + return isUnconditionallyUnavailable(this); +} + bool UnavailabilityReason::requiresDeploymentTargetOrEarlier( ASTContext &Ctx) const { return RequiredDeploymentRange.getLowerEndpoint() <= diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 5b034a60a59..d3d0d40e64e 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1841,7 +1841,7 @@ namespace { void buildMethod(ConstantArrayBuilder &descriptors, AbstractFunctionDecl *method) { - if (Lowering::shouldSkipLowering(method)) + if (!method->isAvailableDuringLowering()) return; auto accessor = dyn_cast(method); diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 8062188cf4c..bb38b62efd2 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1563,7 +1563,7 @@ void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type, if (!type) return; - assert(!Lowering::shouldSkipLowering(type)); + assert(type->isAvailableDuringLowering()); // Force emission of ObjC protocol descriptors used by type refs. if (auto proto = dyn_cast(type)) { @@ -2473,7 +2473,7 @@ void swift::irgen::disableAddressSanitizer(IRGenModule &IGM, llvm::GlobalVariabl /// Emit a global declaration. void IRGenModule::emitGlobalDecl(Decl *D) { - if (Lowering::shouldSkipLowering(D)) + if (!D->isAvailableDuringLowering()) return; D->visitAuxiliaryDecls([&](Decl *decl) { @@ -5550,7 +5550,7 @@ static Address getAddrOfSimpleVariable(IRGenModule &IGM, /// The result is always a GlobalValue. Address IRGenModule::getAddrOfFieldOffset(VarDecl *var, ForDefinition_t forDefinition) { - assert(!Lowering::shouldSkipLowering(var)); + assert(var->isAvailableDuringLowering()); LinkEntity entity = LinkEntity::forFieldOffset(var); return getAddrOfSimpleVariable(*this, GlobalVars, entity, @@ -5559,7 +5559,7 @@ Address IRGenModule::getAddrOfFieldOffset(VarDecl *var, Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case, ForDefinition_t forDefinition) { - assert(!Lowering::shouldSkipLowering(Case)); + assert(Case->isAvailableDuringLowering()); LinkEntity entity = LinkEntity::forEnumCase(Case); auto addr = getAddrOfSimpleVariable(*this, GlobalVars, entity, forDefinition); @@ -5572,7 +5572,7 @@ Address IRGenModule::getAddrOfEnumCase(EnumElementDecl *Case, void IRGenModule::emitNestedTypeDecls(DeclRange members) { for (Decl *member : members) { - if (Lowering::shouldSkipLowering(member)) + if (!member->isAvailableDuringLowering()) continue; member->visitAuxiliaryDecls([&](Decl *decl) { diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index dee1246ff55..b271e81e87b 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -263,7 +263,7 @@ EnumImplStrategy::getTagIndex(EnumElementDecl *Case) const { static void emitResilientTagIndex(IRGenModule &IGM, const EnumImplStrategy *strategy, EnumElementDecl *Case) { - if (Lowering::shouldSkipLowering(Case)) + if (!Case->isAvailableDuringLowering()) return; auto resilientIdx = strategy->getTagIndex(Case); @@ -6175,7 +6175,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) { // For the purposes of memory layout, treat unavailable cases as if they do // not have a payload. - if (Lowering::shouldSkipLowering(elt)) { + if (!elt->isAvailableDuringLowering()) { elementsWithNoPayload.push_back({elt, nullptr, nullptr}); continue; } diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 39cbdd1fb08..5b2ea511f84 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -853,9 +853,9 @@ private: if (hasPayload && (decl->isIndirect() || enumDecl->isIndirect())) flags.setIsIndirectCase(); - Type interfaceType = Lowering::shouldSkipLowering(decl) - ? nullptr - : decl->getArgumentInterfaceType(); + Type interfaceType = decl->isAvailableDuringLowering() + ? decl->getArgumentInterfaceType() + : nullptr; addField(flags, interfaceType, decl->getBaseIdentifier().str()); } diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index e4d96c81aaa..d26650161cc 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -1578,7 +1578,7 @@ void IRGenModule::emitStructDecl(StructDecl *st) { } void IRGenModule::maybeEmitOpaqueTypeDecl(OpaqueTypeDecl *opaque) { - if (Lowering::shouldSkipLowering(opaque)) + if (!opaque->isAvailableDuringLowering()) return; if (IRGen.Opts.EnableAnonymousContextMangledNames) { diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 9d4523bbfd6..1d864c8b141 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -456,7 +456,7 @@ public: } void noteLazyReemissionOfNominalTypeDescriptor(NominalTypeDecl *decl) { - assert(!Lowering::shouldSkipLowering(decl)); + assert(decl->isAvailableDuringLowering()); LazilyReemittedTypeContextDescriptors.insert(decl); } @@ -466,7 +466,7 @@ public: } void noteUseOfMetadataAccessor(NominalTypeDecl *decl) { - assert(!Lowering::shouldSkipLowering(decl)); + assert(decl->isAvailableDuringLowering()); if (LazyMetadataAccessors.count(decl) == 0) { LazyMetadataAccessors.insert(decl); } diff --git a/lib/IRGen/TBDGen.cpp b/lib/IRGen/TBDGen.cpp index fc5d8618d60..38eecb97153 100644 --- a/lib/IRGen/TBDGen.cpp +++ b/lib/IRGen/TBDGen.cpp @@ -414,7 +414,7 @@ void TBDGenVisitor::addSymbol(StringRef name, SymbolSource source, } bool TBDGenVisitor::willVisitDecl(Decl *D) { - if (Lowering::shouldSkipLowering(D)) + if (!D->isAvailableDuringLowering()) return false; // A @_silgen_name("...") function without a body only exists to diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index ad33e1c2081..c9879163258 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -953,30 +953,3 @@ bool Lowering::usesObjCAllocator(ClassDecl *theClass) { // allocation methods because they may have been overridden. return theClass->getObjectModel() == ReferenceCounting::ObjC; } - -static bool isUnconditionallyUnavailable(const Decl *D) { - if (auto unavailableAttrAndDecl = D->getSemanticUnavailableAttr()) - return unavailableAttrAndDecl->first->isUnconditionallyUnavailable(); - - return false; -} - -bool Lowering::shouldSkipLowering(const Decl *D) { - if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode != - UnavailableDeclOptimization::Complete) - return false; - - // Unavailable declarations should be skipped if - // -unavailable-decl-optimization=complete is specified. - return isUnconditionallyUnavailable(D); -} - -bool Lowering::shouldLowerToUnavailableCodeStub(const Decl *D) { - if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode != - UnavailableDeclOptimization::Stub) - return false; - - // Unavailable declarations should trap at runtime if - // -unavailable-decl-optimization=stub is specified. - return isUnconditionallyUnavailable(D); -} diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 556355648cb..195aaae7d7c 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -763,7 +763,7 @@ bool SILGenModule::hasFunction(SILDeclRef constant) { } void SILGenModule::visit(Decl *D) { - if (Lowering::shouldSkipLowering(D)) + if (!D->isAvailableDuringLowering()) return; ASTVisitor::visit(D); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index aed4d9498d6..34920f3d1a9 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1553,7 +1553,7 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { SILDeclRef native = thunk.asForeign(false); if (thunk.hasDecl()) { - if (shouldLowerToUnavailableCodeStub(thunk.getDecl())) + if (thunk.getDecl()->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); } @@ -2068,7 +2068,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { auto nativeFnTy = F.getLoweredFunctionType(); assert(nativeFnTy == nativeCI.SILFnType); - if (shouldLowerToUnavailableCodeStub(fd)) + if (fd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // Use the same generic environment as the native entry point. diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 86bda3fa007..ffd4d33fe92 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -333,7 +333,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, RegularLocation Loc(ctor); Loc.markAutoGenerated(); - if (shouldLowerToUnavailableCodeStub(ctor)) + if (ctor->requiresUnavailableDeclABICompatibilityStubs()) SGF.emitApplyOfUnavailableCodeReached(); AssertingManualScope functionLevelScope(SGF.Cleanups, @@ -612,7 +612,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { bool isDelegating = ctor->getDelegatingOrChainedInitKind().initKind == BodyInitKind::Delegating; - if (shouldLowerToUnavailableCodeStub(ctor)) + if (ctor->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // Get the 'self' decl and type. @@ -839,7 +839,7 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) { auto &enumTI = SGM.Types.getTypeLowering(enumTy, TypeExpansionContext::minimal()); - if (shouldLowerToUnavailableCodeStub(element)) + if (element->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); RegularLocation Loc(element); @@ -918,7 +918,7 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) { SmallVector args; bindParametersForForwarding(ctor->getParameters(), args); - if (shouldLowerToUnavailableCodeStub(ctor)) + if (ctor->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor); @@ -1036,7 +1036,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { assert(ctor->getTypecheckedBody() && "Class constructor without a body?"); - if (shouldLowerToUnavailableCodeStub(ctor)) + if (ctor->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // True if this constructor delegates to a peer constructor with self.init(). diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 23e1d1e87f9..f36a2704fe9 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -35,7 +35,7 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) { if (dd->isImplicit()) Loc.markAutoGenerated(); - if (shouldLowerToUnavailableCodeStub(dd)) + if (dd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); auto cd = cast(dd->getDeclContext()->getSelfNominalTypeDecl()); @@ -181,7 +181,7 @@ void SILGenFunction::emitDeallocatingClassDestructor(DestructorDecl *dd) { RegularLocation loc(dd); loc.markAutoGenerated(); - if (shouldLowerToUnavailableCodeStub(dd)) + if (dd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // Emit the prolog. @@ -239,7 +239,7 @@ void SILGenFunction::emitDeallocatingMoveOnlyDestructor(DestructorDecl *dd) { if (dd->isImplicit()) loc.markAutoGenerated(); - if (shouldLowerToUnavailableCodeStub(dd)) + if (dd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); // Emit the prolog. @@ -561,7 +561,7 @@ void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { if (dd->isImplicit()) loc.markAutoGenerated(); - if (shouldLowerToUnavailableCodeStub(dd)) + if (dd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); SILValue selfValue = emitSelfDeclForDestructor(dd->getImplicitSelfDecl()); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 14a3d71d7b5..955d0aa4e8f 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -1017,7 +1017,7 @@ void SILGenFunction::emitFunction(FuncDecl *fd) { prepareEpilog(fd->getResultInterfaceType(), fd->hasThrows(), CleanupLocation(fd)); - if (shouldLowerToUnavailableCodeStub(fd)) + if (fd->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); emitProfilerIncrement(fd->getTypecheckedBody()); diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index f98d7d35761..cc216829697 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -250,7 +250,7 @@ void SILGenFunction::emitLazyGlobalInitializer(PatternBindingDecl *binding, // Add unused context pointer argument required to pass to `Builtin.once` SILBasicBlock &entry = *F.begin(); - if (shouldLowerToUnavailableCodeStub(binding)) + if (binding->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); SILType rawPointerSILTy = @@ -292,7 +292,7 @@ static void emitOnceCall(SILGenFunction &SGF, VarDecl *global, void SILGenFunction::emitGlobalAccessor(VarDecl *global, SILGlobalVariable *onceToken, SILFunction *onceFunc) { - if (shouldLowerToUnavailableCodeStub(global)) + if (global->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); emitOnceCall(*this, global, onceToken, onceFunc); diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 6ec1119ebe8..8592b56b0a0 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -6025,7 +6025,7 @@ void SILGenFunction::emitProtocolWitness( SmallVector origParams; collectThunkParams(loc, origParams); - if (shouldLowerToUnavailableCodeStub(witness.getDecl())) + if (witness.getDecl()->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); if (enterIsolation) {