text: //===--- SILFunction.cpp - Defines the SILFunction data structure ---------===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2017 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
  //
  //===----------------------------------------------------------------------===//
  
  #define DEBUG_TYPE "sil-function"
  
  #include "swift/SIL/SILArgument.h"
  #include "swift/SIL/SILBasicBlock.h"
  #include "swift/SIL/SILBridging.h"
  #include "swift/SIL/SILFunction.h"
  #include "swift/SIL/SILInstruction.h"
  #include "swift/SIL/SILModule.h"
  #include "swift/SIL/SILProfiler.h"
  #include "swift/SIL/CFG.h"
  #include "swift/SIL/PrettyStackTrace.h"
  #include "swift/AST/Availability.h"
  #include "swift/AST/GenericEnvironment.h"
  #include "swift/AST/Module.h"
  #include "swift/Basic/OptimizationMode.h"
  #include "swift/Basic/Statistic.h"
  #include "llvm/ADT/Optional.h"
  #include "llvm/ADT/Statistic.h"
  #include "llvm/Support/CommandLine.h"
  #include "llvm/Support/GraphWriter.h"
  #include "clang/AST/Decl.h"
  
  using namespace swift;
  using namespace Lowering;
  
  STATISTIC(MaxBitfieldID, "Max value of SILFunction::currentBitfieldID");
  
  SILSpecializeAttr::SILSpecializeAttr(bool exported, SpecializationKind kind,
                                       GenericSignature specializedSig,
                                       SILFunction *target, Identifier spiGroup,
                                       const ModuleDecl *spiModule)
      : kind(kind), exported(exported), specializedSignature(specializedSig),
        spiGroup(spiGroup), spiModule(spiModule), targetFunction(target) {
    if (targetFunction)
      targetFunction->incrementRefCount();
  }
  
  SILSpecializeAttr *
  SILSpecializeAttr::create(SILModule &M, GenericSignature specializedSig,
                            bool exported, SpecializationKind kind,
                            SILFunction *target, Identifier spiGroup,
                            const ModuleDecl *spiModule) {
    void *buf = M.allocate(sizeof(SILSpecializeAttr), alignof(SILSpecializeAttr));
    return ::new (buf) SILSpecializeAttr(exported, kind, specializedSig, target,
                                         spiGroup, spiModule);
  }
  
  void SILFunction::addSpecializeAttr(SILSpecializeAttr *Attr) {
    if (getLoweredFunctionType()->getInvocationGenericSignature()) {
      Attr->F = this;
      SpecializeAttrSet.push_back(Attr);
    }
  }
  
  void SILFunction::removeSpecializeAttr(SILSpecializeAttr *attr) {
    // Drop the reference to the _specialize(target:) function.
    if (auto *targetFun = attr->getTargetFunction()) {
      targetFun->decrementRefCount();
    }
    SpecializeAttrSet.erase(std::remove_if(SpecializeAttrSet.begin(),
                                           SpecializeAttrSet.end(),
                                           [attr](SILSpecializeAttr *member) {
                                             return member == attr;
                                           }),
                            SpecializeAttrSet.end());
  }
  
  SILFunction *
  SILFunction::create(SILModule &M, SILLinkage linkage, StringRef name,
                      CanSILFunctionType loweredType,
                      GenericEnvironment *genericEnv, Optional<SILLocation> loc,
                      IsBare_t isBareSILFunction, IsTransparent_t isTrans,
                      IsSerialized_t isSerialized, ProfileCounter entryCount,
                      IsDynamicallyReplaceable_t isDynamic,
                      IsExactSelfClass_t isExactSelfClass,
                      IsThunk_t isThunk,
                      SubclassScope classSubclassScope, Inline_t inlineStrategy,
                      EffectsKind E, SILFunction *insertBefore,
                      const SILDebugScope *debugScope) {
    // Get a StringMapEntry for the function.  As a sop to error cases,
    // allow the name to have an empty string.
    llvm::StringMapEntry<SILFunction*> *entry = nullptr;
    if (!name.empty()) {
      entry = &*M.FunctionTable.insert(std::make_pair(name, nullptr)).first;
      PrettyStackTraceSILFunction trace("creating", entry->getValue());
      assert(!entry->getValue() && "function already exists");
      name = entry->getKey();
    }
  
    SILFunction *fn = M.removeFromZombieList(name);
    if (fn) {
      // Resurrect a zombie function.
      // This happens for example if a specialized function gets dead and gets
      // deleted. And afterwards the same specialization is created again.
      fn->init(linkage, name, loweredType, genericEnv, loc, isBareSILFunction,
               isTrans, isSerialized, entryCount, isThunk, classSubclassScope,
               inlineStrategy, E, debugScope, isDynamic, isExactSelfClass);
      assert(fn->empty());
    } else {
      fn = new (M) SILFunction(M, linkage, name, loweredType, genericEnv, loc,
                                  isBareSILFunction, isTrans, isSerialized,
                                  entryCount, isThunk, classSubclassScope,
                                  inlineStrategy, E, debugScope,
                                  isDynamic, isExactSelfClass);
    }
    if (entry) entry->setValue(fn);
  
    if (insertBefore)
      M.functions.insert(SILModule::iterator(insertBefore), fn);
    else
      M.functions.push_back(fn);
  
    return fn;
  }
  
  SwiftMetatype SILFunction::registeredMetatype;
  
  SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name,
                           CanSILFunctionType LoweredType,
                           GenericEnvironment *genericEnv,
                           Optional<SILLocation> Loc, IsBare_t isBareSILFunction,
                           IsTransparent_t isTrans, IsSerialized_t isSerialized,
                           ProfileCounter entryCount, IsThunk_t isThunk,
                           SubclassScope classSubclassScope,
                           Inline_t inlineStrategy, EffectsKind E,
                           const SILDebugScope *DebugScope,
                           IsDynamicallyReplaceable_t isDynamic,
                           IsExactSelfClass_t isExactSelfClass)
      : SwiftObjectHeader(registeredMetatype),
        Module(Module), Availability(AvailabilityContext::alwaysAvailable())  {
    init(Linkage, Name, LoweredType, genericEnv, Loc, isBareSILFunction, isTrans,
         isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy,
         E, DebugScope, isDynamic, isExactSelfClass);
    
    // Set our BB list to have this function as its parent. This enables us to
    // splice efficiently basic blocks in between functions.
    BlockList.Parent = this;
  }
  
  void SILFunction::init(SILLinkage Linkage, StringRef Name,
                           CanSILFunctionType LoweredType,
                           GenericEnvironment *genericEnv,
                           Optional<SILLocation> Loc, IsBare_t isBareSILFunction,
                           IsTransparent_t isTrans, IsSerialized_t isSerialized,
                           ProfileCounter entryCount, IsThunk_t isThunk,
                           SubclassScope classSubclassScope,
                           Inline_t inlineStrategy, EffectsKind E,
                           const SILDebugScope *DebugScope,
                           IsDynamicallyReplaceable_t isDynamic,
                           IsExactSelfClass_t isExactSelfClass) {
    this->Name = Name;
    this->LoweredType = LoweredType;
    this->GenericEnv = genericEnv;
    this->SpecializationInfo = nullptr;
    this->EntryCount = entryCount;
    this->Availability = AvailabilityContext::alwaysAvailable();
    this->Bare = isBareSILFunction;
    this->Transparent = isTrans;
    this->Serialized = isSerialized;
    this->Thunk = isThunk;
    this->ClassSubclassScope = unsigned(classSubclassScope);
    this->GlobalInitFlag = false;
    this->InlineStrategy = inlineStrategy;
    this->Linkage = unsigned(Linkage);
    this->HasCReferences = false;
    this->IsWeakImported = false;
    this->IsDynamicReplaceable = isDynamic;
    this->ExactSelfClass = isExactSelfClass;
    this->Inlined = false;
    this->Zombie = false;
    this->HasOwnership = true,
    this->WasDeserializedCanonical = false;
    this->IsStaticallyLinked = false;
    this->IsWithoutActuallyEscapingThunk = false;
    this->OptMode = unsigned(OptimizationMode::NotSet);
    this->EffectsKindAttr = unsigned(E);
    assert(!Transparent || !IsDynamicReplaceable);
    validateSubclassScope(classSubclassScope, isThunk, nullptr);
    setDebugScope(DebugScope);
  }
  
  SILFunction::~SILFunction() {
    // If the function is recursive, a function_ref inst inside of the function
    // will give the function a non-zero ref count triggering the assertion. Thus
    // we drop all instruction references before we erase.
    // We also need to drop all references if instructions are allocated using
    // an allocator that may recycle freed memory.
    dropAllReferences();
  
    if (ReplacedFunction) {
      ReplacedFunction->decrementRefCount();
      ReplacedFunction = nullptr;
    }
  
    auto &M = getModule();
    for (auto &BB : *this) {
      BB.eraseAllInstructions(M);
    }
  
    assert(RefCount == 0 &&
           "Function cannot be deleted while function_ref's still exist");
    assert(!newestAliveBitfield &&
           "Not all BasicBlockBitfields deleted at function destruction");
    if (currentBitfieldID > MaxBitfieldID)
      MaxBitfieldID = currentBitfieldID;
  }
  
  void SILFunction::createProfiler(ASTNode Root, SILDeclRef forDecl,
                                   ForDefinition_t forDefinition) {
    assert(!Profiler && "Function already has a profiler");
    Profiler = SILProfiler::create(Module, forDefinition, Root, forDecl);
  }
  
  bool SILFunction::hasForeignBody() const {
    if (!hasClangNode()) return false;
    return SILDeclRef::isClangGenerated(getClangNode());
  }
  
  const SILFunction *SILFunction::getOriginOfSpecialization() const {
    if (!isSpecialization())
      return nullptr;
  
    const SILFunction *p = getSpecializationInfo()->getParent();
    while (p->isSpecialization()) {
      p = p->getSpecializationInfo()->getParent();
    }
    return p;
  }
  
  void SILFunction::numberValues(llvm::DenseMap<const SILNode*, unsigned> &
                                   ValueToNumberMap) const {
    unsigned idx = 0;
    for (auto &BB : *this) {
      for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I)
        ValueToNumberMap[*I] = idx++;
      
      for (auto &I : BB) {
        auto results = I.getResults();
        if (results.empty()) {
          ValueToNumberMap[I.asSILNode()] = idx++;
        } else {
          // Assign the instruction node the first result ID.
          ValueToNumberMap[I.asSILNode()] = idx;
          for (auto result : results) {
            ValueToNumberMap[result] = idx++;
          }
        }
      }
    }
  }
  
  
  ASTContext &SILFunction::getASTContext() const {
    return getModule().getASTContext();
  }
  
  OptimizationMode SILFunction::getEffectiveOptimizationMode() const {
    if (OptimizationMode(OptMode) != OptimizationMode::NotSet)
      return OptimizationMode(OptMode);
  
    return getModule().getOptions().OptMode;
  }
  
  bool SILFunction::shouldOptimize() const {
    return getEffectiveOptimizationMode() != OptimizationMode::NoOptimization;
  }
  
  Type SILFunction::mapTypeIntoContext(Type type) const {
    return GenericEnvironment::mapTypeIntoContext(
        getGenericEnvironment(), type);
  }
  
  SILType SILFunction::mapTypeIntoContext(SILType type) const {
    if (auto *genericEnv = getGenericEnvironment())
      return genericEnv->mapTypeIntoContext(getModule(), type);
    return type;
  }
  
  SILType GenericEnvironment::mapTypeIntoContext(SILModule &M,
                                                 SILType type) const {
    assert(!type.hasArchetype());
  
    auto genericSig = getGenericSignature().getCanonicalSignature();
    return type.subst(M,
                      QueryInterfaceTypeSubstitutions(this),
                      LookUpConformanceInSignature(genericSig.getPointer()),
                      genericSig);
  }
  
  bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
    return SILType::getPrimitiveObjectType(getLoweredFunctionType())
        .isNoReturnFunction(getModule(), context);
  }
  
  const TypeLowering &
  SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) {
    return getModule().Types.getTypeLowering(orig, subst,
                                             TypeExpansionContext(*this));
  }
  
  const TypeLowering &SILFunction::getTypeLowering(Type t) const {
    return getModule().Types.getTypeLowering(t, TypeExpansionContext(*this));
  }
  
  SILType
  SILFunction::getLoweredType(AbstractionPattern orig, Type subst) const {
    return getModule().Types.getLoweredType(orig, subst,
                                            TypeExpansionContext(*this));
  }
  
  SILType SILFunction::getLoweredType(Type t) const {
    return getModule().Types.getLoweredType(t, TypeExpansionContext(*this));
  }
  
  SILType SILFunction::getLoweredLoadableType(Type t) const {
    auto &M = getModule();
    return M.Types.getLoweredLoadableType(t, TypeExpansionContext(*this), M);
  }
  
  const TypeLowering &SILFunction::getTypeLowering(SILType type) const {
    return getModule().Types.getTypeLowering(type, *this);
  }
  
  SILType SILFunction::getLoweredType(SILType t) const {
    return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory());
  }
  bool SILFunction::isTypeABIAccessible(SILType type) const {
    return getModule().isTypeABIAccessible(type, TypeExpansionContext(*this));
  }
  
  bool SILFunction::isWeakImported() const {
    // For imported functions check the Clang declaration.
    if (ClangNodeOwner)
      return ClangNodeOwner->getClangDecl()->isWeakImported();
  
    // For native functions check a flag on the SILFunction
    // itself.
    if (!isAvailableExternally())
      return false;
  
    if (isAlwaysWeakImported())
      return true;
  
    if (Availability.isAlwaysAvailable())
      return false;
  
    auto fromContext = AvailabilityContext::forDeploymentTarget(
        getASTContext());
    return !fromContext.isContainedIn(Availability);
  }
  
  SILBasicBlock *SILFunction::createBasicBlock() {
    SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
    BlockList.push_back(newBlock);
    return newBlock;
  }
  
  SILBasicBlock *SILFunction::createBasicBlockAfter(SILBasicBlock *afterBB) {
    SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
    BlockList.insertAfter(afterBB->getIterator(), newBlock);
    return newBlock;
  }
  
  SILBasicBlock *SILFunction::createBasicBlockBefore(SILBasicBlock *beforeBB) {
    SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
    BlockList.insert(beforeBB->getIterator(), newBlock);
    return newBlock;
  }
  
  void SILFunction::moveAllBlocksFromOtherFunction(SILFunction *F) {
    BlockList.splice(begin(), F->BlockList);
    
    SILModule &mod = getModule();
    for (SILBasicBlock &block : *this) {
      for (SILInstruction &inst : block) {
        mod.notifyMovedInstruction(&inst, F);
      }
    }
  }
  
  void SILFunction::moveBlockFromOtherFunction(SILBasicBlock *blockInOtherFunction,
                                  iterator insertPointInThisFunction) {
    SILFunction *otherFunc = blockInOtherFunction->getParent();
    assert(otherFunc != this);
    BlockList.splice(insertPointInThisFunction, otherFunc->BlockList,
                     blockInOtherFunction);
  
    SILModule &mod = getModule();
    for (SILInstruction &inst : *blockInOtherFunction) {
      mod.notifyMovedInstruction(&inst, otherFunc);
    }
  }
  
  void SILFunction::moveBlockBefore(SILBasicBlock *BB, SILFunction::iterator IP) {
    assert(BB->getParent() == this);
    if (SILFunction::iterator(BB) == IP)
      return;
    BlockList.remove(BB);
    BlockList.insert(IP, BB);
  }
  
  //===----------------------------------------------------------------------===//
  //                          View CFG Implementation
  //===----------------------------------------------------------------------===//
  
  #ifndef NDEBUG
  
  static llvm::cl::opt<unsigned>
  MaxColumns("view-cfg-max-columns", llvm::cl::init(80),
             llvm::cl::desc("Maximum width of a printed node"));
  
  namespace {
  enum class LongLineBehavior { None, Truncate, Wrap };
  } // end anonymous namespace
  static llvm::cl::opt<LongLineBehavior>
  LLBehavior("view-cfg-long-line-behavior",
             llvm::cl::init(LongLineBehavior::Truncate),
             llvm::cl::desc("Behavior when line width is greater than the "
                            "value provided my -view-cfg-max-columns "
                            "option"),
             llvm::cl::values(
                 clEnumValN(LongLineBehavior::None, "none", "Print everything"),
                 clEnumValN(LongLineBehavior::Truncate, "truncate",
                            "Truncate long lines"),
                 clEnumValN(LongLineBehavior::Wrap, "wrap", "Wrap long lines")));
  
  static llvm::cl::opt<bool>
  RemoveUseListComments("view-cfg-remove-use-list-comments",
                        llvm::cl::init(false),
                        llvm::cl::desc("Should use list comments be removed"));
  
  template <typename InstTy, typename CaseValueTy>
  inline CaseValueTy getCaseValueForBB(const InstTy *Inst,
                                       const SILBasicBlock *BB) {
    for (unsigned i = 0, e = Inst->getNumCases(); i != e; ++i) {
      auto P = Inst->getCase(i);
      if (P.second != BB)
        continue;
      return P.first;
    }
    llvm_unreachable("Error! should never pass in BB that is not a successor");
  }
  
  namespace llvm {
  template <>
  struct DOTGraphTraits<SILFunction *> : public DefaultDOTGraphTraits {
  
    DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
  
    static std::string getGraphName(SILFunction *F) {
      return "CFG for '" + F->getName().str() + "' function";
    }
  
    static std::string getSimpleNodeLabel(SILBasicBlock *Node, SILFunction *F) {
      std::string OutStr;
      raw_string_ostream OSS(OutStr);
      const_cast<SILBasicBlock *>(Node)->printAsOperand(OSS, false);
      return OSS.str();
    }
  
    static std::string getCompleteNodeLabel(SILBasicBlock *Node, SILFunction *F) {
      std::string Str;
      raw_string_ostream OS(Str);
  
      OS << *Node;
      std::string OutStr = OS.str();
      if (OutStr[0] == '\n')
        OutStr.erase(OutStr.begin());
  
      // Process string output to make it nicer...
      unsigned ColNum = 0;
      unsigned LastSpace = 0;
      for (unsigned i = 0; i != OutStr.length(); ++i) {
        if (OutStr[i] == '\n') { // Left justify
          OutStr[i] = '\\';
          OutStr.insert(OutStr.begin() + i + 1, 'l');
          ColNum = 0;
          LastSpace = 0;
        } else if (RemoveUseListComments && OutStr[i] == '/' &&
                   i != (OutStr.size() - 1) && OutStr[i + 1] == '/') {
          unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
          OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
          --i;
  
        } else if (ColNum == MaxColumns) { // Handle long lines.
  
          if (LLBehavior == LongLineBehavior::Wrap) {
            if (!LastSpace)
              LastSpace = i;
            OutStr.insert(LastSpace, "\\l...");
            ColNum = i - LastSpace;
            LastSpace = 0;
            i += 3; // The loop will advance 'i' again.
          } else if (LLBehavior == LongLineBehavior::Truncate) {
            unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
            OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
            --i;
          }
  
          // Else keep trying to find a space.
        } else
          ++ColNum;
        if (OutStr[i] == ' ')
          LastSpace = i;
      }
      return OutStr;
    }
  
    std::string getNodeLabel(SILBasicBlock *Node, SILFunction *Graph) {
      if (isSimple())
        return getSimpleNodeLabel(Node, Graph);
      else
        return getCompleteNodeLabel(Node, Graph);
    }
  
    static std::string getEdgeSourceLabel(SILBasicBlock *Node,
                                          SILBasicBlock::succblock_iterator I) {
      const SILBasicBlock *Succ = *I;
      const TermInst *Term = Node->getTerminator();
  
      // Label source of conditional branches with "T" or "F"
      if (auto *CBI = dyn_cast<CondBranchInst>(Term))
        return (Succ == CBI->getTrueBB()) ? "T" : "F";
  
      // Label source of switch edges with the associated value.
      if (auto *SI = dyn_cast<SwitchValueInst>(Term)) {
        if (SI->hasDefault() && SI->getDefaultBB() == Succ)
          return "def";
  
        std::string Str;
        raw_string_ostream OS(Str);
  
        SILValue I = getCaseValueForBB<SwitchValueInst, SILValue>(SI, Succ);
        OS << I; // TODO: or should we output the literal value of I?
        return OS.str();
      }
  
      if (auto *SEIB = dyn_cast<SwitchEnumInst>(Term)) {
        std::string Str;
        raw_string_ostream OS(Str);
  
        EnumElementDecl *E =
            getCaseValueForBB<SwitchEnumInst, EnumElementDecl *>(SEIB, Succ);
        OS << E->getName();
        return OS.str();
      }
  
      if (auto *SEIB = dyn_cast<SwitchEnumAddrInst>(Term)) {
        std::string Str;
        raw_string_ostream OS(Str);
  
        EnumElementDecl *E =
            getCaseValueForBB<SwitchEnumAddrInst, EnumElementDecl *>(SEIB, Succ);
        OS << E->getName();
        return OS.str();
      }
  
      if (auto *DMBI = dyn_cast<DynamicMethodBranchInst>(Term))
        return (Succ == DMBI->getHasMethodBB()) ? "T" : "F";
  
      if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(Term))
        return (Succ == CCBI->getSuccessBB()) ? "T" : "F";
  
      if (auto *CCBI = dyn_cast<CheckedCastValueBranchInst>(Term))
        return (Succ == CCBI->getSuccessBB()) ? "T" : "F";
  
      if (auto *CCBI = dyn_cast<CheckedCastAddrBranchInst>(Term))
        return (Succ == CCBI->getSuccessBB()) ? "T" : "F";
  
      return "";
    }
  };
  } // namespace llvm
  #endif
  
  #ifndef NDEBUG
  static llvm::cl::opt<std::string>
  TargetFunction("view-cfg-only-for-function", llvm::cl::init(""),
                 llvm::cl::desc("Only print out the cfg for this function"));
  #endif
  
  static void viewCFGHelper(const SILFunction* f, bool skipBBContents) {
  /// When asserts are disabled, this should be a NoOp.
  #ifndef NDEBUG
      // If we have a target function, only print that function out.
      if (!TargetFunction.empty() && !(f->getName().str() == TargetFunction))
        return;
  
      ViewGraph(const_cast<SILFunction *>(f), "cfg" + f->getName().str(),
                /*shortNames=*/skipBBContents);
  #endif
  }
  
  void SILFunction::viewCFG() const {
    viewCFGHelper(this, /*skipBBContents=*/false);
  }
  
  void SILFunction::viewCFGOnly() const {
    viewCFGHelper(this, /*skipBBContents=*/true);
  }
  
  
  bool SILFunction::hasDynamicSelfMetadata() const {
    auto paramTypes =
        getConventions().getParameterSILTypes(TypeExpansionContext::minimal());
    if (paramTypes.empty())
      return false;
  
    auto silTy = *std::prev(paramTypes.end());
    if (!silTy.isObject())
      return false;
  
    auto selfTy = silTy.getASTType();
  
    if (auto metaTy = dyn_cast<MetatypeType>(selfTy)) {
      selfTy = metaTy.getInstanceType();
      if (auto dynamicSelfTy = dyn_cast<DynamicSelfType>(selfTy))
        selfTy = dynamicSelfTy.getSelfType();
    }
  
    return !!selfTy.getClassOrBoundGenericClass();
  }
  
  bool SILFunction::hasName(const char *Name) const {
    return getName() == Name;
  }
  
  /// Returns true if this function can be referenced from a fragile function
  /// body.
  bool SILFunction::hasValidLinkageForFragileRef() const {
    // Fragile functions can reference 'static inline' functions imported
    // from C.
    if (hasForeignBody())
      return true;
  
    // If we can inline it, we can reference it.
    if (hasValidLinkageForFragileInline())
      return true;
  
    // If the containing module has been serialized already, we no longer
    // enforce any invariants.
    if (getModule().isSerialized())
      return true;
  
    // If the function has a subclass scope that limits its visibility outside
    // the module despite its linkage, we cannot reference it.
    if (getClassSubclassScope() == SubclassScope::Resilient &&
        isAvailableExternally())
      return false;
  
    // Otherwise, only public functions can be referenced.
    return hasPublicVisibility(getLinkage());
  }
  
  bool
  SILFunction::isPossiblyUsedExternally() const {
    auto linkage = getLinkage();
  
    // Hidden functions may be referenced by other C code in the linkage unit.
    if (linkage == SILLinkage::Hidden && hasCReferences())
      return true;
  
    if (ReplacedFunction)
      return true;
  
    return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
  }
  
  bool SILFunction::isExternallyUsedSymbol() const {
    return swift::isPossiblyUsedExternally(getEffectiveSymbolLinkage(),
                                           getModule().isWholeModule());
  }
  
  void SILFunction::clear() {
    dropAllReferences();
    eraseAllBlocks();
  }
  
  void SILFunction::eraseAllBlocks() {
    BlockList.clear();
  }
  
  SubstitutionMap SILFunction::getForwardingSubstitutionMap() {
    if (ForwardingSubMap)
      return ForwardingSubMap;
  
    if (auto *env = getGenericEnvironment())
      ForwardingSubMap = env->getForwardingSubstitutionMap();
  
    return ForwardingSubMap;
  }
  
  bool SILFunction::shouldVerifyOwnership() const {
    return !hasSemanticsAttr("verify.ownership.sil.never");
  }
  
  static Identifier getIdentifierForObjCSelector(ObjCSelector selector, ASTContext &Ctxt) {
    SmallVector<char, 64> buffer;
    auto str = selector.getString(buffer);
    return Ctxt.getIdentifier(str);
  }
  
  void SILFunction::setObjCReplacement(AbstractFunctionDecl *replacedFunc) {
    assert(ReplacedFunction == nullptr && ObjCReplacementFor.empty());
    assert(replacedFunc != nullptr);
    ObjCReplacementFor = getIdentifierForObjCSelector(
        replacedFunc->getObjCSelector(), getASTContext());
  }
  
  void SILFunction::setObjCReplacement(Identifier replacedFunc) {
    assert(ReplacedFunction == nullptr && ObjCReplacementFor.empty());
    ObjCReplacementFor = replacedFunc;
  }
  
  // See swift/Basic/Statistic.h for declaration: this enables tracing
  // SILFunctions, is defined here to avoid too much layering violation / circular
  // linkage dependency.
  
  struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
    void traceName(const void *Entity, raw_ostream &OS) const override {
      if (!Entity)
        return;
      const SILFunction *F = static_cast<const SILFunction *>(Entity);
      F->printName(OS);
    }
  
    void traceLoc(const void *Entity, SourceManager *SM,
                  clang::SourceManager *CSM, raw_ostream &OS) const override {
      if (!Entity)
        return;
      const SILFunction *F = static_cast<const SILFunction *>(Entity);
      if (!F->hasLocation())
        return;
      F->getLocation().getSourceRange().print(OS, *SM, false);
    }
  };
  
  static SILFunctionTraceFormatter TF;
  
  template<>
  const UnifiedStatsReporter::TraceFormatter*
  FrontendStatsTracer::getTraceFormatter<const SILFunction *>() {
    return &TF;
  }
  
  bool SILFunction::hasPrespecialization() const {
    for (auto *attr : getSpecializeAttrs()) {
      if (attr->isExported())
        return true;
    }
    return false;
  }
  
  void SILFunction::forEachSpecializeAttrTargetFunction(
        llvm::function_ref<void(SILFunction *)> action) {
    for (auto *attr : getSpecializeAttrs()) {
      if (auto *f = attr->getTargetFunction()) {
        action(f);
      }
    }
  }
  