File: | llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp |
Warning: | line 181, column 8 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This pass implements GCOV-style profiling. When this pass is run it emits | |||
10 | // "gcno" files next to the existing source, and instruments the code that runs | |||
11 | // to records the edges between blocks that run and emit a complementary "gcda" | |||
12 | // file on exit. | |||
13 | // | |||
14 | //===----------------------------------------------------------------------===// | |||
15 | ||||
16 | #include "llvm/ADT/DenseMap.h" | |||
17 | #include "llvm/ADT/Hashing.h" | |||
18 | #include "llvm/ADT/STLExtras.h" | |||
19 | #include "llvm/ADT/Sequence.h" | |||
20 | #include "llvm/ADT/Statistic.h" | |||
21 | #include "llvm/ADT/StringExtras.h" | |||
22 | #include "llvm/ADT/StringMap.h" | |||
23 | #include "llvm/Analysis/EHPersonalities.h" | |||
24 | #include "llvm/Analysis/TargetLibraryInfo.h" | |||
25 | #include "llvm/IR/CFG.h" | |||
26 | #include "llvm/IR/DebugInfo.h" | |||
27 | #include "llvm/IR/DebugLoc.h" | |||
28 | #include "llvm/IR/IRBuilder.h" | |||
29 | #include "llvm/IR/InstIterator.h" | |||
30 | #include "llvm/IR/Instructions.h" | |||
31 | #include "llvm/IR/IntrinsicInst.h" | |||
32 | #include "llvm/IR/Module.h" | |||
33 | #include "llvm/InitializePasses.h" | |||
34 | #include "llvm/Pass.h" | |||
35 | #include "llvm/Support/CommandLine.h" | |||
36 | #include "llvm/Support/Debug.h" | |||
37 | #include "llvm/Support/FileSystem.h" | |||
38 | #include "llvm/Support/Path.h" | |||
39 | #include "llvm/Support/Regex.h" | |||
40 | #include "llvm/Support/raw_ostream.h" | |||
41 | #include "llvm/Transforms/Instrumentation.h" | |||
42 | #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" | |||
43 | #include "llvm/Transforms/Utils/ModuleUtils.h" | |||
44 | #include <algorithm> | |||
45 | #include <memory> | |||
46 | #include <string> | |||
47 | #include <utility> | |||
48 | using namespace llvm; | |||
49 | ||||
50 | #define DEBUG_TYPE"insert-gcov-profiling" "insert-gcov-profiling" | |||
51 | ||||
52 | static cl::opt<std::string> | |||
53 | DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden, | |||
54 | cl::ValueRequired); | |||
55 | static cl::opt<bool> DefaultExitBlockBeforeBody("gcov-exit-block-before-body", | |||
56 | cl::init(false), cl::Hidden); | |||
57 | ||||
58 | GCOVOptions GCOVOptions::getDefault() { | |||
59 | GCOVOptions Options; | |||
60 | Options.EmitNotes = true; | |||
61 | Options.EmitData = true; | |||
62 | Options.UseCfgChecksum = false; | |||
63 | Options.NoRedZone = false; | |||
64 | Options.FunctionNamesInData = true; | |||
65 | Options.ExitBlockBeforeBody = DefaultExitBlockBeforeBody; | |||
66 | ||||
67 | if (DefaultGCOVVersion.size() != 4) { | |||
68 | llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + | |||
69 | DefaultGCOVVersion); | |||
70 | } | |||
71 | memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4); | |||
72 | return Options; | |||
73 | } | |||
74 | ||||
75 | namespace { | |||
76 | class GCOVFunction; | |||
77 | ||||
78 | class GCOVProfiler { | |||
79 | public: | |||
80 | GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} | |||
81 | GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) { | |||
82 | assert((Options.EmitNotes || Options.EmitData) &&(((Options.EmitNotes || Options.EmitData) && "GCOVProfiler asked to do nothing?" ) ? static_cast<void> (0) : __assert_fail ("(Options.EmitNotes || Options.EmitData) && \"GCOVProfiler asked to do nothing?\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 83, __PRETTY_FUNCTION__)) | |||
83 | "GCOVProfiler asked to do nothing?")(((Options.EmitNotes || Options.EmitData) && "GCOVProfiler asked to do nothing?" ) ? static_cast<void> (0) : __assert_fail ("(Options.EmitNotes || Options.EmitData) && \"GCOVProfiler asked to do nothing?\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 83, __PRETTY_FUNCTION__)); | |||
84 | ReversedVersion[0] = Options.Version[3]; | |||
85 | ReversedVersion[1] = Options.Version[2]; | |||
86 | ReversedVersion[2] = Options.Version[1]; | |||
87 | ReversedVersion[3] = Options.Version[0]; | |||
88 | ReversedVersion[4] = '\0'; | |||
89 | } | |||
90 | bool | |||
91 | runOnModule(Module &M, | |||
92 | std::function<const TargetLibraryInfo &(Function &F)> GetTLI); | |||
93 | ||||
94 | private: | |||
95 | // Create the .gcno files for the Module based on DebugInfo. | |||
96 | void emitProfileNotes(); | |||
97 | ||||
98 | // Modify the program to track transitions along edges and call into the | |||
99 | // profiling runtime to emit .gcda files when run. | |||
100 | bool emitProfileArcs(); | |||
101 | ||||
102 | bool isFunctionInstrumented(const Function &F); | |||
103 | std::vector<Regex> createRegexesFromString(StringRef RegexesStr); | |||
104 | static bool doesFilenameMatchARegex(StringRef Filename, | |||
105 | std::vector<Regex> &Regexes); | |||
106 | ||||
107 | // Get pointers to the functions in the runtime library. | |||
108 | FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI); | |||
109 | FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI); | |||
110 | FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI); | |||
111 | FunctionCallee getSummaryInfoFunc(); | |||
112 | FunctionCallee getEndFileFunc(); | |||
113 | ||||
114 | // Add the function to write out all our counters to the global destructor | |||
115 | // list. | |||
116 | Function * | |||
117 | insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); | |||
118 | Function *insertFlush(ArrayRef<std::pair<GlobalVariable *, MDNode *>>); | |||
119 | ||||
120 | void AddFlushBeforeForkAndExec(); | |||
121 | ||||
122 | enum class GCovFileType { GCNO, GCDA }; | |||
123 | std::string mangleName(const DICompileUnit *CU, GCovFileType FileType); | |||
124 | ||||
125 | GCOVOptions Options; | |||
126 | ||||
127 | // Reversed, NUL-terminated copy of Options.Version. | |||
128 | char ReversedVersion[5]; | |||
129 | // Checksum, produced by hash of EdgeDestinations | |||
130 | SmallVector<uint32_t, 4> FileChecksums; | |||
131 | ||||
132 | Module *M = nullptr; | |||
133 | std::function<const TargetLibraryInfo &(Function &F)> GetTLI; | |||
134 | LLVMContext *Ctx = nullptr; | |||
135 | SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs; | |||
136 | std::vector<Regex> FilterRe; | |||
137 | std::vector<Regex> ExcludeRe; | |||
138 | StringMap<bool> InstrumentedFiles; | |||
139 | }; | |||
140 | ||||
141 | class GCOVProfilerLegacyPass : public ModulePass { | |||
142 | public: | |||
143 | static char ID; | |||
144 | GCOVProfilerLegacyPass() | |||
145 | : GCOVProfilerLegacyPass(GCOVOptions::getDefault()) {} | |||
146 | GCOVProfilerLegacyPass(const GCOVOptions &Opts) | |||
147 | : ModulePass(ID), Profiler(Opts) { | |||
148 | initializeGCOVProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); | |||
149 | } | |||
150 | StringRef getPassName() const override { return "GCOV Profiler"; } | |||
151 | ||||
152 | bool runOnModule(Module &M) override { | |||
153 | return Profiler.runOnModule(M, [this](Function &F) -> TargetLibraryInfo & { | |||
154 | return getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); | |||
155 | }); | |||
156 | } | |||
157 | ||||
158 | void getAnalysisUsage(AnalysisUsage &AU) const override { | |||
159 | AU.addRequired<TargetLibraryInfoWrapperPass>(); | |||
160 | } | |||
161 | ||||
162 | private: | |||
163 | GCOVProfiler Profiler; | |||
164 | }; | |||
165 | } | |||
166 | ||||
167 | char GCOVProfilerLegacyPass::ID = 0; | |||
168 | INITIALIZE_PASS_BEGIN(static void *initializeGCOVProfilerLegacyPassPassOnce(PassRegistry &Registry) { | |||
169 | GCOVProfilerLegacyPass, "insert-gcov-profiling",static void *initializeGCOVProfilerLegacyPassPassOnce(PassRegistry &Registry) { | |||
170 | "Insert instrumentation for GCOV profiling", false, false)static void *initializeGCOVProfilerLegacyPassPassOnce(PassRegistry &Registry) { | |||
171 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)initializeTargetLibraryInfoWrapperPassPass(Registry); | |||
172 | INITIALIZE_PASS_END(PassInfo *PI = new PassInfo( "Insert instrumentation for GCOV profiling" , "insert-gcov-profiling", &GCOVProfilerLegacyPass::ID, PassInfo ::NormalCtor_t(callDefaultCtor<GCOVProfilerLegacyPass>) , false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeGCOVProfilerLegacyPassPassFlag ; void llvm::initializeGCOVProfilerLegacyPassPass(PassRegistry &Registry) { llvm::call_once(InitializeGCOVProfilerLegacyPassPassFlag , initializeGCOVProfilerLegacyPassPassOnce, std::ref(Registry )); } | |||
173 | GCOVProfilerLegacyPass, "insert-gcov-profiling",PassInfo *PI = new PassInfo( "Insert instrumentation for GCOV profiling" , "insert-gcov-profiling", &GCOVProfilerLegacyPass::ID, PassInfo ::NormalCtor_t(callDefaultCtor<GCOVProfilerLegacyPass>) , false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeGCOVProfilerLegacyPassPassFlag ; void llvm::initializeGCOVProfilerLegacyPassPass(PassRegistry &Registry) { llvm::call_once(InitializeGCOVProfilerLegacyPassPassFlag , initializeGCOVProfilerLegacyPassPassOnce, std::ref(Registry )); } | |||
174 | "Insert instrumentation for GCOV profiling", false, false)PassInfo *PI = new PassInfo( "Insert instrumentation for GCOV profiling" , "insert-gcov-profiling", &GCOVProfilerLegacyPass::ID, PassInfo ::NormalCtor_t(callDefaultCtor<GCOVProfilerLegacyPass>) , false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeGCOVProfilerLegacyPassPassFlag ; void llvm::initializeGCOVProfilerLegacyPassPass(PassRegistry &Registry) { llvm::call_once(InitializeGCOVProfilerLegacyPassPassFlag , initializeGCOVProfilerLegacyPassPassOnce, std::ref(Registry )); } | |||
175 | ||||
176 | ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) { | |||
177 | return new GCOVProfilerLegacyPass(Options); | |||
178 | } | |||
179 | ||||
180 | static StringRef getFunctionName(const DISubprogram *SP) { | |||
181 | if (!SP->getLinkageName().empty()) | |||
| ||||
182 | return SP->getLinkageName(); | |||
183 | return SP->getName(); | |||
184 | } | |||
185 | ||||
186 | /// Extract a filename for a DISubprogram. | |||
187 | /// | |||
188 | /// Prefer relative paths in the coverage notes. Clang also may split | |||
189 | /// up absolute paths into a directory and filename component. When | |||
190 | /// the relative path doesn't exist, reconstruct the absolute path. | |||
191 | static SmallString<128> getFilename(const DISubprogram *SP) { | |||
192 | SmallString<128> Path; | |||
193 | StringRef RelPath = SP->getFilename(); | |||
194 | if (sys::fs::exists(RelPath)) | |||
195 | Path = RelPath; | |||
196 | else | |||
197 | sys::path::append(Path, SP->getDirectory(), SP->getFilename()); | |||
198 | return Path; | |||
199 | } | |||
200 | ||||
201 | namespace { | |||
202 | class GCOVRecord { | |||
203 | protected: | |||
204 | static const char *const LinesTag; | |||
205 | static const char *const FunctionTag; | |||
206 | static const char *const BlockTag; | |||
207 | static const char *const EdgeTag; | |||
208 | ||||
209 | GCOVRecord() = default; | |||
210 | ||||
211 | void writeBytes(const char *Bytes, int Size) { | |||
212 | os->write(Bytes, Size); | |||
213 | } | |||
214 | ||||
215 | void write(uint32_t i) { | |||
216 | writeBytes(reinterpret_cast<char*>(&i), 4); | |||
217 | } | |||
218 | ||||
219 | // Returns the length measured in 4-byte blocks that will be used to | |||
220 | // represent this string in a GCOV file | |||
221 | static unsigned lengthOfGCOVString(StringRef s) { | |||
222 | // A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs | |||
223 | // padding out to the next 4-byte word. The length is measured in 4-byte | |||
224 | // words including padding, not bytes of actual string. | |||
225 | return (s.size() / 4) + 1; | |||
226 | } | |||
227 | ||||
228 | void writeGCOVString(StringRef s) { | |||
229 | uint32_t Len = lengthOfGCOVString(s); | |||
230 | write(Len); | |||
231 | writeBytes(s.data(), s.size()); | |||
232 | ||||
233 | // Write 1 to 4 bytes of NUL padding. | |||
234 | assert((unsigned)(4 - (s.size() % 4)) > 0)(((unsigned)(4 - (s.size() % 4)) > 0) ? static_cast<void > (0) : __assert_fail ("(unsigned)(4 - (s.size() % 4)) > 0" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 234, __PRETTY_FUNCTION__)); | |||
235 | assert((unsigned)(4 - (s.size() % 4)) <= 4)(((unsigned)(4 - (s.size() % 4)) <= 4) ? static_cast<void > (0) : __assert_fail ("(unsigned)(4 - (s.size() % 4)) <= 4" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 235, __PRETTY_FUNCTION__)); | |||
236 | writeBytes("\0\0\0\0", 4 - (s.size() % 4)); | |||
237 | } | |||
238 | ||||
239 | raw_ostream *os; | |||
240 | }; | |||
241 | const char *const GCOVRecord::LinesTag = "\0\0\x45\x01"; | |||
242 | const char *const GCOVRecord::FunctionTag = "\0\0\0\1"; | |||
243 | const char *const GCOVRecord::BlockTag = "\0\0\x41\x01"; | |||
244 | const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01"; | |||
245 | ||||
246 | class GCOVFunction; | |||
247 | class GCOVBlock; | |||
248 | ||||
249 | // Constructed only by requesting it from a GCOVBlock, this object stores a | |||
250 | // list of line numbers and a single filename, representing lines that belong | |||
251 | // to the block. | |||
252 | class GCOVLines : public GCOVRecord { | |||
253 | public: | |||
254 | void addLine(uint32_t Line) { | |||
255 | assert(Line != 0 && "Line zero is not a valid real line number.")((Line != 0 && "Line zero is not a valid real line number." ) ? static_cast<void> (0) : __assert_fail ("Line != 0 && \"Line zero is not a valid real line number.\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 255, __PRETTY_FUNCTION__)); | |||
256 | Lines.push_back(Line); | |||
257 | } | |||
258 | ||||
259 | uint32_t length() const { | |||
260 | // Here 2 = 1 for string length + 1 for '0' id#. | |||
261 | return lengthOfGCOVString(Filename) + 2 + Lines.size(); | |||
262 | } | |||
263 | ||||
264 | void writeOut() { | |||
265 | write(0); | |||
266 | writeGCOVString(Filename); | |||
267 | for (int i = 0, e = Lines.size(); i != e; ++i) | |||
268 | write(Lines[i]); | |||
269 | } | |||
270 | ||||
271 | GCOVLines(StringRef F, raw_ostream *os) : Filename(std::string(F)) { | |||
272 | this->os = os; | |||
273 | } | |||
274 | ||||
275 | private: | |||
276 | std::string Filename; | |||
277 | SmallVector<uint32_t, 32> Lines; | |||
278 | }; | |||
279 | ||||
280 | ||||
281 | // Represent a basic block in GCOV. Each block has a unique number in the | |||
282 | // function, number of lines belonging to each block, and a set of edges to | |||
283 | // other blocks. | |||
284 | class GCOVBlock : public GCOVRecord { | |||
285 | public: | |||
286 | GCOVLines &getFile(StringRef Filename) { | |||
287 | return LinesByFile.try_emplace(Filename, Filename, os).first->second; | |||
288 | } | |||
289 | ||||
290 | void addEdge(GCOVBlock &Successor) { | |||
291 | OutEdges.push_back(&Successor); | |||
292 | } | |||
293 | ||||
294 | void writeOut() { | |||
295 | uint32_t Len = 3; | |||
296 | SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile; | |||
297 | for (auto &I : LinesByFile) { | |||
298 | Len += I.second.length(); | |||
299 | SortedLinesByFile.push_back(&I); | |||
300 | } | |||
301 | ||||
302 | writeBytes(LinesTag, 4); | |||
303 | write(Len); | |||
304 | write(Number); | |||
305 | ||||
306 | llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS, | |||
307 | StringMapEntry<GCOVLines> *RHS) { | |||
308 | return LHS->getKey() < RHS->getKey(); | |||
309 | }); | |||
310 | for (auto &I : SortedLinesByFile) | |||
311 | I->getValue().writeOut(); | |||
312 | write(0); | |||
313 | write(0); | |||
314 | } | |||
315 | ||||
316 | GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) { | |||
317 | // Only allow copy before edges and lines have been added. After that, | |||
318 | // there are inter-block pointers (eg: edges) that won't take kindly to | |||
319 | // blocks being copied or moved around. | |||
320 | assert(LinesByFile.empty())((LinesByFile.empty()) ? static_cast<void> (0) : __assert_fail ("LinesByFile.empty()", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 320, __PRETTY_FUNCTION__)); | |||
321 | assert(OutEdges.empty())((OutEdges.empty()) ? static_cast<void> (0) : __assert_fail ("OutEdges.empty()", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 321, __PRETTY_FUNCTION__)); | |||
322 | } | |||
323 | ||||
324 | private: | |||
325 | friend class GCOVFunction; | |||
326 | ||||
327 | GCOVBlock(uint32_t Number, raw_ostream *os) | |||
328 | : Number(Number) { | |||
329 | this->os = os; | |||
330 | } | |||
331 | ||||
332 | uint32_t Number; | |||
333 | StringMap<GCOVLines> LinesByFile; | |||
334 | SmallVector<GCOVBlock *, 4> OutEdges; | |||
335 | }; | |||
336 | ||||
337 | // A function has a unique identifier, a checksum (we leave as zero) and a | |||
338 | // set of blocks and a map of edges between blocks. This is the only GCOV | |||
339 | // object users can construct, the blocks and lines will be rooted here. | |||
340 | class GCOVFunction : public GCOVRecord { | |||
341 | public: | |||
342 | GCOVFunction(const DISubprogram *SP, Function *F, raw_ostream *os, | |||
343 | uint32_t Ident, bool UseCfgChecksum, bool ExitBlockBeforeBody) | |||
344 | : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0), | |||
345 | ReturnBlock(1, os) { | |||
346 | this->os = os; | |||
347 | ||||
348 | LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("insert-gcov-profiling")) { dbgs() << "Function: " << getFunctionName(SP) << "\n"; } } while (false); | |||
349 | ||||
350 | uint32_t i = 0; | |||
351 | for (auto &BB : *F) { | |||
352 | // Skip index 1 if it's assigned to the ReturnBlock. | |||
353 | if (i == 1 && ExitBlockBeforeBody) | |||
354 | ++i; | |||
355 | Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os))); | |||
356 | } | |||
357 | if (!ExitBlockBeforeBody) | |||
358 | ReturnBlock.Number = i; | |||
359 | ||||
360 | std::string FunctionNameAndLine; | |||
361 | raw_string_ostream FNLOS(FunctionNameAndLine); | |||
362 | FNLOS << getFunctionName(SP) << SP->getLine(); | |||
363 | FNLOS.flush(); | |||
364 | FuncChecksum = hash_value(FunctionNameAndLine); | |||
365 | } | |||
366 | ||||
367 | GCOVBlock &getBlock(BasicBlock *BB) { | |||
368 | return Blocks.find(BB)->second; | |||
369 | } | |||
370 | ||||
371 | GCOVBlock &getReturnBlock() { | |||
372 | return ReturnBlock; | |||
373 | } | |||
374 | ||||
375 | std::string getEdgeDestinations() { | |||
376 | std::string EdgeDestinations; | |||
377 | raw_string_ostream EDOS(EdgeDestinations); | |||
378 | Function *F = Blocks.begin()->first->getParent(); | |||
379 | for (BasicBlock &I : *F) { | |||
380 | GCOVBlock &Block = getBlock(&I); | |||
381 | for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) | |||
382 | EDOS << Block.OutEdges[i]->Number; | |||
383 | } | |||
384 | return EdgeDestinations; | |||
385 | } | |||
386 | ||||
387 | uint32_t getFuncChecksum() const { | |||
388 | return FuncChecksum; | |||
389 | } | |||
390 | ||||
391 | void setCfgChecksum(uint32_t Checksum) { | |||
392 | CfgChecksum = Checksum; | |||
393 | } | |||
394 | ||||
395 | void writeOut() { | |||
396 | writeBytes(FunctionTag, 4); | |||
397 | SmallString<128> Filename = getFilename(SP); | |||
398 | uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) + | |||
399 | 1 + lengthOfGCOVString(Filename) + 1; | |||
400 | if (UseCfgChecksum) | |||
401 | ++BlockLen; | |||
402 | write(BlockLen); | |||
403 | write(Ident); | |||
404 | write(FuncChecksum); | |||
405 | if (UseCfgChecksum) | |||
406 | write(CfgChecksum); | |||
407 | writeGCOVString(getFunctionName(SP)); | |||
408 | writeGCOVString(Filename); | |||
409 | write(SP->getLine()); | |||
410 | ||||
411 | // Emit count of blocks. | |||
412 | writeBytes(BlockTag, 4); | |||
413 | write(Blocks.size() + 1); | |||
414 | for (int i = 0, e = Blocks.size() + 1; i != e; ++i) { | |||
415 | write(0); // No flags on our blocks. | |||
416 | } | |||
417 | LLVM_DEBUG(dbgs() << Blocks.size() << " blocks.\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("insert-gcov-profiling")) { dbgs() << Blocks.size() << " blocks.\n"; } } while (false); | |||
418 | ||||
419 | // Emit edges between blocks. | |||
420 | if (Blocks.empty()) return; | |||
421 | Function *F = Blocks.begin()->first->getParent(); | |||
422 | for (BasicBlock &I : *F) { | |||
423 | GCOVBlock &Block = getBlock(&I); | |||
424 | if (Block.OutEdges.empty()) continue; | |||
425 | ||||
426 | writeBytes(EdgeTag, 4); | |||
427 | write(Block.OutEdges.size() * 2 + 1); | |||
428 | write(Block.Number); | |||
429 | for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { | |||
430 | LLVM_DEBUG(dbgs() << Block.Number << " -> "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("insert-gcov-profiling")) { dbgs() << Block.Number << " -> " << Block.OutEdges[i]->Number << "\n" ; } } while (false) | |||
431 | << Block.OutEdges[i]->Number << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("insert-gcov-profiling")) { dbgs() << Block.Number << " -> " << Block.OutEdges[i]->Number << "\n" ; } } while (false); | |||
432 | write(Block.OutEdges[i]->Number); | |||
433 | write(0); // no flags | |||
434 | } | |||
435 | } | |||
436 | ||||
437 | // Emit lines for each block. | |||
438 | for (BasicBlock &I : *F) | |||
439 | getBlock(&I).writeOut(); | |||
440 | } | |||
441 | ||||
442 | private: | |||
443 | const DISubprogram *SP; | |||
444 | uint32_t Ident; | |||
445 | uint32_t FuncChecksum; | |||
446 | bool UseCfgChecksum; | |||
447 | uint32_t CfgChecksum; | |||
448 | DenseMap<BasicBlock *, GCOVBlock> Blocks; | |||
449 | GCOVBlock ReturnBlock; | |||
450 | }; | |||
451 | } | |||
452 | ||||
453 | // RegexesStr is a string containing differents regex separated by a semi-colon. | |||
454 | // For example "foo\..*$;bar\..*$". | |||
455 | std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) { | |||
456 | std::vector<Regex> Regexes; | |||
457 | while (!RegexesStr.empty()) { | |||
458 | std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';'); | |||
459 | if (!HeadTail.first.empty()) { | |||
460 | Regex Re(HeadTail.first); | |||
461 | std::string Err; | |||
462 | if (!Re.isValid(Err)) { | |||
463 | Ctx->emitError(Twine("Regex ") + HeadTail.first + | |||
464 | " is not valid: " + Err); | |||
465 | } | |||
466 | Regexes.emplace_back(std::move(Re)); | |||
467 | } | |||
468 | RegexesStr = HeadTail.second; | |||
469 | } | |||
470 | return Regexes; | |||
471 | } | |||
472 | ||||
473 | bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename, | |||
474 | std::vector<Regex> &Regexes) { | |||
475 | for (Regex &Re : Regexes) { | |||
476 | if (Re.match(Filename)) { | |||
477 | return true; | |||
478 | } | |||
479 | } | |||
480 | return false; | |||
481 | } | |||
482 | ||||
483 | bool GCOVProfiler::isFunctionInstrumented(const Function &F) { | |||
484 | if (FilterRe.empty() && ExcludeRe.empty()) { | |||
485 | return true; | |||
486 | } | |||
487 | SmallString<128> Filename = getFilename(F.getSubprogram()); | |||
488 | auto It = InstrumentedFiles.find(Filename); | |||
489 | if (It != InstrumentedFiles.end()) { | |||
490 | return It->second; | |||
491 | } | |||
492 | ||||
493 | SmallString<256> RealPath; | |||
494 | StringRef RealFilename; | |||
495 | ||||
496 | // Path can be | |||
497 | // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for | |||
498 | // such a case we must get the real_path. | |||
499 | if (sys::fs::real_path(Filename, RealPath)) { | |||
500 | // real_path can fail with path like "foo.c". | |||
501 | RealFilename = Filename; | |||
502 | } else { | |||
503 | RealFilename = RealPath; | |||
504 | } | |||
505 | ||||
506 | bool ShouldInstrument; | |||
507 | if (FilterRe.empty()) { | |||
508 | ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe); | |||
509 | } else if (ExcludeRe.empty()) { | |||
510 | ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe); | |||
511 | } else { | |||
512 | ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) && | |||
513 | !doesFilenameMatchARegex(RealFilename, ExcludeRe); | |||
514 | } | |||
515 | InstrumentedFiles[Filename] = ShouldInstrument; | |||
516 | return ShouldInstrument; | |||
517 | } | |||
518 | ||||
519 | std::string GCOVProfiler::mangleName(const DICompileUnit *CU, | |||
520 | GCovFileType OutputType) { | |||
521 | bool Notes = OutputType == GCovFileType::GCNO; | |||
522 | ||||
523 | if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) { | |||
524 | for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) { | |||
525 | MDNode *N = GCov->getOperand(i); | |||
526 | bool ThreeElement = N->getNumOperands() == 3; | |||
527 | if (!ThreeElement && N->getNumOperands() != 2) | |||
528 | continue; | |||
529 | if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU) | |||
530 | continue; | |||
531 | ||||
532 | if (ThreeElement) { | |||
533 | // These nodes have no mangling to apply, it's stored mangled in the | |||
534 | // bitcode. | |||
535 | MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0)); | |||
536 | MDString *DataFile = dyn_cast<MDString>(N->getOperand(1)); | |||
537 | if (!NotesFile || !DataFile) | |||
538 | continue; | |||
539 | return std::string(Notes ? NotesFile->getString() | |||
540 | : DataFile->getString()); | |||
541 | } | |||
542 | ||||
543 | MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0)); | |||
544 | if (!GCovFile) | |||
545 | continue; | |||
546 | ||||
547 | SmallString<128> Filename = GCovFile->getString(); | |||
548 | sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); | |||
549 | return std::string(Filename.str()); | |||
550 | } | |||
551 | } | |||
552 | ||||
553 | SmallString<128> Filename = CU->getFilename(); | |||
554 | sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); | |||
555 | StringRef FName = sys::path::filename(Filename); | |||
556 | SmallString<128> CurPath; | |||
557 | if (sys::fs::current_path(CurPath)) | |||
558 | return std::string(FName); | |||
559 | sys::path::append(CurPath, FName); | |||
560 | return std::string(CurPath.str()); | |||
561 | } | |||
562 | ||||
563 | bool GCOVProfiler::runOnModule( | |||
564 | Module &M, std::function<const TargetLibraryInfo &(Function &F)> GetTLI) { | |||
565 | this->M = &M; | |||
566 | this->GetTLI = std::move(GetTLI); | |||
567 | Ctx = &M.getContext(); | |||
568 | ||||
569 | AddFlushBeforeForkAndExec(); | |||
570 | ||||
571 | FilterRe = createRegexesFromString(Options.Filter); | |||
572 | ExcludeRe = createRegexesFromString(Options.Exclude); | |||
573 | ||||
574 | if (Options.EmitNotes) emitProfileNotes(); | |||
575 | if (Options.EmitData) return emitProfileArcs(); | |||
576 | return false; | |||
577 | } | |||
578 | ||||
579 | PreservedAnalyses GCOVProfilerPass::run(Module &M, | |||
580 | ModuleAnalysisManager &AM) { | |||
581 | ||||
582 | GCOVProfiler Profiler(GCOVOpts); | |||
583 | FunctionAnalysisManager &FAM = | |||
584 | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | |||
585 | ||||
586 | if (!Profiler.runOnModule(M, [&](Function &F) -> TargetLibraryInfo & { | |||
| ||||
587 | return FAM.getResult<TargetLibraryAnalysis>(F); | |||
588 | })) | |||
589 | return PreservedAnalyses::all(); | |||
590 | ||||
591 | return PreservedAnalyses::none(); | |||
592 | } | |||
593 | ||||
594 | static bool functionHasLines(Function &F) { | |||
595 | // Check whether this function actually has any source lines. Not only | |||
596 | // do these waste space, they also can crash gcov. | |||
597 | for (auto &BB : F) { | |||
598 | for (auto &I : BB) { | |||
599 | // Debug intrinsic locations correspond to the location of the | |||
600 | // declaration, not necessarily any statements or expressions. | |||
601 | if (isa<DbgInfoIntrinsic>(&I)) continue; | |||
602 | ||||
603 | const DebugLoc &Loc = I.getDebugLoc(); | |||
604 | if (!Loc) | |||
605 | continue; | |||
606 | ||||
607 | // Artificial lines such as calls to the global constructors. | |||
608 | if (Loc.getLine() == 0) continue; | |||
609 | ||||
610 | return true; | |||
611 | } | |||
612 | } | |||
613 | return false; | |||
614 | } | |||
615 | ||||
616 | static bool isUsingScopeBasedEH(Function &F) { | |||
617 | if (!F.hasPersonalityFn()) return false; | |||
618 | ||||
619 | EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn()); | |||
620 | return isScopedEHPersonality(Personality); | |||
621 | } | |||
622 | ||||
623 | static bool shouldKeepInEntry(BasicBlock::iterator It) { | |||
624 | if (isa<AllocaInst>(*It)) return true; | |||
625 | if (isa<DbgInfoIntrinsic>(*It)) return true; | |||
626 | if (auto *II = dyn_cast<IntrinsicInst>(It)) { | |||
627 | if (II->getIntrinsicID() == llvm::Intrinsic::localescape) return true; | |||
628 | } | |||
629 | ||||
630 | return false; | |||
631 | } | |||
632 | ||||
633 | void GCOVProfiler::AddFlushBeforeForkAndExec() { | |||
634 | SmallVector<Instruction *, 2> ForkAndExecs; | |||
635 | for (auto &F : M->functions()) { | |||
636 | auto *TLI = &GetTLI(F); | |||
637 | for (auto &I : instructions(F)) { | |||
638 | if (CallInst *CI = dyn_cast<CallInst>(&I)) { | |||
639 | if (Function *Callee = CI->getCalledFunction()) { | |||
640 | LibFunc LF; | |||
641 | if (TLI->getLibFunc(*Callee, LF) && | |||
642 | (LF == LibFunc_fork || LF == LibFunc_execl || | |||
643 | LF == LibFunc_execle || LF == LibFunc_execlp || | |||
644 | LF == LibFunc_execv || LF == LibFunc_execvp || | |||
645 | LF == LibFunc_execve || LF == LibFunc_execvpe || | |||
646 | LF == LibFunc_execvP)) { | |||
647 | ForkAndExecs.push_back(&I); | |||
648 | } | |||
649 | } | |||
650 | } | |||
651 | } | |||
652 | } | |||
653 | ||||
654 | // We need to split the block after the fork/exec call | |||
655 | // because else the counters for the lines after will be | |||
656 | // the same as before the call. | |||
657 | for (auto I : ForkAndExecs) { | |||
658 | IRBuilder<> Builder(I); | |||
659 | FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false); | |||
660 | FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy); | |||
661 | Builder.CreateCall(GCOVFlush); | |||
662 | I->getParent()->splitBasicBlock(I); | |||
663 | } | |||
664 | } | |||
665 | ||||
666 | void GCOVProfiler::emitProfileNotes() { | |||
667 | NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); | |||
668 | if (!CU_Nodes) return; | |||
669 | ||||
670 | for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { | |||
671 | // Each compile unit gets its own .gcno file. This means that whether we run | |||
672 | // this pass over the original .o's as they're produced, or run it after | |||
673 | // LTO, we'll generate the same .gcno files. | |||
674 | ||||
675 | auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); | |||
676 | ||||
677 | // Skip module skeleton (and module) CUs. | |||
678 | if (CU->getDWOId()) | |||
679 | continue; | |||
680 | ||||
681 | std::error_code EC; | |||
682 | raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, | |||
683 | sys::fs::OF_None); | |||
684 | if (EC) { | |||
685 | Ctx->emitError(Twine("failed to open coverage notes file for writing: ") + | |||
686 | EC.message()); | |||
687 | continue; | |||
688 | } | |||
689 | ||||
690 | std::string EdgeDestinations; | |||
691 | ||||
692 | unsigned FunctionIdent = 0; | |||
693 | for (auto &F : M->functions()) { | |||
694 | DISubprogram *SP = F.getSubprogram(); | |||
695 | if (!SP) continue; | |||
696 | if (!functionHasLines(F) || !isFunctionInstrumented(F)) | |||
697 | continue; | |||
698 | // TODO: Functions using scope-based EH are currently not supported. | |||
699 | if (isUsingScopeBasedEH(F)) continue; | |||
700 | ||||
701 | // gcov expects every function to start with an entry block that has a | |||
702 | // single successor, so split the entry block to make sure of that. | |||
703 | BasicBlock &EntryBlock = F.getEntryBlock(); | |||
704 | BasicBlock::iterator It = EntryBlock.begin(); | |||
705 | while (shouldKeepInEntry(It)) | |||
706 | ++It; | |||
707 | EntryBlock.splitBasicBlock(It); | |||
708 | ||||
709 | Funcs.push_back(std::make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++, | |||
710 | Options.UseCfgChecksum, | |||
711 | Options.ExitBlockBeforeBody)); | |||
712 | GCOVFunction &Func = *Funcs.back(); | |||
713 | ||||
714 | // Add the function line number to the lines of the entry block | |||
715 | // to have a counter for the function definition. | |||
716 | uint32_t Line = SP->getLine(); | |||
717 | auto Filename = getFilename(SP); | |||
718 | ||||
719 | // Artificial functions such as global initializers | |||
720 | if (!SP->isArtificial()) | |||
721 | Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); | |||
722 | ||||
723 | for (auto &BB : F) { | |||
724 | GCOVBlock &Block = Func.getBlock(&BB); | |||
725 | Instruction *TI = BB.getTerminator(); | |||
726 | if (int successors = TI->getNumSuccessors()) { | |||
727 | for (int i = 0; i != successors; ++i) { | |||
728 | Block.addEdge(Func.getBlock(TI->getSuccessor(i))); | |||
729 | } | |||
730 | } else if (isa<ReturnInst>(TI)) { | |||
731 | Block.addEdge(Func.getReturnBlock()); | |||
732 | } | |||
733 | ||||
734 | for (auto &I : BB) { | |||
735 | // Debug intrinsic locations correspond to the location of the | |||
736 | // declaration, not necessarily any statements or expressions. | |||
737 | if (isa<DbgInfoIntrinsic>(&I)) continue; | |||
738 | ||||
739 | const DebugLoc &Loc = I.getDebugLoc(); | |||
740 | if (!Loc) | |||
741 | continue; | |||
742 | ||||
743 | // Artificial lines such as calls to the global constructors. | |||
744 | if (Loc.getLine() == 0 || Loc.isImplicitCode()) | |||
745 | continue; | |||
746 | ||||
747 | if (Line == Loc.getLine()) continue; | |||
748 | Line = Loc.getLine(); | |||
749 | if (SP != getDISubprogram(Loc.getScope())) | |||
750 | continue; | |||
751 | ||||
752 | GCOVLines &Lines = Block.getFile(Filename); | |||
753 | Lines.addLine(Loc.getLine()); | |||
754 | } | |||
755 | Line = 0; | |||
756 | } | |||
757 | EdgeDestinations += Func.getEdgeDestinations(); | |||
758 | } | |||
759 | ||||
760 | FileChecksums.push_back(hash_value(EdgeDestinations)); | |||
761 | out.write("oncg", 4); | |||
762 | out.write(ReversedVersion, 4); | |||
763 | out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4); | |||
764 | ||||
765 | for (auto &Func : Funcs) { | |||
766 | Func->setCfgChecksum(FileChecksums.back()); | |||
767 | Func->writeOut(); | |||
768 | } | |||
769 | ||||
770 | out.write("\0\0\0\0\0\0\0\0", 8); // EOF | |||
771 | out.close(); | |||
772 | } | |||
773 | } | |||
774 | ||||
775 | bool GCOVProfiler::emitProfileArcs() { | |||
776 | NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); | |||
777 | if (!CU_Nodes) return false; | |||
778 | ||||
779 | bool Result = false; | |||
780 | for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { | |||
781 | SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP; | |||
782 | for (auto &F : M->functions()) { | |||
783 | DISubprogram *SP = F.getSubprogram(); | |||
784 | if (!SP) continue; | |||
785 | if (!functionHasLines(F) || !isFunctionInstrumented(F)) | |||
786 | continue; | |||
787 | // TODO: Functions using scope-based EH are currently not supported. | |||
788 | if (isUsingScopeBasedEH(F)) continue; | |||
789 | if (!Result) Result = true; | |||
790 | ||||
791 | DenseMap<std::pair<BasicBlock *, BasicBlock *>, unsigned> EdgeToCounter; | |||
792 | unsigned Edges = 0; | |||
793 | for (auto &BB : F) { | |||
794 | Instruction *TI = BB.getTerminator(); | |||
795 | if (isa<ReturnInst>(TI)) { | |||
796 | EdgeToCounter[{&BB, nullptr}] = Edges++; | |||
797 | } else { | |||
798 | for (BasicBlock *Succ : successors(TI)) { | |||
799 | EdgeToCounter[{&BB, Succ}] = Edges++; | |||
800 | } | |||
801 | } | |||
802 | } | |||
803 | ||||
804 | ArrayType *CounterTy = | |||
805 | ArrayType::get(Type::getInt64Ty(*Ctx), Edges); | |||
806 | GlobalVariable *Counters = | |||
807 | new GlobalVariable(*M, CounterTy, false, | |||
808 | GlobalValue::InternalLinkage, | |||
809 | Constant::getNullValue(CounterTy), | |||
810 | "__llvm_gcov_ctr"); | |||
811 | CountersBySP.push_back(std::make_pair(Counters, SP)); | |||
812 | ||||
813 | // If a BB has several predecessors, use a PHINode to select | |||
814 | // the correct counter. | |||
815 | for (auto &BB : F) { | |||
816 | const unsigned EdgeCount = | |||
817 | std::distance(pred_begin(&BB), pred_end(&BB)); | |||
818 | if (EdgeCount) { | |||
819 | // The phi node must be at the begin of the BB. | |||
820 | IRBuilder<> BuilderForPhi(&*BB.begin()); | |||
821 | Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); | |||
822 | PHINode *Phi = BuilderForPhi.CreatePHI(Int64PtrTy, EdgeCount); | |||
823 | for (BasicBlock *Pred : predecessors(&BB)) { | |||
824 | auto It = EdgeToCounter.find({Pred, &BB}); | |||
825 | assert(It != EdgeToCounter.end())((It != EdgeToCounter.end()) ? static_cast<void> (0) : __assert_fail ("It != EdgeToCounter.end()", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 825, __PRETTY_FUNCTION__)); | |||
826 | const unsigned Edge = It->second; | |||
827 | Value *EdgeCounter = BuilderForPhi.CreateConstInBoundsGEP2_64( | |||
828 | Counters->getValueType(), Counters, 0, Edge); | |||
829 | Phi->addIncoming(EdgeCounter, Pred); | |||
830 | } | |||
831 | ||||
832 | // Skip phis, landingpads. | |||
833 | IRBuilder<> Builder(&*BB.getFirstInsertionPt()); | |||
834 | Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Phi); | |||
835 | Count = Builder.CreateAdd(Count, Builder.getInt64(1)); | |||
836 | Builder.CreateStore(Count, Phi); | |||
837 | ||||
838 | Instruction *TI = BB.getTerminator(); | |||
839 | if (isa<ReturnInst>(TI)) { | |||
840 | auto It = EdgeToCounter.find({&BB, nullptr}); | |||
841 | assert(It != EdgeToCounter.end())((It != EdgeToCounter.end()) ? static_cast<void> (0) : __assert_fail ("It != EdgeToCounter.end()", "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 841, __PRETTY_FUNCTION__)); | |||
842 | const unsigned Edge = It->second; | |||
843 | Value *Counter = Builder.CreateConstInBoundsGEP2_64( | |||
844 | Counters->getValueType(), Counters, 0, Edge); | |||
845 | Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Counter); | |||
846 | Count = Builder.CreateAdd(Count, Builder.getInt64(1)); | |||
847 | Builder.CreateStore(Count, Counter); | |||
848 | } | |||
849 | } | |||
850 | } | |||
851 | } | |||
852 | ||||
853 | Function *WriteoutF = insertCounterWriteout(CountersBySP); | |||
854 | Function *FlushF = insertFlush(CountersBySP); | |||
855 | ||||
856 | // Create a small bit of code that registers the "__llvm_gcov_writeout" to | |||
857 | // be executed at exit and the "__llvm_gcov_flush" function to be executed | |||
858 | // when "__gcov_flush" is called. | |||
859 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
860 | Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, | |||
861 | "__llvm_gcov_init", M); | |||
862 | F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | |||
863 | F->setLinkage(GlobalValue::InternalLinkage); | |||
864 | F->addFnAttr(Attribute::NoInline); | |||
865 | if (Options.NoRedZone) | |||
866 | F->addFnAttr(Attribute::NoRedZone); | |||
867 | ||||
868 | BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); | |||
869 | IRBuilder<> Builder(BB); | |||
870 | ||||
871 | FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
872 | Type *Params[] = { | |||
873 | PointerType::get(FTy, 0), | |||
874 | PointerType::get(FTy, 0) | |||
875 | }; | |||
876 | FTy = FunctionType::get(Builder.getVoidTy(), Params, false); | |||
877 | ||||
878 | // Initialize the environment and register the local writeout and flush | |||
879 | // functions. | |||
880 | FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); | |||
881 | Builder.CreateCall(GCOVInit, {WriteoutF, FlushF}); | |||
882 | Builder.CreateRetVoid(); | |||
883 | ||||
884 | appendToGlobalCtors(*M, F, 0); | |||
885 | } | |||
886 | ||||
887 | return Result; | |||
888 | } | |||
889 | ||||
890 | FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { | |||
891 | Type *Args[] = { | |||
892 | Type::getInt8PtrTy(*Ctx), // const char *orig_filename | |||
893 | Type::getInt8PtrTy(*Ctx), // const char version[4] | |||
894 | Type::getInt32Ty(*Ctx), // uint32_t checksum | |||
895 | }; | |||
896 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); | |||
897 | AttributeList AL; | |||
898 | if (auto AK = TLI->getExtAttrForI32Param(false)) | |||
899 | AL = AL.addParamAttribute(*Ctx, 2, AK); | |||
900 | FunctionCallee Res = M->getOrInsertFunction("llvm_gcda_start_file", FTy, AL); | |||
901 | return Res; | |||
902 | } | |||
903 | ||||
904 | FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) { | |||
905 | Type *Args[] = { | |||
906 | Type::getInt32Ty(*Ctx), // uint32_t ident | |||
907 | Type::getInt8PtrTy(*Ctx), // const char *function_name | |||
908 | Type::getInt32Ty(*Ctx), // uint32_t func_checksum | |||
909 | Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum | |||
910 | Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum | |||
911 | }; | |||
912 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); | |||
913 | AttributeList AL; | |||
914 | if (auto AK = TLI->getExtAttrForI32Param(false)) { | |||
915 | AL = AL.addParamAttribute(*Ctx, 0, AK); | |||
916 | AL = AL.addParamAttribute(*Ctx, 2, AK); | |||
917 | AL = AL.addParamAttribute(*Ctx, 3, AK); | |||
918 | AL = AL.addParamAttribute(*Ctx, 4, AK); | |||
919 | } | |||
920 | return M->getOrInsertFunction("llvm_gcda_emit_function", FTy); | |||
921 | } | |||
922 | ||||
923 | FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) { | |||
924 | Type *Args[] = { | |||
925 | Type::getInt32Ty(*Ctx), // uint32_t num_counters | |||
926 | Type::getInt64PtrTy(*Ctx), // uint64_t *counters | |||
927 | }; | |||
928 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false); | |||
929 | AttributeList AL; | |||
930 | if (auto AK = TLI->getExtAttrForI32Param(false)) | |||
931 | AL = AL.addParamAttribute(*Ctx, 0, AK); | |||
932 | return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy, AL); | |||
933 | } | |||
934 | ||||
935 | FunctionCallee GCOVProfiler::getSummaryInfoFunc() { | |||
936 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
937 | return M->getOrInsertFunction("llvm_gcda_summary_info", FTy); | |||
938 | } | |||
939 | ||||
940 | FunctionCallee GCOVProfiler::getEndFileFunc() { | |||
941 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
942 | return M->getOrInsertFunction("llvm_gcda_end_file", FTy); | |||
943 | } | |||
944 | ||||
945 | Function *GCOVProfiler::insertCounterWriteout( | |||
946 | ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { | |||
947 | FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
948 | Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); | |||
949 | if (!WriteoutF) | |||
950 | WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, | |||
951 | "__llvm_gcov_writeout", M); | |||
952 | WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | |||
953 | WriteoutF->addFnAttr(Attribute::NoInline); | |||
954 | if (Options.NoRedZone) | |||
955 | WriteoutF->addFnAttr(Attribute::NoRedZone); | |||
956 | ||||
957 | BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); | |||
958 | IRBuilder<> Builder(BB); | |||
959 | ||||
960 | auto *TLI = &GetTLI(*WriteoutF); | |||
961 | ||||
962 | FunctionCallee StartFile = getStartFileFunc(TLI); | |||
963 | FunctionCallee EmitFunction = getEmitFunctionFunc(TLI); | |||
964 | FunctionCallee EmitArcs = getEmitArcsFunc(TLI); | |||
965 | FunctionCallee SummaryInfo = getSummaryInfoFunc(); | |||
966 | FunctionCallee EndFile = getEndFileFunc(); | |||
967 | ||||
968 | NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); | |||
969 | if (!CUNodes) { | |||
970 | Builder.CreateRetVoid(); | |||
971 | return WriteoutF; | |||
972 | } | |||
973 | ||||
974 | // Collect the relevant data into a large constant data structure that we can | |||
975 | // walk to write out everything. | |||
976 | StructType *StartFileCallArgsTy = StructType::create( | |||
977 | {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()}); | |||
978 | StructType *EmitFunctionCallArgsTy = StructType::create( | |||
979 | {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(), | |||
980 | Builder.getInt8Ty(), Builder.getInt32Ty()}); | |||
981 | StructType *EmitArcsCallArgsTy = StructType::create( | |||
982 | {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); | |||
983 | StructType *FileInfoTy = | |||
984 | StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), | |||
985 | EmitFunctionCallArgsTy->getPointerTo(), | |||
986 | EmitArcsCallArgsTy->getPointerTo()}); | |||
987 | ||||
988 | Constant *Zero32 = Builder.getInt32(0); | |||
989 | // Build an explicit array of two zeros for use in ConstantExpr GEP building. | |||
990 | Constant *TwoZero32s[] = {Zero32, Zero32}; | |||
991 | ||||
992 | SmallVector<Constant *, 8> FileInfos; | |||
993 | for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) { | |||
994 | auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i)); | |||
995 | ||||
996 | // Skip module skeleton (and module) CUs. | |||
997 | if (CU->getDWOId()) | |||
998 | continue; | |||
999 | ||||
1000 | std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); | |||
1001 | uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; | |||
1002 | auto *StartFileCallArgs = ConstantStruct::get( | |||
1003 | StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda), | |||
1004 | Builder.CreateGlobalStringPtr(ReversedVersion), | |||
1005 | Builder.getInt32(CfgChecksum)}); | |||
1006 | ||||
1007 | SmallVector<Constant *, 8> EmitFunctionCallArgsArray; | |||
1008 | SmallVector<Constant *, 8> EmitArcsCallArgsArray; | |||
1009 | for (int j : llvm::seq<int>(0, CountersBySP.size())) { | |||
1010 | auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second); | |||
1011 | uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); | |||
1012 | EmitFunctionCallArgsArray.push_back(ConstantStruct::get( | |||
1013 | EmitFunctionCallArgsTy, | |||
1014 | {Builder.getInt32(j), | |||
1015 | Options.FunctionNamesInData | |||
1016 | ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) | |||
1017 | : Constant::getNullValue(Builder.getInt8PtrTy()), | |||
1018 | Builder.getInt32(FuncChecksum), | |||
1019 | Builder.getInt8(Options.UseCfgChecksum), | |||
1020 | Builder.getInt32(CfgChecksum)})); | |||
1021 | ||||
1022 | GlobalVariable *GV = CountersBySP[j].first; | |||
1023 | unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); | |||
1024 | EmitArcsCallArgsArray.push_back(ConstantStruct::get( | |||
1025 | EmitArcsCallArgsTy, | |||
1026 | {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( | |||
1027 | GV->getValueType(), GV, TwoZero32s)})); | |||
1028 | } | |||
1029 | // Create global arrays for the two emit calls. | |||
1030 | int CountersSize = CountersBySP.size(); | |||
1031 | assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&((CountersSize == (int)EmitFunctionCallArgsArray.size() && "Mismatched array size!") ? static_cast<void> (0) : __assert_fail ("CountersSize == (int)EmitFunctionCallArgsArray.size() && \"Mismatched array size!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 1032, __PRETTY_FUNCTION__)) | |||
1032 | "Mismatched array size!")((CountersSize == (int)EmitFunctionCallArgsArray.size() && "Mismatched array size!") ? static_cast<void> (0) : __assert_fail ("CountersSize == (int)EmitFunctionCallArgsArray.size() && \"Mismatched array size!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 1032, __PRETTY_FUNCTION__)); | |||
1033 | assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&((CountersSize == (int)EmitArcsCallArgsArray.size() && "Mismatched array size!") ? static_cast<void> (0) : __assert_fail ("CountersSize == (int)EmitArcsCallArgsArray.size() && \"Mismatched array size!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 1034, __PRETTY_FUNCTION__)) | |||
1034 | "Mismatched array size!")((CountersSize == (int)EmitArcsCallArgsArray.size() && "Mismatched array size!") ? static_cast<void> (0) : __assert_fail ("CountersSize == (int)EmitArcsCallArgsArray.size() && \"Mismatched array size!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 1034, __PRETTY_FUNCTION__)); | |||
1035 | auto *EmitFunctionCallArgsArrayTy = | |||
1036 | ArrayType::get(EmitFunctionCallArgsTy, CountersSize); | |||
1037 | auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( | |||
1038 | *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, | |||
1039 | GlobalValue::InternalLinkage, | |||
1040 | ConstantArray::get(EmitFunctionCallArgsArrayTy, | |||
1041 | EmitFunctionCallArgsArray), | |||
1042 | Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); | |||
1043 | auto *EmitArcsCallArgsArrayTy = | |||
1044 | ArrayType::get(EmitArcsCallArgsTy, CountersSize); | |||
1045 | EmitFunctionCallArgsArrayGV->setUnnamedAddr( | |||
1046 | GlobalValue::UnnamedAddr::Global); | |||
1047 | auto *EmitArcsCallArgsArrayGV = new GlobalVariable( | |||
1048 | *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, | |||
1049 | GlobalValue::InternalLinkage, | |||
1050 | ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), | |||
1051 | Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); | |||
1052 | EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | |||
1053 | ||||
1054 | FileInfos.push_back(ConstantStruct::get( | |||
1055 | FileInfoTy, | |||
1056 | {StartFileCallArgs, Builder.getInt32(CountersSize), | |||
1057 | ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, | |||
1058 | EmitFunctionCallArgsArrayGV, | |||
1059 | TwoZero32s), | |||
1060 | ConstantExpr::getInBoundsGetElementPtr( | |||
1061 | EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); | |||
1062 | } | |||
1063 | ||||
1064 | // If we didn't find anything to actually emit, bail on out. | |||
1065 | if (FileInfos.empty()) { | |||
1066 | Builder.CreateRetVoid(); | |||
1067 | return WriteoutF; | |||
1068 | } | |||
1069 | ||||
1070 | // To simplify code, we cap the number of file infos we write out to fit | |||
1071 | // easily in a 32-bit signed integer. This gives consistent behavior between | |||
1072 | // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit | |||
1073 | // operations on 32-bit systems. It also seems unreasonable to try to handle | |||
1074 | // more than 2 billion files. | |||
1075 | if ((int64_t)FileInfos.size() > (int64_t)INT_MAX2147483647) | |||
1076 | FileInfos.resize(INT_MAX2147483647); | |||
1077 | ||||
1078 | // Create a global for the entire data structure so we can walk it more | |||
1079 | // easily. | |||
1080 | auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); | |||
1081 | auto *FileInfoArrayGV = new GlobalVariable( | |||
1082 | *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, | |||
1083 | ConstantArray::get(FileInfoArrayTy, FileInfos), | |||
1084 | "__llvm_internal_gcov_emit_file_info"); | |||
1085 | FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | |||
1086 | ||||
1087 | // Create the CFG for walking this data structure. | |||
1088 | auto *FileLoopHeader = | |||
1089 | BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); | |||
1090 | auto *CounterLoopHeader = | |||
1091 | BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); | |||
1092 | auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); | |||
1093 | auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); | |||
1094 | ||||
1095 | // We always have at least one file, so just branch to the header. | |||
1096 | Builder.CreateBr(FileLoopHeader); | |||
1097 | ||||
1098 | // The index into the files structure is our loop induction variable. | |||
1099 | Builder.SetInsertPoint(FileLoopHeader); | |||
1100 | PHINode *IV = | |||
1101 | Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); | |||
1102 | IV->addIncoming(Builder.getInt32(0), BB); | |||
1103 | auto *FileInfoPtr = Builder.CreateInBoundsGEP( | |||
1104 | FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); | |||
1105 | auto *StartFileCallArgsPtr = | |||
1106 | Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0); | |||
1107 | auto *StartFileCall = Builder.CreateCall( | |||
1108 | StartFile, | |||
1109 | {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), | |||
1110 | Builder.CreateStructGEP(StartFileCallArgsTy, | |||
1111 | StartFileCallArgsPtr, 0)), | |||
1112 | Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), | |||
1113 | Builder.CreateStructGEP(StartFileCallArgsTy, | |||
1114 | StartFileCallArgsPtr, 1)), | |||
1115 | Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), | |||
1116 | Builder.CreateStructGEP(StartFileCallArgsTy, | |||
1117 | StartFileCallArgsPtr, 2))}); | |||
1118 | if (auto AK = TLI->getExtAttrForI32Param(false)) | |||
1119 | StartFileCall->addParamAttr(2, AK); | |||
1120 | auto *NumCounters = | |||
1121 | Builder.CreateLoad(FileInfoTy->getElementType(1), | |||
1122 | Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1)); | |||
1123 | auto *EmitFunctionCallArgsArray = | |||
1124 | Builder.CreateLoad(FileInfoTy->getElementType(2), | |||
1125 | Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2)); | |||
1126 | auto *EmitArcsCallArgsArray = | |||
1127 | Builder.CreateLoad(FileInfoTy->getElementType(3), | |||
1128 | Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3)); | |||
1129 | auto *EnterCounterLoopCond = | |||
1130 | Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); | |||
1131 | Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); | |||
1132 | ||||
1133 | Builder.SetInsertPoint(CounterLoopHeader); | |||
1134 | auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); | |||
1135 | JV->addIncoming(Builder.getInt32(0), FileLoopHeader); | |||
1136 | auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( | |||
1137 | EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); | |||
1138 | auto *EmitFunctionCall = Builder.CreateCall( | |||
1139 | EmitFunction, | |||
1140 | {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), | |||
1141 | Builder.CreateStructGEP(EmitFunctionCallArgsTy, | |||
1142 | EmitFunctionCallArgsPtr, 0)), | |||
1143 | Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), | |||
1144 | Builder.CreateStructGEP(EmitFunctionCallArgsTy, | |||
1145 | EmitFunctionCallArgsPtr, 1)), | |||
1146 | Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), | |||
1147 | Builder.CreateStructGEP(EmitFunctionCallArgsTy, | |||
1148 | EmitFunctionCallArgsPtr, 2)), | |||
1149 | Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(3), | |||
1150 | Builder.CreateStructGEP(EmitFunctionCallArgsTy, | |||
1151 | EmitFunctionCallArgsPtr, 3)), | |||
1152 | Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(4), | |||
1153 | Builder.CreateStructGEP(EmitFunctionCallArgsTy, | |||
1154 | EmitFunctionCallArgsPtr, | |||
1155 | 4))}); | |||
1156 | if (auto AK = TLI->getExtAttrForI32Param(false)) { | |||
1157 | EmitFunctionCall->addParamAttr(0, AK); | |||
1158 | EmitFunctionCall->addParamAttr(2, AK); | |||
1159 | EmitFunctionCall->addParamAttr(3, AK); | |||
1160 | EmitFunctionCall->addParamAttr(4, AK); | |||
1161 | } | |||
1162 | auto *EmitArcsCallArgsPtr = | |||
1163 | Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV); | |||
1164 | auto *EmitArcsCall = Builder.CreateCall( | |||
1165 | EmitArcs, | |||
1166 | {Builder.CreateLoad( | |||
1167 | EmitArcsCallArgsTy->getElementType(0), | |||
1168 | Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0)), | |||
1169 | Builder.CreateLoad(EmitArcsCallArgsTy->getElementType(1), | |||
1170 | Builder.CreateStructGEP(EmitArcsCallArgsTy, | |||
1171 | EmitArcsCallArgsPtr, 1))}); | |||
1172 | if (auto AK = TLI->getExtAttrForI32Param(false)) | |||
1173 | EmitArcsCall->addParamAttr(0, AK); | |||
1174 | auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); | |||
1175 | auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); | |||
1176 | Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); | |||
1177 | JV->addIncoming(NextJV, CounterLoopHeader); | |||
1178 | ||||
1179 | Builder.SetInsertPoint(FileLoopLatch); | |||
1180 | Builder.CreateCall(SummaryInfo, {}); | |||
1181 | Builder.CreateCall(EndFile, {}); | |||
1182 | auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); | |||
1183 | auto *FileLoopCond = | |||
1184 | Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); | |||
1185 | Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); | |||
1186 | IV->addIncoming(NextIV, FileLoopLatch); | |||
1187 | ||||
1188 | Builder.SetInsertPoint(ExitBB); | |||
1189 | Builder.CreateRetVoid(); | |||
1190 | ||||
1191 | return WriteoutF; | |||
1192 | } | |||
1193 | ||||
1194 | Function *GCOVProfiler:: | |||
1195 | insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) { | |||
1196 | FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); | |||
1197 | Function *FlushF = M->getFunction("__llvm_gcov_flush"); | |||
1198 | if (!FlushF) | |||
1199 | FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, | |||
1200 | "__llvm_gcov_flush", M); | |||
1201 | else | |||
1202 | FlushF->setLinkage(GlobalValue::InternalLinkage); | |||
1203 | FlushF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); | |||
1204 | FlushF->addFnAttr(Attribute::NoInline); | |||
1205 | if (Options.NoRedZone) | |||
1206 | FlushF->addFnAttr(Attribute::NoRedZone); | |||
1207 | ||||
1208 | BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); | |||
1209 | ||||
1210 | // Write out the current counters. | |||
1211 | Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); | |||
1212 | assert(WriteoutF && "Need to create the writeout function first!")((WriteoutF && "Need to create the writeout function first!" ) ? static_cast<void> (0) : __assert_fail ("WriteoutF && \"Need to create the writeout function first!\"" , "/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp" , 1212, __PRETTY_FUNCTION__)); | |||
1213 | ||||
1214 | IRBuilder<> Builder(Entry); | |||
1215 | Builder.CreateCall(WriteoutF, {}); | |||
1216 | ||||
1217 | // Zero out the counters. | |||
1218 | for (const auto &I : CountersBySP) { | |||
1219 | GlobalVariable *GV = I.first; | |||
1220 | Constant *Null = Constant::getNullValue(GV->getValueType()); | |||
1221 | Builder.CreateStore(Null, GV); | |||
1222 | } | |||
1223 | ||||
1224 | Type *RetTy = FlushF->getReturnType(); | |||
1225 | if (RetTy == Type::getVoidTy(*Ctx)) | |||
1226 | Builder.CreateRetVoid(); | |||
1227 | else if (RetTy->isIntegerTy()) | |||
1228 | // Used if __llvm_gcov_flush was implicitly declared. | |||
1229 | Builder.CreateRet(ConstantInt::get(RetTy, 0)); | |||
1230 | else | |||
1231 | report_fatal_error("invalid return type for __llvm_gcov_flush"); | |||
1232 | ||||
1233 | return FlushF; | |||
1234 | } |