Index: lib/Transforms/Instrumentation/PGOInstrumentation.cpp =================================================================== --- lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -51,6 +51,7 @@ #include "CFGMST.h" #include "IndirectCallSiteVisitor.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/BlockFrequencyInfo.h" @@ -219,6 +220,50 @@ } }; +// The helper class checks if a particular function is a global_ctor or +// global_dtor. +class ModuleCtorDtorFuncs { +public: + ModuleCtorDtorFuncs(const Module &M) : M(M) {} + // Return true if F is a function referenced in llvm.global_ctors + // or llvm.global_dtors. + bool isCtorDtor(Function *F) const { return CtorDtorFuncs.count(F) == 1; } + // Collect the functions referenced in llvm.global_ctors and + // llvm.global_dtors and put them in a set. + void collect() { + collectCtorDtorFuncs("llvm.global_ctors"); + collectCtorDtorFuncs("llvm.global_dtors"); + } + +private: + const Module &M; + void collectCtorDtorFuncs(const char *GVName); + SmallPtrSet CtorDtorFuncs; +}; + +// GVName can be either "llvm.global_ctors" and "llvm.global_dtors". +// This function Parses the array in these globals, extracts the function decls, +// and puts them to a set. +void ModuleCtorDtorFuncs::collectCtorDtorFuncs(const char *GVName) { + GlobalVariable *GV = M.getGlobalVariable(GVName); + if (!GV) + return; + ConstantArray *InitList = cast(GV->getInitializer()); + if (!InitList) + return; + for (Value *OI : InitList->operands()) { + ConstantStruct *CS = dyn_cast(OI); + if (!CS) + continue; + // Found a null terminator, skip the rest. + if (CS->getOperand(1)->isNullValue()) + break; + Function *F = dyn_cast(CS->getOperand(1)); + if (F) + CtorDtorFuncs.insert(F); + } +} + // This class implements the CFG edges. Note the CFG can be a multi-graph. template class FuncPGOInstrumentation { private: @@ -328,7 +373,8 @@ // Critical edges will be split. static void instrumentOneFunc(Function &F, Module *M, BranchProbabilityInfo *BPI, - BlockFrequencyInfo *BFI) { + BlockFrequencyInfo *BFI, + const ModuleCtorDtorFuncs &CtorDtorFuncs) { unsigned NumCounters = 0; FuncPGOInstrumentation FuncInfo(F, true, BPI, BFI); for (auto &E : FuncInfo.MST.AllEdges) { @@ -355,6 +401,8 @@ if (DisableValueProfiling) return; + if (CtorDtorFuncs.isCtorDtor(&F)) + return; unsigned NumIndirectCallSites = 0; for (auto &I : findIndirectCallSites(F)) { @@ -442,10 +490,12 @@ class PGOUseFunc { public: - PGOUseFunc(Function &Func, Module *Modu, BranchProbabilityInfo *BPI = nullptr, + PGOUseFunc(Function &Func, Module *Modu, + const ModuleCtorDtorFuncs &CtorDtorFuncs, + BranchProbabilityInfo *BPI = nullptr, BlockFrequencyInfo *BFI = nullptr) - : F(Func), M(Modu), FuncInfo(Func, false, BPI, BFI), - FreqAttr(FFA_Normal) {} + : F(Func), M(Modu), CtorDtorFuncs(CtorDtorFuncs), + FuncInfo(Func, false, BPI, BFI), FreqAttr(FFA_Normal) {} // Read counts for the instrumented BB from profile. bool readCounters(IndexedInstrProfReader *PGOReader); @@ -468,6 +518,7 @@ private: Function &F; Module *M; + const ModuleCtorDtorFuncs &CtorDtorFuncs; // This member stores the shared information with class PGOGenFunc. FuncPGOInstrumentation FuncInfo; @@ -727,7 +778,8 @@ void PGOUseFunc::annotateIndirectCallSites() { if (DisableValueProfiling) return; - + if (CtorDtorFuncs.isCtorDtor(&F)) + return; // Create the PGOFuncName meta data. createPGOFuncNameMetadata(F, FuncInfo.FuncName); @@ -778,12 +830,15 @@ Module &M, function_ref LookupBPI, function_ref LookupBFI) { createIRLevelProfileFlagVariable(M); + ModuleCtorDtorFuncs CtorDtorFuncs(M); + if (!DisableValueProfiling) + CtorDtorFuncs.collect(); for (auto &F : M) { if (F.isDeclaration()) continue; auto &BPI = LookupBPI(F); auto &BFI = LookupBFI(F); - instrumentOneFunc(F, &M, &BPI, &BFI); + instrumentOneFunc(F, &M, &BPI, &BFI, CtorDtorFuncs); } return true; } @@ -837,6 +892,9 @@ return false; } + ModuleCtorDtorFuncs CtorDtorFuncs(M); + if (!DisableValueProfiling) + CtorDtorFuncs.collect(); std::vector HotFunctions; std::vector ColdFunctions; for (auto &F : M) { @@ -846,7 +904,7 @@ &(getAnalysis(F).getBPI()); BlockFrequencyInfo *BFI = &(getAnalysis(F).getBFI()); - PGOUseFunc Func(F, &M, BPI, BFI); + PGOUseFunc Func(F, &M, CtorDtorFuncs, BPI, BFI); setPGOCountOnFunc(Func, PGOReader.get()); PGOUseFunc::FuncFreqAttr FreqAttr = Func.getFuncFreqAttr(); if (FreqAttr == PGOUseFunc::FFA_Cold) Index: test/Transforms/PGOProfile/global_ctor.ll =================================================================== --- test/Transforms/PGOProfile/global_ctor.ll +++ test/Transforms/PGOProfile/global_ctor.ll @@ -0,0 +1,29 @@ +; RUN: opt < %s -pgo-instr-gen -S | FileCheck %s --check-prefix=GEN +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = common global i32 (...)* null, align 8 +@bar = common global i32 (...)* null, align 8 + +define void @c_global_ctor() { +entry: +; GEN: call void @llvm.instrprof.increment +; GEN-NOT: call void @llvm.instrprof.value.profile + %tmp = load i32 (...)*, i32 (...)** @foo, align 8 + %call = call i32 (...) %tmp() + ret void +} + +define void @d_global_ctor() { +entry: +; GEN: call void @llvm.instrprof.increment +; GEN-NOT: call void @llvm.instrprof.value.profile + %tmp = load i32 (...)*, i32 (...)** @bar, align 8 + %call = call i32 (...) %tmp() + ret void +} + +@llvm.global_ctors = appending global [2 x { i32, void ()*, i8* } ] [ + { i32, void ()*, i8* } { i32 65535, void ()* @c_global_ctor, i8* null }, + { i32, void ()*, i8* } { i32 65535, void ()* @d_global_ctor, i8* null } +]