Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
35266 views
//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This pass implements GCOV-style profiling. When this pass is run it emits9// "gcno" files next to the existing source, and instruments the code that runs10// to records the edges between blocks that run and emit a complementary "gcda"11// file on exit.12//13//===----------------------------------------------------------------------===//1415#include "llvm/ADT/Hashing.h"16#include "llvm/ADT/MapVector.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/Sequence.h"19#include "llvm/ADT/StringMap.h"20#include "llvm/Analysis/BlockFrequencyInfo.h"21#include "llvm/Analysis/BranchProbabilityInfo.h"22#include "llvm/Analysis/TargetLibraryInfo.h"23#include "llvm/IR/DebugInfo.h"24#include "llvm/IR/DebugLoc.h"25#include "llvm/IR/EHPersonalities.h"26#include "llvm/IR/IRBuilder.h"27#include "llvm/IR/InstIterator.h"28#include "llvm/IR/Instructions.h"29#include "llvm/IR/IntrinsicInst.h"30#include "llvm/IR/Module.h"31#include "llvm/Support/CRC.h"32#include "llvm/Support/CommandLine.h"33#include "llvm/Support/Debug.h"34#include "llvm/Support/FileSystem.h"35#include "llvm/Support/Path.h"36#include "llvm/Support/Regex.h"37#include "llvm/Support/raw_ostream.h"38#include "llvm/Transforms/Instrumentation.h"39#include "llvm/Transforms/Instrumentation/CFGMST.h"40#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"41#include "llvm/Transforms/Utils/ModuleUtils.h"42#include <algorithm>43#include <memory>44#include <string>45#include <utility>4647using namespace llvm;48namespace endian = llvm::support::endian;4950#define DEBUG_TYPE "insert-gcov-profiling"5152enum : uint32_t {53GCOV_ARC_ON_TREE = 1 << 0,5455GCOV_TAG_FUNCTION = 0x01000000,56GCOV_TAG_BLOCKS = 0x01410000,57GCOV_TAG_ARCS = 0x01430000,58GCOV_TAG_LINES = 0x01450000,59};6061static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version",62cl::init("408*"), cl::Hidden,63cl::ValueRequired);6465static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden,66cl::desc("Make counter updates atomic"));6768// Returns the number of words which will be used to represent this string.69static unsigned wordsOfString(StringRef s) {70// Length + NUL-terminated string + 0~3 padding NULs.71return (s.size() / 4) + 2;72}7374GCOVOptions GCOVOptions::getDefault() {75GCOVOptions Options;76Options.EmitNotes = true;77Options.EmitData = true;78Options.NoRedZone = false;79Options.Atomic = AtomicCounter;8081if (DefaultGCOVVersion.size() != 4) {82llvm::report_fatal_error(Twine("Invalid -default-gcov-version: ") +83DefaultGCOVVersion, /*GenCrashDiag=*/false);84}85memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4);86return Options;87}8889namespace {90class GCOVFunction;9192class GCOVProfiler {93public:94GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {}95GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {}96bool97runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,98function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,99std::function<const TargetLibraryInfo &(Function &F)> GetTLI);100101void write(uint32_t i) {102char Bytes[4];103endian::write32(Bytes, i, Endian);104os->write(Bytes, 4);105}106void writeString(StringRef s) {107write(wordsOfString(s) - 1);108os->write(s.data(), s.size());109os->write_zeros(4 - s.size() % 4);110}111void writeBytes(const char *Bytes, int Size) { os->write(Bytes, Size); }112113private:114// Create the .gcno files for the Module based on DebugInfo.115bool116emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork,117function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,118function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,119function_ref<const TargetLibraryInfo &(Function &F)> GetTLI);120121Function *createInternalFunction(FunctionType *FTy, StringRef Name,122StringRef MangledType = "");123void emitGlobalConstructor(124SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);125126bool isFunctionInstrumented(const Function &F);127std::vector<Regex> createRegexesFromString(StringRef RegexesStr);128static bool doesFilenameMatchARegex(StringRef Filename,129std::vector<Regex> &Regexes);130131// Get pointers to the functions in the runtime library.132FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI);133FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI);134FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI);135FunctionCallee getSummaryInfoFunc();136FunctionCallee getEndFileFunc();137138// Add the function to write out all our counters to the global destructor139// list.140Function *141insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);142Function *insertReset(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);143144bool AddFlushBeforeForkAndExec();145146enum class GCovFileType { GCNO, GCDA };147std::string mangleName(const DICompileUnit *CU, GCovFileType FileType);148149GCOVOptions Options;150llvm::endianness Endian;151raw_ostream *os;152153// Checksum, produced by hash of EdgeDestinations154SmallVector<uint32_t, 4> FileChecksums;155156Module *M = nullptr;157std::function<const TargetLibraryInfo &(Function &F)> GetTLI;158LLVMContext *Ctx = nullptr;159SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;160std::vector<Regex> FilterRe;161std::vector<Regex> ExcludeRe;162DenseSet<const BasicBlock *> ExecBlocks;163StringMap<bool> InstrumentedFiles;164};165166struct BBInfo {167BBInfo *Group;168uint32_t Index;169uint32_t Rank = 0;170171BBInfo(unsigned Index) : Group(this), Index(Index) {}172std::string infoString() const {173return (Twine("Index=") + Twine(Index)).str();174}175};176177struct Edge {178// This class implements the CFG edges. Note the CFG can be a multi-graph.179// So there might be multiple edges with same SrcBB and DestBB.180const BasicBlock *SrcBB;181const BasicBlock *DestBB;182uint64_t Weight;183BasicBlock *Place = nullptr;184uint32_t SrcNumber, DstNumber;185bool InMST = false;186bool Removed = false;187bool IsCritical = false;188189Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1)190: SrcBB(Src), DestBB(Dest), Weight(W) {}191192// Return the information string of an edge.193std::string infoString() const {194return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") +195(IsCritical ? "c" : " ") + " W=" + Twine(Weight))196.str();197}198};199}200201static StringRef getFunctionName(const DISubprogram *SP) {202if (!SP->getLinkageName().empty())203return SP->getLinkageName();204return SP->getName();205}206207/// Extract a filename for a DISubprogram.208///209/// Prefer relative paths in the coverage notes. Clang also may split210/// up absolute paths into a directory and filename component. When211/// the relative path doesn't exist, reconstruct the absolute path.212static SmallString<128> getFilename(const DISubprogram *SP) {213SmallString<128> Path;214StringRef RelPath = SP->getFilename();215if (sys::fs::exists(RelPath))216Path = RelPath;217else218sys::path::append(Path, SP->getDirectory(), SP->getFilename());219return Path;220}221222namespace {223class GCOVRecord {224protected:225GCOVProfiler *P;226227GCOVRecord(GCOVProfiler *P) : P(P) {}228229void write(uint32_t i) { P->write(i); }230void writeString(StringRef s) { P->writeString(s); }231void writeBytes(const char *Bytes, int Size) { P->writeBytes(Bytes, Size); }232};233234class GCOVFunction;235class GCOVBlock;236237// Constructed only by requesting it from a GCOVBlock, this object stores a238// list of line numbers and a single filename, representing lines that belong239// to the block.240class GCOVLines : public GCOVRecord {241public:242void addLine(uint32_t Line) {243assert(Line != 0 && "Line zero is not a valid real line number.");244Lines.push_back(Line);245}246247uint32_t length() const {248return 1 + wordsOfString(Filename) + Lines.size();249}250251void writeOut() {252write(0);253writeString(Filename);254for (uint32_t L : Lines)255write(L);256}257258GCOVLines(GCOVProfiler *P, StringRef F)259: GCOVRecord(P), Filename(std::string(F)) {}260261private:262std::string Filename;263SmallVector<uint32_t, 32> Lines;264};265266267// Represent a basic block in GCOV. Each block has a unique number in the268// function, number of lines belonging to each block, and a set of edges to269// other blocks.270class GCOVBlock : public GCOVRecord {271public:272GCOVLines &getFile(StringRef Filename) {273return LinesByFile.try_emplace(Filename, P, Filename).first->second;274}275276void addEdge(GCOVBlock &Successor, uint32_t Flags) {277OutEdges.emplace_back(&Successor, Flags);278}279280void writeOut() {281uint32_t Len = 3;282SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile;283for (auto &I : LinesByFile) {284Len += I.second.length();285SortedLinesByFile.push_back(&I);286}287288write(GCOV_TAG_LINES);289write(Len);290write(Number);291292llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS,293StringMapEntry<GCOVLines> *RHS) {294return LHS->getKey() < RHS->getKey();295});296for (auto &I : SortedLinesByFile)297I->getValue().writeOut();298write(0);299write(0);300}301302GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) {303// Only allow copy before edges and lines have been added. After that,304// there are inter-block pointers (eg: edges) that won't take kindly to305// blocks being copied or moved around.306assert(LinesByFile.empty());307assert(OutEdges.empty());308}309310uint32_t Number;311SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges;312313private:314friend class GCOVFunction;315316GCOVBlock(GCOVProfiler *P, uint32_t Number)317: GCOVRecord(P), Number(Number) {}318319StringMap<GCOVLines> LinesByFile;320};321322// A function has a unique identifier, a checksum (we leave as zero) and a323// set of blocks and a map of edges between blocks. This is the only GCOV324// object users can construct, the blocks and lines will be rooted here.325class GCOVFunction : public GCOVRecord {326public:327GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP,328unsigned EndLine, uint32_t Ident, int Version)329: GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident),330Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) {331LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n");332bool ExitBlockBeforeBody = Version >= 48;333uint32_t i = ExitBlockBeforeBody ? 2 : 1;334for (BasicBlock &BB : *F)335Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++)));336if (!ExitBlockBeforeBody)337ReturnBlock.Number = i;338339std::string FunctionNameAndLine;340raw_string_ostream FNLOS(FunctionNameAndLine);341FNLOS << getFunctionName(SP) << SP->getLine();342FNLOS.flush();343FuncChecksum = hash_value(FunctionNameAndLine);344}345346GCOVBlock &getBlock(const BasicBlock *BB) {347return Blocks.find(const_cast<BasicBlock *>(BB))->second;348}349350GCOVBlock &getEntryBlock() { return EntryBlock; }351GCOVBlock &getReturnBlock() {352return ReturnBlock;353}354355uint32_t getFuncChecksum() const {356return FuncChecksum;357}358359void writeOut(uint32_t CfgChecksum) {360write(GCOV_TAG_FUNCTION);361SmallString<128> Filename = getFilename(SP);362uint32_t BlockLen =3632 + (Version >= 47) + wordsOfString(getFunctionName(SP));364if (Version < 80)365BlockLen += wordsOfString(Filename) + 1;366else367BlockLen += 1 + wordsOfString(Filename) + 3 + (Version >= 90);368369write(BlockLen);370write(Ident);371write(FuncChecksum);372if (Version >= 47)373write(CfgChecksum);374writeString(getFunctionName(SP));375if (Version < 80) {376writeString(Filename);377write(SP->getLine());378} else {379write(SP->isArtificial()); // artificial380writeString(Filename);381write(SP->getLine()); // start_line382write(0); // start_column383// EndLine is the last line with !dbg. It is not the } line as in GCC,384// but good enough.385write(EndLine);386if (Version >= 90)387write(0); // end_column388}389390// Emit count of blocks.391write(GCOV_TAG_BLOCKS);392if (Version < 80) {393write(Blocks.size() + 2);394for (int i = Blocks.size() + 2; i; --i)395write(0);396} else {397write(1);398write(Blocks.size() + 2);399}400LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n");401402// Emit edges between blocks.403const uint32_t Outgoing = EntryBlock.OutEdges.size();404if (Outgoing) {405write(GCOV_TAG_ARCS);406write(Outgoing * 2 + 1);407write(EntryBlock.Number);408for (const auto &E : EntryBlock.OutEdges) {409write(E.first->Number);410write(E.second);411}412}413for (auto &It : Blocks) {414const GCOVBlock &Block = It.second;415if (Block.OutEdges.empty()) continue;416417write(GCOV_TAG_ARCS);418write(Block.OutEdges.size() * 2 + 1);419write(Block.Number);420for (const auto &E : Block.OutEdges) {421write(E.first->Number);422write(E.second);423}424}425426// Emit lines for each block.427for (auto &It : Blocks)428It.second.writeOut();429}430431public:432const DISubprogram *SP;433unsigned EndLine;434uint32_t Ident;435uint32_t FuncChecksum;436int Version;437MapVector<BasicBlock *, GCOVBlock> Blocks;438GCOVBlock EntryBlock;439GCOVBlock ReturnBlock;440};441}442443// RegexesStr is a string containing differents regex separated by a semi-colon.444// For example "foo\..*$;bar\..*$".445std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {446std::vector<Regex> Regexes;447while (!RegexesStr.empty()) {448std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';');449if (!HeadTail.first.empty()) {450Regex Re(HeadTail.first);451std::string Err;452if (!Re.isValid(Err)) {453Ctx->emitError(Twine("Regex ") + HeadTail.first +454" is not valid: " + Err);455}456Regexes.emplace_back(std::move(Re));457}458RegexesStr = HeadTail.second;459}460return Regexes;461}462463bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,464std::vector<Regex> &Regexes) {465for (Regex &Re : Regexes)466if (Re.match(Filename))467return true;468return false;469}470471bool GCOVProfiler::isFunctionInstrumented(const Function &F) {472if (FilterRe.empty() && ExcludeRe.empty()) {473return true;474}475SmallString<128> Filename = getFilename(F.getSubprogram());476auto It = InstrumentedFiles.find(Filename);477if (It != InstrumentedFiles.end()) {478return It->second;479}480481SmallString<256> RealPath;482StringRef RealFilename;483484// Path can be485// /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for486// such a case we must get the real_path.487if (sys::fs::real_path(Filename, RealPath)) {488// real_path can fail with path like "foo.c".489RealFilename = Filename;490} else {491RealFilename = RealPath;492}493494bool ShouldInstrument;495if (FilterRe.empty()) {496ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe);497} else if (ExcludeRe.empty()) {498ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe);499} else {500ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) &&501!doesFilenameMatchARegex(RealFilename, ExcludeRe);502}503InstrumentedFiles[Filename] = ShouldInstrument;504return ShouldInstrument;505}506507std::string GCOVProfiler::mangleName(const DICompileUnit *CU,508GCovFileType OutputType) {509bool Notes = OutputType == GCovFileType::GCNO;510511if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) {512for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) {513MDNode *N = GCov->getOperand(i);514bool ThreeElement = N->getNumOperands() == 3;515if (!ThreeElement && N->getNumOperands() != 2)516continue;517if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU)518continue;519520if (ThreeElement) {521// These nodes have no mangling to apply, it's stored mangled in the522// bitcode.523MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0));524MDString *DataFile = dyn_cast<MDString>(N->getOperand(1));525if (!NotesFile || !DataFile)526continue;527return std::string(Notes ? NotesFile->getString()528: DataFile->getString());529}530531MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0));532if (!GCovFile)533continue;534535SmallString<128> Filename = GCovFile->getString();536sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");537return std::string(Filename);538}539}540541SmallString<128> Filename = CU->getFilename();542sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");543StringRef FName = sys::path::filename(Filename);544SmallString<128> CurPath;545if (sys::fs::current_path(CurPath))546return std::string(FName);547sys::path::append(CurPath, FName);548return std::string(CurPath);549}550551bool GCOVProfiler::runOnModule(552Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,553function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,554std::function<const TargetLibraryInfo &(Function &F)> GetTLI) {555this->M = &M;556this->GetTLI = std::move(GetTLI);557Ctx = &M.getContext();558559NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu");560if (!CUNode || (!Options.EmitNotes && !Options.EmitData))561return false;562563bool HasExecOrFork = AddFlushBeforeForkAndExec();564565FilterRe = createRegexesFromString(Options.Filter);566ExcludeRe = createRegexesFromString(Options.Exclude);567emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI);568return true;569}570571PreservedAnalyses GCOVProfilerPass::run(Module &M,572ModuleAnalysisManager &AM) {573574GCOVProfiler Profiler(GCOVOpts);575FunctionAnalysisManager &FAM =576AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();577578auto GetBFI = [&FAM](Function &F) {579return &FAM.getResult<BlockFrequencyAnalysis>(F);580};581auto GetBPI = [&FAM](Function &F) {582return &FAM.getResult<BranchProbabilityAnalysis>(F);583};584auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & {585return FAM.getResult<TargetLibraryAnalysis>(F);586};587588if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI))589return PreservedAnalyses::all();590591return PreservedAnalyses::none();592}593594static bool functionHasLines(const Function &F, unsigned &EndLine) {595// Check whether this function actually has any source lines. Not only596// do these waste space, they also can crash gcov.597EndLine = 0;598for (const auto &BB : F) {599for (const auto &I : BB) {600// Debug intrinsic locations correspond to the location of the601// declaration, not necessarily any statements or expressions.602if (isa<DbgInfoIntrinsic>(&I)) continue;603604const DebugLoc &Loc = I.getDebugLoc();605if (!Loc)606continue;607608// Artificial lines such as calls to the global constructors.609if (Loc.getLine() == 0) continue;610EndLine = std::max(EndLine, Loc.getLine());611612return true;613}614}615return false;616}617618static bool isUsingScopeBasedEH(Function &F) {619if (!F.hasPersonalityFn()) return false;620621EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn());622return isScopedEHPersonality(Personality);623}624625bool GCOVProfiler::AddFlushBeforeForkAndExec() {626const TargetLibraryInfo *TLI = nullptr;627SmallVector<CallInst *, 2> Forks;628SmallVector<CallInst *, 2> Execs;629for (auto &F : M->functions()) {630TLI = TLI == nullptr ? &GetTLI(F) : TLI;631for (auto &I : instructions(F)) {632if (CallInst *CI = dyn_cast<CallInst>(&I)) {633if (Function *Callee = CI->getCalledFunction()) {634LibFunc LF;635if (TLI->getLibFunc(*Callee, LF)) {636if (LF == LibFunc_fork) {637#if !defined(_WIN32)638Forks.push_back(CI);639#endif640} else if (LF == LibFunc_execl || LF == LibFunc_execle ||641LF == LibFunc_execlp || LF == LibFunc_execv ||642LF == LibFunc_execvp || LF == LibFunc_execve ||643LF == LibFunc_execvpe || LF == LibFunc_execvP) {644Execs.push_back(CI);645}646}647}648}649}650}651652for (auto *F : Forks) {653IRBuilder<> Builder(F);654BasicBlock *Parent = F->getParent();655auto NextInst = ++F->getIterator();656657// We've a fork so just reset the counters in the child process658FunctionType *FTy = FunctionType::get(Builder.getInt32Ty(), {}, false);659FunctionCallee GCOVFork = M->getOrInsertFunction(660"__gcov_fork", FTy,661TLI->getAttrList(Ctx, {}, /*Signed=*/true, /*Ret=*/true));662F->setCalledFunction(GCOVFork);663664// We split just after the fork to have a counter for the lines after665// Anyway there's a bug:666// void foo() { fork(); }667// void bar() { foo(); blah(); }668// then "blah();" will be called 2 times but showed as 1669// because "blah()" belongs to the same block as "foo();"670Parent->splitBasicBlock(NextInst);671672// back() is a br instruction with a debug location673// equals to the one from NextAfterFork674// So to avoid to have two debug locs on two blocks just change it675DebugLoc Loc = F->getDebugLoc();676Parent->back().setDebugLoc(Loc);677}678679for (auto *E : Execs) {680IRBuilder<> Builder(E);681BasicBlock *Parent = E->getParent();682auto NextInst = ++E->getIterator();683684// Since the process is replaced by a new one we need to write out gcdas685// No need to reset the counters since they'll be lost after the exec**686FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false);687FunctionCallee WriteoutF =688M->getOrInsertFunction("llvm_writeout_files", FTy);689Builder.CreateCall(WriteoutF);690691DebugLoc Loc = E->getDebugLoc();692Builder.SetInsertPoint(&*NextInst);693// If the exec** fails we must reset the counters since they've been694// dumped695FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy);696Builder.CreateCall(ResetF)->setDebugLoc(Loc);697ExecBlocks.insert(Parent);698Parent->splitBasicBlock(NextInst);699Parent->back().setDebugLoc(Loc);700}701702return !Forks.empty() || !Execs.empty();703}704705static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E,706const DenseSet<const BasicBlock *> &ExecBlocks) {707if (E.InMST || E.Removed)708return nullptr;709710BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB);711BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB);712// For a fake edge, instrument the real BB.713if (SrcBB == nullptr)714return DestBB;715if (DestBB == nullptr)716return SrcBB;717718auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * {719// There are basic blocks (such as catchswitch) cannot be instrumented.720// If the returned first insertion point is the end of BB, skip this BB.721if (BB->getFirstInsertionPt() == BB->end())722return nullptr;723return BB;724};725726// Instrument the SrcBB if it has a single successor,727// otherwise, the DestBB if this is not a critical edge.728Instruction *TI = SrcBB->getTerminator();729if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB))730return CanInstrument(SrcBB);731if (!E.IsCritical)732return CanInstrument(DestBB);733734// Some IndirectBr critical edges cannot be split by the previous735// SplitIndirectBrCriticalEdges call. Bail out.736const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB);737BasicBlock *InstrBB =738isa<IndirectBrInst>(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum);739if (!InstrBB)740return nullptr;741742MST.addEdge(SrcBB, InstrBB, 0);743MST.addEdge(InstrBB, DestBB, 0).InMST = true;744E.Removed = true;745746return CanInstrument(InstrBB);747}748749#ifndef NDEBUG750static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) {751size_t ID = 0;752for (const auto &E : make_pointee_range(MST.allEdges())) {753GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock();754GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock();755dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number756<< E.infoString() << "\n";757}758}759#endif760761bool GCOVProfiler::emitProfileNotes(762NamedMDNode *CUNode, bool HasExecOrFork,763function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,764function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,765function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) {766int Version;767{768uint8_t c3 = Options.Version[0];769uint8_t c2 = Options.Version[1];770uint8_t c1 = Options.Version[2];771Version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0'772: (c3 - '0') * 10 + c1 - '0';773}774775bool EmitGCDA = Options.EmitData;776for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) {777// Each compile unit gets its own .gcno file. This means that whether we run778// this pass over the original .o's as they're produced, or run it after779// LTO, we'll generate the same .gcno files.780781auto *CU = cast<DICompileUnit>(CUNode->getOperand(i));782783// Skip module skeleton (and module) CUs.784if (CU->getDWOId())785continue;786787std::vector<uint8_t> EdgeDestinations;788SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP;789790Endian = M->getDataLayout().isLittleEndian() ? llvm::endianness::little791: llvm::endianness::big;792unsigned FunctionIdent = 0;793for (auto &F : M->functions()) {794DISubprogram *SP = F.getSubprogram();795unsigned EndLine;796if (!SP) continue;797if (!functionHasLines(F, EndLine) || !isFunctionInstrumented(F))798continue;799// TODO: Functions using scope-based EH are currently not supported.800if (isUsingScopeBasedEH(F)) continue;801if (F.hasFnAttribute(llvm::Attribute::NoProfile))802continue;803if (F.hasFnAttribute(llvm::Attribute::SkipProfile))804continue;805806// Add the function line number to the lines of the entry block807// to have a counter for the function definition.808uint32_t Line = SP->getLine();809auto Filename = getFilename(SP);810811BranchProbabilityInfo *BPI = GetBPI(F);812BlockFrequencyInfo *BFI = GetBFI(F);813814// Split indirectbr critical edges here before computing the MST rather815// than later in getInstrBB() to avoid invalidating it.816SplitIndirectBrCriticalEdges(F, /*IgnoreBlocksWithoutPHI=*/false, BPI,817BFI);818819CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI);820821// getInstrBB can split basic blocks and push elements to AllEdges.822for (size_t I : llvm::seq<size_t>(0, MST.numEdges())) {823auto &E = *MST.allEdges()[I];824// For now, disable spanning tree optimization when fork or exec* is825// used.826if (HasExecOrFork)827E.InMST = false;828E.Place = getInstrBB(MST, E, ExecBlocks);829}830// Basic blocks in F are finalized at this point.831BasicBlock &EntryBlock = F.getEntryBlock();832Funcs.push_back(std::make_unique<GCOVFunction>(this, &F, SP, EndLine,833FunctionIdent++, Version));834GCOVFunction &Func = *Funcs.back();835836// Some non-tree edges are IndirectBr which cannot be split. Ignore them837// as well.838llvm::erase_if(MST.allEdges(), [](std::unique_ptr<Edge> &E) {839return E->Removed || (!E->InMST && !E->Place);840});841const size_t Measured =842std::stable_partition(843MST.allEdges().begin(), MST.allEdges().end(),844[](std::unique_ptr<Edge> &E) { return E->Place; }) -845MST.allEdges().begin();846for (size_t I : llvm::seq<size_t>(0, Measured)) {847Edge &E = *MST.allEdges()[I];848GCOVBlock &Src =849E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock();850GCOVBlock &Dst =851E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock();852E.SrcNumber = Src.Number;853E.DstNumber = Dst.Number;854}855std::stable_sort(856MST.allEdges().begin(), MST.allEdges().begin() + Measured,857[](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) {858return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber859: L->DstNumber < R->DstNumber;860});861862for (const Edge &E : make_pointee_range(MST.allEdges())) {863GCOVBlock &Src =864E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock();865GCOVBlock &Dst =866E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock();867Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE));868}869870// Artificial functions such as global initializers871if (!SP->isArtificial())872Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line);873874LLVM_DEBUG(dumpEdges(MST, Func));875876for (auto &GB : Func.Blocks) {877const BasicBlock &BB = *GB.first;878auto &Block = GB.second;879for (auto Succ : Block.OutEdges) {880uint32_t Idx = Succ.first->Number;881do EdgeDestinations.push_back(Idx & 255);882while ((Idx >>= 8) > 0);883}884885for (const auto &I : BB) {886// Debug intrinsic locations correspond to the location of the887// declaration, not necessarily any statements or expressions.888if (isa<DbgInfoIntrinsic>(&I)) continue;889890const DebugLoc &Loc = I.getDebugLoc();891if (!Loc)892continue;893894// Artificial lines such as calls to the global constructors.895if (Loc.getLine() == 0 || Loc.isImplicitCode())896continue;897898if (Line == Loc.getLine()) continue;899Line = Loc.getLine();900MDNode *Scope = Loc.getScope();901// TODO: Handle blocks from another file due to #line, #include, etc.902if (isa<DILexicalBlockFile>(Scope) || SP != getDISubprogram(Scope))903continue;904905GCOVLines &Lines = Block.getFile(Filename);906Lines.addLine(Loc.getLine());907}908Line = 0;909}910if (EmitGCDA) {911DISubprogram *SP = F.getSubprogram();912ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured);913GlobalVariable *Counters = new GlobalVariable(914*M, CounterTy, false, GlobalValue::InternalLinkage,915Constant::getNullValue(CounterTy), "__llvm_gcov_ctr");916CountersBySP.emplace_back(Counters, SP);917918for (size_t I : llvm::seq<size_t>(0, Measured)) {919const Edge &E = *MST.allEdges()[I];920IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt());921Value *V = Builder.CreateConstInBoundsGEP2_64(922Counters->getValueType(), Counters, 0, I);923// Disable sanitizers to decrease size bloat. We don't expect924// sanitizers to catch interesting issues.925Instruction *Inst;926if (Options.Atomic) {927Inst = Builder.CreateAtomicRMW(AtomicRMWInst::Add, V,928Builder.getInt64(1), MaybeAlign(),929AtomicOrdering::Monotonic);930} else {931LoadInst *OldCount =932Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr");933OldCount->setNoSanitizeMetadata();934Value *NewCount = Builder.CreateAdd(OldCount, Builder.getInt64(1));935Inst = Builder.CreateStore(NewCount, V);936}937Inst->setNoSanitizeMetadata();938}939}940}941942char Tmp[4];943JamCRC JC;944JC.update(EdgeDestinations);945uint32_t Stamp = JC.getCRC();946FileChecksums.push_back(Stamp);947948if (Options.EmitNotes) {949std::error_code EC;950raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC,951sys::fs::OF_None);952if (EC) {953Ctx->emitError(954Twine("failed to open coverage notes file for writing: ") +955EC.message());956continue;957}958os = &out;959if (Endian == llvm::endianness::big) {960out.write("gcno", 4);961out.write(Options.Version, 4);962} else {963out.write("oncg", 4);964std::reverse_copy(Options.Version, Options.Version + 4, Tmp);965out.write(Tmp, 4);966}967write(Stamp);968if (Version >= 90)969writeString(""); // unuseful current_working_directory970if (Version >= 80)971write(0); // unuseful has_unexecuted_blocks972973for (auto &Func : Funcs)974Func->writeOut(Stamp);975976write(0);977write(0);978out.close();979}980981if (EmitGCDA) {982emitGlobalConstructor(CountersBySP);983EmitGCDA = false;984}985}986return true;987}988989Function *GCOVProfiler::createInternalFunction(FunctionType *FTy,990StringRef Name,991StringRef MangledType /*=""*/) {992Function *F = Function::createWithDefaultAttr(993FTy, GlobalValue::InternalLinkage, 0, Name, M);994F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);995F->addFnAttr(Attribute::NoUnwind);996if (Options.NoRedZone)997F->addFnAttr(Attribute::NoRedZone);998if (!MangledType.empty())999setKCFIType(*M, *F, MangledType);1000return F;1001}10021003void GCOVProfiler::emitGlobalConstructor(1004SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {1005Function *WriteoutF = insertCounterWriteout(CountersBySP);1006Function *ResetF = insertReset(CountersBySP);10071008// Create a small bit of code that registers the "__llvm_gcov_writeout" to1009// be executed at exit and the "__llvm_gcov_reset" function to be executed1010// when "__gcov_flush" is called.1011FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1012Function *F = createInternalFunction(FTy, "__llvm_gcov_init", "_ZTSFvvE");1013F->addFnAttr(Attribute::NoInline);10141015BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);1016IRBuilder<> Builder(BB);10171018FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1019auto *PFTy = PointerType::get(FTy, 0);1020FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false);10211022// Initialize the environment and register the local writeout, flush and1023// reset functions.1024FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);1025Builder.CreateCall(GCOVInit, {WriteoutF, ResetF});1026Builder.CreateRetVoid();10271028appendToGlobalCtors(*M, F, 0);1029}10301031FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {1032Type *Args[] = {1033PointerType::getUnqual(*Ctx), // const char *orig_filename1034Type::getInt32Ty(*Ctx), // uint32_t version1035Type::getInt32Ty(*Ctx), // uint32_t checksum1036};1037FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1038return M->getOrInsertFunction("llvm_gcda_start_file", FTy,1039TLI->getAttrList(Ctx, {1, 2}, /*Signed=*/false));1040}10411042FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) {1043Type *Args[] = {1044Type::getInt32Ty(*Ctx), // uint32_t ident1045Type::getInt32Ty(*Ctx), // uint32_t func_checksum1046Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum1047};1048FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1049return M->getOrInsertFunction("llvm_gcda_emit_function", FTy,1050TLI->getAttrList(Ctx, {0, 1, 2}, /*Signed=*/false));1051}10521053FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) {1054Type *Args[] = {1055Type::getInt32Ty(*Ctx), // uint32_t num_counters1056PointerType::getUnqual(*Ctx), // uint64_t *counters1057};1058FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);1059return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy,1060TLI->getAttrList(Ctx, {0}, /*Signed=*/false));1061}10621063FunctionCallee GCOVProfiler::getSummaryInfoFunc() {1064FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1065return M->getOrInsertFunction("llvm_gcda_summary_info", FTy);1066}10671068FunctionCallee GCOVProfiler::getEndFileFunc() {1069FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1070return M->getOrInsertFunction("llvm_gcda_end_file", FTy);1071}10721073Function *GCOVProfiler::insertCounterWriteout(1074ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {1075FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1076Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");1077if (!WriteoutF)1078WriteoutF =1079createInternalFunction(WriteoutFTy, "__llvm_gcov_writeout", "_ZTSFvvE");1080WriteoutF->addFnAttr(Attribute::NoInline);10811082BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);1083IRBuilder<> Builder(BB);10841085auto *TLI = &GetTLI(*WriteoutF);10861087FunctionCallee StartFile = getStartFileFunc(TLI);1088FunctionCallee EmitFunction = getEmitFunctionFunc(TLI);1089FunctionCallee EmitArcs = getEmitArcsFunc(TLI);1090FunctionCallee SummaryInfo = getSummaryInfoFunc();1091FunctionCallee EndFile = getEndFileFunc();10921093NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu");1094if (!CUNodes) {1095Builder.CreateRetVoid();1096return WriteoutF;1097}10981099// Collect the relevant data into a large constant data structure that we can1100// walk to write out everything.1101StructType *StartFileCallArgsTy = StructType::create(1102{Builder.getPtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()},1103"start_file_args_ty");1104StructType *EmitFunctionCallArgsTy = StructType::create(1105{Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()},1106"emit_function_args_ty");1107auto *PtrTy = Builder.getPtrTy();1108StructType *EmitArcsCallArgsTy =1109StructType::create({Builder.getInt32Ty(), PtrTy}, "emit_arcs_args_ty");1110StructType *FileInfoTy = StructType::create(1111{StartFileCallArgsTy, Builder.getInt32Ty(), PtrTy, PtrTy}, "file_info");11121113Constant *Zero32 = Builder.getInt32(0);1114// Build an explicit array of two zeros for use in ConstantExpr GEP building.1115Constant *TwoZero32s[] = {Zero32, Zero32};11161117SmallVector<Constant *, 8> FileInfos;1118for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) {1119auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i));11201121// Skip module skeleton (and module) CUs.1122if (CU->getDWOId())1123continue;11241125std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);1126uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];1127auto *StartFileCallArgs = ConstantStruct::get(1128StartFileCallArgsTy,1129{Builder.CreateGlobalStringPtr(FilenameGcda),1130Builder.getInt32(endian::read32be(Options.Version)),1131Builder.getInt32(CfgChecksum)});11321133SmallVector<Constant *, 8> EmitFunctionCallArgsArray;1134SmallVector<Constant *, 8> EmitArcsCallArgsArray;1135for (int j : llvm::seq<int>(0, CountersBySP.size())) {1136uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();1137EmitFunctionCallArgsArray.push_back(ConstantStruct::get(1138EmitFunctionCallArgsTy,1139{Builder.getInt32(j),1140Builder.getInt32(FuncChecksum),1141Builder.getInt32(CfgChecksum)}));11421143GlobalVariable *GV = CountersBySP[j].first;1144unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements();1145EmitArcsCallArgsArray.push_back(ConstantStruct::get(1146EmitArcsCallArgsTy,1147{Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr(1148GV->getValueType(), GV, TwoZero32s)}));1149}1150// Create global arrays for the two emit calls.1151int CountersSize = CountersBySP.size();1152assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&1153"Mismatched array size!");1154assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&1155"Mismatched array size!");1156auto *EmitFunctionCallArgsArrayTy =1157ArrayType::get(EmitFunctionCallArgsTy, CountersSize);1158auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(1159*M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,1160GlobalValue::InternalLinkage,1161ConstantArray::get(EmitFunctionCallArgsArrayTy,1162EmitFunctionCallArgsArray),1163Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));1164auto *EmitArcsCallArgsArrayTy =1165ArrayType::get(EmitArcsCallArgsTy, CountersSize);1166EmitFunctionCallArgsArrayGV->setUnnamedAddr(1167GlobalValue::UnnamedAddr::Global);1168auto *EmitArcsCallArgsArrayGV = new GlobalVariable(1169*M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,1170GlobalValue::InternalLinkage,1171ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray),1172Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));1173EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);11741175FileInfos.push_back(ConstantStruct::get(1176FileInfoTy,1177{StartFileCallArgs, Builder.getInt32(CountersSize),1178ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy,1179EmitFunctionCallArgsArrayGV,1180TwoZero32s),1181ConstantExpr::getInBoundsGetElementPtr(1182EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)}));1183}11841185// If we didn't find anything to actually emit, bail on out.1186if (FileInfos.empty()) {1187Builder.CreateRetVoid();1188return WriteoutF;1189}11901191// To simplify code, we cap the number of file infos we write out to fit1192// easily in a 32-bit signed integer. This gives consistent behavior between1193// 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit1194// operations on 32-bit systems. It also seems unreasonable to try to handle1195// more than 2 billion files.1196if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)1197FileInfos.resize(INT_MAX);11981199// Create a global for the entire data structure so we can walk it more1200// easily.1201auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size());1202auto *FileInfoArrayGV = new GlobalVariable(1203*M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,1204ConstantArray::get(FileInfoArrayTy, FileInfos),1205"__llvm_internal_gcov_emit_file_info");1206FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);12071208// Create the CFG for walking this data structure.1209auto *FileLoopHeader =1210BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF);1211auto *CounterLoopHeader =1212BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF);1213auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF);1214auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF);12151216// We always have at least one file, so just branch to the header.1217Builder.CreateBr(FileLoopHeader);12181219// The index into the files structure is our loop induction variable.1220Builder.SetInsertPoint(FileLoopHeader);1221PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2,1222"file_idx");1223IV->addIncoming(Builder.getInt32(0), BB);1224auto *FileInfoPtr = Builder.CreateInBoundsGEP(1225FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV});1226auto *StartFileCallArgsPtr =1227Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args");1228auto *StartFileCall = Builder.CreateCall(1229StartFile,1230{Builder.CreateLoad(StartFileCallArgsTy->getElementType(0),1231Builder.CreateStructGEP(StartFileCallArgsTy,1232StartFileCallArgsPtr, 0),1233"filename"),1234Builder.CreateLoad(StartFileCallArgsTy->getElementType(1),1235Builder.CreateStructGEP(StartFileCallArgsTy,1236StartFileCallArgsPtr, 1),1237"version"),1238Builder.CreateLoad(StartFileCallArgsTy->getElementType(2),1239Builder.CreateStructGEP(StartFileCallArgsTy,1240StartFileCallArgsPtr, 2),1241"stamp")});1242if (auto AK = TLI->getExtAttrForI32Param(false))1243StartFileCall->addParamAttr(2, AK);1244auto *NumCounters = Builder.CreateLoad(1245FileInfoTy->getElementType(1),1246Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs");1247auto *EmitFunctionCallArgsArray =1248Builder.CreateLoad(FileInfoTy->getElementType(2),1249Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2),1250"emit_function_args");1251auto *EmitArcsCallArgsArray = Builder.CreateLoad(1252FileInfoTy->getElementType(3),1253Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args");1254auto *EnterCounterLoopCond =1255Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters);1256Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch);12571258Builder.SetInsertPoint(CounterLoopHeader);1259auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2,1260"ctr_idx");1261JV->addIncoming(Builder.getInt32(0), FileLoopHeader);1262auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(1263EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV);1264auto *EmitFunctionCall = Builder.CreateCall(1265EmitFunction,1266{Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0),1267Builder.CreateStructGEP(EmitFunctionCallArgsTy,1268EmitFunctionCallArgsPtr, 0),1269"ident"),1270Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1),1271Builder.CreateStructGEP(EmitFunctionCallArgsTy,1272EmitFunctionCallArgsPtr, 1),1273"func_checkssum"),1274Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2),1275Builder.CreateStructGEP(EmitFunctionCallArgsTy,1276EmitFunctionCallArgsPtr, 2),1277"cfg_checksum")});1278if (auto AK = TLI->getExtAttrForI32Param(false)) {1279EmitFunctionCall->addParamAttr(0, AK);1280EmitFunctionCall->addParamAttr(1, AK);1281EmitFunctionCall->addParamAttr(2, AK);1282}1283auto *EmitArcsCallArgsPtr =1284Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV);1285auto *EmitArcsCall = Builder.CreateCall(1286EmitArcs,1287{Builder.CreateLoad(1288EmitArcsCallArgsTy->getElementType(0),1289Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0),1290"num_counters"),1291Builder.CreateLoad(1292EmitArcsCallArgsTy->getElementType(1),1293Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1),1294"counters")});1295if (auto AK = TLI->getExtAttrForI32Param(false))1296EmitArcsCall->addParamAttr(0, AK);1297auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1));1298auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters);1299Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch);1300JV->addIncoming(NextJV, CounterLoopHeader);13011302Builder.SetInsertPoint(FileLoopLatch);1303Builder.CreateCall(SummaryInfo, {});1304Builder.CreateCall(EndFile, {});1305auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx");1306auto *FileLoopCond =1307Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size()));1308Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB);1309IV->addIncoming(NextIV, FileLoopLatch);13101311Builder.SetInsertPoint(ExitBB);1312Builder.CreateRetVoid();13131314return WriteoutF;1315}13161317Function *GCOVProfiler::insertReset(1318ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) {1319FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);1320Function *ResetF = M->getFunction("__llvm_gcov_reset");1321if (!ResetF)1322ResetF = createInternalFunction(FTy, "__llvm_gcov_reset", "_ZTSFvvE");1323ResetF->addFnAttr(Attribute::NoInline);13241325BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", ResetF);1326IRBuilder<> Builder(Entry);1327LLVMContext &C = Entry->getContext();13281329// Zero out the counters.1330for (const auto &I : CountersBySP) {1331GlobalVariable *GV = I.first;1332auto *GVTy = cast<ArrayType>(GV->getValueType());1333Builder.CreateMemSet(GV, Constant::getNullValue(Type::getInt8Ty(C)),1334GVTy->getNumElements() *1335GVTy->getElementType()->getScalarSizeInBits() / 8,1336GV->getAlign());1337}13381339Type *RetTy = ResetF->getReturnType();1340if (RetTy->isVoidTy())1341Builder.CreateRetVoid();1342else if (RetTy->isIntegerTy())1343// Used if __llvm_gcov_reset was implicitly declared.1344Builder.CreateRet(ConstantInt::get(RetTy, 0));1345else1346report_fatal_error("invalid return type for __llvm_gcov_reset");13471348return ResetF;1349}135013511352