| //===- ModuleSummaryAnalysis.cpp - Module summary index builder -----------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This pass builds a ModuleSummaryIndex object for the module, to be written | 
 | // to bitcode or LLVM assembly. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/Analysis/ModuleSummaryAnalysis.h" | 
 | #include "llvm/ADT/ArrayRef.h" | 
 | #include "llvm/ADT/DenseSet.h" | 
 | #include "llvm/ADT/MapVector.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/SetVector.h" | 
 | #include "llvm/ADT/SmallPtrSet.h" | 
 | #include "llvm/ADT/SmallVector.h" | 
 | #include "llvm/ADT/StringRef.h" | 
 | #include "llvm/Analysis/BlockFrequencyInfo.h" | 
 | #include "llvm/Analysis/BranchProbabilityInfo.h" | 
 | #include "llvm/Analysis/IndirectCallPromotionAnalysis.h" | 
 | #include "llvm/Analysis/LoopInfo.h" | 
 | #include "llvm/Analysis/ProfileSummaryInfo.h" | 
 | #include "llvm/Analysis/TypeMetadataUtils.h" | 
 | #include "llvm/IR/Attributes.h" | 
 | #include "llvm/IR/BasicBlock.h" | 
 | #include "llvm/IR/CallSite.h" | 
 | #include "llvm/IR/Constant.h" | 
 | #include "llvm/IR/Constants.h" | 
 | #include "llvm/IR/Dominators.h" | 
 | #include "llvm/IR/Function.h" | 
 | #include "llvm/IR/GlobalAlias.h" | 
 | #include "llvm/IR/GlobalValue.h" | 
 | #include "llvm/IR/GlobalVariable.h" | 
 | #include "llvm/IR/Instructions.h" | 
 | #include "llvm/IR/IntrinsicInst.h" | 
 | #include "llvm/IR/Intrinsics.h" | 
 | #include "llvm/IR/Metadata.h" | 
 | #include "llvm/IR/Module.h" | 
 | #include "llvm/IR/ModuleSummaryIndex.h" | 
 | #include "llvm/IR/Use.h" | 
 | #include "llvm/IR/User.h" | 
 | #include "llvm/Object/ModuleSymbolTable.h" | 
 | #include "llvm/Object/SymbolicFile.h" | 
 | #include "llvm/Pass.h" | 
 | #include "llvm/Support/Casting.h" | 
 | #include "llvm/Support/CommandLine.h" | 
 | #include <algorithm> | 
 | #include <cassert> | 
 | #include <cstdint> | 
 | #include <vector> | 
 |  | 
 | using namespace llvm; | 
 |  | 
 | #define DEBUG_TYPE "module-summary-analysis" | 
 |  | 
 | // Option to force edges cold which will block importing when the | 
 | // -import-cold-multiplier is set to 0. Useful for debugging. | 
 | FunctionSummary::ForceSummaryHotnessType ForceSummaryEdgesCold = | 
 |     FunctionSummary::FSHT_None; | 
 | cl::opt<FunctionSummary::ForceSummaryHotnessType, true> FSEC( | 
 |     "force-summary-edges-cold", cl::Hidden, cl::location(ForceSummaryEdgesCold), | 
 |     cl::desc("Force all edges in the function summary to cold"), | 
 |     cl::values(clEnumValN(FunctionSummary::FSHT_None, "none", "None."), | 
 |                clEnumValN(FunctionSummary::FSHT_AllNonCritical, | 
 |                           "all-non-critical", "All non-critical edges."), | 
 |                clEnumValN(FunctionSummary::FSHT_All, "all", "All edges."))); | 
 |  | 
 | // Walk through the operands of a given User via worklist iteration and populate | 
 | // the set of GlobalValue references encountered. Invoked either on an | 
 | // Instruction or a GlobalVariable (which walks its initializer). | 
 | // Return true if any of the operands contains blockaddress. This is important | 
 | // to know when computing summary for global var, because if global variable | 
 | // references basic block address we can't import it separately from function | 
 | // containing that basic block. For simplicity we currently don't import such | 
 | // global vars at all. When importing function we aren't interested if any  | 
 | // instruction in it takes an address of any basic block, because instruction | 
 | // can only take an address of basic block located in the same function. | 
 | static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser, | 
 |                          SetVector<ValueInfo> &RefEdges, | 
 |                          SmallPtrSet<const User *, 8> &Visited) { | 
 |   bool HasBlockAddress = false; | 
 |   SmallVector<const User *, 32> Worklist; | 
 |   Worklist.push_back(CurUser); | 
 |  | 
 |   while (!Worklist.empty()) { | 
 |     const User *U = Worklist.pop_back_val(); | 
 |  | 
 |     if (!Visited.insert(U).second) | 
 |       continue; | 
 |  | 
 |     ImmutableCallSite CS(U); | 
 |  | 
 |     for (const auto &OI : U->operands()) { | 
 |       const User *Operand = dyn_cast<User>(OI); | 
 |       if (!Operand) | 
 |         continue; | 
 |       if (isa<BlockAddress>(Operand)) { | 
 |         HasBlockAddress = true; | 
 |         continue; | 
 |       } | 
 |       if (auto *GV = dyn_cast<GlobalValue>(Operand)) { | 
 |         // We have a reference to a global value. This should be added to | 
 |         // the reference set unless it is a callee. Callees are handled | 
 |         // specially by WriteFunction and are added to a separate list. | 
 |         if (!(CS && CS.isCallee(&OI))) | 
 |           RefEdges.insert(Index.getOrInsertValueInfo(GV)); | 
 |         continue; | 
 |       } | 
 |       Worklist.push_back(Operand); | 
 |     } | 
 |   } | 
 |   return HasBlockAddress; | 
 | } | 
 |  | 
 | static CalleeInfo::HotnessType getHotness(uint64_t ProfileCount, | 
 |                                           ProfileSummaryInfo *PSI) { | 
 |   if (!PSI) | 
 |     return CalleeInfo::HotnessType::Unknown; | 
 |   if (PSI->isHotCount(ProfileCount)) | 
 |     return CalleeInfo::HotnessType::Hot; | 
 |   if (PSI->isColdCount(ProfileCount)) | 
 |     return CalleeInfo::HotnessType::Cold; | 
 |   return CalleeInfo::HotnessType::None; | 
 | } | 
 |  | 
 | static bool isNonRenamableLocal(const GlobalValue &GV) { | 
 |   return GV.hasSection() && GV.hasLocalLinkage(); | 
 | } | 
 |  | 
 | /// Determine whether this call has all constant integer arguments (excluding | 
 | /// "this") and summarize it to VCalls or ConstVCalls as appropriate. | 
 | static void addVCallToSet(DevirtCallSite Call, GlobalValue::GUID Guid, | 
 |                           SetVector<FunctionSummary::VFuncId> &VCalls, | 
 |                           SetVector<FunctionSummary::ConstVCall> &ConstVCalls) { | 
 |   std::vector<uint64_t> Args; | 
 |   // Start from the second argument to skip the "this" pointer. | 
 |   for (auto &Arg : make_range(Call.CS.arg_begin() + 1, Call.CS.arg_end())) { | 
 |     auto *CI = dyn_cast<ConstantInt>(Arg); | 
 |     if (!CI || CI->getBitWidth() > 64) { | 
 |       VCalls.insert({Guid, Call.Offset}); | 
 |       return; | 
 |     } | 
 |     Args.push_back(CI->getZExtValue()); | 
 |   } | 
 |   ConstVCalls.insert({{Guid, Call.Offset}, std::move(Args)}); | 
 | } | 
 |  | 
 | /// If this intrinsic call requires that we add information to the function | 
 | /// summary, do so via the non-constant reference arguments. | 
 | static void addIntrinsicToSummary( | 
 |     const CallInst *CI, SetVector<GlobalValue::GUID> &TypeTests, | 
 |     SetVector<FunctionSummary::VFuncId> &TypeTestAssumeVCalls, | 
 |     SetVector<FunctionSummary::VFuncId> &TypeCheckedLoadVCalls, | 
 |     SetVector<FunctionSummary::ConstVCall> &TypeTestAssumeConstVCalls, | 
 |     SetVector<FunctionSummary::ConstVCall> &TypeCheckedLoadConstVCalls) { | 
 |   switch (CI->getCalledFunction()->getIntrinsicID()) { | 
 |   case Intrinsic::type_test: { | 
 |     auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(1)); | 
 |     auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata()); | 
 |     if (!TypeId) | 
 |       break; | 
 |     GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString()); | 
 |  | 
 |     // Produce a summary from type.test intrinsics. We only summarize type.test | 
 |     // intrinsics that are used other than by an llvm.assume intrinsic. | 
 |     // Intrinsics that are assumed are relevant only to the devirtualization | 
 |     // pass, not the type test lowering pass. | 
 |     bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) { | 
 |       auto *AssumeCI = dyn_cast<CallInst>(CIU.getUser()); | 
 |       if (!AssumeCI) | 
 |         return true; | 
 |       Function *F = AssumeCI->getCalledFunction(); | 
 |       return !F || F->getIntrinsicID() != Intrinsic::assume; | 
 |     }); | 
 |     if (HasNonAssumeUses) | 
 |       TypeTests.insert(Guid); | 
 |  | 
 |     SmallVector<DevirtCallSite, 4> DevirtCalls; | 
 |     SmallVector<CallInst *, 4> Assumes; | 
 |     findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI); | 
 |     for (auto &Call : DevirtCalls) | 
 |       addVCallToSet(Call, Guid, TypeTestAssumeVCalls, | 
 |                     TypeTestAssumeConstVCalls); | 
 |  | 
 |     break; | 
 |   } | 
 |  | 
 |   case Intrinsic::type_checked_load: { | 
 |     auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(2)); | 
 |     auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata()); | 
 |     if (!TypeId) | 
 |       break; | 
 |     GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString()); | 
 |  | 
 |     SmallVector<DevirtCallSite, 4> DevirtCalls; | 
 |     SmallVector<Instruction *, 4> LoadedPtrs; | 
 |     SmallVector<Instruction *, 4> Preds; | 
 |     bool HasNonCallUses = false; | 
 |     findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds, | 
 |                                                HasNonCallUses, CI); | 
 |     // Any non-call uses of the result of llvm.type.checked.load will | 
 |     // prevent us from optimizing away the llvm.type.test. | 
 |     if (HasNonCallUses) | 
 |       TypeTests.insert(Guid); | 
 |     for (auto &Call : DevirtCalls) | 
 |       addVCallToSet(Call, Guid, TypeCheckedLoadVCalls, | 
 |                     TypeCheckedLoadConstVCalls); | 
 |  | 
 |     break; | 
 |   } | 
 |   default: | 
 |     break; | 
 |   } | 
 | } | 
 |  | 
 | static void | 
 | computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, | 
 |                        const Function &F, BlockFrequencyInfo *BFI, | 
 |                        ProfileSummaryInfo *PSI, bool HasLocalsInUsedOrAsm, | 
 |                        DenseSet<GlobalValue::GUID> &CantBePromoted) { | 
 |   // Summary not currently supported for anonymous functions, they should | 
 |   // have been named. | 
 |   assert(F.hasName()); | 
 |  | 
 |   unsigned NumInsts = 0; | 
 |   // Map from callee ValueId to profile count. Used to accumulate profile | 
 |   // counts for all static calls to a given callee. | 
 |   MapVector<ValueInfo, CalleeInfo> CallGraphEdges; | 
 |   SetVector<ValueInfo> RefEdges; | 
 |   SetVector<GlobalValue::GUID> TypeTests; | 
 |   SetVector<FunctionSummary::VFuncId> TypeTestAssumeVCalls, | 
 |       TypeCheckedLoadVCalls; | 
 |   SetVector<FunctionSummary::ConstVCall> TypeTestAssumeConstVCalls, | 
 |       TypeCheckedLoadConstVCalls; | 
 |   ICallPromotionAnalysis ICallAnalysis; | 
 |   SmallPtrSet<const User *, 8> Visited; | 
 |  | 
 |   // Add personality function, prefix data and prologue data to function's ref | 
 |   // list. | 
 |   findRefEdges(Index, &F, RefEdges, Visited); | 
 |  | 
 |   bool HasInlineAsmMaybeReferencingInternal = false; | 
 |   for (const BasicBlock &BB : F) | 
 |     for (const Instruction &I : BB) { | 
 |       if (isa<DbgInfoIntrinsic>(I)) | 
 |         continue; | 
 |       ++NumInsts; | 
 |       findRefEdges(Index, &I, RefEdges, Visited); | 
 |       auto CS = ImmutableCallSite(&I); | 
 |       if (!CS) | 
 |         continue; | 
 |  | 
 |       const auto *CI = dyn_cast<CallInst>(&I); | 
 |       // Since we don't know exactly which local values are referenced in inline | 
 |       // assembly, conservatively mark the function as possibly referencing | 
 |       // a local value from inline assembly to ensure we don't export a | 
 |       // reference (which would require renaming and promotion of the | 
 |       // referenced value). | 
 |       if (HasLocalsInUsedOrAsm && CI && CI->isInlineAsm()) | 
 |         HasInlineAsmMaybeReferencingInternal = true; | 
 |  | 
 |       auto *CalledValue = CS.getCalledValue(); | 
 |       auto *CalledFunction = CS.getCalledFunction(); | 
 |       if (CalledValue && !CalledFunction) { | 
 |         CalledValue = CalledValue->stripPointerCastsNoFollowAliases(); | 
 |         // Stripping pointer casts can reveal a called function. | 
 |         CalledFunction = dyn_cast<Function>(CalledValue); | 
 |       } | 
 |       // Check if this is an alias to a function. If so, get the | 
 |       // called aliasee for the checks below. | 
 |       if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) { | 
 |         assert(!CalledFunction && "Expected null called function in callsite for alias"); | 
 |         CalledFunction = dyn_cast<Function>(GA->getBaseObject()); | 
 |       } | 
 |       // Check if this is a direct call to a known function or a known | 
 |       // intrinsic, or an indirect call with profile data. | 
 |       if (CalledFunction) { | 
 |         if (CI && CalledFunction->isIntrinsic()) { | 
 |           addIntrinsicToSummary( | 
 |               CI, TypeTests, TypeTestAssumeVCalls, TypeCheckedLoadVCalls, | 
 |               TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls); | 
 |           continue; | 
 |         } | 
 |         // We should have named any anonymous globals | 
 |         assert(CalledFunction->hasName()); | 
 |         auto ScaledCount = PSI->getProfileCount(&I, BFI); | 
 |         auto Hotness = ScaledCount ? getHotness(ScaledCount.getValue(), PSI) | 
 |                                    : CalleeInfo::HotnessType::Unknown; | 
 |         if (ForceSummaryEdgesCold != FunctionSummary::FSHT_None) | 
 |           Hotness = CalleeInfo::HotnessType::Cold; | 
 |  | 
 |         // Use the original CalledValue, in case it was an alias. We want | 
 |         // to record the call edge to the alias in that case. Eventually | 
 |         // an alias summary will be created to associate the alias and | 
 |         // aliasee. | 
 |         auto &ValueInfo = CallGraphEdges[Index.getOrInsertValueInfo( | 
 |             cast<GlobalValue>(CalledValue))]; | 
 |         ValueInfo.updateHotness(Hotness); | 
 |         // Add the relative block frequency to CalleeInfo if there is no profile | 
 |         // information. | 
 |         if (BFI != nullptr && Hotness == CalleeInfo::HotnessType::Unknown) { | 
 |           uint64_t BBFreq = BFI->getBlockFreq(&BB).getFrequency(); | 
 |           uint64_t EntryFreq = BFI->getEntryFreq(); | 
 |           ValueInfo.updateRelBlockFreq(BBFreq, EntryFreq); | 
 |         } | 
 |       } else { | 
 |         // Skip inline assembly calls. | 
 |         if (CI && CI->isInlineAsm()) | 
 |           continue; | 
 |         // Skip direct calls. | 
 |         if (!CalledValue || isa<Constant>(CalledValue)) | 
 |           continue; | 
 |  | 
 |         // Check if the instruction has a callees metadata. If so, add callees | 
 |         // to CallGraphEdges to reflect the references from the metadata, and | 
 |         // to enable importing for subsequent indirect call promotion and | 
 |         // inlining. | 
 |         if (auto *MD = I.getMetadata(LLVMContext::MD_callees)) { | 
 |           for (auto &Op : MD->operands()) { | 
 |             Function *Callee = mdconst::extract_or_null<Function>(Op); | 
 |             if (Callee) | 
 |               CallGraphEdges[Index.getOrInsertValueInfo(Callee)]; | 
 |           } | 
 |         } | 
 |  | 
 |         uint32_t NumVals, NumCandidates; | 
 |         uint64_t TotalCount; | 
 |         auto CandidateProfileData = | 
 |             ICallAnalysis.getPromotionCandidatesForInstruction( | 
 |                 &I, NumVals, TotalCount, NumCandidates); | 
 |         for (auto &Candidate : CandidateProfileData) | 
 |           CallGraphEdges[Index.getOrInsertValueInfo(Candidate.Value)] | 
 |               .updateHotness(getHotness(Candidate.Count, PSI)); | 
 |       } | 
 |     } | 
 |  | 
 |   // Explicit add hot edges to enforce importing for designated GUIDs for | 
 |   // sample PGO, to enable the same inlines as the profiled optimized binary. | 
 |   for (auto &I : F.getImportGUIDs()) | 
 |     CallGraphEdges[Index.getOrInsertValueInfo(I)].updateHotness( | 
 |         ForceSummaryEdgesCold == FunctionSummary::FSHT_All | 
 |             ? CalleeInfo::HotnessType::Cold | 
 |             : CalleeInfo::HotnessType::Critical); | 
 |  | 
 |   bool NonRenamableLocal = isNonRenamableLocal(F); | 
 |   bool NotEligibleForImport = | 
 |       NonRenamableLocal || HasInlineAsmMaybeReferencingInternal || | 
 |       // Inliner doesn't handle variadic functions. | 
 |       // FIXME: refactor this to use the same code that inliner is using. | 
 |       F.isVarArg() || | 
 |       // Don't try to import functions with noinline attribute. | 
 |       F.getAttributes().hasFnAttribute(Attribute::NoInline); | 
 |   GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport, | 
 |                                     /* Live = */ false, F.isDSOLocal()); | 
 |   FunctionSummary::FFlags FunFlags{ | 
 |       F.hasFnAttribute(Attribute::ReadNone), | 
 |       F.hasFnAttribute(Attribute::ReadOnly), | 
 |       F.hasFnAttribute(Attribute::NoRecurse), | 
 |       F.returnDoesNotAlias(), | 
 |   }; | 
 |   auto FuncSummary = llvm::make_unique<FunctionSummary>( | 
 |       Flags, NumInsts, FunFlags, RefEdges.takeVector(), | 
 |       CallGraphEdges.takeVector(), TypeTests.takeVector(), | 
 |       TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(), | 
 |       TypeTestAssumeConstVCalls.takeVector(), | 
 |       TypeCheckedLoadConstVCalls.takeVector()); | 
 |   if (NonRenamableLocal) | 
 |     CantBePromoted.insert(F.getGUID()); | 
 |   Index.addGlobalValueSummary(F, std::move(FuncSummary)); | 
 | } | 
 |  | 
 | static void | 
 | computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V, | 
 |                        DenseSet<GlobalValue::GUID> &CantBePromoted) { | 
 |   SetVector<ValueInfo> RefEdges; | 
 |   SmallPtrSet<const User *, 8> Visited; | 
 |   bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited); | 
 |   bool NonRenamableLocal = isNonRenamableLocal(V); | 
 |   GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal, | 
 |                                     /* Live = */ false, V.isDSOLocal()); | 
 |   auto GVarSummary = | 
 |       llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector()); | 
 |   if (NonRenamableLocal) | 
 |     CantBePromoted.insert(V.getGUID()); | 
 |   if (HasBlockAddress) | 
 |     GVarSummary->setNotEligibleToImport(); | 
 |   Index.addGlobalValueSummary(V, std::move(GVarSummary)); | 
 | } | 
 |  | 
 | static void | 
 | computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A, | 
 |                     DenseSet<GlobalValue::GUID> &CantBePromoted) { | 
 |   bool NonRenamableLocal = isNonRenamableLocal(A); | 
 |   GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal, | 
 |                                     /* Live = */ false, A.isDSOLocal()); | 
 |   auto AS = llvm::make_unique<AliasSummary>(Flags); | 
 |   auto *Aliasee = A.getBaseObject(); | 
 |   auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee); | 
 |   assert(AliaseeSummary && "Alias expects aliasee summary to be parsed"); | 
 |   AS->setAliasee(AliaseeSummary); | 
 |   if (NonRenamableLocal) | 
 |     CantBePromoted.insert(A.getGUID()); | 
 |   Index.addGlobalValueSummary(A, std::move(AS)); | 
 | } | 
 |  | 
 | // Set LiveRoot flag on entries matching the given value name. | 
 | static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) { | 
 |   if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name))) | 
 |     for (auto &Summary : VI.getSummaryList()) | 
 |       Summary->setLive(true); | 
 | } | 
 |  | 
 | ModuleSummaryIndex llvm::buildModuleSummaryIndex( | 
 |     const Module &M, | 
 |     std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback, | 
 |     ProfileSummaryInfo *PSI) { | 
 |   assert(PSI); | 
 |   ModuleSummaryIndex Index(/*HaveGVs=*/true); | 
 |  | 
 |   // Identify the local values in the llvm.used and llvm.compiler.used sets, | 
 |   // which should not be exported as they would then require renaming and | 
 |   // promotion, but we may have opaque uses e.g. in inline asm. We collect them | 
 |   // here because we use this information to mark functions containing inline | 
 |   // assembly calls as not importable. | 
 |   SmallPtrSet<GlobalValue *, 8> LocalsUsed; | 
 |   SmallPtrSet<GlobalValue *, 8> Used; | 
 |   // First collect those in the llvm.used set. | 
 |   collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); | 
 |   // Next collect those in the llvm.compiler.used set. | 
 |   collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ true); | 
 |   DenseSet<GlobalValue::GUID> CantBePromoted; | 
 |   for (auto *V : Used) { | 
 |     if (V->hasLocalLinkage()) { | 
 |       LocalsUsed.insert(V); | 
 |       CantBePromoted.insert(V->getGUID()); | 
 |     } | 
 |   } | 
 |  | 
 |   bool HasLocalInlineAsmSymbol = false; | 
 |   if (!M.getModuleInlineAsm().empty()) { | 
 |     // Collect the local values defined by module level asm, and set up | 
 |     // summaries for these symbols so that they can be marked as NoRename, | 
 |     // to prevent export of any use of them in regular IR that would require | 
 |     // renaming within the module level asm. Note we don't need to create a | 
 |     // summary for weak or global defs, as they don't need to be flagged as | 
 |     // NoRename, and defs in module level asm can't be imported anyway. | 
 |     // Also, any values used but not defined within module level asm should | 
 |     // be listed on the llvm.used or llvm.compiler.used global and marked as | 
 |     // referenced from there. | 
 |     ModuleSymbolTable::CollectAsmSymbols( | 
 |         M, [&](StringRef Name, object::BasicSymbolRef::Flags Flags) { | 
 |           // Symbols not marked as Weak or Global are local definitions. | 
 |           if (Flags & (object::BasicSymbolRef::SF_Weak | | 
 |                        object::BasicSymbolRef::SF_Global)) | 
 |             return; | 
 |           HasLocalInlineAsmSymbol = true; | 
 |           GlobalValue *GV = M.getNamedValue(Name); | 
 |           if (!GV) | 
 |             return; | 
 |           assert(GV->isDeclaration() && "Def in module asm already has definition"); | 
 |           GlobalValueSummary::GVFlags GVFlags(GlobalValue::InternalLinkage, | 
 |                                               /* NotEligibleToImport = */ true, | 
 |                                               /* Live = */ true, | 
 |                                               /* Local */ GV->isDSOLocal()); | 
 |           CantBePromoted.insert(GV->getGUID()); | 
 |           // Create the appropriate summary type. | 
 |           if (Function *F = dyn_cast<Function>(GV)) { | 
 |             std::unique_ptr<FunctionSummary> Summary = | 
 |                 llvm::make_unique<FunctionSummary>( | 
 |                     GVFlags, 0, | 
 |                     FunctionSummary::FFlags{ | 
 |                         F->hasFnAttribute(Attribute::ReadNone), | 
 |                         F->hasFnAttribute(Attribute::ReadOnly), | 
 |                         F->hasFnAttribute(Attribute::NoRecurse), | 
 |                         F->returnDoesNotAlias()}, | 
 |                     ArrayRef<ValueInfo>{}, ArrayRef<FunctionSummary::EdgeTy>{}, | 
 |                     ArrayRef<GlobalValue::GUID>{}, | 
 |                     ArrayRef<FunctionSummary::VFuncId>{}, | 
 |                     ArrayRef<FunctionSummary::VFuncId>{}, | 
 |                     ArrayRef<FunctionSummary::ConstVCall>{}, | 
 |                     ArrayRef<FunctionSummary::ConstVCall>{}); | 
 |             Index.addGlobalValueSummary(*GV, std::move(Summary)); | 
 |           } else { | 
 |             std::unique_ptr<GlobalVarSummary> Summary = | 
 |                 llvm::make_unique<GlobalVarSummary>(GVFlags, | 
 |                                                     ArrayRef<ValueInfo>{}); | 
 |             Index.addGlobalValueSummary(*GV, std::move(Summary)); | 
 |           } | 
 |         }); | 
 |   } | 
 |  | 
 |   // Compute summaries for all functions defined in module, and save in the | 
 |   // index. | 
 |   for (auto &F : M) { | 
 |     if (F.isDeclaration()) | 
 |       continue; | 
 |  | 
 |     BlockFrequencyInfo *BFI = nullptr; | 
 |     std::unique_ptr<BlockFrequencyInfo> BFIPtr; | 
 |     if (GetBFICallback) | 
 |       BFI = GetBFICallback(F); | 
 |     else if (F.hasProfileData()) { | 
 |       LoopInfo LI{DominatorTree(const_cast<Function &>(F))}; | 
 |       BranchProbabilityInfo BPI{F, LI}; | 
 |       BFIPtr = llvm::make_unique<BlockFrequencyInfo>(F, BPI, LI); | 
 |       BFI = BFIPtr.get(); | 
 |     } | 
 |  | 
 |     computeFunctionSummary(Index, M, F, BFI, PSI, | 
 |                            !LocalsUsed.empty() || HasLocalInlineAsmSymbol, | 
 |                            CantBePromoted); | 
 |   } | 
 |  | 
 |   // Compute summaries for all variables defined in module, and save in the | 
 |   // index. | 
 |   for (const GlobalVariable &G : M.globals()) { | 
 |     if (G.isDeclaration()) | 
 |       continue; | 
 |     computeVariableSummary(Index, G, CantBePromoted); | 
 |   } | 
 |  | 
 |   // Compute summaries for all aliases defined in module, and save in the | 
 |   // index. | 
 |   for (const GlobalAlias &A : M.aliases()) | 
 |     computeAliasSummary(Index, A, CantBePromoted); | 
 |  | 
 |   for (auto *V : LocalsUsed) { | 
 |     auto *Summary = Index.getGlobalValueSummary(*V); | 
 |     assert(Summary && "Missing summary for global value"); | 
 |     Summary->setNotEligibleToImport(); | 
 |   } | 
 |  | 
 |   // The linker doesn't know about these LLVM produced values, so we need | 
 |   // to flag them as live in the index to ensure index-based dead value | 
 |   // analysis treats them as live roots of the analysis. | 
 |   setLiveRoot(Index, "llvm.used"); | 
 |   setLiveRoot(Index, "llvm.compiler.used"); | 
 |   setLiveRoot(Index, "llvm.global_ctors"); | 
 |   setLiveRoot(Index, "llvm.global_dtors"); | 
 |   setLiveRoot(Index, "llvm.global.annotations"); | 
 |  | 
 |   bool IsThinLTO = true; | 
 |   if (auto *MD = | 
 |           mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO"))) | 
 |     IsThinLTO = MD->getZExtValue(); | 
 |  | 
 |   for (auto &GlobalList : Index) { | 
 |     // Ignore entries for references that are undefined in the current module. | 
 |     if (GlobalList.second.SummaryList.empty()) | 
 |       continue; | 
 |  | 
 |     assert(GlobalList.second.SummaryList.size() == 1 && | 
 |            "Expected module's index to have one summary per GUID"); | 
 |     auto &Summary = GlobalList.second.SummaryList[0]; | 
 |     if (!IsThinLTO) { | 
 |       Summary->setNotEligibleToImport(); | 
 |       continue; | 
 |     } | 
 |  | 
 |     bool AllRefsCanBeExternallyReferenced = | 
 |         llvm::all_of(Summary->refs(), [&](const ValueInfo &VI) { | 
 |           return !CantBePromoted.count(VI.getGUID()); | 
 |         }); | 
 |     if (!AllRefsCanBeExternallyReferenced) { | 
 |       Summary->setNotEligibleToImport(); | 
 |       continue; | 
 |     } | 
 |  | 
 |     if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) { | 
 |       bool AllCallsCanBeExternallyReferenced = llvm::all_of( | 
 |           FuncSummary->calls(), [&](const FunctionSummary::EdgeTy &Edge) { | 
 |             return !CantBePromoted.count(Edge.first.getGUID()); | 
 |           }); | 
 |       if (!AllCallsCanBeExternallyReferenced) | 
 |         Summary->setNotEligibleToImport(); | 
 |     } | 
 |   } | 
 |  | 
 |   return Index; | 
 | } | 
 |  | 
 | AnalysisKey ModuleSummaryIndexAnalysis::Key; | 
 |  | 
 | ModuleSummaryIndex | 
 | ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) { | 
 |   ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M); | 
 |   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | 
 |   return buildModuleSummaryIndex( | 
 |       M, | 
 |       [&FAM](const Function &F) { | 
 |         return &FAM.getResult<BlockFrequencyAnalysis>( | 
 |             *const_cast<Function *>(&F)); | 
 |       }, | 
 |       &PSI); | 
 | } | 
 |  | 
 | char ModuleSummaryIndexWrapperPass::ID = 0; | 
 |  | 
 | INITIALIZE_PASS_BEGIN(ModuleSummaryIndexWrapperPass, "module-summary-analysis", | 
 |                       "Module Summary Analysis", false, true) | 
 | INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) | 
 | INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) | 
 | INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis", | 
 |                     "Module Summary Analysis", false, true) | 
 |  | 
 | ModulePass *llvm::createModuleSummaryIndexWrapperPass() { | 
 |   return new ModuleSummaryIndexWrapperPass(); | 
 | } | 
 |  | 
 | ModuleSummaryIndexWrapperPass::ModuleSummaryIndexWrapperPass() | 
 |     : ModulePass(ID) { | 
 |   initializeModuleSummaryIndexWrapperPassPass(*PassRegistry::getPassRegistry()); | 
 | } | 
 |  | 
 | bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) { | 
 |   auto &PSI = *getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI(); | 
 |   Index.emplace(buildModuleSummaryIndex( | 
 |       M, | 
 |       [this](const Function &F) { | 
 |         return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>( | 
 |                          *const_cast<Function *>(&F)) | 
 |                      .getBFI()); | 
 |       }, | 
 |       &PSI)); | 
 |   return false; | 
 | } | 
 |  | 
 | bool ModuleSummaryIndexWrapperPass::doFinalization(Module &M) { | 
 |   Index.reset(); | 
 |   return false; | 
 | } | 
 |  | 
 | void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { | 
 |   AU.setPreservesAll(); | 
 |   AU.addRequired<BlockFrequencyInfoWrapperPass>(); | 
 |   AU.addRequired<ProfileSummaryInfoWrapperPass>(); | 
 | } |