2011-04-16 09:20:23 +08:00
|
|
|
//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-04-16 09:20:23 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass implements GCOV-style profiling. When this pass is run it emits
|
|
|
|
// "gcno" files next to the existing source, and instruments the code that runs
|
|
|
|
// to records the edges between blocks that run and emit a complementary "gcda"
|
|
|
|
// file on exit.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2013-11-20 12:15:05 +08:00
|
|
|
#include "llvm/ADT/Hashing.h"
|
2011-04-16 09:20:23 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2018-05-03 06:24:39 +08:00
|
|
|
#include "llvm/ADT/Sequence.h"
|
2012-06-29 20:38:19 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2011-04-16 09:20:23 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
2017-10-13 21:49:15 +08:00
|
|
|
#include "llvm/Analysis/EHPersonalities.h"
|
2018-07-11 00:05:47 +08:00
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
2018-09-12 02:38:34 +08:00
|
|
|
#include "llvm/IR/CFG.h"
|
2014-03-06 08:46:21 +08:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2014-03-05 18:30:38 +08:00
|
|
|
#include "llvm/IR/DebugLoc.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2014-03-04 18:30:26 +08:00
|
|
|
#include "llvm/IR/InstIterator.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2014-01-31 13:24:01 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/InitializePasses.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/Pass.h"
|
2013-03-14 13:13:26 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2012-06-29 20:38:19 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2013-03-27 06:47:50 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2013-06-12 06:21:28 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2018-11-12 17:01:43 +08:00
|
|
|
#include "llvm/Support/Regex.h"
|
2012-06-29 20:38:19 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-06-05 13:12:23 +08:00
|
|
|
#include "llvm/Transforms/Instrumentation.h"
|
2018-05-03 06:24:39 +08:00
|
|
|
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
|
2012-06-29 20:38:19 +08:00
|
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
2013-06-18 14:38:21 +08:00
|
|
|
#include <algorithm>
|
2014-04-22 04:41:55 +08:00
|
|
|
#include <memory>
|
2011-04-16 09:20:23 +08:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-22 10:55:47 +08:00
|
|
|
#define DEBUG_TYPE "insert-gcov-profiling"
|
|
|
|
|
2013-03-14 13:13:26 +08:00
|
|
|
static cl::opt<std::string>
|
|
|
|
DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden,
|
|
|
|
cl::ValueRequired);
|
2015-03-17 07:52:03 +08:00
|
|
|
static cl::opt<bool> DefaultExitBlockBeforeBody("gcov-exit-block-before-body",
|
|
|
|
cl::init(false), cl::Hidden);
|
2013-03-14 13:13:26 +08:00
|
|
|
|
|
|
|
GCOVOptions GCOVOptions::getDefault() {
|
|
|
|
GCOVOptions Options;
|
|
|
|
Options.EmitNotes = true;
|
|
|
|
Options.EmitData = true;
|
|
|
|
Options.UseCfgChecksum = false;
|
|
|
|
Options.NoRedZone = false;
|
|
|
|
Options.FunctionNamesInData = true;
|
2015-03-17 07:52:03 +08:00
|
|
|
Options.ExitBlockBeforeBody = DefaultExitBlockBeforeBody;
|
2013-03-14 13:13:26 +08:00
|
|
|
|
|
|
|
if (DefaultGCOVVersion.size() != 4) {
|
|
|
|
llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") +
|
|
|
|
DefaultGCOVVersion);
|
|
|
|
}
|
|
|
|
memcpy(Options.Version, DefaultGCOVVersion.c_str(), 4);
|
|
|
|
return Options;
|
|
|
|
}
|
|
|
|
|
2011-04-16 09:20:23 +08:00
|
|
|
namespace {
|
2016-06-05 11:40:03 +08:00
|
|
|
class GCOVFunction;
|
|
|
|
|
|
|
|
class GCOVProfiler {
|
|
|
|
public:
|
|
|
|
GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {}
|
|
|
|
GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {
|
|
|
|
assert((Options.EmitNotes || Options.EmitData) &&
|
|
|
|
"GCOVProfiler asked to do nothing?");
|
|
|
|
ReversedVersion[0] = Options.Version[3];
|
|
|
|
ReversedVersion[1] = Options.Version[2];
|
|
|
|
ReversedVersion[2] = Options.Version[1];
|
|
|
|
ReversedVersion[3] = Options.Version[0];
|
|
|
|
ReversedVersion[4] = '\0';
|
|
|
|
}
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
bool
|
|
|
|
runOnModule(Module &M,
|
|
|
|
std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
|
2016-06-05 11:40:03 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
// Create the .gcno files for the Module based on DebugInfo.
|
|
|
|
void emitProfileNotes();
|
|
|
|
|
|
|
|
// Modify the program to track transitions along edges and call into the
|
|
|
|
// profiling runtime to emit .gcda files when run.
|
|
|
|
bool emitProfileArcs();
|
|
|
|
|
2018-11-12 17:01:43 +08:00
|
|
|
bool isFunctionInstrumented(const Function &F);
|
|
|
|
std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
|
|
|
|
static bool doesFilenameMatchARegex(StringRef Filename,
|
|
|
|
std::vector<Regex> &Regexes);
|
|
|
|
|
2016-06-05 11:40:03 +08:00
|
|
|
// Get pointers to the functions in the runtime library.
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI);
|
|
|
|
FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI);
|
|
|
|
FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee getSummaryInfoFunc();
|
|
|
|
FunctionCallee getEndFileFunc();
|
2016-06-05 11:40:03 +08:00
|
|
|
|
|
|
|
// Add the function to write out all our counters to the global destructor
|
|
|
|
// list.
|
|
|
|
Function *
|
|
|
|
insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
|
|
|
|
Function *insertFlush(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
|
|
|
|
|
2018-11-07 21:49:17 +08:00
|
|
|
void AddFlushBeforeForkAndExec();
|
|
|
|
|
2016-09-01 07:04:32 +08:00
|
|
|
enum class GCovFileType { GCNO, GCDA };
|
|
|
|
std::string mangleName(const DICompileUnit *CU, GCovFileType FileType);
|
2016-06-05 11:40:03 +08:00
|
|
|
|
|
|
|
GCOVOptions Options;
|
|
|
|
|
|
|
|
// Reversed, NUL-terminated copy of Options.Version.
|
|
|
|
char ReversedVersion[5];
|
|
|
|
// Checksum, produced by hash of EdgeDestinations
|
|
|
|
SmallVector<uint32_t, 4> FileChecksums;
|
|
|
|
|
2019-11-14 21:55:28 +08:00
|
|
|
Module *M = nullptr;
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
|
2019-11-14 21:55:28 +08:00
|
|
|
LLVMContext *Ctx = nullptr;
|
2016-06-05 11:40:03 +08:00
|
|
|
SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;
|
2018-11-12 17:01:43 +08:00
|
|
|
std::vector<Regex> FilterRe;
|
|
|
|
std::vector<Regex> ExcludeRe;
|
|
|
|
StringMap<bool> InstrumentedFiles;
|
2016-06-05 11:40:03 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class GCOVProfilerLegacyPass : public ModulePass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
GCOVProfilerLegacyPass()
|
|
|
|
: GCOVProfilerLegacyPass(GCOVOptions::getDefault()) {}
|
|
|
|
GCOVProfilerLegacyPass(const GCOVOptions &Opts)
|
|
|
|
: ModulePass(ID), Profiler(Opts) {
|
|
|
|
initializeGCOVProfilerLegacyPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef getPassName() const override { return "GCOV Profiler"; }
|
2016-06-05 11:40:03 +08:00
|
|
|
|
2018-07-31 03:41:25 +08:00
|
|
|
bool runOnModule(Module &M) override {
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
return Profiler.runOnModule(M, [this](Function &F) -> TargetLibraryInfo & {
|
|
|
|
return getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
|
|
|
});
|
2018-07-11 00:05:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
|
|
}
|
2015-03-07 00:21:15 +08:00
|
|
|
|
2016-06-05 11:40:03 +08:00
|
|
|
private:
|
|
|
|
GCOVProfiler Profiler;
|
|
|
|
};
|
2015-06-23 17:49:53 +08:00
|
|
|
}
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2016-06-05 11:40:03 +08:00
|
|
|
char GCOVProfilerLegacyPass::ID = 0;
|
2018-07-11 00:05:47 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(
|
|
|
|
GCOVProfilerLegacyPass, "insert-gcov-profiling",
|
|
|
|
"Insert instrumentation for GCOV profiling", false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
|
|
|
INITIALIZE_PASS_END(
|
|
|
|
GCOVProfilerLegacyPass, "insert-gcov-profiling",
|
|
|
|
"Insert instrumentation for GCOV profiling", false, false)
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2013-03-14 13:13:26 +08:00
|
|
|
ModulePass *llvm::createGCOVProfilerPass(const GCOVOptions &Options) {
|
2016-06-05 11:40:03 +08:00
|
|
|
return new GCOVProfilerLegacyPass(Options);
|
2011-04-21 09:56:25 +08:00
|
|
|
}
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2015-04-30 00:38:44 +08:00
|
|
|
static StringRef getFunctionName(const DISubprogram *SP) {
|
2015-04-14 11:40:37 +08:00
|
|
|
if (!SP->getLinkageName().empty())
|
|
|
|
return SP->getLinkageName();
|
|
|
|
return SP->getName();
|
2013-03-19 09:37:55 +08:00
|
|
|
}
|
|
|
|
|
2018-12-07 02:44:48 +08:00
|
|
|
/// Extract a filename for a DISubprogram.
|
|
|
|
///
|
|
|
|
/// Prefer relative paths in the coverage notes. Clang also may split
|
|
|
|
/// up absolute paths into a directory and filename component. When
|
|
|
|
/// the relative path doesn't exist, reconstruct the absolute path.
|
2019-01-13 02:36:22 +08:00
|
|
|
static SmallString<128> getFilename(const DISubprogram *SP) {
|
2018-12-07 02:44:48 +08:00
|
|
|
SmallString<128> Path;
|
|
|
|
StringRef RelPath = SP->getFilename();
|
|
|
|
if (sys::fs::exists(RelPath))
|
|
|
|
Path = RelPath;
|
|
|
|
else
|
|
|
|
sys::path::append(Path, SP->getDirectory(), SP->getFilename());
|
|
|
|
return Path;
|
|
|
|
}
|
|
|
|
|
2011-04-16 09:20:23 +08:00
|
|
|
namespace {
|
|
|
|
class GCOVRecord {
|
|
|
|
protected:
|
2013-07-17 11:43:10 +08:00
|
|
|
static const char *const LinesTag;
|
|
|
|
static const char *const FunctionTag;
|
|
|
|
static const char *const BlockTag;
|
|
|
|
static const char *const EdgeTag;
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2015-04-12 02:57:14 +08:00
|
|
|
GCOVRecord() = default;
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void writeBytes(const char *Bytes, int Size) {
|
|
|
|
os->write(Bytes, Size);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void write(uint32_t i) {
|
|
|
|
writeBytes(reinterpret_cast<char*>(&i), 4);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the length measured in 4-byte blocks that will be used to
|
|
|
|
// represent this string in a GCOV file
|
2013-07-17 11:54:53 +08:00
|
|
|
static unsigned lengthOfGCOVString(StringRef s) {
|
2011-04-16 09:20:23 +08:00
|
|
|
// A GCOV string is a length, followed by a NUL, then between 0 and 3 NULs
|
2011-04-21 10:48:39 +08:00
|
|
|
// padding out to the next 4-byte word. The length is measured in 4-byte
|
|
|
|
// words including padding, not bytes of actual string.
|
2011-05-06 07:52:18 +08:00
|
|
|
return (s.size() / 4) + 1;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void writeGCOVString(StringRef s) {
|
|
|
|
uint32_t Len = lengthOfGCOVString(s);
|
|
|
|
write(Len);
|
|
|
|
writeBytes(s.data(), s.size());
|
2011-04-16 09:20:23 +08:00
|
|
|
|
|
|
|
// Write 1 to 4 bytes of NUL padding.
|
2011-04-29 05:35:49 +08:00
|
|
|
assert((unsigned)(4 - (s.size() % 4)) > 0);
|
|
|
|
assert((unsigned)(4 - (s.size() % 4)) <= 4);
|
|
|
|
writeBytes("\0\0\0\0", 4 - (s.size() % 4));
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream *os;
|
|
|
|
};
|
2013-07-17 11:43:10 +08:00
|
|
|
const char *const GCOVRecord::LinesTag = "\0\0\x45\x01";
|
|
|
|
const char *const GCOVRecord::FunctionTag = "\0\0\0\1";
|
|
|
|
const char *const GCOVRecord::BlockTag = "\0\0\x41\x01";
|
|
|
|
const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01";
|
2011-04-16 09:20:23 +08:00
|
|
|
|
|
|
|
class GCOVFunction;
|
|
|
|
class GCOVBlock;
|
|
|
|
|
|
|
|
// Constructed only by requesting it from a GCOVBlock, this object stores a
|
2011-09-21 02:35:00 +08:00
|
|
|
// list of line numbers and a single filename, representing lines that belong
|
|
|
|
// to the block.
|
2011-04-16 09:20:23 +08:00
|
|
|
class GCOVLines : public GCOVRecord {
|
|
|
|
public:
|
2011-04-26 11:54:16 +08:00
|
|
|
void addLine(uint32_t Line) {
|
2014-06-03 12:25:36 +08:00
|
|
|
assert(Line != 0 && "Line zero is not a valid real line number.");
|
2011-04-26 11:54:16 +08:00
|
|
|
Lines.push_back(Line);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2013-07-17 11:54:53 +08:00
|
|
|
uint32_t length() const {
|
2011-11-28 07:22:20 +08:00
|
|
|
// Here 2 = 1 for string length + 1 for '0' id#.
|
2011-09-21 02:35:00 +08:00
|
|
|
return lengthOfGCOVString(Filename) + 2 + Lines.size();
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-09-21 02:35:00 +08:00
|
|
|
void writeOut() {
|
|
|
|
write(0);
|
|
|
|
writeGCOVString(Filename);
|
|
|
|
for (int i = 0, e = Lines.size(); i != e; ++i)
|
|
|
|
write(Lines[i]);
|
|
|
|
}
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2014-03-11 10:44:45 +08:00
|
|
|
GCOVLines(StringRef F, raw_ostream *os)
|
2011-09-21 02:35:00 +08:00
|
|
|
: Filename(F) {
|
2011-04-16 09:20:23 +08:00
|
|
|
this->os = os;
|
|
|
|
}
|
|
|
|
|
2011-09-21 02:48:56 +08:00
|
|
|
private:
|
2018-12-07 02:44:48 +08:00
|
|
|
std::string Filename;
|
2011-04-26 11:54:16 +08:00
|
|
|
SmallVector<uint32_t, 32> Lines;
|
2011-04-16 09:20:23 +08:00
|
|
|
};
|
|
|
|
|
2013-06-18 14:38:21 +08:00
|
|
|
|
2011-04-16 09:20:23 +08:00
|
|
|
// Represent a basic block in GCOV. Each block has a unique number in the
|
|
|
|
// function, number of lines belonging to each block, and a set of edges to
|
|
|
|
// other blocks.
|
|
|
|
class GCOVBlock : public GCOVRecord {
|
|
|
|
public:
|
2011-09-21 01:55:19 +08:00
|
|
|
GCOVLines &getFile(StringRef Filename) {
|
2016-07-21 21:37:48 +08:00
|
|
|
return LinesByFile.try_emplace(Filename, Filename, os).first->second;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void addEdge(GCOVBlock &Successor) {
|
|
|
|
OutEdges.push_back(&Successor);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void writeOut() {
|
|
|
|
uint32_t Len = 3;
|
2016-07-21 20:06:31 +08:00
|
|
|
SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile;
|
2016-06-26 20:28:59 +08:00
|
|
|
for (auto &I : LinesByFile) {
|
2016-07-21 20:06:31 +08:00
|
|
|
Len += I.second.length();
|
2016-06-26 20:28:59 +08:00
|
|
|
SortedLinesByFile.push_back(&I);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
writeBytes(LinesTag, 4);
|
|
|
|
write(Len);
|
|
|
|
write(Number);
|
2013-06-18 14:38:21 +08:00
|
|
|
|
2018-10-01 06:31:29 +08:00
|
|
|
llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS,
|
|
|
|
StringMapEntry<GCOVLines> *RHS) {
|
|
|
|
return LHS->getKey() < RHS->getKey();
|
|
|
|
});
|
2016-06-26 20:28:59 +08:00
|
|
|
for (auto &I : SortedLinesByFile)
|
2016-07-21 20:06:31 +08:00
|
|
|
I->getValue().writeOut();
|
2011-04-26 11:54:16 +08:00
|
|
|
write(0);
|
|
|
|
write(0);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2014-12-23 07:12:42 +08:00
|
|
|
GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) {
|
|
|
|
// Only allow copy before edges and lines have been added. After that,
|
|
|
|
// there are inter-block pointers (eg: edges) that won't take kindly to
|
|
|
|
// blocks being copied or moved around.
|
|
|
|
assert(LinesByFile.empty());
|
|
|
|
assert(OutEdges.empty());
|
|
|
|
}
|
|
|
|
|
2011-04-16 09:20:23 +08:00
|
|
|
private:
|
|
|
|
friend class GCOVFunction;
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
GCOVBlock(uint32_t Number, raw_ostream *os)
|
|
|
|
: Number(Number) {
|
2011-04-16 09:20:23 +08:00
|
|
|
this->os = os;
|
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
uint32_t Number;
|
2016-07-21 20:06:31 +08:00
|
|
|
StringMap<GCOVLines> LinesByFile;
|
2011-04-26 11:54:16 +08:00
|
|
|
SmallVector<GCOVBlock *, 4> OutEdges;
|
2011-04-16 09:20:23 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// A function has a unique identifier, a checksum (we leave as zero) and a
|
|
|
|
// set of blocks and a map of edges between blocks. This is the only GCOV
|
|
|
|
// object users can construct, the blocks and lines will be rooted here.
|
|
|
|
class GCOVFunction : public GCOVRecord {
|
|
|
|
public:
|
2015-11-06 06:03:56 +08:00
|
|
|
GCOVFunction(const DISubprogram *SP, Function *F, raw_ostream *os,
|
|
|
|
uint32_t Ident, bool UseCfgChecksum, bool ExitBlockBeforeBody)
|
2014-12-23 07:12:42 +08:00
|
|
|
: SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0),
|
|
|
|
ReturnBlock(1, os) {
|
2011-04-16 09:20:23 +08:00
|
|
|
this->os = os;
|
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n");
|
2014-12-03 10:45:01 +08:00
|
|
|
|
2014-12-23 07:12:42 +08:00
|
|
|
uint32_t i = 0;
|
|
|
|
for (auto &BB : *F) {
|
2015-03-17 07:52:03 +08:00
|
|
|
// Skip index 1 if it's assigned to the ReturnBlock.
|
|
|
|
if (i == 1 && ExitBlockBeforeBody)
|
|
|
|
++i;
|
|
|
|
Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os)));
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2015-03-17 07:52:03 +08:00
|
|
|
if (!ExitBlockBeforeBody)
|
|
|
|
ReturnBlock.Number = i;
|
2013-12-04 16:57:17 +08:00
|
|
|
|
2014-06-27 06:52:05 +08:00
|
|
|
std::string FunctionNameAndLine;
|
|
|
|
raw_string_ostream FNLOS(FunctionNameAndLine);
|
2015-04-14 11:40:37 +08:00
|
|
|
FNLOS << getFunctionName(SP) << SP->getLine();
|
2014-06-27 06:52:05 +08:00
|
|
|
FNLOS.flush();
|
|
|
|
FuncChecksum = hash_value(FunctionNameAndLine);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
GCOVBlock &getBlock(BasicBlock *BB) {
|
2014-12-23 07:12:42 +08:00
|
|
|
return Blocks.find(BB)->second;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
GCOVBlock &getReturnBlock() {
|
2014-12-23 07:12:42 +08:00
|
|
|
return ReturnBlock;
|
2011-04-21 11:18:00 +08:00
|
|
|
}
|
|
|
|
|
2013-11-20 12:15:05 +08:00
|
|
|
std::string getEdgeDestinations() {
|
2014-06-27 06:52:05 +08:00
|
|
|
std::string EdgeDestinations;
|
|
|
|
raw_string_ostream EDOS(EdgeDestinations);
|
2013-11-20 12:15:05 +08:00
|
|
|
Function *F = Blocks.begin()->first->getParent();
|
2015-10-14 01:39:10 +08:00
|
|
|
for (BasicBlock &I : *F) {
|
|
|
|
GCOVBlock &Block = getBlock(&I);
|
2013-11-20 12:15:05 +08:00
|
|
|
for (int i = 0, e = Block.OutEdges.size(); i != e; ++i)
|
2014-06-27 06:52:05 +08:00
|
|
|
EDOS << Block.OutEdges[i]->Number;
|
2013-11-20 12:15:05 +08:00
|
|
|
}
|
2014-06-27 06:52:05 +08:00
|
|
|
return EdgeDestinations;
|
2013-11-20 12:15:05 +08:00
|
|
|
}
|
|
|
|
|
2019-11-14 21:55:28 +08:00
|
|
|
uint32_t getFuncChecksum() const {
|
2013-12-04 16:57:17 +08:00
|
|
|
return FuncChecksum;
|
|
|
|
}
|
|
|
|
|
2013-11-20 12:15:05 +08:00
|
|
|
void setCfgChecksum(uint32_t Checksum) {
|
|
|
|
CfgChecksum = Checksum;
|
|
|
|
}
|
|
|
|
|
2011-04-26 11:54:16 +08:00
|
|
|
void writeOut() {
|
2013-11-20 12:15:05 +08:00
|
|
|
writeBytes(FunctionTag, 4);
|
2018-12-07 02:44:48 +08:00
|
|
|
SmallString<128> Filename = getFilename(SP);
|
2013-11-20 12:15:05 +08:00
|
|
|
uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) +
|
2018-12-07 02:44:48 +08:00
|
|
|
1 + lengthOfGCOVString(Filename) + 1;
|
2013-11-20 12:15:05 +08:00
|
|
|
if (UseCfgChecksum)
|
|
|
|
++BlockLen;
|
|
|
|
write(BlockLen);
|
|
|
|
write(Ident);
|
2013-12-04 16:57:17 +08:00
|
|
|
write(FuncChecksum);
|
2013-11-20 12:15:05 +08:00
|
|
|
if (UseCfgChecksum)
|
|
|
|
write(CfgChecksum);
|
|
|
|
writeGCOVString(getFunctionName(SP));
|
2018-12-07 02:44:48 +08:00
|
|
|
writeGCOVString(Filename);
|
2015-04-14 11:40:37 +08:00
|
|
|
write(SP->getLine());
|
2013-11-20 12:15:05 +08:00
|
|
|
|
2011-04-16 09:20:23 +08:00
|
|
|
// Emit count of blocks.
|
2011-04-26 11:54:16 +08:00
|
|
|
writeBytes(BlockTag, 4);
|
|
|
|
write(Blocks.size() + 1);
|
|
|
|
for (int i = 0, e = Blocks.size() + 1; i != e; ++i) {
|
|
|
|
write(0); // No flags on our blocks.
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << Blocks.size() << " blocks.\n");
|
2011-04-16 09:20:23 +08:00
|
|
|
|
|
|
|
// Emit edges between blocks.
|
2013-06-18 14:38:21 +08:00
|
|
|
if (Blocks.empty()) return;
|
|
|
|
Function *F = Blocks.begin()->first->getParent();
|
2015-10-14 01:39:10 +08:00
|
|
|
for (BasicBlock &I : *F) {
|
|
|
|
GCOVBlock &Block = getBlock(&I);
|
2011-04-26 11:54:16 +08:00
|
|
|
if (Block.OutEdges.empty()) continue;
|
|
|
|
|
|
|
|
writeBytes(EdgeTag, 4);
|
|
|
|
write(Block.OutEdges.size() * 2 + 1);
|
|
|
|
write(Block.Number);
|
|
|
|
for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << Block.Number << " -> "
|
|
|
|
<< Block.OutEdges[i]->Number << "\n");
|
2011-04-26 11:54:16 +08:00
|
|
|
write(Block.OutEdges[i]->Number);
|
|
|
|
write(0); // no flags
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit lines for each block.
|
2015-10-14 01:39:10 +08:00
|
|
|
for (BasicBlock &I : *F)
|
|
|
|
getBlock(&I).writeOut();
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-04-30 00:38:44 +08:00
|
|
|
const DISubprogram *SP;
|
2013-11-20 12:15:05 +08:00
|
|
|
uint32_t Ident;
|
2013-12-04 16:57:17 +08:00
|
|
|
uint32_t FuncChecksum;
|
2013-11-20 12:15:05 +08:00
|
|
|
bool UseCfgChecksum;
|
|
|
|
uint32_t CfgChecksum;
|
2014-12-23 07:12:42 +08:00
|
|
|
DenseMap<BasicBlock *, GCOVBlock> Blocks;
|
|
|
|
GCOVBlock ReturnBlock;
|
2011-04-16 09:20:23 +08:00
|
|
|
};
|
2015-06-23 17:49:53 +08:00
|
|
|
}
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2018-11-12 17:01:43 +08:00
|
|
|
// RegexesStr is a string containing differents regex separated by a semi-colon.
|
|
|
|
// For example "foo\..*$;bar\..*$".
|
|
|
|
std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {
|
|
|
|
std::vector<Regex> Regexes;
|
|
|
|
while (!RegexesStr.empty()) {
|
|
|
|
std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';');
|
|
|
|
if (!HeadTail.first.empty()) {
|
|
|
|
Regex Re(HeadTail.first);
|
|
|
|
std::string Err;
|
|
|
|
if (!Re.isValid(Err)) {
|
|
|
|
Ctx->emitError(Twine("Regex ") + HeadTail.first +
|
|
|
|
" is not valid: " + Err);
|
|
|
|
}
|
|
|
|
Regexes.emplace_back(std::move(Re));
|
|
|
|
}
|
|
|
|
RegexesStr = HeadTail.second;
|
|
|
|
}
|
|
|
|
return Regexes;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,
|
|
|
|
std::vector<Regex> &Regexes) {
|
|
|
|
for (Regex &Re : Regexes) {
|
|
|
|
if (Re.match(Filename)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GCOVProfiler::isFunctionInstrumented(const Function &F) {
|
|
|
|
if (FilterRe.empty() && ExcludeRe.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-12-07 02:44:48 +08:00
|
|
|
SmallString<128> Filename = getFilename(F.getSubprogram());
|
2018-11-12 17:01:43 +08:00
|
|
|
auto It = InstrumentedFiles.find(Filename);
|
|
|
|
if (It != InstrumentedFiles.end()) {
|
|
|
|
return It->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallString<256> RealPath;
|
|
|
|
StringRef RealFilename;
|
|
|
|
|
|
|
|
// Path can be
|
|
|
|
// /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for
|
|
|
|
// such a case we must get the real_path.
|
|
|
|
if (sys::fs::real_path(Filename, RealPath)) {
|
|
|
|
// real_path can fail with path like "foo.c".
|
|
|
|
RealFilename = Filename;
|
|
|
|
} else {
|
|
|
|
RealFilename = RealPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShouldInstrument;
|
|
|
|
if (FilterRe.empty()) {
|
|
|
|
ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe);
|
|
|
|
} else if (ExcludeRe.empty()) {
|
|
|
|
ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe);
|
|
|
|
} else {
|
|
|
|
ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) &&
|
|
|
|
!doesFilenameMatchARegex(RealFilename, ExcludeRe);
|
|
|
|
}
|
|
|
|
InstrumentedFiles[Filename] = ShouldInstrument;
|
|
|
|
return ShouldInstrument;
|
|
|
|
}
|
|
|
|
|
2015-04-30 00:38:44 +08:00
|
|
|
std::string GCOVProfiler::mangleName(const DICompileUnit *CU,
|
2016-09-01 07:04:32 +08:00
|
|
|
GCovFileType OutputType) {
|
|
|
|
bool Notes = OutputType == GCovFileType::GCNO;
|
|
|
|
|
2011-05-04 12:03:04 +08:00
|
|
|
if (NamedMDNode *GCov = M->getNamedMetadata("llvm.gcov")) {
|
|
|
|
for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) {
|
2014-11-12 05:30:22 +08:00
|
|
|
MDNode *N = GCov->getOperand(i);
|
2016-09-01 07:04:32 +08:00
|
|
|
bool ThreeElement = N->getNumOperands() == 3;
|
|
|
|
if (!ThreeElement && N->getNumOperands() != 2)
|
|
|
|
continue;
|
2016-09-01 07:24:43 +08:00
|
|
|
if (dyn_cast<MDNode>(N->getOperand(ThreeElement ? 2 : 1)) != CU)
|
2016-09-01 07:04:32 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ThreeElement) {
|
|
|
|
// These nodes have no mangling to apply, it's stored mangled in the
|
|
|
|
// bitcode.
|
|
|
|
MDString *NotesFile = dyn_cast<MDString>(N->getOperand(0));
|
|
|
|
MDString *DataFile = dyn_cast<MDString>(N->getOperand(1));
|
|
|
|
if (!NotesFile || !DataFile)
|
|
|
|
continue;
|
|
|
|
return Notes ? NotesFile->getString() : DataFile->getString();
|
2011-05-05 08:03:30 +08:00
|
|
|
}
|
2016-09-01 07:04:32 +08:00
|
|
|
|
|
|
|
MDString *GCovFile = dyn_cast<MDString>(N->getOperand(0));
|
|
|
|
if (!GCovFile)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SmallString<128> Filename = GCovFile->getString();
|
|
|
|
sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");
|
|
|
|
return Filename.str();
|
2011-05-04 12:03:04 +08:00
|
|
|
}
|
|
|
|
}
|
2011-05-05 08:03:30 +08:00
|
|
|
|
2018-12-05 00:30:31 +08:00
|
|
|
SmallString<128> Filename = CU->getFilename();
|
2016-09-01 07:04:32 +08:00
|
|
|
sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda");
|
2013-03-27 06:47:50 +08:00
|
|
|
StringRef FName = sys::path::filename(Filename);
|
|
|
|
SmallString<128> CurPath;
|
|
|
|
if (sys::fs::current_path(CurPath)) return FName;
|
2015-03-28 01:51:30 +08:00
|
|
|
sys::path::append(CurPath, FName);
|
2013-03-27 06:47:50 +08:00
|
|
|
return CurPath.str();
|
2011-05-04 12:03:04 +08:00
|
|
|
}
|
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
bool GCOVProfiler::runOnModule(
|
|
|
|
Module &M, std::function<const TargetLibraryInfo &(Function &F)> GetTLI) {
|
2011-04-26 11:54:16 +08:00
|
|
|
this->M = &M;
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
this->GetTLI = std::move(GetTLI);
|
2011-04-16 10:05:18 +08:00
|
|
|
Ctx = &M.getContext();
|
|
|
|
|
2018-11-07 21:49:17 +08:00
|
|
|
AddFlushBeforeForkAndExec();
|
|
|
|
|
2018-11-12 17:01:43 +08:00
|
|
|
FilterRe = createRegexesFromString(Options.Filter);
|
|
|
|
ExcludeRe = createRegexesFromString(Options.Exclude);
|
|
|
|
|
2013-03-14 13:13:26 +08:00
|
|
|
if (Options.EmitNotes) emitProfileNotes();
|
|
|
|
if (Options.EmitData) return emitProfileArcs();
|
2011-04-21 09:56:25 +08:00
|
|
|
return false;
|
2011-04-16 10:05:18 +08:00
|
|
|
}
|
|
|
|
|
2016-06-05 13:12:23 +08:00
|
|
|
PreservedAnalyses GCOVProfilerPass::run(Module &M,
|
2016-08-09 08:28:38 +08:00
|
|
|
ModuleAnalysisManager &AM) {
|
2016-06-05 13:12:23 +08:00
|
|
|
|
|
|
|
GCOVProfiler Profiler(GCOVOpts);
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
FunctionAnalysisManager &FAM =
|
|
|
|
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
2016-06-05 13:12:23 +08:00
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
if (!Profiler.runOnModule(M, [&](Function &F) -> TargetLibraryInfo & {
|
|
|
|
return FAM.getResult<TargetLibraryAnalysis>(F);
|
|
|
|
}))
|
2016-06-05 13:12:23 +08:00
|
|
|
return PreservedAnalyses::all();
|
|
|
|
|
|
|
|
return PreservedAnalyses::none();
|
|
|
|
}
|
|
|
|
|
2016-04-15 23:57:41 +08:00
|
|
|
static bool functionHasLines(Function &F) {
|
2014-04-19 07:32:28 +08:00
|
|
|
// Check whether this function actually has any source lines. Not only
|
|
|
|
// do these waste space, they also can crash gcov.
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &BB : F) {
|
|
|
|
for (auto &I : BB) {
|
2014-06-05 05:47:19 +08:00
|
|
|
// Debug intrinsic locations correspond to the location of the
|
|
|
|
// declaration, not necessarily any statements or expressions.
|
2016-04-15 23:57:41 +08:00
|
|
|
if (isa<DbgInfoIntrinsic>(&I)) continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
2016-04-15 23:57:41 +08:00
|
|
|
const DebugLoc &Loc = I.getDebugLoc();
|
2015-03-31 03:49:49 +08:00
|
|
|
if (!Loc)
|
|
|
|
continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
|
|
|
// Artificial lines such as calls to the global constructors.
|
2015-03-17 07:52:03 +08:00
|
|
|
if (Loc.getLine() == 0) continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
2014-06-03 12:25:36 +08:00
|
|
|
return true;
|
2014-04-19 07:32:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Add Wasm personality and isScopedEHPersonality()
Summary:
- Add wasm personality function
- Re-categorize the existing `isFuncletEHPersonality()` function into
two different functions: `isFuncletEHPersonality()` and
`isScopedEHPersonality(). This becomes necessary as wasm EH uses scoped
EH instructions (catchswitch, catchpad/ret, and cleanuppad/ret) but not
outlined funclets.
- Changed some callsites of `isFuncletEHPersonality()` to
`isScopedEHPersonality()` if they are related to scoped EH IR-level
stuff.
Reviewers: majnemer, dschuff, rnk
Subscribers: jfb, sbc100, jgravelle-google, eraman, JDevlieghere, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D45559
llvm-svn: 332667
2018-05-18 04:52:03 +08:00
|
|
|
static bool isUsingScopeBasedEH(Function &F) {
|
2017-10-13 21:49:15 +08:00
|
|
|
if (!F.hasPersonalityFn()) return false;
|
|
|
|
|
|
|
|
EHPersonality Personality = classifyEHPersonality(F.getPersonalityFn());
|
[WebAssembly] Add Wasm personality and isScopedEHPersonality()
Summary:
- Add wasm personality function
- Re-categorize the existing `isFuncletEHPersonality()` function into
two different functions: `isFuncletEHPersonality()` and
`isScopedEHPersonality(). This becomes necessary as wasm EH uses scoped
EH instructions (catchswitch, catchpad/ret, and cleanuppad/ret) but not
outlined funclets.
- Changed some callsites of `isFuncletEHPersonality()` to
`isScopedEHPersonality()` if they are related to scoped EH IR-level
stuff.
Reviewers: majnemer, dschuff, rnk
Subscribers: jfb, sbc100, jgravelle-google, eraman, JDevlieghere, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D45559
llvm-svn: 332667
2018-05-18 04:52:03 +08:00
|
|
|
return isScopedEHPersonality(Personality);
|
2017-10-13 21:49:15 +08:00
|
|
|
}
|
|
|
|
|
2017-09-26 19:56:43 +08:00
|
|
|
static bool shouldKeepInEntry(BasicBlock::iterator It) {
|
|
|
|
if (isa<AllocaInst>(*It)) return true;
|
|
|
|
if (isa<DbgInfoIntrinsic>(*It)) return true;
|
|
|
|
if (auto *II = dyn_cast<IntrinsicInst>(It)) {
|
|
|
|
if (II->getIntrinsicID() == llvm::Intrinsic::localescape) return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-07 21:49:17 +08:00
|
|
|
void GCOVProfiler::AddFlushBeforeForkAndExec() {
|
|
|
|
SmallVector<Instruction *, 2> ForkAndExecs;
|
|
|
|
for (auto &F : M->functions()) {
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
auto *TLI = &GetTLI(F);
|
2018-11-07 21:49:17 +08:00
|
|
|
for (auto &I : instructions(F)) {
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(&I)) {
|
|
|
|
if (Function *Callee = CI->getCalledFunction()) {
|
|
|
|
LibFunc LF;
|
|
|
|
if (TLI->getLibFunc(*Callee, LF) &&
|
|
|
|
(LF == LibFunc_fork || LF == LibFunc_execl ||
|
|
|
|
LF == LibFunc_execle || LF == LibFunc_execlp ||
|
|
|
|
LF == LibFunc_execv || LF == LibFunc_execvp ||
|
|
|
|
LF == LibFunc_execve || LF == LibFunc_execvpe ||
|
|
|
|
LF == LibFunc_execvP)) {
|
|
|
|
ForkAndExecs.push_back(&I);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to split the block after the fork/exec call
|
|
|
|
// because else the counters for the lines after will be
|
|
|
|
// the same as before the call.
|
|
|
|
for (auto I : ForkAndExecs) {
|
|
|
|
IRBuilder<> Builder(I);
|
|
|
|
FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), {}, false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee GCOVFlush = M->getOrInsertFunction("__gcov_flush", FTy);
|
2018-11-07 21:49:17 +08:00
|
|
|
Builder.CreateCall(GCOVFlush);
|
|
|
|
I->getParent()->splitBasicBlock(I);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-14 06:55:42 +08:00
|
|
|
void GCOVProfiler::emitProfileNotes() {
|
2011-08-18 06:49:38 +08:00
|
|
|
NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
|
2011-11-28 07:22:20 +08:00
|
|
|
if (!CU_Nodes) return;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
|
|
|
|
// Each compile unit gets its own .gcno file. This means that whether we run
|
|
|
|
// this pass over the original .o's as they're produced, or run it after
|
|
|
|
// LTO, we'll generate the same .gcno files.
|
|
|
|
|
2015-04-30 00:38:44 +08:00
|
|
|
auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i));
|
2016-01-22 01:04:42 +08:00
|
|
|
|
|
|
|
// Skip module skeleton (and module) CUs.
|
|
|
|
if (CU->getDWOId())
|
|
|
|
continue;
|
|
|
|
|
2014-08-26 02:16:47 +08:00
|
|
|
std::error_code EC;
|
2019-08-05 13:43:48 +08:00
|
|
|
raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC,
|
|
|
|
sys::fs::OF_None);
|
2017-09-19 05:31:48 +08:00
|
|
|
if (EC) {
|
|
|
|
Ctx->emitError(Twine("failed to open coverage notes file for writing: ") +
|
|
|
|
EC.message());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-11-20 12:15:05 +08:00
|
|
|
std::string EdgeDestinations;
|
2011-11-28 07:22:20 +08:00
|
|
|
|
2014-11-06 14:55:02 +08:00
|
|
|
unsigned FunctionIdent = 0;
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &F : M->functions()) {
|
|
|
|
DISubprogram *SP = F.getSubprogram();
|
|
|
|
if (!SP) continue;
|
2018-11-12 17:01:43 +08:00
|
|
|
if (!functionHasLines(F) || !isFunctionInstrumented(F))
|
|
|
|
continue;
|
[WebAssembly] Add Wasm personality and isScopedEHPersonality()
Summary:
- Add wasm personality function
- Re-categorize the existing `isFuncletEHPersonality()` function into
two different functions: `isFuncletEHPersonality()` and
`isScopedEHPersonality(). This becomes necessary as wasm EH uses scoped
EH instructions (catchswitch, catchpad/ret, and cleanuppad/ret) but not
outlined funclets.
- Changed some callsites of `isFuncletEHPersonality()` to
`isScopedEHPersonality()` if they are related to scoped EH IR-level
stuff.
Reviewers: majnemer, dschuff, rnk
Subscribers: jfb, sbc100, jgravelle-google, eraman, JDevlieghere, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D45559
llvm-svn: 332667
2018-05-18 04:52:03 +08:00
|
|
|
// TODO: Functions using scope-based EH are currently not supported.
|
|
|
|
if (isUsingScopeBasedEH(F)) continue;
|
2014-01-31 13:24:01 +08:00
|
|
|
|
|
|
|
// gcov expects every function to start with an entry block that has a
|
|
|
|
// single successor, so split the entry block to make sure of that.
|
2016-04-15 23:57:41 +08:00
|
|
|
BasicBlock &EntryBlock = F.getEntryBlock();
|
2014-01-31 13:24:01 +08:00
|
|
|
BasicBlock::iterator It = EntryBlock.begin();
|
2017-09-26 19:56:43 +08:00
|
|
|
while (shouldKeepInEntry(It))
|
2014-01-31 13:24:01 +08:00
|
|
|
++It;
|
|
|
|
EntryBlock.splitBasicBlock(It);
|
2013-11-23 07:07:45 +08:00
|
|
|
|
2019-08-15 23:54:37 +08:00
|
|
|
Funcs.push_back(std::make_unique<GCOVFunction>(SP, &F, &out, FunctionIdent++,
|
2015-03-17 07:52:03 +08:00
|
|
|
Options.UseCfgChecksum,
|
|
|
|
Options.ExitBlockBeforeBody));
|
2014-04-22 04:41:55 +08:00
|
|
|
GCOVFunction &Func = *Funcs.back();
|
2011-11-28 07:22:20 +08:00
|
|
|
|
2018-10-11 16:53:43 +08:00
|
|
|
// Add the function line number to the lines of the entry block
|
|
|
|
// to have a counter for the function definition.
|
2018-10-31 02:41:31 +08:00
|
|
|
uint32_t Line = SP->getLine();
|
2018-12-07 02:44:48 +08:00
|
|
|
auto Filename = getFilename(SP);
|
2019-11-16 03:23:05 +08:00
|
|
|
|
|
|
|
// Artificial functions such as global initializers
|
|
|
|
if (!SP->isArtificial())
|
|
|
|
Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line);
|
2018-10-11 16:53:43 +08:00
|
|
|
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &BB : F) {
|
|
|
|
GCOVBlock &Block = Func.getBlock(&BB);
|
2018-10-15 18:04:59 +08:00
|
|
|
Instruction *TI = BB.getTerminator();
|
2011-11-28 07:22:20 +08:00
|
|
|
if (int successors = TI->getNumSuccessors()) {
|
|
|
|
for (int i = 0; i != successors; ++i) {
|
2014-04-22 04:41:55 +08:00
|
|
|
Block.addEdge(Func.getBlock(TI->getSuccessor(i)));
|
2011-08-18 06:49:38 +08:00
|
|
|
}
|
2011-11-28 07:22:20 +08:00
|
|
|
} else if (isa<ReturnInst>(TI)) {
|
2014-04-22 04:41:55 +08:00
|
|
|
Block.addEdge(Func.getReturnBlock());
|
2011-11-28 07:22:20 +08:00
|
|
|
}
|
|
|
|
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &I : BB) {
|
2014-06-05 05:47:19 +08:00
|
|
|
// Debug intrinsic locations correspond to the location of the
|
|
|
|
// declaration, not necessarily any statements or expressions.
|
2016-04-15 23:57:41 +08:00
|
|
|
if (isa<DbgInfoIntrinsic>(&I)) continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
2016-04-15 23:57:41 +08:00
|
|
|
const DebugLoc &Loc = I.getDebugLoc();
|
2015-03-31 03:49:49 +08:00
|
|
|
if (!Loc)
|
|
|
|
continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
|
|
|
// Artificial lines such as calls to the global constructors.
|
[IR] Add a boolean field in DILocation to know if a line must covered or not
Summary:
Some lines have a hit counter where they should not have one.
For example, in C++, some cleanup is adding at the end of a scope represented by a '}'.
So such a line has a hit counter where a user expects to not have one.
The goal of the patch is to add this information in DILocation which is used to get the covered lines in GCOVProfiling.cpp.
A following patch in clang will add this information when generating IR (https://reviews.llvm.org/D49916).
Reviewers: marco-c, davidxl, vsk, javed.absar, rnk
Reviewed By: rnk
Subscribers: eraman, xur, danielcdh, aprantl, rnk, dblaikie, #debug-info, vsk, llvm-commits, sylvestre.ledru
Tags: #debug-info
Differential Revision: https://reviews.llvm.org/D49915
llvm-svn: 342631
2018-09-20 16:53:06 +08:00
|
|
|
if (Loc.getLine() == 0 || Loc.isImplicitCode())
|
|
|
|
continue;
|
2014-06-05 12:31:43 +08:00
|
|
|
|
2011-11-28 07:22:20 +08:00
|
|
|
if (Line == Loc.getLine()) continue;
|
|
|
|
Line = Loc.getLine();
|
2015-03-31 03:49:49 +08:00
|
|
|
if (SP != getDISubprogram(Loc.getScope()))
|
|
|
|
continue;
|
2011-11-28 07:22:20 +08:00
|
|
|
|
2018-12-07 02:44:48 +08:00
|
|
|
GCOVLines &Lines = Block.getFile(Filename);
|
2011-11-28 07:22:20 +08:00
|
|
|
Lines.addLine(Loc.getLine());
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2018-10-31 02:41:31 +08:00
|
|
|
Line = 0;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2014-04-22 04:41:55 +08:00
|
|
|
EdgeDestinations += Func.getEdgeDestinations();
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2013-11-20 12:15:05 +08:00
|
|
|
|
2013-11-21 12:01:05 +08:00
|
|
|
FileChecksums.push_back(hash_value(EdgeDestinations));
|
2013-11-20 12:15:05 +08:00
|
|
|
out.write("oncg", 4);
|
|
|
|
out.write(ReversedVersion, 4);
|
2013-11-21 12:01:05 +08:00
|
|
|
out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4);
|
2013-11-20 12:15:05 +08:00
|
|
|
|
2014-04-22 04:41:55 +08:00
|
|
|
for (auto &Func : Funcs) {
|
2013-11-21 12:01:05 +08:00
|
|
|
Func->setCfgChecksum(FileChecksums.back());
|
|
|
|
Func->writeOut();
|
|
|
|
}
|
2013-11-20 12:15:05 +08:00
|
|
|
|
2011-11-28 07:22:20 +08:00
|
|
|
out.write("\0\0\0\0\0\0\0\0", 8); // EOF
|
|
|
|
out.close();
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-18 06:49:38 +08:00
|
|
|
bool GCOVProfiler::emitProfileArcs() {
|
|
|
|
NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu");
|
|
|
|
if (!CU_Nodes) return false;
|
|
|
|
|
2014-03-11 10:44:45 +08:00
|
|
|
bool Result = false;
|
2011-08-18 06:49:38 +08:00
|
|
|
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
|
|
|
|
SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP;
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &F : M->functions()) {
|
|
|
|
DISubprogram *SP = F.getSubprogram();
|
|
|
|
if (!SP) continue;
|
2018-11-12 17:01:43 +08:00
|
|
|
if (!functionHasLines(F) || !isFunctionInstrumented(F))
|
|
|
|
continue;
|
[WebAssembly] Add Wasm personality and isScopedEHPersonality()
Summary:
- Add wasm personality function
- Re-categorize the existing `isFuncletEHPersonality()` function into
two different functions: `isFuncletEHPersonality()` and
`isScopedEHPersonality(). This becomes necessary as wasm EH uses scoped
EH instructions (catchswitch, catchpad/ret, and cleanuppad/ret) but not
outlined funclets.
- Changed some callsites of `isFuncletEHPersonality()` to
`isScopedEHPersonality()` if they are related to scoped EH IR-level
stuff.
Reviewers: majnemer, dschuff, rnk
Subscribers: jfb, sbc100, jgravelle-google, eraman, JDevlieghere, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D45559
llvm-svn: 332667
2018-05-18 04:52:03 +08:00
|
|
|
// TODO: Functions using scope-based EH are currently not supported.
|
|
|
|
if (isUsingScopeBasedEH(F)) continue;
|
2011-08-18 06:49:38 +08:00
|
|
|
if (!Result) Result = true;
|
2017-10-13 21:49:15 +08:00
|
|
|
|
2018-09-12 02:38:34 +08:00
|
|
|
DenseMap<std::pair<BasicBlock *, BasicBlock *>, unsigned> EdgeToCounter;
|
2011-08-18 06:49:38 +08:00
|
|
|
unsigned Edges = 0;
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &BB : F) {
|
2018-10-15 18:04:59 +08:00
|
|
|
Instruction *TI = BB.getTerminator();
|
2018-09-12 02:38:34 +08:00
|
|
|
if (isa<ReturnInst>(TI)) {
|
|
|
|
EdgeToCounter[{&BB, nullptr}] = Edges++;
|
|
|
|
} else {
|
|
|
|
for (BasicBlock *Succ : successors(TI)) {
|
|
|
|
EdgeToCounter[{&BB, Succ}] = Edges++;
|
|
|
|
}
|
|
|
|
}
|
2011-08-18 06:49:38 +08:00
|
|
|
}
|
2014-03-11 10:44:45 +08:00
|
|
|
|
2011-08-18 06:49:38 +08:00
|
|
|
ArrayType *CounterTy =
|
2011-04-26 11:54:16 +08:00
|
|
|
ArrayType::get(Type::getInt64Ty(*Ctx), Edges);
|
2011-08-18 06:49:38 +08:00
|
|
|
GlobalVariable *Counters =
|
2011-04-26 11:54:16 +08:00
|
|
|
new GlobalVariable(*M, CounterTy, false,
|
2011-04-16 09:20:23 +08:00
|
|
|
GlobalValue::InternalLinkage,
|
2011-04-26 11:54:16 +08:00
|
|
|
Constant::getNullValue(CounterTy),
|
2012-06-23 19:37:03 +08:00
|
|
|
"__llvm_gcov_ctr");
|
2015-04-14 11:40:37 +08:00
|
|
|
CountersBySP.push_back(std::make_pair(Counters, SP));
|
2014-03-11 10:44:45 +08:00
|
|
|
|
2018-09-12 02:38:34 +08:00
|
|
|
// If a BB has several predecessors, use a PHINode to select
|
|
|
|
// the correct counter.
|
2016-04-15 23:57:41 +08:00
|
|
|
for (auto &BB : F) {
|
2018-09-12 02:38:34 +08:00
|
|
|
const unsigned EdgeCount =
|
|
|
|
std::distance(pred_begin(&BB), pred_end(&BB));
|
|
|
|
if (EdgeCount) {
|
|
|
|
// The phi node must be at the begin of the BB.
|
|
|
|
IRBuilder<> BuilderForPhi(&*BB.begin());
|
|
|
|
Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx);
|
|
|
|
PHINode *Phi = BuilderForPhi.CreatePHI(Int64PtrTy, EdgeCount);
|
|
|
|
for (BasicBlock *Pred : predecessors(&BB)) {
|
|
|
|
auto It = EdgeToCounter.find({Pred, &BB});
|
|
|
|
assert(It != EdgeToCounter.end());
|
|
|
|
const unsigned Edge = It->second;
|
2019-02-02 04:44:47 +08:00
|
|
|
Value *EdgeCounter = BuilderForPhi.CreateConstInBoundsGEP2_64(
|
|
|
|
Counters->getValueType(), Counters, 0, Edge);
|
2018-09-12 02:38:34 +08:00
|
|
|
Phi->addIncoming(EdgeCounter, Pred);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip phis, landingpads.
|
|
|
|
IRBuilder<> Builder(&*BB.getFirstInsertionPt());
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Phi);
|
2018-09-12 02:38:34 +08:00
|
|
|
Count = Builder.CreateAdd(Count, Builder.getInt64(1));
|
|
|
|
Builder.CreateStore(Count, Phi);
|
|
|
|
|
2018-10-15 18:04:59 +08:00
|
|
|
Instruction *TI = BB.getTerminator();
|
2018-09-12 02:38:34 +08:00
|
|
|
if (isa<ReturnInst>(TI)) {
|
|
|
|
auto It = EdgeToCounter.find({&BB, nullptr});
|
|
|
|
assert(It != EdgeToCounter.end());
|
|
|
|
const unsigned Edge = It->second;
|
2019-02-02 04:44:47 +08:00
|
|
|
Value *Counter = Builder.CreateConstInBoundsGEP2_64(
|
|
|
|
Counters->getValueType(), Counters, 0, Edge);
|
2019-02-02 04:44:24 +08:00
|
|
|
Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Counter);
|
2013-02-27 13:46:30 +08:00
|
|
|
Count = Builder.CreateAdd(Count, Builder.getInt64(1));
|
2011-08-18 06:49:38 +08:00
|
|
|
Builder.CreateStore(Count, Counter);
|
|
|
|
}
|
|
|
|
}
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
}
|
2012-06-02 07:14:32 +08:00
|
|
|
|
2013-03-19 07:04:39 +08:00
|
|
|
Function *WriteoutF = insertCounterWriteout(CountersBySP);
|
|
|
|
Function *FlushF = insertFlush(CountersBySP);
|
|
|
|
|
|
|
|
// Create a small bit of code that registers the "__llvm_gcov_writeout" to
|
2013-03-20 05:03:22 +08:00
|
|
|
// be executed at exit and the "__llvm_gcov_flush" function to be executed
|
|
|
|
// when "__gcov_flush" is called.
|
2013-03-19 07:04:39 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
|
|
|
Function *F = Function::Create(FTy, GlobalValue::InternalLinkage,
|
|
|
|
"__llvm_gcov_init", M);
|
2016-06-15 05:01:22 +08:00
|
|
|
F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
2013-03-19 07:04:39 +08:00
|
|
|
F->setLinkage(GlobalValue::InternalLinkage);
|
|
|
|
F->addFnAttr(Attribute::NoInline);
|
|
|
|
if (Options.NoRedZone)
|
|
|
|
F->addFnAttr(Attribute::NoRedZone);
|
|
|
|
|
|
|
|
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F);
|
|
|
|
IRBuilder<> Builder(BB);
|
|
|
|
|
|
|
|
FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
2013-03-21 05:13:59 +08:00
|
|
|
Type *Params[] = {
|
|
|
|
PointerType::get(FTy, 0),
|
|
|
|
PointerType::get(FTy, 0)
|
|
|
|
};
|
|
|
|
FTy = FunctionType::get(Builder.getVoidTy(), Params, false);
|
|
|
|
|
2013-10-24 04:35:00 +08:00
|
|
|
// Initialize the environment and register the local writeout and flush
|
2013-03-21 05:13:59 +08:00
|
|
|
// functions.
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy);
|
2015-05-19 06:13:54 +08:00
|
|
|
Builder.CreateCall(GCOVInit, {WriteoutF, FlushF});
|
2013-03-19 07:04:39 +08:00
|
|
|
Builder.CreateRetVoid();
|
|
|
|
|
|
|
|
appendToGlobalCtors(*M, F, 0);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2012-05-28 14:10:56 +08:00
|
|
|
|
2011-08-18 06:49:38 +08:00
|
|
|
return Result;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {
|
2013-03-07 16:28:49 +08:00
|
|
|
Type *Args[] = {
|
|
|
|
Type::getInt8PtrTy(*Ctx), // const char *orig_filename
|
|
|
|
Type::getInt8PtrTy(*Ctx), // const char version[4]
|
2013-11-20 12:15:05 +08:00
|
|
|
Type::getInt32Ty(*Ctx), // uint32_t checksum
|
2013-03-07 16:28:49 +08:00
|
|
|
};
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AttributeList AL;
|
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false))
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 2, AK);
|
|
|
|
FunctionCallee Res = M->getOrInsertFunction("llvm_gcda_start_file", FTy, AL);
|
2018-07-11 00:05:47 +08:00
|
|
|
return Res;
|
2011-04-26 11:54:16 +08:00
|
|
|
}
|
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) {
|
2013-11-20 12:15:05 +08:00
|
|
|
Type *Args[] = {
|
2011-05-05 10:46:38 +08:00
|
|
|
Type::getInt32Ty(*Ctx), // uint32_t ident
|
|
|
|
Type::getInt8PtrTy(*Ctx), // const char *function_name
|
2013-12-04 16:57:17 +08:00
|
|
|
Type::getInt32Ty(*Ctx), // uint32_t func_checksum
|
2013-03-09 09:33:06 +08:00
|
|
|
Type::getInt8Ty(*Ctx), // uint8_t use_extra_checksum
|
2013-11-20 12:15:05 +08:00
|
|
|
Type::getInt32Ty(*Ctx), // uint32_t cfg_checksum
|
2011-05-05 10:46:38 +08:00
|
|
|
};
|
2012-05-26 07:55:00 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AttributeList AL;
|
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false)) {
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 0, AK);
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 2, AK);
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 3, AK);
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 4, AK);
|
|
|
|
}
|
|
|
|
return M->getOrInsertFunction("llvm_gcda_emit_function", FTy);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) {
|
2011-07-12 22:06:48 +08:00
|
|
|
Type *Args[] = {
|
2011-04-16 09:20:23 +08:00
|
|
|
Type::getInt32Ty(*Ctx), // uint32_t num_counters
|
|
|
|
Type::getInt64PtrTy(*Ctx), // uint64_t *counters
|
|
|
|
};
|
2013-03-07 16:28:49 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
AttributeList AL;
|
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false))
|
|
|
|
AL = AL.addParamAttribute(*Ctx, 0, AK);
|
|
|
|
return M->getOrInsertFunction("llvm_gcda_emit_arcs", FTy, AL);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee GCOVProfiler::getSummaryInfoFunc() {
|
2013-11-12 12:59:08 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
|
|
|
return M->getOrInsertFunction("llvm_gcda_summary_info", FTy);
|
|
|
|
}
|
|
|
|
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee GCOVProfiler::getEndFileFunc() {
|
2011-07-18 12:54:35 +08:00
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
2011-04-26 11:54:16 +08:00
|
|
|
return M->getOrInsertFunction("llvm_gcda_end_file", FTy);
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2013-03-19 07:04:39 +08:00
|
|
|
Function *GCOVProfiler::insertCounterWriteout(
|
2012-08-30 02:45:41 +08:00
|
|
|
ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {
|
2012-09-13 08:09:55 +08:00
|
|
|
FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
|
|
|
Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");
|
|
|
|
if (!WriteoutF)
|
|
|
|
WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage,
|
|
|
|
"__llvm_gcov_writeout", M);
|
2016-06-15 05:01:22 +08:00
|
|
|
WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
2012-12-19 15:18:57 +08:00
|
|
|
WriteoutF->addFnAttr(Attribute::NoInline);
|
2013-03-14 13:13:26 +08:00
|
|
|
if (Options.NoRedZone)
|
2012-12-19 15:18:57 +08:00
|
|
|
WriteoutF->addFnAttr(Attribute::NoRedZone);
|
2012-09-13 08:09:55 +08:00
|
|
|
|
|
|
|
BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF);
|
2011-04-26 11:54:16 +08:00
|
|
|
IRBuilder<> Builder(BB);
|
2011-04-16 09:20:23 +08:00
|
|
|
|
Change TargetLibraryInfo analysis passes to always require Function
Summary:
This is the first change to enable the TLI to be built per-function so
that -fno-builtin* handling can be migrated to use function attributes.
See discussion on D61634 for background. This is an enabler for fixing
handling of these options for LTO, for example.
This change should not affect behavior, as the provided function is not
yet used to build a specifically per-function TLI, but rather enables
that migration.
Most of the changes were very mechanical, e.g. passing a Function to the
legacy analysis pass's getTLI interface, or in Module level cases,
adding a callback. This is similar to the way the per-function TTI
analysis works.
There was one place where we were looking for builtins but not in the
context of a specific function. See FindCXAAtExit in
lib/Transforms/IPO/GlobalOpt.cpp. I'm somewhat concerned my workaround
could provide the wrong behavior in some corner cases. Suggestions
welcome.
Reviewers: chandlerc, hfinkel
Subscribers: arsenm, dschuff, jvesely, nhaehnle, mehdi_amini, javed.absar, sbc100, jgravelle-google, eraman, aheejin, steven_wu, george.burgess.iv, dexonsmith, jfb, asbirlea, gchatelet, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D66428
llvm-svn: 371284
2019-09-07 11:09:36 +08:00
|
|
|
auto *TLI = &GetTLI(*WriteoutF);
|
|
|
|
|
|
|
|
FunctionCallee StartFile = getStartFileFunc(TLI);
|
|
|
|
FunctionCallee EmitFunction = getEmitFunctionFunc(TLI);
|
|
|
|
FunctionCallee EmitArcs = getEmitArcsFunc(TLI);
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee SummaryInfo = getSummaryInfoFunc();
|
|
|
|
FunctionCallee EndFile = getEndFileFunc();
|
2011-04-16 09:20:23 +08:00
|
|
|
|
2018-05-03 06:24:39 +08:00
|
|
|
NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu");
|
|
|
|
if (!CUNodes) {
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
return WriteoutF;
|
|
|
|
}
|
2016-01-22 01:04:42 +08:00
|
|
|
|
2018-05-03 06:24:39 +08:00
|
|
|
// Collect the relevant data into a large constant data structure that we can
|
|
|
|
// walk to write out everything.
|
|
|
|
StructType *StartFileCallArgsTy = StructType::create(
|
|
|
|
{Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()});
|
|
|
|
StructType *EmitFunctionCallArgsTy = StructType::create(
|
|
|
|
{Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(),
|
|
|
|
Builder.getInt8Ty(), Builder.getInt32Ty()});
|
|
|
|
StructType *EmitArcsCallArgsTy = StructType::create(
|
|
|
|
{Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()});
|
|
|
|
StructType *FileInfoTy =
|
|
|
|
StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(),
|
|
|
|
EmitFunctionCallArgsTy->getPointerTo(),
|
|
|
|
EmitArcsCallArgsTy->getPointerTo()});
|
|
|
|
|
|
|
|
Constant *Zero32 = Builder.getInt32(0);
|
2018-05-03 08:11:03 +08:00
|
|
|
// Build an explicit array of two zeros for use in ConstantExpr GEP building.
|
|
|
|
Constant *TwoZero32s[] = {Zero32, Zero32};
|
2018-05-03 06:24:39 +08:00
|
|
|
|
|
|
|
SmallVector<Constant *, 8> FileInfos;
|
|
|
|
for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) {
|
|
|
|
auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i));
|
2016-01-22 01:04:42 +08:00
|
|
|
|
2018-05-03 06:24:39 +08:00
|
|
|
// Skip module skeleton (and module) CUs.
|
|
|
|
if (CU->getDWOId())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
|
|
|
|
uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
|
|
|
|
auto *StartFileCallArgs = ConstantStruct::get(
|
|
|
|
StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda),
|
|
|
|
Builder.CreateGlobalStringPtr(ReversedVersion),
|
|
|
|
Builder.getInt32(CfgChecksum)});
|
|
|
|
|
|
|
|
SmallVector<Constant *, 8> EmitFunctionCallArgsArray;
|
|
|
|
SmallVector<Constant *, 8> EmitArcsCallArgsArray;
|
|
|
|
for (int j : llvm::seq<int>(0, CountersBySP.size())) {
|
|
|
|
auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second);
|
|
|
|
uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
|
|
|
|
EmitFunctionCallArgsArray.push_back(ConstantStruct::get(
|
|
|
|
EmitFunctionCallArgsTy,
|
|
|
|
{Builder.getInt32(j),
|
|
|
|
Options.FunctionNamesInData
|
|
|
|
? Builder.CreateGlobalStringPtr(getFunctionName(SP))
|
|
|
|
: Constant::getNullValue(Builder.getInt8PtrTy()),
|
|
|
|
Builder.getInt32(FuncChecksum),
|
|
|
|
Builder.getInt8(Options.UseCfgChecksum),
|
|
|
|
Builder.getInt32(CfgChecksum)}));
|
|
|
|
|
|
|
|
GlobalVariable *GV = CountersBySP[j].first;
|
|
|
|
unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements();
|
|
|
|
EmitArcsCallArgsArray.push_back(ConstantStruct::get(
|
|
|
|
EmitArcsCallArgsTy,
|
2018-05-03 08:11:03 +08:00
|
|
|
{Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr(
|
|
|
|
GV->getValueType(), GV, TwoZero32s)}));
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2018-05-03 06:24:39 +08:00
|
|
|
// Create global arrays for the two emit calls.
|
|
|
|
int CountersSize = CountersBySP.size();
|
|
|
|
assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&
|
|
|
|
"Mismatched array size!");
|
|
|
|
assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&
|
|
|
|
"Mismatched array size!");
|
|
|
|
auto *EmitFunctionCallArgsArrayTy =
|
|
|
|
ArrayType::get(EmitFunctionCallArgsTy, CountersSize);
|
|
|
|
auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(
|
|
|
|
*M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,
|
|
|
|
GlobalValue::InternalLinkage,
|
|
|
|
ConstantArray::get(EmitFunctionCallArgsArrayTy,
|
|
|
|
EmitFunctionCallArgsArray),
|
|
|
|
Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));
|
|
|
|
auto *EmitArcsCallArgsArrayTy =
|
|
|
|
ArrayType::get(EmitArcsCallArgsTy, CountersSize);
|
|
|
|
EmitFunctionCallArgsArrayGV->setUnnamedAddr(
|
|
|
|
GlobalValue::UnnamedAddr::Global);
|
|
|
|
auto *EmitArcsCallArgsArrayGV = new GlobalVariable(
|
|
|
|
*M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,
|
|
|
|
GlobalValue::InternalLinkage,
|
|
|
|
ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray),
|
|
|
|
Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));
|
|
|
|
EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
|
|
|
|
|
|
|
FileInfos.push_back(ConstantStruct::get(
|
|
|
|
FileInfoTy,
|
|
|
|
{StartFileCallArgs, Builder.getInt32(CountersSize),
|
2018-05-03 08:11:03 +08:00
|
|
|
ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy,
|
|
|
|
EmitFunctionCallArgsArrayGV,
|
|
|
|
TwoZero32s),
|
2018-05-03 06:24:39 +08:00
|
|
|
ConstantExpr::getInBoundsGetElementPtr(
|
2018-05-03 08:11:03 +08:00
|
|
|
EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)}));
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
|
|
|
|
2018-05-03 06:24:39 +08:00
|
|
|
// If we didn't find anything to actually emit, bail on out.
|
|
|
|
if (FileInfos.empty()) {
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
return WriteoutF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// To simplify code, we cap the number of file infos we write out to fit
|
|
|
|
// easily in a 32-bit signed integer. This gives consistent behavior between
|
|
|
|
// 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit
|
|
|
|
// operations on 32-bit systems. It also seems unreasonable to try to handle
|
|
|
|
// more than 2 billion files.
|
|
|
|
if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)
|
|
|
|
FileInfos.resize(INT_MAX);
|
|
|
|
|
|
|
|
// Create a global for the entire data structure so we can walk it more
|
|
|
|
// easily.
|
|
|
|
auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size());
|
|
|
|
auto *FileInfoArrayGV = new GlobalVariable(
|
|
|
|
*M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,
|
|
|
|
ConstantArray::get(FileInfoArrayTy, FileInfos),
|
|
|
|
"__llvm_internal_gcov_emit_file_info");
|
|
|
|
FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
|
|
|
|
|
|
|
// Create the CFG for walking this data structure.
|
|
|
|
auto *FileLoopHeader =
|
|
|
|
BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF);
|
|
|
|
auto *CounterLoopHeader =
|
|
|
|
BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF);
|
|
|
|
auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF);
|
|
|
|
auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF);
|
|
|
|
|
|
|
|
// We always have at least one file, so just branch to the header.
|
|
|
|
Builder.CreateBr(FileLoopHeader);
|
|
|
|
|
|
|
|
// The index into the files structure is our loop induction variable.
|
|
|
|
Builder.SetInsertPoint(FileLoopHeader);
|
|
|
|
PHINode *IV =
|
|
|
|
Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
|
|
|
|
IV->addIncoming(Builder.getInt32(0), BB);
|
2019-02-02 04:44:47 +08:00
|
|
|
auto *FileInfoPtr = Builder.CreateInBoundsGEP(
|
|
|
|
FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV});
|
|
|
|
auto *StartFileCallArgsPtr =
|
|
|
|
Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0);
|
2018-07-11 00:05:47 +08:00
|
|
|
auto *StartFileCall = Builder.CreateCall(
|
2018-05-03 06:24:39 +08:00
|
|
|
StartFile,
|
2019-02-02 04:44:24 +08:00
|
|
|
{Builder.CreateLoad(StartFileCallArgsTy->getElementType(0),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(StartFileCallArgsTy,
|
|
|
|
StartFileCallArgsPtr, 0)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(StartFileCallArgsTy->getElementType(1),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(StartFileCallArgsTy,
|
|
|
|
StartFileCallArgsPtr, 1)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(StartFileCallArgsTy->getElementType(2),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(StartFileCallArgsTy,
|
|
|
|
StartFileCallArgsPtr, 2))});
|
2018-07-11 00:05:47 +08:00
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false))
|
|
|
|
StartFileCall->addParamAttr(2, AK);
|
2019-02-02 04:44:47 +08:00
|
|
|
auto *NumCounters =
|
|
|
|
Builder.CreateLoad(FileInfoTy->getElementType(1),
|
|
|
|
Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1));
|
|
|
|
auto *EmitFunctionCallArgsArray =
|
|
|
|
Builder.CreateLoad(FileInfoTy->getElementType(2),
|
|
|
|
Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2));
|
|
|
|
auto *EmitArcsCallArgsArray =
|
|
|
|
Builder.CreateLoad(FileInfoTy->getElementType(3),
|
|
|
|
Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3));
|
2018-05-03 06:24:39 +08:00
|
|
|
auto *EnterCounterLoopCond =
|
|
|
|
Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters);
|
|
|
|
Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch);
|
|
|
|
|
|
|
|
Builder.SetInsertPoint(CounterLoopHeader);
|
|
|
|
auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2);
|
|
|
|
JV->addIncoming(Builder.getInt32(0), FileLoopHeader);
|
2019-02-02 04:44:47 +08:00
|
|
|
auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(
|
|
|
|
EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV);
|
2018-07-11 00:05:47 +08:00
|
|
|
auto *EmitFunctionCall = Builder.CreateCall(
|
2018-05-03 06:24:39 +08:00
|
|
|
EmitFunction,
|
2019-02-02 04:44:24 +08:00
|
|
|
{Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(EmitFunctionCallArgsTy,
|
|
|
|
EmitFunctionCallArgsPtr, 0)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(EmitFunctionCallArgsTy,
|
|
|
|
EmitFunctionCallArgsPtr, 1)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(EmitFunctionCallArgsTy,
|
|
|
|
EmitFunctionCallArgsPtr, 2)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(3),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(EmitFunctionCallArgsTy,
|
|
|
|
EmitFunctionCallArgsPtr, 3)),
|
|
|
|
Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(4),
|
|
|
|
Builder.CreateStructGEP(EmitFunctionCallArgsTy,
|
|
|
|
EmitFunctionCallArgsPtr,
|
|
|
|
4))});
|
2018-07-11 00:05:47 +08:00
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false)) {
|
|
|
|
EmitFunctionCall->addParamAttr(0, AK);
|
|
|
|
EmitFunctionCall->addParamAttr(2, AK);
|
|
|
|
EmitFunctionCall->addParamAttr(3, AK);
|
|
|
|
EmitFunctionCall->addParamAttr(4, AK);
|
|
|
|
}
|
2018-05-03 06:24:39 +08:00
|
|
|
auto *EmitArcsCallArgsPtr =
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateInBoundsGEP(EmitArcsCallArgsTy, EmitArcsCallArgsArray, JV);
|
2018-07-11 00:05:47 +08:00
|
|
|
auto *EmitArcsCall = Builder.CreateCall(
|
2018-05-03 06:24:39 +08:00
|
|
|
EmitArcs,
|
2019-02-02 04:44:47 +08:00
|
|
|
{Builder.CreateLoad(
|
|
|
|
EmitArcsCallArgsTy->getElementType(0),
|
|
|
|
Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0)),
|
2019-02-02 04:44:24 +08:00
|
|
|
Builder.CreateLoad(EmitArcsCallArgsTy->getElementType(1),
|
2019-02-02 04:44:47 +08:00
|
|
|
Builder.CreateStructGEP(EmitArcsCallArgsTy,
|
|
|
|
EmitArcsCallArgsPtr, 1))});
|
2018-07-11 00:05:47 +08:00
|
|
|
if (auto AK = TLI->getExtAttrForI32Param(false))
|
|
|
|
EmitArcsCall->addParamAttr(0, AK);
|
2018-05-03 06:24:39 +08:00
|
|
|
auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1));
|
|
|
|
auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters);
|
|
|
|
Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch);
|
|
|
|
JV->addIncoming(NextJV, CounterLoopHeader);
|
|
|
|
|
|
|
|
Builder.SetInsertPoint(FileLoopLatch);
|
|
|
|
Builder.CreateCall(SummaryInfo, {});
|
|
|
|
Builder.CreateCall(EndFile, {});
|
|
|
|
auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1));
|
|
|
|
auto *FileLoopCond =
|
|
|
|
Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size()));
|
|
|
|
Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB);
|
|
|
|
IV->addIncoming(NextIV, FileLoopLatch);
|
|
|
|
|
|
|
|
Builder.SetInsertPoint(ExitBB);
|
2012-06-02 07:14:32 +08:00
|
|
|
Builder.CreateRetVoid();
|
2018-05-03 06:24:39 +08:00
|
|
|
|
2013-03-19 07:04:39 +08:00
|
|
|
return WriteoutF;
|
2011-04-16 09:20:23 +08:00
|
|
|
}
|
2012-05-28 14:10:56 +08:00
|
|
|
|
2013-03-19 07:04:39 +08:00
|
|
|
Function *GCOVProfiler::
|
2012-09-13 08:09:55 +08:00
|
|
|
insertFlush(ArrayRef<std::pair<GlobalVariable*, MDNode*> > CountersBySP) {
|
|
|
|
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false);
|
2013-03-19 07:04:39 +08:00
|
|
|
Function *FlushF = M->getFunction("__llvm_gcov_flush");
|
2012-09-13 08:09:55 +08:00
|
|
|
if (!FlushF)
|
|
|
|
FlushF = Function::Create(FTy, GlobalValue::InternalLinkage,
|
2013-03-19 07:04:39 +08:00
|
|
|
"__llvm_gcov_flush", M);
|
2012-09-13 08:09:55 +08:00
|
|
|
else
|
|
|
|
FlushF->setLinkage(GlobalValue::InternalLinkage);
|
2016-06-15 05:01:22 +08:00
|
|
|
FlushF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
2012-12-19 15:18:57 +08:00
|
|
|
FlushF->addFnAttr(Attribute::NoInline);
|
2013-03-14 13:13:26 +08:00
|
|
|
if (Options.NoRedZone)
|
2012-12-19 15:18:57 +08:00
|
|
|
FlushF->addFnAttr(Attribute::NoRedZone);
|
2012-09-13 08:09:55 +08:00
|
|
|
|
|
|
|
BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF);
|
|
|
|
|
|
|
|
// Write out the current counters.
|
2019-02-02 04:43:25 +08:00
|
|
|
Function *WriteoutF = M->getFunction("__llvm_gcov_writeout");
|
2012-09-13 08:09:55 +08:00
|
|
|
assert(WriteoutF && "Need to create the writeout function first!");
|
|
|
|
|
|
|
|
IRBuilder<> Builder(Entry);
|
2015-05-19 06:13:54 +08:00
|
|
|
Builder.CreateCall(WriteoutF, {});
|
2012-09-13 08:09:55 +08:00
|
|
|
|
2012-09-13 22:32:30 +08:00
|
|
|
// Zero out the counters.
|
2016-06-26 20:28:59 +08:00
|
|
|
for (const auto &I : CountersBySP) {
|
|
|
|
GlobalVariable *GV = I.first;
|
2016-01-17 04:30:46 +08:00
|
|
|
Constant *Null = Constant::getNullValue(GV->getValueType());
|
2012-09-15 06:35:49 +08:00
|
|
|
Builder.CreateStore(Null, GV);
|
2012-09-13 22:32:30 +08:00
|
|
|
}
|
2012-09-13 08:09:55 +08:00
|
|
|
|
|
|
|
Type *RetTy = FlushF->getReturnType();
|
|
|
|
if (RetTy == Type::getVoidTy(*Ctx))
|
|
|
|
Builder.CreateRetVoid();
|
|
|
|
else if (RetTy->isIntegerTy())
|
2013-03-19 07:04:39 +08:00
|
|
|
// Used if __llvm_gcov_flush was implicitly declared.
|
2012-09-13 08:09:55 +08:00
|
|
|
Builder.CreateRet(ConstantInt::get(RetTy, 0));
|
|
|
|
else
|
2013-03-19 07:04:39 +08:00
|
|
|
report_fatal_error("invalid return type for __llvm_gcov_flush");
|
|
|
|
|
|
|
|
return FlushF;
|
2012-09-13 08:09:55 +08:00
|
|
|
}
|