10b57cec5SDimitry Andric //===- ModuleSummaryAnalysis.cpp - Module summary index builder -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass builds a ModuleSummaryIndex object for the module, to be written
100b57cec5SDimitry Andric // to bitcode or LLVM assembly.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/Analysis/ModuleSummaryAnalysis.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
160b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
170b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h"
180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
210b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
230b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
240b57cec5SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h"
25*0fca6ea1SDimitry Andric #include "llvm/Analysis/ConstantFolding.h"
260b57cec5SDimitry Andric #include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
270b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
28bdd1243dSDimitry Andric #include "llvm/Analysis/MemoryProfileInfo.h"
290b57cec5SDimitry Andric #include "llvm/Analysis/ProfileSummaryInfo.h"
305ffd83dbSDimitry Andric #include "llvm/Analysis/StackSafetyAnalysis.h"
310b57cec5SDimitry Andric #include "llvm/Analysis/TypeMetadataUtils.h"
320b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
330b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
340b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
350b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
360b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
370b57cec5SDimitry Andric #include "llvm/IR/Function.h"
380b57cec5SDimitry Andric #include "llvm/IR/GlobalAlias.h"
390b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h"
400b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
410b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
420b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
430b57cec5SDimitry Andric #include "llvm/IR/Metadata.h"
440b57cec5SDimitry Andric #include "llvm/IR/Module.h"
450b57cec5SDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h"
460b57cec5SDimitry Andric #include "llvm/IR/Use.h"
470b57cec5SDimitry Andric #include "llvm/IR/User.h"
48480093f4SDimitry Andric #include "llvm/InitializePasses.h"
490b57cec5SDimitry Andric #include "llvm/Object/ModuleSymbolTable.h"
500b57cec5SDimitry Andric #include "llvm/Object/SymbolicFile.h"
510b57cec5SDimitry Andric #include "llvm/Pass.h"
520b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
530b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
54fe6060f1SDimitry Andric #include "llvm/Support/FileSystem.h"
550b57cec5SDimitry Andric #include <algorithm>
560b57cec5SDimitry Andric #include <cassert>
570b57cec5SDimitry Andric #include <cstdint>
580b57cec5SDimitry Andric #include <vector>
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric using namespace llvm;
61bdd1243dSDimitry Andric using namespace llvm::memprof;
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric #define DEBUG_TYPE "module-summary-analysis"
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric // Option to force edges cold which will block importing when the
660b57cec5SDimitry Andric // -import-cold-multiplier is set to 0. Useful for debugging.
67bdd1243dSDimitry Andric namespace llvm {
680b57cec5SDimitry Andric FunctionSummary::ForceSummaryHotnessType ForceSummaryEdgesCold =
690b57cec5SDimitry Andric FunctionSummary::FSHT_None;
70bdd1243dSDimitry Andric } // namespace llvm
71bdd1243dSDimitry Andric
72bdd1243dSDimitry Andric static cl::opt<FunctionSummary::ForceSummaryHotnessType, true> FSEC(
730b57cec5SDimitry Andric "force-summary-edges-cold", cl::Hidden, cl::location(ForceSummaryEdgesCold),
740b57cec5SDimitry Andric cl::desc("Force all edges in the function summary to cold"),
750b57cec5SDimitry Andric cl::values(clEnumValN(FunctionSummary::FSHT_None, "none", "None."),
760b57cec5SDimitry Andric clEnumValN(FunctionSummary::FSHT_AllNonCritical,
770b57cec5SDimitry Andric "all-non-critical", "All non-critical edges."),
780b57cec5SDimitry Andric clEnumValN(FunctionSummary::FSHT_All, "all", "All edges.")));
790b57cec5SDimitry Andric
80bdd1243dSDimitry Andric static cl::opt<std::string> ModuleSummaryDotFile(
81bdd1243dSDimitry Andric "module-summary-dot-file", cl::Hidden, cl::value_desc("filename"),
82bdd1243dSDimitry Andric cl::desc("File to emit dot graph of new summary into"));
830b57cec5SDimitry Andric
8406c3fb27SDimitry Andric extern cl::opt<bool> ScalePartialSampleProfileWorkingSetSize;
8506c3fb27SDimitry Andric
86*0fca6ea1SDimitry Andric extern cl::opt<unsigned> MaxNumVTableAnnotations;
87*0fca6ea1SDimitry Andric
88*0fca6ea1SDimitry Andric extern cl::opt<bool> MemProfReportHintedSizes;
89*0fca6ea1SDimitry Andric
900b57cec5SDimitry Andric // Walk through the operands of a given User via worklist iteration and populate
910b57cec5SDimitry Andric // the set of GlobalValue references encountered. Invoked either on an
920b57cec5SDimitry Andric // Instruction or a GlobalVariable (which walks its initializer).
930b57cec5SDimitry Andric // Return true if any of the operands contains blockaddress. This is important
940b57cec5SDimitry Andric // to know when computing summary for global var, because if global variable
950b57cec5SDimitry Andric // references basic block address we can't import it separately from function
960b57cec5SDimitry Andric // containing that basic block. For simplicity we currently don't import such
970b57cec5SDimitry Andric // global vars at all. When importing function we aren't interested if any
980b57cec5SDimitry Andric // instruction in it takes an address of any basic block, because instruction
990b57cec5SDimitry Andric // can only take an address of basic block located in the same function.
100*0fca6ea1SDimitry Andric // Set `RefLocalLinkageIFunc` to true if the analyzed value references a
101*0fca6ea1SDimitry Andric // local-linkage ifunc.
findRefEdges(ModuleSummaryIndex & Index,const User * CurUser,SetVector<ValueInfo,std::vector<ValueInfo>> & RefEdges,SmallPtrSet<const User *,8> & Visited,bool & RefLocalLinkageIFunc)1020b57cec5SDimitry Andric static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
1035f757f3fSDimitry Andric SetVector<ValueInfo, std::vector<ValueInfo>> &RefEdges,
104*0fca6ea1SDimitry Andric SmallPtrSet<const User *, 8> &Visited,
105*0fca6ea1SDimitry Andric bool &RefLocalLinkageIFunc) {
1060b57cec5SDimitry Andric bool HasBlockAddress = false;
1070b57cec5SDimitry Andric SmallVector<const User *, 32> Worklist;
108fe6060f1SDimitry Andric if (Visited.insert(CurUser).second)
1090b57cec5SDimitry Andric Worklist.push_back(CurUser);
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric while (!Worklist.empty()) {
1120b57cec5SDimitry Andric const User *U = Worklist.pop_back_val();
1135ffd83dbSDimitry Andric const auto *CB = dyn_cast<CallBase>(U);
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric for (const auto &OI : U->operands()) {
1160b57cec5SDimitry Andric const User *Operand = dyn_cast<User>(OI);
1170b57cec5SDimitry Andric if (!Operand)
1180b57cec5SDimitry Andric continue;
1190b57cec5SDimitry Andric if (isa<BlockAddress>(Operand)) {
1200b57cec5SDimitry Andric HasBlockAddress = true;
1210b57cec5SDimitry Andric continue;
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric if (auto *GV = dyn_cast<GlobalValue>(Operand)) {
1240b57cec5SDimitry Andric // We have a reference to a global value. This should be added to
1250b57cec5SDimitry Andric // the reference set unless it is a callee. Callees are handled
1260b57cec5SDimitry Andric // specially by WriteFunction and are added to a separate list.
127*0fca6ea1SDimitry Andric if (!(CB && CB->isCallee(&OI))) {
128*0fca6ea1SDimitry Andric // If an ifunc has local linkage, do not add it into ref edges, and
129*0fca6ea1SDimitry Andric // sets `RefLocalLinkageIFunc` to true. The referencer is not eligible
130*0fca6ea1SDimitry Andric // for import. An ifunc doesn't have summary and ThinLTO cannot
131*0fca6ea1SDimitry Andric // promote it; importing the referencer may cause linkage errors.
132*0fca6ea1SDimitry Andric if (auto *GI = dyn_cast_if_present<GlobalIFunc>(GV);
133*0fca6ea1SDimitry Andric GI && GI->hasLocalLinkage()) {
134*0fca6ea1SDimitry Andric RefLocalLinkageIFunc = true;
135*0fca6ea1SDimitry Andric continue;
136*0fca6ea1SDimitry Andric }
1370b57cec5SDimitry Andric RefEdges.insert(Index.getOrInsertValueInfo(GV));
138*0fca6ea1SDimitry Andric }
1390b57cec5SDimitry Andric continue;
1400b57cec5SDimitry Andric }
141fe6060f1SDimitry Andric if (Visited.insert(Operand).second)
1420b57cec5SDimitry Andric Worklist.push_back(Operand);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric }
145*0fca6ea1SDimitry Andric
146*0fca6ea1SDimitry Andric const Instruction *I = dyn_cast<Instruction>(CurUser);
147*0fca6ea1SDimitry Andric if (I) {
148*0fca6ea1SDimitry Andric uint64_t TotalCount = 0;
149*0fca6ea1SDimitry Andric // MaxNumVTableAnnotations is the maximum number of vtables annotated on
150*0fca6ea1SDimitry Andric // the instruction.
151*0fca6ea1SDimitry Andric auto ValueDataArray = getValueProfDataFromInst(
152*0fca6ea1SDimitry Andric *I, IPVK_VTableTarget, MaxNumVTableAnnotations, TotalCount);
153*0fca6ea1SDimitry Andric
154*0fca6ea1SDimitry Andric for (const auto &V : ValueDataArray)
155*0fca6ea1SDimitry Andric RefEdges.insert(Index.getOrInsertValueInfo(/* VTableGUID = */
156*0fca6ea1SDimitry Andric V.Value));
157*0fca6ea1SDimitry Andric }
1580b57cec5SDimitry Andric return HasBlockAddress;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric
getHotness(uint64_t ProfileCount,ProfileSummaryInfo * PSI)1610b57cec5SDimitry Andric static CalleeInfo::HotnessType getHotness(uint64_t ProfileCount,
1620b57cec5SDimitry Andric ProfileSummaryInfo *PSI) {
1630b57cec5SDimitry Andric if (!PSI)
1640b57cec5SDimitry Andric return CalleeInfo::HotnessType::Unknown;
1650b57cec5SDimitry Andric if (PSI->isHotCount(ProfileCount))
1660b57cec5SDimitry Andric return CalleeInfo::HotnessType::Hot;
1670b57cec5SDimitry Andric if (PSI->isColdCount(ProfileCount))
1680b57cec5SDimitry Andric return CalleeInfo::HotnessType::Cold;
1690b57cec5SDimitry Andric return CalleeInfo::HotnessType::None;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
isNonRenamableLocal(const GlobalValue & GV)1720b57cec5SDimitry Andric static bool isNonRenamableLocal(const GlobalValue &GV) {
1730b57cec5SDimitry Andric return GV.hasSection() && GV.hasLocalLinkage();
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric /// Determine whether this call has all constant integer arguments (excluding
1770b57cec5SDimitry Andric /// "this") and summarize it to VCalls or ConstVCalls as appropriate.
addVCallToSet(DevirtCallSite Call,GlobalValue::GUID Guid,SetVector<FunctionSummary::VFuncId,std::vector<FunctionSummary::VFuncId>> & VCalls,SetVector<FunctionSummary::ConstVCall,std::vector<FunctionSummary::ConstVCall>> & ConstVCalls)1785f757f3fSDimitry Andric static void addVCallToSet(
1795f757f3fSDimitry Andric DevirtCallSite Call, GlobalValue::GUID Guid,
1805f757f3fSDimitry Andric SetVector<FunctionSummary::VFuncId, std::vector<FunctionSummary::VFuncId>>
1815f757f3fSDimitry Andric &VCalls,
1825f757f3fSDimitry Andric SetVector<FunctionSummary::ConstVCall,
1835f757f3fSDimitry Andric std::vector<FunctionSummary::ConstVCall>> &ConstVCalls) {
1840b57cec5SDimitry Andric std::vector<uint64_t> Args;
1850b57cec5SDimitry Andric // Start from the second argument to skip the "this" pointer.
186e8d8bef9SDimitry Andric for (auto &Arg : drop_begin(Call.CB.args())) {
1870b57cec5SDimitry Andric auto *CI = dyn_cast<ConstantInt>(Arg);
1880b57cec5SDimitry Andric if (!CI || CI->getBitWidth() > 64) {
1890b57cec5SDimitry Andric VCalls.insert({Guid, Call.Offset});
1900b57cec5SDimitry Andric return;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric Args.push_back(CI->getZExtValue());
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric ConstVCalls.insert({{Guid, Call.Offset}, std::move(Args)});
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric /// If this intrinsic call requires that we add information to the function
1980b57cec5SDimitry Andric /// summary, do so via the non-constant reference arguments.
addIntrinsicToSummary(const CallInst * CI,SetVector<GlobalValue::GUID,std::vector<GlobalValue::GUID>> & TypeTests,SetVector<FunctionSummary::VFuncId,std::vector<FunctionSummary::VFuncId>> & TypeTestAssumeVCalls,SetVector<FunctionSummary::VFuncId,std::vector<FunctionSummary::VFuncId>> & TypeCheckedLoadVCalls,SetVector<FunctionSummary::ConstVCall,std::vector<FunctionSummary::ConstVCall>> & TypeTestAssumeConstVCalls,SetVector<FunctionSummary::ConstVCall,std::vector<FunctionSummary::ConstVCall>> & TypeCheckedLoadConstVCalls,DominatorTree & DT)1990b57cec5SDimitry Andric static void addIntrinsicToSummary(
2005f757f3fSDimitry Andric const CallInst *CI,
2015f757f3fSDimitry Andric SetVector<GlobalValue::GUID, std::vector<GlobalValue::GUID>> &TypeTests,
2025f757f3fSDimitry Andric SetVector<FunctionSummary::VFuncId, std::vector<FunctionSummary::VFuncId>>
2035f757f3fSDimitry Andric &TypeTestAssumeVCalls,
2045f757f3fSDimitry Andric SetVector<FunctionSummary::VFuncId, std::vector<FunctionSummary::VFuncId>>
2055f757f3fSDimitry Andric &TypeCheckedLoadVCalls,
2065f757f3fSDimitry Andric SetVector<FunctionSummary::ConstVCall,
2075f757f3fSDimitry Andric std::vector<FunctionSummary::ConstVCall>>
2085f757f3fSDimitry Andric &TypeTestAssumeConstVCalls,
2095f757f3fSDimitry Andric SetVector<FunctionSummary::ConstVCall,
2105f757f3fSDimitry Andric std::vector<FunctionSummary::ConstVCall>>
2115f757f3fSDimitry Andric &TypeCheckedLoadConstVCalls,
2120b57cec5SDimitry Andric DominatorTree &DT) {
2130b57cec5SDimitry Andric switch (CI->getCalledFunction()->getIntrinsicID()) {
214972a253aSDimitry Andric case Intrinsic::type_test:
215972a253aSDimitry Andric case Intrinsic::public_type_test: {
2160b57cec5SDimitry Andric auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(1));
2170b57cec5SDimitry Andric auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata());
2180b57cec5SDimitry Andric if (!TypeId)
2190b57cec5SDimitry Andric break;
2200b57cec5SDimitry Andric GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric // Produce a summary from type.test intrinsics. We only summarize type.test
2230b57cec5SDimitry Andric // intrinsics that are used other than by an llvm.assume intrinsic.
2240b57cec5SDimitry Andric // Intrinsics that are assumed are relevant only to the devirtualization
2250b57cec5SDimitry Andric // pass, not the type test lowering pass.
2260b57cec5SDimitry Andric bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) {
227fe6060f1SDimitry Andric return !isa<AssumeInst>(CIU.getUser());
2280b57cec5SDimitry Andric });
2290b57cec5SDimitry Andric if (HasNonAssumeUses)
2300b57cec5SDimitry Andric TypeTests.insert(Guid);
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric SmallVector<DevirtCallSite, 4> DevirtCalls;
2330b57cec5SDimitry Andric SmallVector<CallInst *, 4> Assumes;
2340b57cec5SDimitry Andric findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI, DT);
2350b57cec5SDimitry Andric for (auto &Call : DevirtCalls)
2360b57cec5SDimitry Andric addVCallToSet(Call, Guid, TypeTestAssumeVCalls,
2370b57cec5SDimitry Andric TypeTestAssumeConstVCalls);
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric break;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
24206c3fb27SDimitry Andric case Intrinsic::type_checked_load_relative:
2430b57cec5SDimitry Andric case Intrinsic::type_checked_load: {
2440b57cec5SDimitry Andric auto *TypeMDVal = cast<MetadataAsValue>(CI->getArgOperand(2));
2450b57cec5SDimitry Andric auto *TypeId = dyn_cast<MDString>(TypeMDVal->getMetadata());
2460b57cec5SDimitry Andric if (!TypeId)
2470b57cec5SDimitry Andric break;
2480b57cec5SDimitry Andric GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
2490b57cec5SDimitry Andric
2500b57cec5SDimitry Andric SmallVector<DevirtCallSite, 4> DevirtCalls;
2510b57cec5SDimitry Andric SmallVector<Instruction *, 4> LoadedPtrs;
2520b57cec5SDimitry Andric SmallVector<Instruction *, 4> Preds;
2530b57cec5SDimitry Andric bool HasNonCallUses = false;
2540b57cec5SDimitry Andric findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
2550b57cec5SDimitry Andric HasNonCallUses, CI, DT);
2560b57cec5SDimitry Andric // Any non-call uses of the result of llvm.type.checked.load will
2570b57cec5SDimitry Andric // prevent us from optimizing away the llvm.type.test.
2580b57cec5SDimitry Andric if (HasNonCallUses)
2590b57cec5SDimitry Andric TypeTests.insert(Guid);
2600b57cec5SDimitry Andric for (auto &Call : DevirtCalls)
2610b57cec5SDimitry Andric addVCallToSet(Call, Guid, TypeCheckedLoadVCalls,
2620b57cec5SDimitry Andric TypeCheckedLoadConstVCalls);
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andric break;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric default:
2670b57cec5SDimitry Andric break;
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric
isNonVolatileLoad(const Instruction * I)2710b57cec5SDimitry Andric static bool isNonVolatileLoad(const Instruction *I) {
2720b57cec5SDimitry Andric if (const auto *LI = dyn_cast<LoadInst>(I))
2730b57cec5SDimitry Andric return !LI->isVolatile();
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric return false;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric
isNonVolatileStore(const Instruction * I)2780b57cec5SDimitry Andric static bool isNonVolatileStore(const Instruction *I) {
2790b57cec5SDimitry Andric if (const auto *SI = dyn_cast<StoreInst>(I))
2800b57cec5SDimitry Andric return !SI->isVolatile();
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric return false;
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric
2850eae32dcSDimitry Andric // Returns true if the function definition must be unreachable.
2860eae32dcSDimitry Andric //
2870eae32dcSDimitry Andric // Note if this helper function returns true, `F` is guaranteed
2880eae32dcSDimitry Andric // to be unreachable; if it returns false, `F` might still
2890eae32dcSDimitry Andric // be unreachable but not covered by this helper function.
mustBeUnreachableFunction(const Function & F)2900eae32dcSDimitry Andric static bool mustBeUnreachableFunction(const Function &F) {
2910eae32dcSDimitry Andric // A function must be unreachable if its entry block ends with an
2920eae32dcSDimitry Andric // 'unreachable'.
2930eae32dcSDimitry Andric assert(!F.isDeclaration());
2940eae32dcSDimitry Andric return isa<UnreachableInst>(F.getEntryBlock().getTerminator());
2950eae32dcSDimitry Andric }
2960eae32dcSDimitry Andric
computeFunctionSummary(ModuleSummaryIndex & Index,const Module & M,const Function & F,BlockFrequencyInfo * BFI,ProfileSummaryInfo * PSI,DominatorTree & DT,bool HasLocalsInUsedOrAsm,DenseSet<GlobalValue::GUID> & CantBePromoted,bool IsThinLTO,std::function<const StackSafetyInfo * (const Function & F)> GetSSICallback)2975ffd83dbSDimitry Andric static void computeFunctionSummary(
2985ffd83dbSDimitry Andric ModuleSummaryIndex &Index, const Module &M, const Function &F,
2995ffd83dbSDimitry Andric BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT,
3005ffd83dbSDimitry Andric bool HasLocalsInUsedOrAsm, DenseSet<GlobalValue::GUID> &CantBePromoted,
3015ffd83dbSDimitry Andric bool IsThinLTO,
3025ffd83dbSDimitry Andric std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
3030b57cec5SDimitry Andric // Summary not currently supported for anonymous functions, they should
3040b57cec5SDimitry Andric // have been named.
3050b57cec5SDimitry Andric assert(F.hasName());
3060b57cec5SDimitry Andric
3070b57cec5SDimitry Andric unsigned NumInsts = 0;
3080b57cec5SDimitry Andric // Map from callee ValueId to profile count. Used to accumulate profile
3090b57cec5SDimitry Andric // counts for all static calls to a given callee.
31006c3fb27SDimitry Andric MapVector<ValueInfo, CalleeInfo, DenseMap<ValueInfo, unsigned>,
31106c3fb27SDimitry Andric std::vector<std::pair<ValueInfo, CalleeInfo>>>
31206c3fb27SDimitry Andric CallGraphEdges;
3135f757f3fSDimitry Andric SetVector<ValueInfo, std::vector<ValueInfo>> RefEdges, LoadRefEdges,
3145f757f3fSDimitry Andric StoreRefEdges;
3155f757f3fSDimitry Andric SetVector<GlobalValue::GUID, std::vector<GlobalValue::GUID>> TypeTests;
3165f757f3fSDimitry Andric SetVector<FunctionSummary::VFuncId, std::vector<FunctionSummary::VFuncId>>
3175f757f3fSDimitry Andric TypeTestAssumeVCalls, TypeCheckedLoadVCalls;
3185f757f3fSDimitry Andric SetVector<FunctionSummary::ConstVCall,
3195f757f3fSDimitry Andric std::vector<FunctionSummary::ConstVCall>>
3205f757f3fSDimitry Andric TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls;
3210b57cec5SDimitry Andric ICallPromotionAnalysis ICallAnalysis;
3220b57cec5SDimitry Andric SmallPtrSet<const User *, 8> Visited;
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric // Add personality function, prefix data and prologue data to function's ref
3250b57cec5SDimitry Andric // list.
326*0fca6ea1SDimitry Andric bool HasLocalIFuncCallOrRef = false;
327*0fca6ea1SDimitry Andric findRefEdges(Index, &F, RefEdges, Visited, HasLocalIFuncCallOrRef);
3280b57cec5SDimitry Andric std::vector<const Instruction *> NonVolatileLoads;
3290b57cec5SDimitry Andric std::vector<const Instruction *> NonVolatileStores;
3300b57cec5SDimitry Andric
331bdd1243dSDimitry Andric std::vector<CallsiteInfo> Callsites;
332bdd1243dSDimitry Andric std::vector<AllocInfo> Allocs;
333bdd1243dSDimitry Andric
33406c3fb27SDimitry Andric #ifndef NDEBUG
33506c3fb27SDimitry Andric DenseSet<const CallBase *> CallsThatMayHaveMemprofSummary;
33606c3fb27SDimitry Andric #endif
33706c3fb27SDimitry Andric
3380b57cec5SDimitry Andric bool HasInlineAsmMaybeReferencingInternal = false;
339349cc55cSDimitry Andric bool HasIndirBranchToBlockAddress = false;
340349cc55cSDimitry Andric bool HasUnknownCall = false;
341349cc55cSDimitry Andric bool MayThrow = false;
342349cc55cSDimitry Andric for (const BasicBlock &BB : F) {
343349cc55cSDimitry Andric // We don't allow inlining of function with indirect branch to blockaddress.
344349cc55cSDimitry Andric // If the blockaddress escapes the function, e.g., via a global variable,
345349cc55cSDimitry Andric // inlining may lead to an invalid cross-function reference. So we shouldn't
346349cc55cSDimitry Andric // import such function either.
347349cc55cSDimitry Andric if (BB.hasAddressTaken()) {
348349cc55cSDimitry Andric for (User *U : BlockAddress::get(const_cast<BasicBlock *>(&BB))->users())
349349cc55cSDimitry Andric if (!isa<CallBrInst>(*U)) {
350349cc55cSDimitry Andric HasIndirBranchToBlockAddress = true;
351349cc55cSDimitry Andric break;
352349cc55cSDimitry Andric }
353349cc55cSDimitry Andric }
354349cc55cSDimitry Andric
3550b57cec5SDimitry Andric for (const Instruction &I : BB) {
356349cc55cSDimitry Andric if (I.isDebugOrPseudoInst())
3570b57cec5SDimitry Andric continue;
3580b57cec5SDimitry Andric ++NumInsts;
359349cc55cSDimitry Andric
3600b57cec5SDimitry Andric // Regular LTO module doesn't participate in ThinLTO import,
3610b57cec5SDimitry Andric // so no reference from it can be read/writeonly, since this
3620b57cec5SDimitry Andric // would require importing variable as local copy
3630b57cec5SDimitry Andric if (IsThinLTO) {
3640b57cec5SDimitry Andric if (isNonVolatileLoad(&I)) {
3650b57cec5SDimitry Andric // Postpone processing of non-volatile load instructions
3660b57cec5SDimitry Andric // See comments below
3670b57cec5SDimitry Andric Visited.insert(&I);
3680b57cec5SDimitry Andric NonVolatileLoads.push_back(&I);
3690b57cec5SDimitry Andric continue;
3700b57cec5SDimitry Andric } else if (isNonVolatileStore(&I)) {
3710b57cec5SDimitry Andric Visited.insert(&I);
3720b57cec5SDimitry Andric NonVolatileStores.push_back(&I);
3730b57cec5SDimitry Andric // All references from second operand of store (destination address)
3740b57cec5SDimitry Andric // can be considered write-only if they're not referenced by any
3750b57cec5SDimitry Andric // non-store instruction. References from first operand of store
3760b57cec5SDimitry Andric // (stored value) can't be treated either as read- or as write-only
3770b57cec5SDimitry Andric // so we add them to RefEdges as we do with all other instructions
3780b57cec5SDimitry Andric // except non-volatile load.
3790b57cec5SDimitry Andric Value *Stored = I.getOperand(0);
3800b57cec5SDimitry Andric if (auto *GV = dyn_cast<GlobalValue>(Stored))
3810b57cec5SDimitry Andric // findRefEdges will try to examine GV operands, so instead
3820b57cec5SDimitry Andric // of calling it we should add GV to RefEdges directly.
3830b57cec5SDimitry Andric RefEdges.insert(Index.getOrInsertValueInfo(GV));
3840b57cec5SDimitry Andric else if (auto *U = dyn_cast<User>(Stored))
385*0fca6ea1SDimitry Andric findRefEdges(Index, U, RefEdges, Visited, HasLocalIFuncCallOrRef);
3860b57cec5SDimitry Andric continue;
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric }
389*0fca6ea1SDimitry Andric findRefEdges(Index, &I, RefEdges, Visited, HasLocalIFuncCallOrRef);
3905ffd83dbSDimitry Andric const auto *CB = dyn_cast<CallBase>(&I);
391349cc55cSDimitry Andric if (!CB) {
392349cc55cSDimitry Andric if (I.mayThrow())
393349cc55cSDimitry Andric MayThrow = true;
3940b57cec5SDimitry Andric continue;
395349cc55cSDimitry Andric }
3960b57cec5SDimitry Andric
3970b57cec5SDimitry Andric const auto *CI = dyn_cast<CallInst>(&I);
3980b57cec5SDimitry Andric // Since we don't know exactly which local values are referenced in inline
3990b57cec5SDimitry Andric // assembly, conservatively mark the function as possibly referencing
4000b57cec5SDimitry Andric // a local value from inline assembly to ensure we don't export a
4010b57cec5SDimitry Andric // reference (which would require renaming and promotion of the
4020b57cec5SDimitry Andric // referenced value).
4030b57cec5SDimitry Andric if (HasLocalsInUsedOrAsm && CI && CI->isInlineAsm())
4040b57cec5SDimitry Andric HasInlineAsmMaybeReferencingInternal = true;
4050b57cec5SDimitry Andric
4065ffd83dbSDimitry Andric auto *CalledValue = CB->getCalledOperand();
4075ffd83dbSDimitry Andric auto *CalledFunction = CB->getCalledFunction();
4080b57cec5SDimitry Andric if (CalledValue && !CalledFunction) {
4098bcb0991SDimitry Andric CalledValue = CalledValue->stripPointerCasts();
4100b57cec5SDimitry Andric // Stripping pointer casts can reveal a called function.
4110b57cec5SDimitry Andric CalledFunction = dyn_cast<Function>(CalledValue);
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric // Check if this is an alias to a function. If so, get the
4140b57cec5SDimitry Andric // called aliasee for the checks below.
4150b57cec5SDimitry Andric if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
4160b57cec5SDimitry Andric assert(!CalledFunction && "Expected null called function in callsite for alias");
417349cc55cSDimitry Andric CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
4180b57cec5SDimitry Andric }
4190b57cec5SDimitry Andric // Check if this is a direct call to a known function or a known
4200b57cec5SDimitry Andric // intrinsic, or an indirect call with profile data.
4210b57cec5SDimitry Andric if (CalledFunction) {
4220b57cec5SDimitry Andric if (CI && CalledFunction->isIntrinsic()) {
4230b57cec5SDimitry Andric addIntrinsicToSummary(
4240b57cec5SDimitry Andric CI, TypeTests, TypeTestAssumeVCalls, TypeCheckedLoadVCalls,
4250b57cec5SDimitry Andric TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls, DT);
4260b57cec5SDimitry Andric continue;
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric // We should have named any anonymous globals
4290b57cec5SDimitry Andric assert(CalledFunction->hasName());
4305ffd83dbSDimitry Andric auto ScaledCount = PSI->getProfileCount(*CB, BFI);
43181ad6265SDimitry Andric auto Hotness = ScaledCount ? getHotness(*ScaledCount, PSI)
4320b57cec5SDimitry Andric : CalleeInfo::HotnessType::Unknown;
4330b57cec5SDimitry Andric if (ForceSummaryEdgesCold != FunctionSummary::FSHT_None)
4340b57cec5SDimitry Andric Hotness = CalleeInfo::HotnessType::Cold;
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric // Use the original CalledValue, in case it was an alias. We want
4370b57cec5SDimitry Andric // to record the call edge to the alias in that case. Eventually
4380b57cec5SDimitry Andric // an alias summary will be created to associate the alias and
4390b57cec5SDimitry Andric // aliasee.
4400b57cec5SDimitry Andric auto &ValueInfo = CallGraphEdges[Index.getOrInsertValueInfo(
4410b57cec5SDimitry Andric cast<GlobalValue>(CalledValue))];
4420b57cec5SDimitry Andric ValueInfo.updateHotness(Hotness);
4435f757f3fSDimitry Andric if (CB->isTailCall())
4445f757f3fSDimitry Andric ValueInfo.setHasTailCall(true);
4450b57cec5SDimitry Andric // Add the relative block frequency to CalleeInfo if there is no profile
4460b57cec5SDimitry Andric // information.
4470b57cec5SDimitry Andric if (BFI != nullptr && Hotness == CalleeInfo::HotnessType::Unknown) {
4480b57cec5SDimitry Andric uint64_t BBFreq = BFI->getBlockFreq(&BB).getFrequency();
4495f757f3fSDimitry Andric uint64_t EntryFreq = BFI->getEntryFreq().getFrequency();
4500b57cec5SDimitry Andric ValueInfo.updateRelBlockFreq(BBFreq, EntryFreq);
4510b57cec5SDimitry Andric }
4520b57cec5SDimitry Andric } else {
453349cc55cSDimitry Andric HasUnknownCall = true;
4545f757f3fSDimitry Andric // If F is imported, a local linkage ifunc (e.g. target_clones on a
4555f757f3fSDimitry Andric // static function) called by F will be cloned. Since summaries don't
4565f757f3fSDimitry Andric // track ifunc, we do not know implementation functions referenced by
4575f757f3fSDimitry Andric // the ifunc resolver need to be promoted in the exporter, and we will
4585f757f3fSDimitry Andric // get linker errors due to cloned declarations for implementation
4595f757f3fSDimitry Andric // functions. As a simple fix, just mark F as not eligible for import.
4605f757f3fSDimitry Andric // Non-local ifunc is not cloned and does not have the issue.
4615f757f3fSDimitry Andric if (auto *GI = dyn_cast_if_present<GlobalIFunc>(CalledValue))
4625f757f3fSDimitry Andric if (GI->hasLocalLinkage())
463*0fca6ea1SDimitry Andric HasLocalIFuncCallOrRef = true;
4640b57cec5SDimitry Andric // Skip inline assembly calls.
4650b57cec5SDimitry Andric if (CI && CI->isInlineAsm())
4660b57cec5SDimitry Andric continue;
4670b57cec5SDimitry Andric // Skip direct calls.
4680b57cec5SDimitry Andric if (!CalledValue || isa<Constant>(CalledValue))
4690b57cec5SDimitry Andric continue;
4700b57cec5SDimitry Andric
4710b57cec5SDimitry Andric // Check if the instruction has a callees metadata. If so, add callees
4720b57cec5SDimitry Andric // to CallGraphEdges to reflect the references from the metadata, and
4730b57cec5SDimitry Andric // to enable importing for subsequent indirect call promotion and
4740b57cec5SDimitry Andric // inlining.
4750b57cec5SDimitry Andric if (auto *MD = I.getMetadata(LLVMContext::MD_callees)) {
476fcaf7f86SDimitry Andric for (const auto &Op : MD->operands()) {
4770b57cec5SDimitry Andric Function *Callee = mdconst::extract_or_null<Function>(Op);
4780b57cec5SDimitry Andric if (Callee)
4790b57cec5SDimitry Andric CallGraphEdges[Index.getOrInsertValueInfo(Callee)];
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric }
4820b57cec5SDimitry Andric
483*0fca6ea1SDimitry Andric uint32_t NumCandidates;
4840b57cec5SDimitry Andric uint64_t TotalCount;
4850b57cec5SDimitry Andric auto CandidateProfileData =
486*0fca6ea1SDimitry Andric ICallAnalysis.getPromotionCandidatesForInstruction(&I, TotalCount,
487*0fca6ea1SDimitry Andric NumCandidates);
488fcaf7f86SDimitry Andric for (const auto &Candidate : CandidateProfileData)
4890b57cec5SDimitry Andric CallGraphEdges[Index.getOrInsertValueInfo(Candidate.Value)]
4900b57cec5SDimitry Andric .updateHotness(getHotness(Candidate.Count, PSI));
4910b57cec5SDimitry Andric }
492bdd1243dSDimitry Andric
49306c3fb27SDimitry Andric // Summarize memprof related metadata. This is only needed for ThinLTO.
49406c3fb27SDimitry Andric if (!IsThinLTO)
49506c3fb27SDimitry Andric continue;
49606c3fb27SDimitry Andric
497bdd1243dSDimitry Andric // TODO: Skip indirect calls for now. Need to handle these better, likely
498bdd1243dSDimitry Andric // by creating multiple Callsites, one per target, then speculatively
499bdd1243dSDimitry Andric // devirtualize while applying clone info in the ThinLTO backends. This
500bdd1243dSDimitry Andric // will also be important because we will have a different set of clone
501bdd1243dSDimitry Andric // versions per target. This handling needs to match that in the ThinLTO
502bdd1243dSDimitry Andric // backend so we handle things consistently for matching of callsite
503bdd1243dSDimitry Andric // summaries to instructions.
504bdd1243dSDimitry Andric if (!CalledFunction)
505bdd1243dSDimitry Andric continue;
506bdd1243dSDimitry Andric
50706c3fb27SDimitry Andric // Ensure we keep this analysis in sync with the handling in the ThinLTO
50806c3fb27SDimitry Andric // backend (see MemProfContextDisambiguation::applyImport). Save this call
50906c3fb27SDimitry Andric // so that we can skip it in checking the reverse case later.
51006c3fb27SDimitry Andric assert(mayHaveMemprofSummary(CB));
51106c3fb27SDimitry Andric #ifndef NDEBUG
51206c3fb27SDimitry Andric CallsThatMayHaveMemprofSummary.insert(CB);
51306c3fb27SDimitry Andric #endif
51406c3fb27SDimitry Andric
515bdd1243dSDimitry Andric // Compute the list of stack ids first (so we can trim them from the stack
516bdd1243dSDimitry Andric // ids on any MIBs).
517bdd1243dSDimitry Andric CallStack<MDNode, MDNode::op_iterator> InstCallsite(
518bdd1243dSDimitry Andric I.getMetadata(LLVMContext::MD_callsite));
519bdd1243dSDimitry Andric auto *MemProfMD = I.getMetadata(LLVMContext::MD_memprof);
520bdd1243dSDimitry Andric if (MemProfMD) {
521bdd1243dSDimitry Andric std::vector<MIBInfo> MIBs;
522*0fca6ea1SDimitry Andric std::vector<uint64_t> TotalSizes;
523bdd1243dSDimitry Andric for (auto &MDOp : MemProfMD->operands()) {
524bdd1243dSDimitry Andric auto *MIBMD = cast<const MDNode>(MDOp);
525bdd1243dSDimitry Andric MDNode *StackNode = getMIBStackNode(MIBMD);
526bdd1243dSDimitry Andric assert(StackNode);
527bdd1243dSDimitry Andric SmallVector<unsigned> StackIdIndices;
528bdd1243dSDimitry Andric CallStack<MDNode, MDNode::op_iterator> StackContext(StackNode);
529bdd1243dSDimitry Andric // Collapse out any on the allocation call (inlining).
530bdd1243dSDimitry Andric for (auto ContextIter =
531bdd1243dSDimitry Andric StackContext.beginAfterSharedPrefix(InstCallsite);
532bdd1243dSDimitry Andric ContextIter != StackContext.end(); ++ContextIter) {
533bdd1243dSDimitry Andric unsigned StackIdIdx = Index.addOrGetStackIdIndex(*ContextIter);
534bdd1243dSDimitry Andric // If this is a direct recursion, simply skip the duplicate
535bdd1243dSDimitry Andric // entries. If this is mutual recursion, handling is left to
536bdd1243dSDimitry Andric // the LTO link analysis client.
537bdd1243dSDimitry Andric if (StackIdIndices.empty() || StackIdIndices.back() != StackIdIdx)
538bdd1243dSDimitry Andric StackIdIndices.push_back(StackIdIdx);
539bdd1243dSDimitry Andric }
540bdd1243dSDimitry Andric MIBs.push_back(
541bdd1243dSDimitry Andric MIBInfo(getMIBAllocType(MIBMD), std::move(StackIdIndices)));
542*0fca6ea1SDimitry Andric if (MemProfReportHintedSizes) {
543*0fca6ea1SDimitry Andric auto TotalSize = getMIBTotalSize(MIBMD);
544*0fca6ea1SDimitry Andric assert(TotalSize);
545*0fca6ea1SDimitry Andric TotalSizes.push_back(TotalSize);
546*0fca6ea1SDimitry Andric }
547bdd1243dSDimitry Andric }
548bdd1243dSDimitry Andric Allocs.push_back(AllocInfo(std::move(MIBs)));
549*0fca6ea1SDimitry Andric if (MemProfReportHintedSizes) {
550*0fca6ea1SDimitry Andric assert(Allocs.back().MIBs.size() == TotalSizes.size());
551*0fca6ea1SDimitry Andric Allocs.back().TotalSizes = std::move(TotalSizes);
552*0fca6ea1SDimitry Andric }
553bdd1243dSDimitry Andric } else if (!InstCallsite.empty()) {
554bdd1243dSDimitry Andric SmallVector<unsigned> StackIdIndices;
555bdd1243dSDimitry Andric for (auto StackId : InstCallsite)
556bdd1243dSDimitry Andric StackIdIndices.push_back(Index.addOrGetStackIdIndex(StackId));
557bdd1243dSDimitry Andric // Use the original CalledValue, in case it was an alias. We want
558bdd1243dSDimitry Andric // to record the call edge to the alias in that case. Eventually
559bdd1243dSDimitry Andric // an alias summary will be created to associate the alias and
560bdd1243dSDimitry Andric // aliasee.
561bdd1243dSDimitry Andric auto CalleeValueInfo =
562bdd1243dSDimitry Andric Index.getOrInsertValueInfo(cast<GlobalValue>(CalledValue));
563bdd1243dSDimitry Andric Callsites.push_back({CalleeValueInfo, StackIdIndices});
564bdd1243dSDimitry Andric }
5650b57cec5SDimitry Andric }
566349cc55cSDimitry Andric }
56706c3fb27SDimitry Andric
56806c3fb27SDimitry Andric if (PSI->hasPartialSampleProfile() && ScalePartialSampleProfileWorkingSetSize)
5695ffd83dbSDimitry Andric Index.addBlockCount(F.size());
5700b57cec5SDimitry Andric
5710b57cec5SDimitry Andric std::vector<ValueInfo> Refs;
5720b57cec5SDimitry Andric if (IsThinLTO) {
5730b57cec5SDimitry Andric auto AddRefEdges = [&](const std::vector<const Instruction *> &Instrs,
5745f757f3fSDimitry Andric SetVector<ValueInfo, std::vector<ValueInfo>> &Edges,
5750b57cec5SDimitry Andric SmallPtrSet<const User *, 8> &Cache) {
5760b57cec5SDimitry Andric for (const auto *I : Instrs) {
5770b57cec5SDimitry Andric Cache.erase(I);
578*0fca6ea1SDimitry Andric findRefEdges(Index, I, Edges, Cache, HasLocalIFuncCallOrRef);
5790b57cec5SDimitry Andric }
5800b57cec5SDimitry Andric };
5810b57cec5SDimitry Andric
5820b57cec5SDimitry Andric // By now we processed all instructions in a function, except
5830b57cec5SDimitry Andric // non-volatile loads and non-volatile value stores. Let's find
5840b57cec5SDimitry Andric // ref edges for both of instruction sets
5850b57cec5SDimitry Andric AddRefEdges(NonVolatileLoads, LoadRefEdges, Visited);
5860b57cec5SDimitry Andric // We can add some values to the Visited set when processing load
5870b57cec5SDimitry Andric // instructions which are also used by stores in NonVolatileStores.
5880b57cec5SDimitry Andric // For example this can happen if we have following code:
5890b57cec5SDimitry Andric //
5900b57cec5SDimitry Andric // store %Derived* @foo, %Derived** bitcast (%Base** @bar to %Derived**)
5910b57cec5SDimitry Andric // %42 = load %Derived*, %Derived** bitcast (%Base** @bar to %Derived**)
5920b57cec5SDimitry Andric //
5930b57cec5SDimitry Andric // After processing loads we'll add bitcast to the Visited set, and if
5940b57cec5SDimitry Andric // we use the same set while processing stores, we'll never see store
5950b57cec5SDimitry Andric // to @bar and @bar will be mistakenly treated as readonly.
5960b57cec5SDimitry Andric SmallPtrSet<const llvm::User *, 8> StoreCache;
5970b57cec5SDimitry Andric AddRefEdges(NonVolatileStores, StoreRefEdges, StoreCache);
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric // If both load and store instruction reference the same variable
6000b57cec5SDimitry Andric // we won't be able to optimize it. Add all such reference edges
6010b57cec5SDimitry Andric // to RefEdges set.
602fcaf7f86SDimitry Andric for (const auto &VI : StoreRefEdges)
6030b57cec5SDimitry Andric if (LoadRefEdges.remove(VI))
6040b57cec5SDimitry Andric RefEdges.insert(VI);
6050b57cec5SDimitry Andric
6060b57cec5SDimitry Andric unsigned RefCnt = RefEdges.size();
6070b57cec5SDimitry Andric // All new reference edges inserted in two loops below are either
6080b57cec5SDimitry Andric // read or write only. They will be grouped in the end of RefEdges
6090b57cec5SDimitry Andric // vector, so we can use a single integer value to identify them.
610fcaf7f86SDimitry Andric for (const auto &VI : LoadRefEdges)
6110b57cec5SDimitry Andric RefEdges.insert(VI);
6120b57cec5SDimitry Andric
6130b57cec5SDimitry Andric unsigned FirstWORef = RefEdges.size();
614fcaf7f86SDimitry Andric for (const auto &VI : StoreRefEdges)
6150b57cec5SDimitry Andric RefEdges.insert(VI);
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric Refs = RefEdges.takeVector();
6180b57cec5SDimitry Andric for (; RefCnt < FirstWORef; ++RefCnt)
6190b57cec5SDimitry Andric Refs[RefCnt].setReadOnly();
6200b57cec5SDimitry Andric
6210b57cec5SDimitry Andric for (; RefCnt < Refs.size(); ++RefCnt)
6220b57cec5SDimitry Andric Refs[RefCnt].setWriteOnly();
6230b57cec5SDimitry Andric } else {
6240b57cec5SDimitry Andric Refs = RefEdges.takeVector();
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric // Explicit add hot edges to enforce importing for designated GUIDs for
6270b57cec5SDimitry Andric // sample PGO, to enable the same inlines as the profiled optimized binary.
6280b57cec5SDimitry Andric for (auto &I : F.getImportGUIDs())
6290b57cec5SDimitry Andric CallGraphEdges[Index.getOrInsertValueInfo(I)].updateHotness(
6300b57cec5SDimitry Andric ForceSummaryEdgesCold == FunctionSummary::FSHT_All
6310b57cec5SDimitry Andric ? CalleeInfo::HotnessType::Cold
6320b57cec5SDimitry Andric : CalleeInfo::HotnessType::Critical);
6330b57cec5SDimitry Andric
63406c3fb27SDimitry Andric #ifndef NDEBUG
63506c3fb27SDimitry Andric // Make sure that all calls we decided could not have memprof summaries get a
63606c3fb27SDimitry Andric // false value for mayHaveMemprofSummary, to ensure that this handling remains
63706c3fb27SDimitry Andric // in sync with the ThinLTO backend handling.
63806c3fb27SDimitry Andric if (IsThinLTO) {
63906c3fb27SDimitry Andric for (const BasicBlock &BB : F) {
64006c3fb27SDimitry Andric for (const Instruction &I : BB) {
64106c3fb27SDimitry Andric const auto *CB = dyn_cast<CallBase>(&I);
64206c3fb27SDimitry Andric if (!CB)
64306c3fb27SDimitry Andric continue;
64406c3fb27SDimitry Andric // We already checked these above.
64506c3fb27SDimitry Andric if (CallsThatMayHaveMemprofSummary.count(CB))
64606c3fb27SDimitry Andric continue;
64706c3fb27SDimitry Andric assert(!mayHaveMemprofSummary(CB));
64806c3fb27SDimitry Andric }
64906c3fb27SDimitry Andric }
65006c3fb27SDimitry Andric }
65106c3fb27SDimitry Andric #endif
65206c3fb27SDimitry Andric
6530b57cec5SDimitry Andric bool NonRenamableLocal = isNonRenamableLocal(F);
654*0fca6ea1SDimitry Andric bool NotEligibleForImport =
655*0fca6ea1SDimitry Andric NonRenamableLocal || HasInlineAsmMaybeReferencingInternal ||
656*0fca6ea1SDimitry Andric HasIndirBranchToBlockAddress || HasLocalIFuncCallOrRef;
657fe6060f1SDimitry Andric GlobalValueSummary::GVFlags Flags(
658fe6060f1SDimitry Andric F.getLinkage(), F.getVisibility(), NotEligibleForImport,
659*0fca6ea1SDimitry Andric /* Live = */ false, F.isDSOLocal(), F.canBeOmittedFromSymbolTable(),
660*0fca6ea1SDimitry Andric GlobalValueSummary::ImportKind::Definition);
6610b57cec5SDimitry Andric FunctionSummary::FFlags FunFlags{
662bdd1243dSDimitry Andric F.doesNotAccessMemory(), F.onlyReadsMemory() && !F.doesNotAccessMemory(),
6630b57cec5SDimitry Andric F.hasFnAttribute(Attribute::NoRecurse), F.returnDoesNotAlias(),
6640b57cec5SDimitry Andric // FIXME: refactor this to use the same code that inliner is using.
6650b57cec5SDimitry Andric // Don't try to import functions with noinline attribute.
666349cc55cSDimitry Andric F.getAttributes().hasFnAttr(Attribute::NoInline),
667349cc55cSDimitry Andric F.hasFnAttribute(Attribute::AlwaysInline),
6680eae32dcSDimitry Andric F.hasFnAttribute(Attribute::NoUnwind), MayThrow, HasUnknownCall,
6690eae32dcSDimitry Andric mustBeUnreachableFunction(F)};
6705ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> ParamAccesses;
6715ffd83dbSDimitry Andric if (auto *SSI = GetSSICallback(F))
672e8d8bef9SDimitry Andric ParamAccesses = SSI->getParamAccesses(Index);
6738bcb0991SDimitry Andric auto FuncSummary = std::make_unique<FunctionSummary>(
6740b57cec5SDimitry Andric Flags, NumInsts, FunFlags, /*EntryCount=*/0, std::move(Refs),
6750b57cec5SDimitry Andric CallGraphEdges.takeVector(), TypeTests.takeVector(),
6760b57cec5SDimitry Andric TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
6770b57cec5SDimitry Andric TypeTestAssumeConstVCalls.takeVector(),
678bdd1243dSDimitry Andric TypeCheckedLoadConstVCalls.takeVector(), std::move(ParamAccesses),
679bdd1243dSDimitry Andric std::move(Callsites), std::move(Allocs));
6800b57cec5SDimitry Andric if (NonRenamableLocal)
6810b57cec5SDimitry Andric CantBePromoted.insert(F.getGUID());
6820b57cec5SDimitry Andric Index.addGlobalValueSummary(F, std::move(FuncSummary));
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric
6850b57cec5SDimitry Andric /// Find function pointers referenced within the given vtable initializer
6860b57cec5SDimitry Andric /// (or subset of an initializer) \p I. The starting offset of \p I within
6870b57cec5SDimitry Andric /// the vtable initializer is \p StartingOffset. Any discovered function
6880b57cec5SDimitry Andric /// pointers are added to \p VTableFuncs along with their cumulative offset
6890b57cec5SDimitry Andric /// within the initializer.
findFuncPointers(const Constant * I,uint64_t StartingOffset,const Module & M,ModuleSummaryIndex & Index,VTableFuncList & VTableFuncs,const GlobalVariable & OrigGV)6900b57cec5SDimitry Andric static void findFuncPointers(const Constant *I, uint64_t StartingOffset,
6910b57cec5SDimitry Andric const Module &M, ModuleSummaryIndex &Index,
692*0fca6ea1SDimitry Andric VTableFuncList &VTableFuncs,
693*0fca6ea1SDimitry Andric const GlobalVariable &OrigGV) {
6940b57cec5SDimitry Andric // First check if this is a function pointer.
6950b57cec5SDimitry Andric if (I->getType()->isPointerTy()) {
69606c3fb27SDimitry Andric auto C = I->stripPointerCasts();
69706c3fb27SDimitry Andric auto A = dyn_cast<GlobalAlias>(C);
69806c3fb27SDimitry Andric if (isa<Function>(C) || (A && isa<Function>(A->getAliasee()))) {
69906c3fb27SDimitry Andric auto GV = dyn_cast<GlobalValue>(C);
70006c3fb27SDimitry Andric assert(GV);
7010b57cec5SDimitry Andric // We can disregard __cxa_pure_virtual as a possible call target, as
7020b57cec5SDimitry Andric // calls to pure virtuals are UB.
70306c3fb27SDimitry Andric if (GV && GV->getName() != "__cxa_pure_virtual")
70406c3fb27SDimitry Andric VTableFuncs.push_back({Index.getOrInsertValueInfo(GV), StartingOffset});
7050b57cec5SDimitry Andric return;
7060b57cec5SDimitry Andric }
70706c3fb27SDimitry Andric }
7080b57cec5SDimitry Andric
7090b57cec5SDimitry Andric // Walk through the elements in the constant struct or array and recursively
7100b57cec5SDimitry Andric // look for virtual function pointers.
7110b57cec5SDimitry Andric const DataLayout &DL = M.getDataLayout();
7120b57cec5SDimitry Andric if (auto *C = dyn_cast<ConstantStruct>(I)) {
7130b57cec5SDimitry Andric StructType *STy = dyn_cast<StructType>(C->getType());
7140b57cec5SDimitry Andric assert(STy);
7150b57cec5SDimitry Andric const StructLayout *SL = DL.getStructLayout(C->getType());
7160b57cec5SDimitry Andric
717fe6060f1SDimitry Andric for (auto EI : llvm::enumerate(STy->elements())) {
718fe6060f1SDimitry Andric auto Offset = SL->getElementOffset(EI.index());
7190b57cec5SDimitry Andric unsigned Op = SL->getElementContainingOffset(Offset);
7200b57cec5SDimitry Andric findFuncPointers(cast<Constant>(I->getOperand(Op)),
721*0fca6ea1SDimitry Andric StartingOffset + Offset, M, Index, VTableFuncs, OrigGV);
7220b57cec5SDimitry Andric }
7230b57cec5SDimitry Andric } else if (auto *C = dyn_cast<ConstantArray>(I)) {
7240b57cec5SDimitry Andric ArrayType *ATy = C->getType();
7250b57cec5SDimitry Andric Type *EltTy = ATy->getElementType();
7260b57cec5SDimitry Andric uint64_t EltSize = DL.getTypeAllocSize(EltTy);
7270b57cec5SDimitry Andric for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
7280b57cec5SDimitry Andric findFuncPointers(cast<Constant>(I->getOperand(i)),
729*0fca6ea1SDimitry Andric StartingOffset + i * EltSize, M, Index, VTableFuncs,
730*0fca6ea1SDimitry Andric OrigGV);
731*0fca6ea1SDimitry Andric }
732*0fca6ea1SDimitry Andric } else if (const auto *CE = dyn_cast<ConstantExpr>(I)) {
733*0fca6ea1SDimitry Andric // For relative vtables, the next sub-component should be a trunc.
734*0fca6ea1SDimitry Andric if (CE->getOpcode() != Instruction::Trunc ||
735*0fca6ea1SDimitry Andric !(CE = dyn_cast<ConstantExpr>(CE->getOperand(0))))
736*0fca6ea1SDimitry Andric return;
737*0fca6ea1SDimitry Andric
738*0fca6ea1SDimitry Andric // If this constant can be reduced to the offset between a function and a
739*0fca6ea1SDimitry Andric // global, then we know this is a valid virtual function if the RHS is the
740*0fca6ea1SDimitry Andric // original vtable we're scanning through.
741*0fca6ea1SDimitry Andric if (CE->getOpcode() == Instruction::Sub) {
742*0fca6ea1SDimitry Andric GlobalValue *LHS, *RHS;
743*0fca6ea1SDimitry Andric APSInt LHSOffset, RHSOffset;
744*0fca6ea1SDimitry Andric if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHS, LHSOffset, DL) &&
745*0fca6ea1SDimitry Andric IsConstantOffsetFromGlobal(CE->getOperand(1), RHS, RHSOffset, DL) &&
746*0fca6ea1SDimitry Andric RHS == &OrigGV &&
747*0fca6ea1SDimitry Andric
748*0fca6ea1SDimitry Andric // For relative vtables, this component should point to the callable
749*0fca6ea1SDimitry Andric // function without any offsets.
750*0fca6ea1SDimitry Andric LHSOffset == 0 &&
751*0fca6ea1SDimitry Andric
752*0fca6ea1SDimitry Andric // Also, the RHS should always point to somewhere within the vtable.
753*0fca6ea1SDimitry Andric RHSOffset <=
754*0fca6ea1SDimitry Andric static_cast<uint64_t>(DL.getTypeAllocSize(OrigGV.getInitializer()->getType()))) {
755*0fca6ea1SDimitry Andric findFuncPointers(LHS, StartingOffset, M, Index, VTableFuncs, OrigGV);
756*0fca6ea1SDimitry Andric }
7570b57cec5SDimitry Andric }
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric
7610b57cec5SDimitry Andric // Identify the function pointers referenced by vtable definition \p V.
computeVTableFuncs(ModuleSummaryIndex & Index,const GlobalVariable & V,const Module & M,VTableFuncList & VTableFuncs)7620b57cec5SDimitry Andric static void computeVTableFuncs(ModuleSummaryIndex &Index,
7630b57cec5SDimitry Andric const GlobalVariable &V, const Module &M,
7640b57cec5SDimitry Andric VTableFuncList &VTableFuncs) {
7650b57cec5SDimitry Andric if (!V.isConstant())
7660b57cec5SDimitry Andric return;
7670b57cec5SDimitry Andric
7680b57cec5SDimitry Andric findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,
769*0fca6ea1SDimitry Andric VTableFuncs, V);
7700b57cec5SDimitry Andric
7710b57cec5SDimitry Andric #ifndef NDEBUG
7720b57cec5SDimitry Andric // Validate that the VTableFuncs list is ordered by offset.
7730b57cec5SDimitry Andric uint64_t PrevOffset = 0;
7740b57cec5SDimitry Andric for (auto &P : VTableFuncs) {
7750b57cec5SDimitry Andric // The findVFuncPointers traversal should have encountered the
7760b57cec5SDimitry Andric // functions in offset order. We need to use ">=" since PrevOffset
7770b57cec5SDimitry Andric // starts at 0.
7780b57cec5SDimitry Andric assert(P.VTableOffset >= PrevOffset);
7790b57cec5SDimitry Andric PrevOffset = P.VTableOffset;
7800b57cec5SDimitry Andric }
7810b57cec5SDimitry Andric #endif
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric
7840b57cec5SDimitry Andric /// Record vtable definition \p V for each type metadata it references.
7850b57cec5SDimitry Andric static void
recordTypeIdCompatibleVtableReferences(ModuleSummaryIndex & Index,const GlobalVariable & V,SmallVectorImpl<MDNode * > & Types)7860b57cec5SDimitry Andric recordTypeIdCompatibleVtableReferences(ModuleSummaryIndex &Index,
7870b57cec5SDimitry Andric const GlobalVariable &V,
7880b57cec5SDimitry Andric SmallVectorImpl<MDNode *> &Types) {
7890b57cec5SDimitry Andric for (MDNode *Type : Types) {
7900b57cec5SDimitry Andric auto TypeID = Type->getOperand(1).get();
7910b57cec5SDimitry Andric
7920b57cec5SDimitry Andric uint64_t Offset =
7930b57cec5SDimitry Andric cast<ConstantInt>(
7940b57cec5SDimitry Andric cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
7950b57cec5SDimitry Andric ->getZExtValue();
7960b57cec5SDimitry Andric
7970b57cec5SDimitry Andric if (auto *TypeId = dyn_cast<MDString>(TypeID))
7980b57cec5SDimitry Andric Index.getOrInsertTypeIdCompatibleVtableSummary(TypeId->getString())
7990b57cec5SDimitry Andric .push_back({Offset, Index.getOrInsertValueInfo(&V)});
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric
computeVariableSummary(ModuleSummaryIndex & Index,const GlobalVariable & V,DenseSet<GlobalValue::GUID> & CantBePromoted,const Module & M,SmallVectorImpl<MDNode * > & Types)8030b57cec5SDimitry Andric static void computeVariableSummary(ModuleSummaryIndex &Index,
8040b57cec5SDimitry Andric const GlobalVariable &V,
8050b57cec5SDimitry Andric DenseSet<GlobalValue::GUID> &CantBePromoted,
8060b57cec5SDimitry Andric const Module &M,
8070b57cec5SDimitry Andric SmallVectorImpl<MDNode *> &Types) {
8085f757f3fSDimitry Andric SetVector<ValueInfo, std::vector<ValueInfo>> RefEdges;
8090b57cec5SDimitry Andric SmallPtrSet<const User *, 8> Visited;
810*0fca6ea1SDimitry Andric bool RefLocalIFunc = false;
811*0fca6ea1SDimitry Andric bool HasBlockAddress =
812*0fca6ea1SDimitry Andric findRefEdges(Index, &V, RefEdges, Visited, RefLocalIFunc);
813*0fca6ea1SDimitry Andric const bool NotEligibleForImport = (HasBlockAddress || RefLocalIFunc);
8140b57cec5SDimitry Andric bool NonRenamableLocal = isNonRenamableLocal(V);
815fe6060f1SDimitry Andric GlobalValueSummary::GVFlags Flags(
816fe6060f1SDimitry Andric V.getLinkage(), V.getVisibility(), NonRenamableLocal,
817*0fca6ea1SDimitry Andric /* Live = */ false, V.isDSOLocal(), V.canBeOmittedFromSymbolTable(),
818*0fca6ea1SDimitry Andric GlobalValueSummary::Definition);
8190b57cec5SDimitry Andric
8200b57cec5SDimitry Andric VTableFuncList VTableFuncs;
8210b57cec5SDimitry Andric // If splitting is not enabled, then we compute the summary information
8220b57cec5SDimitry Andric // necessary for index-based whole program devirtualization.
8230b57cec5SDimitry Andric if (!Index.enableSplitLTOUnit()) {
8240b57cec5SDimitry Andric Types.clear();
8250b57cec5SDimitry Andric V.getMetadata(LLVMContext::MD_type, Types);
8260b57cec5SDimitry Andric if (!Types.empty()) {
8270b57cec5SDimitry Andric // Identify the function pointers referenced by this vtable definition.
8280b57cec5SDimitry Andric computeVTableFuncs(Index, V, M, VTableFuncs);
8290b57cec5SDimitry Andric
8300b57cec5SDimitry Andric // Record this vtable definition for each type metadata it references.
8310b57cec5SDimitry Andric recordTypeIdCompatibleVtableReferences(Index, V, Types);
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric
8350b57cec5SDimitry Andric // Don't mark variables we won't be able to internalize as read/write-only.
8360b57cec5SDimitry Andric bool CanBeInternalized =
8370b57cec5SDimitry Andric !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
8380b57cec5SDimitry Andric !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass();
8395ffd83dbSDimitry Andric bool Constant = V.isConstant();
8405ffd83dbSDimitry Andric GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized,
8415ffd83dbSDimitry Andric Constant ? false : CanBeInternalized,
8425ffd83dbSDimitry Andric Constant, V.getVCallVisibility());
8438bcb0991SDimitry Andric auto GVarSummary = std::make_unique<GlobalVarSummary>(Flags, VarFlags,
8440b57cec5SDimitry Andric RefEdges.takeVector());
8450b57cec5SDimitry Andric if (NonRenamableLocal)
8460b57cec5SDimitry Andric CantBePromoted.insert(V.getGUID());
847*0fca6ea1SDimitry Andric if (NotEligibleForImport)
8480b57cec5SDimitry Andric GVarSummary->setNotEligibleToImport();
8490b57cec5SDimitry Andric if (!VTableFuncs.empty())
8500b57cec5SDimitry Andric GVarSummary->setVTableFuncs(VTableFuncs);
8510b57cec5SDimitry Andric Index.addGlobalValueSummary(V, std::move(GVarSummary));
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric
computeAliasSummary(ModuleSummaryIndex & Index,const GlobalAlias & A,DenseSet<GlobalValue::GUID> & CantBePromoted)854fcaf7f86SDimitry Andric static void computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
8550b57cec5SDimitry Andric DenseSet<GlobalValue::GUID> &CantBePromoted) {
856fcaf7f86SDimitry Andric // Skip summary for indirect function aliases as summary for aliasee will not
857fcaf7f86SDimitry Andric // be emitted.
858fcaf7f86SDimitry Andric const GlobalObject *Aliasee = A.getAliaseeObject();
859fcaf7f86SDimitry Andric if (isa<GlobalIFunc>(Aliasee))
860fcaf7f86SDimitry Andric return;
8610b57cec5SDimitry Andric bool NonRenamableLocal = isNonRenamableLocal(A);
862fe6060f1SDimitry Andric GlobalValueSummary::GVFlags Flags(
863fe6060f1SDimitry Andric A.getLinkage(), A.getVisibility(), NonRenamableLocal,
864*0fca6ea1SDimitry Andric /* Live = */ false, A.isDSOLocal(), A.canBeOmittedFromSymbolTable(),
865*0fca6ea1SDimitry Andric GlobalValueSummary::Definition);
8668bcb0991SDimitry Andric auto AS = std::make_unique<AliasSummary>(Flags);
8670b57cec5SDimitry Andric auto AliaseeVI = Index.getValueInfo(Aliasee->getGUID());
8680b57cec5SDimitry Andric assert(AliaseeVI && "Alias expects aliasee summary to be available");
8690b57cec5SDimitry Andric assert(AliaseeVI.getSummaryList().size() == 1 &&
8700b57cec5SDimitry Andric "Expected a single entry per aliasee in per-module index");
8710b57cec5SDimitry Andric AS->setAliasee(AliaseeVI, AliaseeVI.getSummaryList()[0].get());
8720b57cec5SDimitry Andric if (NonRenamableLocal)
8730b57cec5SDimitry Andric CantBePromoted.insert(A.getGUID());
8740b57cec5SDimitry Andric Index.addGlobalValueSummary(A, std::move(AS));
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric
8770b57cec5SDimitry Andric // Set LiveRoot flag on entries matching the given value name.
setLiveRoot(ModuleSummaryIndex & Index,StringRef Name)8780b57cec5SDimitry Andric static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
8790b57cec5SDimitry Andric if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name)))
880fcaf7f86SDimitry Andric for (const auto &Summary : VI.getSummaryList())
8810b57cec5SDimitry Andric Summary->setLive(true);
8820b57cec5SDimitry Andric }
8830b57cec5SDimitry Andric
buildModuleSummaryIndex(const Module & M,std::function<BlockFrequencyInfo * (const Function & F)> GetBFICallback,ProfileSummaryInfo * PSI,std::function<const StackSafetyInfo * (const Function & F)> GetSSICallback)8840b57cec5SDimitry Andric ModuleSummaryIndex llvm::buildModuleSummaryIndex(
8850b57cec5SDimitry Andric const Module &M,
8860b57cec5SDimitry Andric std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
8875ffd83dbSDimitry Andric ProfileSummaryInfo *PSI,
8885ffd83dbSDimitry Andric std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
8890b57cec5SDimitry Andric assert(PSI);
8900b57cec5SDimitry Andric bool EnableSplitLTOUnit = false;
89106c3fb27SDimitry Andric bool UnifiedLTO = false;
8920b57cec5SDimitry Andric if (auto *MD = mdconst::extract_or_null<ConstantInt>(
8930b57cec5SDimitry Andric M.getModuleFlag("EnableSplitLTOUnit")))
8940b57cec5SDimitry Andric EnableSplitLTOUnit = MD->getZExtValue();
89506c3fb27SDimitry Andric if (auto *MD =
89606c3fb27SDimitry Andric mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("UnifiedLTO")))
89706c3fb27SDimitry Andric UnifiedLTO = MD->getZExtValue();
89806c3fb27SDimitry Andric ModuleSummaryIndex Index(/*HaveGVs=*/true, EnableSplitLTOUnit, UnifiedLTO);
8990b57cec5SDimitry Andric
9000b57cec5SDimitry Andric // Identify the local values in the llvm.used and llvm.compiler.used sets,
9010b57cec5SDimitry Andric // which should not be exported as they would then require renaming and
9020b57cec5SDimitry Andric // promotion, but we may have opaque uses e.g. in inline asm. We collect them
9030b57cec5SDimitry Andric // here because we use this information to mark functions containing inline
9040b57cec5SDimitry Andric // assembly calls as not importable.
905fe6060f1SDimitry Andric SmallPtrSet<GlobalValue *, 4> LocalsUsed;
906fe6060f1SDimitry Andric SmallVector<GlobalValue *, 4> Used;
9070b57cec5SDimitry Andric // First collect those in the llvm.used set.
908fe6060f1SDimitry Andric collectUsedGlobalVariables(M, Used, /*CompilerUsed=*/false);
9090b57cec5SDimitry Andric // Next collect those in the llvm.compiler.used set.
910fe6060f1SDimitry Andric collectUsedGlobalVariables(M, Used, /*CompilerUsed=*/true);
9110b57cec5SDimitry Andric DenseSet<GlobalValue::GUID> CantBePromoted;
9120b57cec5SDimitry Andric for (auto *V : Used) {
9130b57cec5SDimitry Andric if (V->hasLocalLinkage()) {
9140b57cec5SDimitry Andric LocalsUsed.insert(V);
9150b57cec5SDimitry Andric CantBePromoted.insert(V->getGUID());
9160b57cec5SDimitry Andric }
9170b57cec5SDimitry Andric }
9180b57cec5SDimitry Andric
9190b57cec5SDimitry Andric bool HasLocalInlineAsmSymbol = false;
9200b57cec5SDimitry Andric if (!M.getModuleInlineAsm().empty()) {
9210b57cec5SDimitry Andric // Collect the local values defined by module level asm, and set up
9220b57cec5SDimitry Andric // summaries for these symbols so that they can be marked as NoRename,
9230b57cec5SDimitry Andric // to prevent export of any use of them in regular IR that would require
9240b57cec5SDimitry Andric // renaming within the module level asm. Note we don't need to create a
9250b57cec5SDimitry Andric // summary for weak or global defs, as they don't need to be flagged as
9260b57cec5SDimitry Andric // NoRename, and defs in module level asm can't be imported anyway.
9270b57cec5SDimitry Andric // Also, any values used but not defined within module level asm should
9280b57cec5SDimitry Andric // be listed on the llvm.used or llvm.compiler.used global and marked as
9290b57cec5SDimitry Andric // referenced from there.
9300b57cec5SDimitry Andric ModuleSymbolTable::CollectAsmSymbols(
9310b57cec5SDimitry Andric M, [&](StringRef Name, object::BasicSymbolRef::Flags Flags) {
9320b57cec5SDimitry Andric // Symbols not marked as Weak or Global are local definitions.
9330b57cec5SDimitry Andric if (Flags & (object::BasicSymbolRef::SF_Weak |
9340b57cec5SDimitry Andric object::BasicSymbolRef::SF_Global))
9350b57cec5SDimitry Andric return;
9360b57cec5SDimitry Andric HasLocalInlineAsmSymbol = true;
9370b57cec5SDimitry Andric GlobalValue *GV = M.getNamedValue(Name);
9380b57cec5SDimitry Andric if (!GV)
9390b57cec5SDimitry Andric return;
9400b57cec5SDimitry Andric assert(GV->isDeclaration() && "Def in module asm already has definition");
941fe6060f1SDimitry Andric GlobalValueSummary::GVFlags GVFlags(
942fe6060f1SDimitry Andric GlobalValue::InternalLinkage, GlobalValue::DefaultVisibility,
9430b57cec5SDimitry Andric /* NotEligibleToImport = */ true,
9440b57cec5SDimitry Andric /* Live = */ true,
945*0fca6ea1SDimitry Andric /* Local */ GV->isDSOLocal(), GV->canBeOmittedFromSymbolTable(),
946*0fca6ea1SDimitry Andric GlobalValueSummary::Definition);
9470b57cec5SDimitry Andric CantBePromoted.insert(GV->getGUID());
9480b57cec5SDimitry Andric // Create the appropriate summary type.
9490b57cec5SDimitry Andric if (Function *F = dyn_cast<Function>(GV)) {
9500b57cec5SDimitry Andric std::unique_ptr<FunctionSummary> Summary =
9518bcb0991SDimitry Andric std::make_unique<FunctionSummary>(
9520b57cec5SDimitry Andric GVFlags, /*InstCount=*/0,
9530b57cec5SDimitry Andric FunctionSummary::FFlags{
9540b57cec5SDimitry Andric F->hasFnAttribute(Attribute::ReadNone),
9550b57cec5SDimitry Andric F->hasFnAttribute(Attribute::ReadOnly),
9560b57cec5SDimitry Andric F->hasFnAttribute(Attribute::NoRecurse),
9570b57cec5SDimitry Andric F->returnDoesNotAlias(),
958480093f4SDimitry Andric /* NoInline = */ false,
959349cc55cSDimitry Andric F->hasFnAttribute(Attribute::AlwaysInline),
960349cc55cSDimitry Andric F->hasFnAttribute(Attribute::NoUnwind),
961349cc55cSDimitry Andric /* MayThrow */ true,
9620eae32dcSDimitry Andric /* HasUnknownCall */ true,
9630eae32dcSDimitry Andric /* MustBeUnreachable */ false},
9640b57cec5SDimitry Andric /*EntryCount=*/0, ArrayRef<ValueInfo>{},
9650b57cec5SDimitry Andric ArrayRef<FunctionSummary::EdgeTy>{},
9660b57cec5SDimitry Andric ArrayRef<GlobalValue::GUID>{},
9670b57cec5SDimitry Andric ArrayRef<FunctionSummary::VFuncId>{},
9680b57cec5SDimitry Andric ArrayRef<FunctionSummary::VFuncId>{},
9690b57cec5SDimitry Andric ArrayRef<FunctionSummary::ConstVCall>{},
9705ffd83dbSDimitry Andric ArrayRef<FunctionSummary::ConstVCall>{},
971bdd1243dSDimitry Andric ArrayRef<FunctionSummary::ParamAccess>{},
972bdd1243dSDimitry Andric ArrayRef<CallsiteInfo>{}, ArrayRef<AllocInfo>{});
9730b57cec5SDimitry Andric Index.addGlobalValueSummary(*GV, std::move(Summary));
9740b57cec5SDimitry Andric } else {
9750b57cec5SDimitry Andric std::unique_ptr<GlobalVarSummary> Summary =
9768bcb0991SDimitry Andric std::make_unique<GlobalVarSummary>(
9775ffd83dbSDimitry Andric GVFlags,
9785ffd83dbSDimitry Andric GlobalVarSummary::GVarFlags(
9795ffd83dbSDimitry Andric false, false, cast<GlobalVariable>(GV)->isConstant(),
9805ffd83dbSDimitry Andric GlobalObject::VCallVisibilityPublic),
9810b57cec5SDimitry Andric ArrayRef<ValueInfo>{});
9820b57cec5SDimitry Andric Index.addGlobalValueSummary(*GV, std::move(Summary));
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric });
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric
9870b57cec5SDimitry Andric bool IsThinLTO = true;
9880b57cec5SDimitry Andric if (auto *MD =
9890b57cec5SDimitry Andric mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
9900b57cec5SDimitry Andric IsThinLTO = MD->getZExtValue();
9910b57cec5SDimitry Andric
9920b57cec5SDimitry Andric // Compute summaries for all functions defined in module, and save in the
9930b57cec5SDimitry Andric // index.
994fcaf7f86SDimitry Andric for (const auto &F : M) {
9950b57cec5SDimitry Andric if (F.isDeclaration())
9960b57cec5SDimitry Andric continue;
9970b57cec5SDimitry Andric
9980b57cec5SDimitry Andric DominatorTree DT(const_cast<Function &>(F));
9990b57cec5SDimitry Andric BlockFrequencyInfo *BFI = nullptr;
10000b57cec5SDimitry Andric std::unique_ptr<BlockFrequencyInfo> BFIPtr;
10010b57cec5SDimitry Andric if (GetBFICallback)
10020b57cec5SDimitry Andric BFI = GetBFICallback(F);
10030b57cec5SDimitry Andric else if (F.hasProfileData()) {
10040b57cec5SDimitry Andric LoopInfo LI{DT};
10050b57cec5SDimitry Andric BranchProbabilityInfo BPI{F, LI};
10068bcb0991SDimitry Andric BFIPtr = std::make_unique<BlockFrequencyInfo>(F, BPI, LI);
10070b57cec5SDimitry Andric BFI = BFIPtr.get();
10080b57cec5SDimitry Andric }
10090b57cec5SDimitry Andric
10100b57cec5SDimitry Andric computeFunctionSummary(Index, M, F, BFI, PSI, DT,
10110b57cec5SDimitry Andric !LocalsUsed.empty() || HasLocalInlineAsmSymbol,
10125ffd83dbSDimitry Andric CantBePromoted, IsThinLTO, GetSSICallback);
10130b57cec5SDimitry Andric }
10140b57cec5SDimitry Andric
10150b57cec5SDimitry Andric // Compute summaries for all variables defined in module, and save in the
10160b57cec5SDimitry Andric // index.
10170b57cec5SDimitry Andric SmallVector<MDNode *, 2> Types;
10180b57cec5SDimitry Andric for (const GlobalVariable &G : M.globals()) {
10190b57cec5SDimitry Andric if (G.isDeclaration())
10200b57cec5SDimitry Andric continue;
10210b57cec5SDimitry Andric computeVariableSummary(Index, G, CantBePromoted, M, Types);
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric
10240b57cec5SDimitry Andric // Compute summaries for all aliases defined in module, and save in the
10250b57cec5SDimitry Andric // index.
10260b57cec5SDimitry Andric for (const GlobalAlias &A : M.aliases())
10270b57cec5SDimitry Andric computeAliasSummary(Index, A, CantBePromoted);
10280b57cec5SDimitry Andric
1029fcaf7f86SDimitry Andric // Iterate through ifuncs, set their resolvers all alive.
1030fcaf7f86SDimitry Andric for (const GlobalIFunc &I : M.ifuncs()) {
1031fcaf7f86SDimitry Andric I.applyAlongResolverPath([&Index](const GlobalValue &GV) {
1032fcaf7f86SDimitry Andric Index.getGlobalValueSummary(GV)->setLive(true);
1033fcaf7f86SDimitry Andric });
1034fcaf7f86SDimitry Andric }
1035fcaf7f86SDimitry Andric
10360b57cec5SDimitry Andric for (auto *V : LocalsUsed) {
10370b57cec5SDimitry Andric auto *Summary = Index.getGlobalValueSummary(*V);
10380b57cec5SDimitry Andric assert(Summary && "Missing summary for global value");
10390b57cec5SDimitry Andric Summary->setNotEligibleToImport();
10400b57cec5SDimitry Andric }
10410b57cec5SDimitry Andric
10420b57cec5SDimitry Andric // The linker doesn't know about these LLVM produced values, so we need
10430b57cec5SDimitry Andric // to flag them as live in the index to ensure index-based dead value
10440b57cec5SDimitry Andric // analysis treats them as live roots of the analysis.
10450b57cec5SDimitry Andric setLiveRoot(Index, "llvm.used");
10460b57cec5SDimitry Andric setLiveRoot(Index, "llvm.compiler.used");
10470b57cec5SDimitry Andric setLiveRoot(Index, "llvm.global_ctors");
10480b57cec5SDimitry Andric setLiveRoot(Index, "llvm.global_dtors");
10490b57cec5SDimitry Andric setLiveRoot(Index, "llvm.global.annotations");
10500b57cec5SDimitry Andric
10510b57cec5SDimitry Andric for (auto &GlobalList : Index) {
10520b57cec5SDimitry Andric // Ignore entries for references that are undefined in the current module.
10530b57cec5SDimitry Andric if (GlobalList.second.SummaryList.empty())
10540b57cec5SDimitry Andric continue;
10550b57cec5SDimitry Andric
10560b57cec5SDimitry Andric assert(GlobalList.second.SummaryList.size() == 1 &&
10570b57cec5SDimitry Andric "Expected module's index to have one summary per GUID");
10580b57cec5SDimitry Andric auto &Summary = GlobalList.second.SummaryList[0];
10590b57cec5SDimitry Andric if (!IsThinLTO) {
10600b57cec5SDimitry Andric Summary->setNotEligibleToImport();
10610b57cec5SDimitry Andric continue;
10620b57cec5SDimitry Andric }
10630b57cec5SDimitry Andric
10640b57cec5SDimitry Andric bool AllRefsCanBeExternallyReferenced =
10650b57cec5SDimitry Andric llvm::all_of(Summary->refs(), [&](const ValueInfo &VI) {
10660b57cec5SDimitry Andric return !CantBePromoted.count(VI.getGUID());
10670b57cec5SDimitry Andric });
10680b57cec5SDimitry Andric if (!AllRefsCanBeExternallyReferenced) {
10690b57cec5SDimitry Andric Summary->setNotEligibleToImport();
10700b57cec5SDimitry Andric continue;
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric
10730b57cec5SDimitry Andric if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
10740b57cec5SDimitry Andric bool AllCallsCanBeExternallyReferenced = llvm::all_of(
10750b57cec5SDimitry Andric FuncSummary->calls(), [&](const FunctionSummary::EdgeTy &Edge) {
10760b57cec5SDimitry Andric return !CantBePromoted.count(Edge.first.getGUID());
10770b57cec5SDimitry Andric });
10780b57cec5SDimitry Andric if (!AllCallsCanBeExternallyReferenced)
10790b57cec5SDimitry Andric Summary->setNotEligibleToImport();
10800b57cec5SDimitry Andric }
10810b57cec5SDimitry Andric }
10820b57cec5SDimitry Andric
10830b57cec5SDimitry Andric if (!ModuleSummaryDotFile.empty()) {
10840b57cec5SDimitry Andric std::error_code EC;
1085*0fca6ea1SDimitry Andric raw_fd_ostream OSDot(ModuleSummaryDotFile, EC, sys::fs::OpenFlags::OF_Text);
10860b57cec5SDimitry Andric if (EC)
10870b57cec5SDimitry Andric report_fatal_error(Twine("Failed to open dot file ") +
10880b57cec5SDimitry Andric ModuleSummaryDotFile + ": " + EC.message() + "\n");
1089480093f4SDimitry Andric Index.exportToDot(OSDot, {});
10900b57cec5SDimitry Andric }
10910b57cec5SDimitry Andric
10920b57cec5SDimitry Andric return Index;
10930b57cec5SDimitry Andric }
10940b57cec5SDimitry Andric
10950b57cec5SDimitry Andric AnalysisKey ModuleSummaryIndexAnalysis::Key;
10960b57cec5SDimitry Andric
10970b57cec5SDimitry Andric ModuleSummaryIndex
run(Module & M,ModuleAnalysisManager & AM)10980b57cec5SDimitry Andric ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
10990b57cec5SDimitry Andric ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
11000b57cec5SDimitry Andric auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
11015ffd83dbSDimitry Andric bool NeedSSI = needsParamAccessSummary(M);
11020b57cec5SDimitry Andric return buildModuleSummaryIndex(
11030b57cec5SDimitry Andric M,
11040b57cec5SDimitry Andric [&FAM](const Function &F) {
11050b57cec5SDimitry Andric return &FAM.getResult<BlockFrequencyAnalysis>(
11060b57cec5SDimitry Andric *const_cast<Function *>(&F));
11070b57cec5SDimitry Andric },
11085ffd83dbSDimitry Andric &PSI,
11095ffd83dbSDimitry Andric [&FAM, NeedSSI](const Function &F) -> const StackSafetyInfo * {
11105ffd83dbSDimitry Andric return NeedSSI ? &FAM.getResult<StackSafetyAnalysis>(
11115ffd83dbSDimitry Andric const_cast<Function &>(F))
11125ffd83dbSDimitry Andric : nullptr;
11135ffd83dbSDimitry Andric });
11140b57cec5SDimitry Andric }
11150b57cec5SDimitry Andric
11160b57cec5SDimitry Andric char ModuleSummaryIndexWrapperPass::ID = 0;
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
11190b57cec5SDimitry Andric "Module Summary Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)11200b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
11210b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
11225ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass)
11230b57cec5SDimitry Andric INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
11240b57cec5SDimitry Andric "Module Summary Analysis", false, true)
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric ModulePass *llvm::createModuleSummaryIndexWrapperPass() {
11270b57cec5SDimitry Andric return new ModuleSummaryIndexWrapperPass();
11280b57cec5SDimitry Andric }
11290b57cec5SDimitry Andric
ModuleSummaryIndexWrapperPass()11300b57cec5SDimitry Andric ModuleSummaryIndexWrapperPass::ModuleSummaryIndexWrapperPass()
11310b57cec5SDimitry Andric : ModulePass(ID) {
11320b57cec5SDimitry Andric initializeModuleSummaryIndexWrapperPassPass(*PassRegistry::getPassRegistry());
11330b57cec5SDimitry Andric }
11340b57cec5SDimitry Andric
runOnModule(Module & M)11350b57cec5SDimitry Andric bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
11360b57cec5SDimitry Andric auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
11375ffd83dbSDimitry Andric bool NeedSSI = needsParamAccessSummary(M);
11380b57cec5SDimitry Andric Index.emplace(buildModuleSummaryIndex(
11390b57cec5SDimitry Andric M,
11400b57cec5SDimitry Andric [this](const Function &F) {
11410b57cec5SDimitry Andric return &(this->getAnalysis<BlockFrequencyInfoWrapperPass>(
11420b57cec5SDimitry Andric *const_cast<Function *>(&F))
11430b57cec5SDimitry Andric .getBFI());
11440b57cec5SDimitry Andric },
11455ffd83dbSDimitry Andric PSI,
11465ffd83dbSDimitry Andric [&](const Function &F) -> const StackSafetyInfo * {
11475ffd83dbSDimitry Andric return NeedSSI ? &getAnalysis<StackSafetyInfoWrapperPass>(
11485ffd83dbSDimitry Andric const_cast<Function &>(F))
11495ffd83dbSDimitry Andric .getResult()
11505ffd83dbSDimitry Andric : nullptr;
11515ffd83dbSDimitry Andric }));
11520b57cec5SDimitry Andric return false;
11530b57cec5SDimitry Andric }
11540b57cec5SDimitry Andric
doFinalization(Module & M)11550b57cec5SDimitry Andric bool ModuleSummaryIndexWrapperPass::doFinalization(Module &M) {
11560b57cec5SDimitry Andric Index.reset();
11570b57cec5SDimitry Andric return false;
11580b57cec5SDimitry Andric }
11590b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const11600b57cec5SDimitry Andric void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
11610b57cec5SDimitry Andric AU.setPreservesAll();
11620b57cec5SDimitry Andric AU.addRequired<BlockFrequencyInfoWrapperPass>();
11630b57cec5SDimitry Andric AU.addRequired<ProfileSummaryInfoWrapperPass>();
11645ffd83dbSDimitry Andric AU.addRequired<StackSafetyInfoWrapperPass>();
11650b57cec5SDimitry Andric }
11665ffd83dbSDimitry Andric
11675ffd83dbSDimitry Andric char ImmutableModuleSummaryIndexWrapperPass::ID = 0;
11685ffd83dbSDimitry Andric
ImmutableModuleSummaryIndexWrapperPass(const ModuleSummaryIndex * Index)11695ffd83dbSDimitry Andric ImmutableModuleSummaryIndexWrapperPass::ImmutableModuleSummaryIndexWrapperPass(
11705ffd83dbSDimitry Andric const ModuleSummaryIndex *Index)
11715ffd83dbSDimitry Andric : ImmutablePass(ID), Index(Index) {
11725ffd83dbSDimitry Andric initializeImmutableModuleSummaryIndexWrapperPassPass(
11735ffd83dbSDimitry Andric *PassRegistry::getPassRegistry());
11745ffd83dbSDimitry Andric }
11755ffd83dbSDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const11765ffd83dbSDimitry Andric void ImmutableModuleSummaryIndexWrapperPass::getAnalysisUsage(
11775ffd83dbSDimitry Andric AnalysisUsage &AU) const {
11785ffd83dbSDimitry Andric AU.setPreservesAll();
11795ffd83dbSDimitry Andric }
11805ffd83dbSDimitry Andric
createImmutableModuleSummaryIndexWrapperPass(const ModuleSummaryIndex * Index)11815ffd83dbSDimitry Andric ImmutablePass *llvm::createImmutableModuleSummaryIndexWrapperPass(
11825ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) {
11835ffd83dbSDimitry Andric return new ImmutableModuleSummaryIndexWrapperPass(Index);
11845ffd83dbSDimitry Andric }
11855ffd83dbSDimitry Andric
11865ffd83dbSDimitry Andric INITIALIZE_PASS(ImmutableModuleSummaryIndexWrapperPass, "module-summary-info",
11875ffd83dbSDimitry Andric "Module summary info", false, true)
118806c3fb27SDimitry Andric
mayHaveMemprofSummary(const CallBase * CB)118906c3fb27SDimitry Andric bool llvm::mayHaveMemprofSummary(const CallBase *CB) {
119006c3fb27SDimitry Andric if (!CB)
119106c3fb27SDimitry Andric return false;
119206c3fb27SDimitry Andric if (CB->isDebugOrPseudoInst())
119306c3fb27SDimitry Andric return false;
119406c3fb27SDimitry Andric auto *CI = dyn_cast<CallInst>(CB);
119506c3fb27SDimitry Andric auto *CalledValue = CB->getCalledOperand();
119606c3fb27SDimitry Andric auto *CalledFunction = CB->getCalledFunction();
119706c3fb27SDimitry Andric if (CalledValue && !CalledFunction) {
119806c3fb27SDimitry Andric CalledValue = CalledValue->stripPointerCasts();
119906c3fb27SDimitry Andric // Stripping pointer casts can reveal a called function.
120006c3fb27SDimitry Andric CalledFunction = dyn_cast<Function>(CalledValue);
120106c3fb27SDimitry Andric }
120206c3fb27SDimitry Andric // Check if this is an alias to a function. If so, get the
120306c3fb27SDimitry Andric // called aliasee for the checks below.
120406c3fb27SDimitry Andric if (auto *GA = dyn_cast<GlobalAlias>(CalledValue)) {
120506c3fb27SDimitry Andric assert(!CalledFunction &&
120606c3fb27SDimitry Andric "Expected null called function in callsite for alias");
120706c3fb27SDimitry Andric CalledFunction = dyn_cast<Function>(GA->getAliaseeObject());
120806c3fb27SDimitry Andric }
120906c3fb27SDimitry Andric // Check if this is a direct call to a known function or a known
121006c3fb27SDimitry Andric // intrinsic, or an indirect call with profile data.
121106c3fb27SDimitry Andric if (CalledFunction) {
121206c3fb27SDimitry Andric if (CI && CalledFunction->isIntrinsic())
121306c3fb27SDimitry Andric return false;
121406c3fb27SDimitry Andric } else {
121506c3fb27SDimitry Andric // TODO: For now skip indirect calls. See comments in
121606c3fb27SDimitry Andric // computeFunctionSummary for what is needed to handle this.
121706c3fb27SDimitry Andric return false;
121806c3fb27SDimitry Andric }
121906c3fb27SDimitry Andric return true;
122006c3fb27SDimitry Andric }
1221