aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorJustin Bogner <mail@justinbogner.com>2014-02-04 10:45:02 +0000
committerJustin Bogner <mail@justinbogner.com>2014-02-04 10:45:02 +0000
commitc6af3506980bdd215de3787cd72d6f8c22d57099 (patch)
tree9dcab9f688d94f7fe2a9dd22689b38eae5592664 /llvm
parentad560c4c1170f3c6aee3103279df2566d72e9090 (diff)
downloadllvm-c6af3506980bdd215de3787cd72d6f8c22d57099.zip
llvm-c6af3506980bdd215de3787cd72d6f8c22d57099.tar.gz
llvm-c6af3506980bdd215de3787cd72d6f8c22d57099.tar.bz2
llvm-cov: Implement the preserve-paths flag
Until now, when a path in a gcno file included a directory, we would emit our .gcov file in that directory, whereas gcov always emits the file in the current directory. In doing so, this implements gcov's strange name-mangling -p flag, which is needed to avoid clobbering files when two with the same name exist in different directories. The path mangling is a bit ugly and only handles unix-like paths, but it's simple, and it doesn't make any guesses as to how it should behave outside of what gcov documents. If we decide this should be cross platform later, we can consider the compatibility implications then. llvm-svn: 200754
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/Support/GCOV.h16
-rw-r--r--llvm/lib/IR/GCOV.cpp59
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_-b.output2
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_-f.output2
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_no_gcda.output2
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_no_options.output2
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_no_preserve_paths.output8
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_paths.cpp.gcov79
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_paths.gcdabin0 -> 904 bytes
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_paths.gcnobin0 -> 4476 bytes
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_paths.h.gcov8
-rw-r--r--llvm/test/tools/llvm-cov/Inputs/test_preserve_paths.output8
-rw-r--r--llvm/test/tools/llvm-cov/llvm-cov.test12
-rw-r--r--llvm/tools/llvm-cov/llvm-cov.cpp6
14 files changed, 184 insertions, 20 deletions
diff --git a/llvm/include/llvm/Support/GCOV.h b/llvm/include/llvm/Support/GCOV.h
index 4e7920b..aeac455 100644
--- a/llvm/include/llvm/Support/GCOV.h
+++ b/llvm/include/llvm/Support/GCOV.h
@@ -37,14 +37,15 @@ namespace GCOV {
/// GCOVOptions - A struct for passing gcov options between functions.
struct GCOVOptions {
- GCOVOptions(bool A, bool B, bool C, bool F, bool U) :
- AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), UncondBranch(U)
- {}
+ GCOVOptions(bool A, bool B, bool C, bool F, bool P, bool U)
+ : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
+ PreservePaths(P), UncondBranch(U) {}
bool AllBlocks;
bool BranchInfo;
bool BranchCount;
bool FuncCoverage;
+ bool PreservePaths;
bool UncondBranch;
};
@@ -401,8 +402,13 @@ private:
StringMap<LineData> LineInfo;
uint32_t RunCount;
uint32_t ProgramCount;
- SmallVector<GCOVCoverage, 4> FileCoverages;
- MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverages;
+
+ typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4>
+ FileCoverageList;
+ typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap;
+
+ FileCoverageList FileCoverages;
+ FuncCoverageMap FuncCoverages;
};
}
diff --git a/llvm/lib/IR/GCOV.cpp b/llvm/lib/IR/GCOV.cpp
index 4668281..45ef78e 100644
--- a/llvm/lib/IR/GCOV.cpp
+++ b/llvm/lib/IR/GCOV.cpp
@@ -16,8 +16,10 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GCOV.h"
#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
using namespace llvm;
@@ -429,6 +431,42 @@ static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
return OS;
}
+/// Convert a path to a gcov filename. If PreservePaths is true, this
+/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
+static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
+ if (!PreservePaths)
+ return (sys::path::filename(Filename) + ".gcov").str();
+
+ // This behaviour is defined by gcov in terms of text replacements, so it's
+ // not likely to do anything useful on filesystems with different textual
+ // conventions.
+ llvm::SmallString<256> Result("");
+ StringRef::iterator I, S, E;
+ for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
+ if (*I != '/')
+ continue;
+
+ if (I - S == 1 && *S == '.') {
+ // ".", the current directory, is skipped.
+ } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
+ // "..", the parent directory, is replaced with "^".
+ Result.append("^#");
+ } else {
+ if (S < I)
+ // Leave other components intact,
+ Result.append(S, I);
+ // And separate with "#".
+ Result.push_back('#');
+ }
+ S = I + 1;
+ }
+
+ if (S < I)
+ Result.append(S, I);
+ Result.append(".gcov");
+ return Result.str();
+}
+
/// print - Print source files with collected line count information.
void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) {
for (StringMap<LineData>::const_iterator I = LineInfo.begin(),
@@ -441,9 +479,10 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) {
}
StringRef AllLines = Buff->getBuffer();
- std::string CovFilename = Filename.str() + ".gcov";
+ std::string CoveragePath = mangleCoveragePath(Filename,
+ Options.PreservePaths);
std::string ErrorInfo;
- raw_fd_ostream OS(CovFilename.c_str(), ErrorInfo);
+ raw_fd_ostream OS(CoveragePath.c_str(), ErrorInfo);
if (!ErrorInfo.empty())
errs() << ErrorInfo << "\n";
@@ -555,7 +594,7 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) {
}
}
}
- FileCoverages.push_back(FileCoverage);
+ FileCoverages.push_back(std::make_pair(CoveragePath, FileCoverage));
}
// FIXME: There is no way to detect calls given current instrumentation.
@@ -656,8 +695,8 @@ void FileInfo::printCoverage(const GCOVCoverage &Coverage) const {
// printFuncCoverage - Print per-function coverage info.
void FileInfo::printFuncCoverage() const {
- for (MapVector<const GCOVFunction *, GCOVCoverage>::const_iterator I =
- FuncCoverages.begin(), E = FuncCoverages.end(); I != E; ++I) {
+ for (FuncCoverageMap::const_iterator I = FuncCoverages.begin(),
+ E = FuncCoverages.end(); I != E; ++I) {
const GCOVCoverage &Coverage = I->second;
outs() << "Function '" << Coverage.Name << "'\n";
printCoverage(Coverage);
@@ -667,12 +706,12 @@ void FileInfo::printFuncCoverage() const {
// printFileCoverage - Print per-file coverage info.
void FileInfo::printFileCoverage() const {
- for (SmallVectorImpl<GCOVCoverage>::const_iterator I =
- FileCoverages.begin(), E = FileCoverages.end(); I != E; ++I) {
- const GCOVCoverage &Coverage = *I;
+ for (FileCoverageList::const_iterator I = FileCoverages.begin(),
+ E = FileCoverages.end(); I != E; ++I) {
+ const std::string &Filename = I->first;
+ const GCOVCoverage &Coverage = I->second;
outs() << "File '" << Coverage.Name << "'\n";
printCoverage(Coverage);
- outs() << Coverage.Name << ":creating '" << Coverage.Name
- << ".gcov'\n\n";
+ outs() << Coverage.Name << ":creating '" << Filename << "'\n\n";
}
}
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_-b.output b/llvm/test/tools/llvm-cov/Inputs/test_-b.output
index 4003ce8..515987d 100644
--- a/llvm/test/tools/llvm-cov/Inputs/test_-b.output
+++ b/llvm/test/tools/llvm-cov/Inputs/test_-b.output
@@ -9,5 +9,5 @@ File './test.h'
Lines executed:100.00% of 1
No branches
No calls
-./test.h:creating './test.h.gcov'
+./test.h:creating 'test.h.gcov'
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_-f.output b/llvm/test/tools/llvm-cov/Inputs/test_-f.output
index 9e98d88..d97aa18 100644
--- a/llvm/test/tools/llvm-cov/Inputs/test_-f.output
+++ b/llvm/test/tools/llvm-cov/Inputs/test_-f.output
@@ -34,5 +34,5 @@ test.cpp:creating 'test.cpp.gcov'
File './test.h'
Lines executed:100.00% of 1
-./test.h:creating './test.h.gcov'
+./test.h:creating 'test.h.gcov'
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_no_gcda.output b/llvm/test/tools/llvm-cov/Inputs/test_no_gcda.output
index 69adce2..e994be7 100644
--- a/llvm/test/tools/llvm-cov/Inputs/test_no_gcda.output
+++ b/llvm/test/tools/llvm-cov/Inputs/test_no_gcda.output
@@ -4,5 +4,5 @@ test.cpp:creating 'test.cpp.gcov'
File './test.h'
Lines executed:0.00% of 1
-./test.h:creating './test.h.gcov'
+./test.h:creating 'test.h.gcov'
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_no_options.output b/llvm/test/tools/llvm-cov/Inputs/test_no_options.output
index 93ea726..8be8c1c 100644
--- a/llvm/test/tools/llvm-cov/Inputs/test_no_options.output
+++ b/llvm/test/tools/llvm-cov/Inputs/test_no_options.output
@@ -4,5 +4,5 @@ test.cpp:creating 'test.cpp.gcov'
File './test.h'
Lines executed:100.00% of 1
-./test.h:creating './test.h.gcov'
+./test.h:creating 'test.h.gcov'
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_no_preserve_paths.output b/llvm/test/tools/llvm-cov/Inputs/test_no_preserve_paths.output
new file mode 100644
index 0000000..ada0c36
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_no_preserve_paths.output
@@ -0,0 +1,8 @@
+File 'srcdir/./nested_dir/../test.h'
+Lines executed:100.00% of 1
+srcdir/./nested_dir/../test.h:creating 'test.h.gcov'
+
+File 'srcdir/./nested_dir/../test.cpp'
+Lines executed:84.21% of 38
+srcdir/./nested_dir/../test.cpp:creating 'test.cpp.gcov'
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_paths.cpp.gcov b/llvm/test/tools/llvm-cov/Inputs/test_paths.cpp.gcov
new file mode 100644
index 0000000..3982ddf
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_paths.cpp.gcov
@@ -0,0 +1,79 @@
+ -: 0:Source:srcdir/./nested_dir/../test.cpp
+ -: 0:Graph:test_paths.gcno
+ -: 0:Data:test_paths.gcda
+ -: 0:Runs:3
+ -: 0:Programs:1
+ -: 1:#include "test.h"
+ -: 2:#include <cstdlib>
+ -: 3:
+ -: 4:bool on = false;
+ -: 5:int len = 42;
+ -: 6:double grid[10][10] = {0};
+ -: 7:const char * hello = "world";
+ -: 8:const char * world = "hello";
+ -: 9:
+12884901888: 10:void A::B() {}
+ -: 11:
+ #####: 12:void useless() {}
+ -: 13:
+ -: 14:double more_useless() {
+ #####: 15: return 0;
+ -: 16:}
+ -: 17:
+ -: 18:int foo() {
+ 3: 19: on = true;
+ 3: 20: return 3;
+ -: 21:}
+ -: 22:
+ -: 23:int bar() {
+ #####: 24: len--;
+ #####: 25: return foo() + 45;
+ -: 26:}
+ -: 27:
+ 12: 28:void assign(int ii, int jj) {
+ 12: 29: grid[ii][jj] = (ii+1) * (jj+1);
+ 12: 30:}
+ -: 31:
+ -: 32:void initialize_grid() {
+ 21: 33: for (int ii = 0; ii < 2; ii++)
+ 36: 34: for (int jj = 0; jj < 2; jj++)
+ 18: 35: assign(ii, jj);
+ 3: 36:}
+ -: 37:
+ -: 38:int main() {
+ 3: 39: initialize_grid();
+ -: 40:
+ 3: 41: int a = 2;
+ 3: 42: on = rand() % 2;
+ 3: 43: if (on) {
+ 3: 44: foo();
+ 3: 45: ++a;
+ 3: 46: } else {
+ #####: 47: bar();
+ #####: 48: a += rand();
+ -: 49: }
+ -: 50:
+ 66: 51: for (int ii = 0; ii < 10; ++ii) {
+ 30: 52: switch (rand() % 5) {
+ -: 53: case 0:
+ 6: 54: a += rand();
+ 6: 55: break;
+ -: 56: case 1:
+ -: 57: case 2:
+ 3: 58: a += rand() / rand();
+ 3: 59: break;
+ -: 60: case 3:
+ 9: 61: a -= rand();
+ 9: 62: break;
+ -: 63: default:
+ 12: 64: a = -1;
+ 12: 65: }
+ 30: 66: }
+ -: 67:
+ 3: 68: A thing;
+25769803782: 69: for (uint64_t ii = 0; ii < 4294967296; ++ii)
+12884901888: 70: thing.B();
+ -: 71:
+ 3: 72: return a + 8 + grid[2][3] + len;
+ -: 73: return more_useless();
+ -: 74:}
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_paths.gcda b/llvm/test/tools/llvm-cov/Inputs/test_paths.gcda
new file mode 100644
index 0000000..7e2cf9e
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_paths.gcda
Binary files differ
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_paths.gcno b/llvm/test/tools/llvm-cov/Inputs/test_paths.gcno
new file mode 100644
index 0000000..aada974
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_paths.gcno
Binary files differ
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_paths.h.gcov b/llvm/test/tools/llvm-cov/Inputs/test_paths.h.gcov
new file mode 100644
index 0000000..95e90ca
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_paths.h.gcov
@@ -0,0 +1,8 @@
+ -: 0:Source:srcdir/./nested_dir/../test.h
+ -: 0:Graph:test_paths.gcno
+ -: 0:Data:test_paths.gcda
+ -: 0:Runs:3
+ -: 0:Programs:1
+ 6: 1:struct A {
+ -: 2: virtual void B();
+ -: 3:};
diff --git a/llvm/test/tools/llvm-cov/Inputs/test_preserve_paths.output b/llvm/test/tools/llvm-cov/Inputs/test_preserve_paths.output
new file mode 100644
index 0000000..5331972
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/test_preserve_paths.output
@@ -0,0 +1,8 @@
+File 'srcdir/./nested_dir/../test.h'
+Lines executed:100.00% of 1
+srcdir/./nested_dir/../test.h:creating 'srcdir#nested_dir#^#test.h.gcov'
+
+File 'srcdir/./nested_dir/../test.cpp'
+Lines executed:84.21% of 38
+srcdir/./nested_dir/../test.cpp:creating 'srcdir#nested_dir#^#test.cpp.gcov'
+
diff --git a/llvm/test/tools/llvm-cov/llvm-cov.test b/llvm/test/tools/llvm-cov/llvm-cov.test
index 2391082..c52a981 100644
--- a/llvm/test/tools/llvm-cov/llvm-cov.test
+++ b/llvm/test/tools/llvm-cov/llvm-cov.test
@@ -21,6 +21,18 @@ RUN: llvm-cov -o objdir test.c | diff -u test_no_options.output -
RUN: diff -aub test_objdir.cpp.gcov test.cpp.gcov
RUN: diff -aub test_objdir.h.gcov test.h.gcov
+# Preserve paths. This mangles the output filenames.
+RUN: mkdir -p %t/srcdir/nested_dir
+RUN: cp test.cpp test.h %t/srcdir
+RUN: llvm-cov -p test_paths.cpp | diff -u test_preserve_paths.output -
+RUN: diff -aub test_paths.cpp.gcov srcdir#nested_dir#^#test.cpp.gcov
+RUN: diff -aub test_paths.h.gcov srcdir#nested_dir#^#test.h.gcov
+
+# Don't preserve paths. Same results as preserve paths, but no mangling.
+RUN: llvm-cov test_paths.cpp | diff -u test_no_preserve_paths.output -
+RUN: diff -aub test_paths.cpp.gcov test.cpp.gcov
+RUN: diff -aub test_paths.h.gcov test.h.gcov
+
# Function summaries. This changes stdout, but not the gcov files.
RUN: llvm-cov test.c -f | diff -u test_-f.output -
RUN: diff -aub test_no_options.cpp.gcov test.cpp.gcov
diff --git a/llvm/tools/llvm-cov/llvm-cov.cpp b/llvm/tools/llvm-cov/llvm-cov.cpp
index 61bee43..d7162c4 100644
--- a/llvm/tools/llvm-cov/llvm-cov.cpp
+++ b/llvm/tools/llvm-cov/llvm-cov.cpp
@@ -47,6 +47,10 @@ static cl::opt<std::string> ObjectDir("o", cl::value_desc("DIR"), cl::init(""),
cl::desc("Search for objects in DIR"));
static cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir));
+static cl::opt<bool> PreservePaths("p", cl::init(false),
+ cl::desc("Preserve path components"));
+static cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths));
+
static cl::opt<bool> UncondBranch("u", cl::init(false),
cl::desc("Display unconditional branch info "
"(requires -b)"));
@@ -113,7 +117,7 @@ int main(int argc, char **argv) {
GF.dump();
GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
- UncondBranch);
+ PreservePaths, UncondBranch);
FileInfo FI(Options);
GF.collectLineCounts(FI);
FI.print(InputGCNO, InputGCDA);