//===--- GenHasSymbol.cpp - IR Generation for #_hasSymbol queries ---------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR generation for `if #_hasSymbol` condition queries. // //===----------------------------------------------------------------------===// #include "swift/AST/ASTMangler.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/Basic/Assertions.h" #include "swift/IRGen/IRSymbolVisitor.h" #include "swift/IRGen/Linking.h" #include "swift/SIL/SILFunctionBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILSymbolVisitor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/GlobalDecl.h" #include "GenDecl.h" #include "GenericArguments.h" #include "IRGenFunction.h" #include "IRGenModule.h" using namespace swift; using namespace irgen; /// Wrapper for IRGenModule::getAddrOfLLVMVariable() that also handles a few /// additional types of entities that the main utility cannot. static llvm::Constant *getAddrOfLLVMVariable(IRGenModule &IGM, LinkEntity entity) { if (entity.isTypeMetadataAccessFunction()) { auto type = entity.getType(); auto nominal = type->getAnyNominal(); assert(nominal); if (nominal->isGenericContext()) { GenericArguments genericArgs; genericArgs.collectTypes(IGM, nominal); return IGM.getAddrOfGenericTypeMetadataAccessFunction(nominal, genericArgs.Types, NotForDefinition); } else { return IGM.getAddrOfTypeMetadataAccessFunction(type, NotForDefinition); } } if (entity.isDispatchThunk()) return IGM.getAddrOfDispatchThunk(entity.getSILDeclRef(), NotForDefinition); if (entity.isOpaqueTypeDescriptorAccessor()) { OpaqueTypeDecl *decl = const_cast(cast(entity.getDecl())); bool isImplementation = entity.isOpaqueTypeDescriptorAccessorImpl(); return IGM .getAddrOfOpaqueTypeDescriptorAccessFunction(decl, NotForDefinition, isImplementation) .getDirectPointer(); } // FIXME: Look up addr of the replaceable function (has "TI" mangling suffix) if (entity.isDynamicallyReplaceableFunctionImpl()) return nullptr; return IGM.getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); } class HasSymbolIRGenVisitor : public IRSymbolVisitor { IRGenModule &IGM; llvm::SmallVector &Addrs; void addFunction(SILFunction *fn) { Addrs.emplace_back(IGM.getAddrOfSILFunction(fn, NotForDefinition)); } void addFunction(StringRef name) { SILFunction *silFn = IGM.getSILModule().lookUpFunction(name); // Definitions for each SIL function should have been emitted by SILGen. assert(silFn && "missing SIL function?"); if (silFn) addFunction(silFn); } public: HasSymbolIRGenVisitor(IRGenModule &IGM, llvm::SmallVector &Addrs) : IGM{IGM}, Addrs{Addrs} {}; void addFunction(SILDeclRef declRef) override { addFunction(declRef.mangle()); } void addFunction(StringRef name, SILDeclRef declRef) override { addFunction(name); } void addGlobalVar(VarDecl *VD) override { // FIXME: Handle global vars llvm::report_fatal_error("unhandled global var"); } void addLinkEntity(LinkEntity entity) override { // Skip property descriptors for static properties, which were only // introduced with SE-0438 and are therefore not present in all libraries. if (entity.isPropertyDescriptor()) { if (entity.getAbstractStorageDecl()->isStatic()) return; } if (entity.hasSILFunction()) { addFunction(entity.getSILFunction()); return; } auto constant = getAddrOfLLVMVariable(IGM, entity); if (constant) { auto global = cast(constant); Addrs.emplace_back(global); } } void addProtocolWitnessThunk(RootProtocolConformance *C, ValueDecl *requirementDecl) override { // FIXME: Handle protocol witness thunks llvm::report_fatal_error("unhandled protocol witness thunk"); } }; static llvm::Constant * getAddrOfLLVMVariableForClangDecl(IRGenModule &IGM, ValueDecl *decl, const clang::Decl *clangDecl) { if (isa(clangDecl)) { SILFunction *silFn = IGM.getSILModule().lookUpFunction(SILDeclRef(decl).asForeign()); assert(silFn && "missing SIL function?"); return silFn ? IGM.getAddrOfSILFunction(silFn, NotForDefinition) : nullptr; } if (auto var = dyn_cast(clangDecl)) return IGM.getAddrOfObjCClass(cast(decl), NotForDefinition); llvm::report_fatal_error("Unexpected clang decl kind"); } static void getSymbolAddrsForDecl(IRGenModule &IGM, ValueDecl *decl, llvm::SmallVector &addrs) { if (auto *clangDecl = decl->getClangDecl()) { if (auto *addr = getAddrOfLLVMVariableForClangDecl(IGM, decl, clangDecl)) addrs.push_back(addr); return; } SILSymbolVisitorOptions opts; opts.VisitMembers = false; auto silCtx = SILSymbolVisitorContext(IGM.getSwiftModule(), opts); auto linkInfo = UniversalLinkageInfo(IGM); auto symbolVisitorCtx = IRSymbolVisitorContext(linkInfo, silCtx); HasSymbolIRGenVisitor(IGM, addrs).visit(decl, symbolVisitorCtx); } llvm::Function *IRGenModule::emitHasSymbolFunction(ValueDecl *decl) { PrettyStackTraceDecl trace("emitting #_hasSymbol query for", decl); Mangle::ASTMangler mangler(Context); auto func = cast(getOrCreateHelperFunction( mangler.mangleHasSymbolQuery(decl), Int1Ty, {}, [decl, this](IRGenFunction &IGF) { auto &Builder = IGF.Builder; llvm::SmallVector addrs; getSymbolAddrsForDecl(*this, decl, addrs); llvm::Value *ret = nullptr; for (llvm::Constant *addr : addrs) { assert(cast(addr)->hasExternalWeakLinkage()); auto isNonNull = IGF.Builder.CreateIsNotNull(addr); ret = (ret) ? IGF.Builder.CreateAnd(ret, isNonNull) : isNonNull; } if (ret) { Builder.CreateRet(ret); } else { // There were no addresses produced by the visitor, return true. Builder.CreateRet(llvm::ConstantInt::get(Int1Ty, 1)); } }, /*IsNoInline*/ false)); func->setDoesNotThrow(); func->setCallingConv(DefaultCC); func->setOnlyReadsMemory(); return func; }