[llvm-commits] [llvm] r140712 - in /llvm/trunk/tools: Makefile llvm-cov/ llvm-cov/CMakeLists.txt llvm-cov/GCOVReader.cpp llvm-cov/GCOVReader.h llvm-cov/Makefile llvm-cov/llvm-cov.cpp

Nick Lewycky nlewycky at google.com
Wed Sep 28 18:01:34 PDT 2011


On 28 September 2011 11:50, Devang Patel <dpatel at apple.com> wrote:
> Author: dpatel
> Date: Wed Sep 28 13:50:00 2011
> New Revision: 140712
>
> URL: http://llvm.org/viewvc/llvm-project?rev=140712&view=rev
> Log:
> Introduce llvm-cov.

Cool!!

At a high-level, is there any interest in creating a GCOV data storage
for reading/manipulating/writing? I didn't think anyone would ever
need to write llvm-cov, so I decided to make GCOVProfiling write-only,
but you have types with the same name here.

> Add llvm-cov skeleton. It has initial support to read coverage info generated by GCOVProfiling.cpp.
> Today, you can do
> prompt> clang a.c -ftest-coverage -fprofile-arcs -o a
> prompt> ./a
> prompt> llvm-cov -gcno a.gcno -gcda a.gcda
> a.c
>  :      #include "a.h"
>  :
>  :      int main() {
>  :              int i = 0;
>  :              if (i) {
> 1:                      int j = 0;
> 1:                      j = 1;
> 1:              } else {
>  :                      int k = 1;
>  :                      k = 2;
>  :              }
> 1:              return 0;
>  :      }
>  :
>  :
>
>
>
> Added:
>    llvm/trunk/tools/llvm-cov/
>    llvm/trunk/tools/llvm-cov/CMakeLists.txt
>    llvm/trunk/tools/llvm-cov/GCOVReader.cpp
>    llvm/trunk/tools/llvm-cov/GCOVReader.h
>    llvm/trunk/tools/llvm-cov/Makefile
>    llvm/trunk/tools/llvm-cov/llvm-cov.cpp
> Modified:
>    llvm/trunk/tools/Makefile
>
> Modified: llvm/trunk/tools/Makefile
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/Makefile?rev=140712&r1=140711&r2=140712&view=diff
> ==============================================================================
> --- llvm/trunk/tools/Makefile (original)
> +++ llvm/trunk/tools/Makefile Wed Sep 28 13:50:00 2011
> @@ -26,7 +26,7 @@
>                  lli llvm-extract llvm-mc \
>                  bugpoint llvm-bcanalyzer llvm-stub \
>                  llvm-diff macho-dump llvm-objdump \
> -                llvm-rtdyld llvm-dwarfdump
> +                llvm-rtdyld llvm-dwarfdump llvm-cov
>
>  # Let users override the set of tools to build from the command line.
>  ifdef ONLY_TOOLS
>
> Added: llvm/trunk/tools/llvm-cov/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=140712&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CMakeLists.txt (added)
> +++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Wed Sep 28 13:50:00 2011
> @@ -0,0 +1,6 @@
> +set(LLVM_LINK_COMPONENTS instrumentation )
> +
> +add_llvm_tool(llvm-cov
> +  GCOVReader.cpp
> +  llvm-cov.cpp
> +  )
>
> Added: llvm/trunk/tools/llvm-cov/GCOVReader.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/GCOVReader.cpp?rev=140712&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/GCOVReader.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/GCOVReader.cpp Wed Sep 28 13:50:00 2011
> @@ -0,0 +1,276 @@
> +//===- tools/llvm-cov/GCOVReader.cpp - LLVM coverage tool -----------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// GCOVReader implements the interface to read coverage files that use 'gcov'
> +// format.
> +//
> +//

Extra // line.

> +//===----------------------------------------------------------------------===//
> +
> +#include "GCOVReader.h"
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/OwningPtr.h"

Alphabetize.

> +#include "llvm/Support/MemoryObject.h"
> +#include "llvm/Support/system_error.h"
> +using namespace llvm;
> +
> +//===----------------------------------------------------------------------===//
> +// GCOVFile implementation.
> +
> +/// ~GCOVFile - Delete GCOVFile and its content.
> +GCOVFile::~GCOVFile() {
> +  DeleteContainerPointers(Functions);
> +}
> +
> +/// read - Read GCOV buffer.
> +bool GCOVFile::read(GCOVBuffer &Buffer) {
> +  Format = Buffer.readGCOVFormat();
> +  if (Format == InvalidGCOV)
> +    return false;
> +
> +  unsigned i = 0;
> +  while(1) {

"while(" --> "while (".

> +    GCOVFunction *GFun = NULL;
> +    if(Format == GCDA_402 || Format == GCDA_404) {

"if(" --> "if (".

> +      if (i < Functions.size())
> +       GFun = Functions[i];
> +    } else
> +      GFun = new GCOVFunction();
> +
> +    if (GFun && GFun->read(Buffer, Format)) {
> +      if(Format == GCNO_402 || Format == GCNO_404)

"if(" --> "if (".

> +       Functions.push_back(GFun);
> +    }
> +    else {
> +      delete GFun;
> +      break;
> +    }
> +    ++i;
> +  }

This is a really confusing loop. In concept, I would've liked an outer
loop that does:
  tag = readTag();
  size = readSize();
  switch (tag) {
    case FUNCTION_TAG: ... break;
    case EOF_TAG: return;
    default: skip_block(size);
  }

with additional checks to quit when the EOF was reached (without EOF
tag). However, keeping along the lines of the way it works now, I
think you could do:

  int i = 0;
  while (1) {
    if (i > Functions.size())
      Functions.push_back(NULL);
    GCOVFunction *&GFun = Functions.back();
    if (!GFun) GFun = new GCOVFunction();
    if (!GFun->read(Buffer, Format)) {
      delete GFun;
      GFun = 0;
      return true;
    }
  }

I think that's clearer. Does that work?

> +  return true;
> +}
> +
> +/// dump - Dump GCOVFile content on standard out for debugging purposes.
> +void GCOVFile::dump() {
> +  for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(),
> +        E = Functions.end(); I != E; ++I)
> +    (*I)->dump();
> +}
> +
> +/// collectLineCounts - Collect line counts. This must be used after
> +/// reading .gcno and .gcda files.
> +void GCOVFile::collectLineCounts(FileInfo &FI) {
> +  for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(),
> +        E = Functions.end(); I != E; ++I)
> +    (*I)->collectLineCounts(FI);
> +  FI.print();
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// GCOVFunction implementation.
> +
> +/// ~GCOVFunction - Delete GCOVFunction and its content.
> +GCOVFunction::~GCOVFunction() {
> +  DeleteContainerPointers(Blocks);
> +}
> +
> +/// read - Read a aunction from the buffer. Return false if buffer cursor

Typo: "aunction" --> "function".

> +/// does not point to a function tag.
> +bool GCOVFunction::read(GCOVBuffer &Buff, GCOVFormat Format) {
> +  if (!Buff.readFunctionTag())
> +    return false;
> +
> +  Buff.readInt(); // Function header length
> +  Ident = Buff.readInt();
> +  Buff.readInt(); // Checksum #1
> +  if (Format != GCNO_402)
> +    Buff.readInt(); // Checksum #2
> +
> +  Name = Buff.readString();
> +  if(Format == GCNO_402 || Format == GCNO_404)

"if(" --> "if (".

> +    Filename = Buff.readString();
> +
> +  if(Format == GCDA_402 || Format == GCDA_404) {

"if(" --> "if (".

> +    Buff.readArcTag();
> +    uint32_t Count = Buff.readInt() / 2;
> +    for (unsigned i = 0, e = Count; i != e; ++i) {
> +      Blocks[i]->addCount(Buff.readInt64());
> +    }
> +    return true;;

Bonus semicolon.

> +  }
> +
> +  LineNumber = Buff.readInt();
> +
> +  // read blocks.
> +  assert (Buff.readBlockTag() && "Block Tag not found!");

"assert (" --> "assert(".

> +  uint32_t BlockCount = Buff.readInt();
> +  for (int i = 0, e = BlockCount; i != e; ++i) {
> +    Buff.readInt(); // Block flags;
> +    Blocks.push_back(new GCOVBlock(i));
> +  }
> +
> +  // read edges.
> +  while (Buff.readEdgeTag()) {
> +    uint32_t EdgeCount = (Buff.readInt() - 1) / 2;
> +    uint32_t BlockNo = Buff.readInt();
> +    assert (BlockNo < BlockCount && "Unexpected Block number!");

"assert (" --> "assert(".

> +    for (int i = 0, e = EdgeCount; i != e; ++i) {
> +      Blocks[BlockNo]->addEdge(Buff.readInt());
> +      Buff.readInt(); // Edge flag
> +    }
> +  }
> +
> +  // read line table.
> +  while (Buff.readLineTag()) {
> +    uint32_t LineTableLength = Buff.readInt();
> +    uint32_t Size = Buff.getCursor() + LineTableLength*4;

It's not the size though, that's the EndCursor.

> +    uint32_t BlockNo = Buff.readInt();
> +    assert (BlockNo < BlockCount && "Unexpected Block number!");

"assert (" --> "assert("

> +    GCOVBlock *Block = Blocks[BlockNo];
> +    Buff.readInt(); // flag
> +    while (Buff.getCursor() != (Size - 4)) {
> +      StringRef Filename = Buff.readString();
> +      if (Buff.getCursor() == (Size - 4)) break;
> +      while (uint32_t L = Buff.readInt())
> +       Block->addLine(Filename, L);
> +    }
> +    Buff.readInt(); // flag
> +  }
> +  return true;
> +}
> +
> +/// dump - Dump GCOVFunction content on standard out for debugging purposes.
> +void GCOVFunction::dump() {
> +  outs() <<  "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n";
> +  for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(),
> +        E = Blocks.end(); I != E; ++I)
> +    (*I)->dump();
> +}
> +
> +/// collectLineCounts - Collect line counts. This must be used after
> +/// reading .gcno and .gcda files.
> +void GCOVFunction::collectLineCounts(FileInfo &FI) {
> +  for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(),
> +        E = Blocks.end(); I != E; ++I)
> +    (*I)->collectLineCounts(FI);
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// GCOVBlock implementation.
> +
> +/// ~GCOVBlock - Delete GCOVBlock and its content.
> +GCOVBlock::~GCOVBlock() {
> +  Edges.clear();
> +  DeleteContainerSeconds(Lines);
> +}
> +
> +void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) {
> +  GCOVLines *&LinesForFile = Lines[Filename];
> +  if (!LinesForFile)
> +    LinesForFile = new GCOVLines();
> +  LinesForFile->add(LineNo);
> +}
> +
> +/// collectLineCounts - Collect line counts. This must be used after
> +/// reading .gcno and .gcda files.
> +void GCOVBlock::collectLineCounts(FileInfo &FI) {
> +  for (StringMap<GCOVLines *>::iterator I = Lines.begin(),
> +        E = Lines.end(); I != E; ++I)
> +    I->second->collectLineCounts(FI, I->first(), Counter);
> +}
> +
> +/// dump - Dump GCOVBlock content on standard out for debugging purposes.
> +void GCOVBlock::dump() {
> +  outs() << "Block : " << Number << " Counter : " << Counter << "\n";
> +  if (!Edges.empty()) {
> +    outs() << "\tEdges : ";
> +    for (SmallVector<uint32_t, 16>::iterator I = Edges.begin(), E = Edges.end();
> +        I != E; ++I)
> +      outs() << (*I) << ",";
> +    outs() << "\n";
> +  }
> +  if (!Lines.empty()) {
> +    outs() << "\tLines : ";
> +    for (StringMap<GCOVLines *>::iterator LI = Lines.begin(),
> +          LE = Lines.end(); LI != LE; ++LI) {
> +      outs() << LI->first() << " -> ";
> +      LI->second->dump();
> +      outs() << "\n";
> +    }
> +  }
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// GCOVLines implementation.
> +
> +/// collectLineCounts - Collect line counts. This must be used after
> +/// reading .gcno and .gcda files.
> +void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename,
> +                                 uint32_t Count) {
> +  for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(),
> +        E = Lines.end(); I != E; ++I)
> +    FI.addLineCount(Filename, *I, Count);
> +}
> +
> +/// dump - Dump GCOVLines content on standard out for debugging purposes.
> +void GCOVLines::dump() {
> +  for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(),
> +        E = Lines.end(); I != E; ++I)
> +    outs() << (*I) << ",";
> +}
> +
> +//===----------------------------------------------------------------------===//
> +// FileInfo implementation.
> +
> +/// addLineCount - Add line count for the given line number in a file.
> +void FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint32_t Count) {
> +  if (LineInfo.find(Filename) == LineInfo.end()) {
> +    OwningPtr<MemoryBuffer> Buff;
> +    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
> +      errs() << Filename << ": " << ec.message() << "\n";
> +      return;
> +    }
> +    StringRef AllLines = Buff.take()->getBuffer();
> +    LineCounts L(AllLines.count('\n')+2);
> +    L[Line-1] = Count;
> +    LineInfo[Filename] = L;
> +    return;
> +  }
> +  LineCounts &L = LineInfo[Filename];
> +  L[Line-1] = Count;
> +}
> +
> +/// print -  Print source files with collected line count information.
> +void FileInfo::print() {
> +  for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end();
> +       I != E; ++I) {
> +    StringRef Filename = I->first();
> +    outs() << Filename << "\n";
> +    LineCounts &L = LineInfo[Filename];
> +    OwningPtr<MemoryBuffer> Buff;
> +    if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
> +      errs() << Filename << ": " << ec.message() << "\n";
> +      return;
> +    }
> +    StringRef AllLines = Buff.take()->getBuffer();
> +    for (unsigned i = 0, e = L.size(); i != e; ++i) {
> +      if (L[i])
> +       outs() << L[i] << ":\t";
> +      else
> +       outs() << " :\t";
> +      std::pair<StringRef, StringRef> P = AllLines.split('\n');
> +      if (AllLines != P.first)
> +       outs() << P.first;
> +      outs() << "\n";
> +      AllLines = P.second;
> +    }
> +  }
> +}
> +
> +
>
> Added: llvm/trunk/tools/llvm-cov/GCOVReader.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/GCOVReader.h?rev=140712&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/GCOVReader.h (added)
> +++ llvm/trunk/tools/llvm-cov/GCOVReader.h Wed Sep 28 13:50:00 2011
> @@ -0,0 +1,225 @@
> +//===-- tools/cov/GCOVReader.h - LLVM coverage tool -------------*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This header provides the interface to read coverage files that use 'gcov'
> +// format.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef GCOVREADER_H
> +#define GCOVREADER_H

Optional: LLVMCOV_GCOVREADER_H.

> +
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringMap.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +namespace llvm {
> +
> +class GCOVFunction;
> +class GCOVBlock;
> +class GCOVLines;
> +class FileInfo;
> +
> +enum GCOVFormat {
> +  InvalidGCOV,
> +  GCNO_402,
> +  GCNO_404,
> +  GCDA_402,
> +  GCDA_404
> +};
> +
> +/// GCOVBuffer - A wrapper around MemoryBuffer to provid GCOV specific

Typo, "provid" -> "provide".

> +/// read operations.
> +class GCOVBuffer {
> +public:
> +  GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
> +
> +  /// readGCOVFormat - Read GCOV signature at the beginning of buffer.
> +  enum GCOVFormat readGCOVFormat() {
> +    StringRef Magic = Buffer->getBuffer().slice(0, 12);
> +    Cursor = 12;
> +    if (Magic == "oncg*404MVLL")
> +      return GCNO_404;
> +    else if (Magic == "oncg*204MVLL")
> +      return GCNO_402;
> +    else if (Magic == "adcg*404MVLL")
> +      return GCDA_404;
> +    else if (Magic == "adcg*204MVLL")
> +      return GCDA_402;

Do we really want to check the "LLVM" part? With this, we can't read
GCC-produced .gcov files, and that really limits how useful this code
can ever be. In particular, we can't test it against gcc-generated
gcov files.

> +
> +    Cursor = 0;
> +    return InvalidGCOV;
> +  }
> +
> +  /// readFunctionTag - If cursor points to a function tag then increment the
> +  /// cursor and return true otherwise return false.
> +  bool readFunctionTag() {
> +    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    if (Tag.empty() ||
> +       Tag[0] != '\0' || Tag[1] != '\0' ||
> +       Tag[2] != '\0' || Tag[3] != '\1') {
> +      return false;
> +    }
> +    Cursor += 4;
> +    return true;
> +  }
> +
> +  /// readBlockTag - If cursor points to a block tag then increment the
> +  /// cursor and return true otherwise return false.
> +  bool readBlockTag() {
> +    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    if (Tag.empty() ||
> +       Tag[0] != '\0' || Tag[1] != '\0' ||
> +       Tag[2] != '\x41' || Tag[3] != '\x01') {
> +      return false;
> +    }
> +    Cursor += 4;
> +    return true;
> +  }
> +
> +  /// readEdgeTag - If cursor points to an edge tag then increment the
> +  /// cursor and return true otherwise return false.
> +  bool readEdgeTag() {
> +    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    if (Tag.empty() ||
> +       Tag[0] != '\0' || Tag[1] != '\0' ||
> +       Tag[2] != '\x43' || Tag[3] != '\x01') {
> +      return false;
> +    }
> +    Cursor += 4;
> +    return true;
> +  }
> +
> +  /// readLineTag - If cursor points to a line tag then increment the
> +  /// cursor and return true otherwise return false.
> +  bool readLineTag() {
> +    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    if (Tag.empty() ||
> +       Tag[0] != '\0' || Tag[1] != '\0' ||
> +       Tag[2] != '\x45' || Tag[3] != '\x01') {
> +      return false;
> +    }
> +    Cursor += 4;
> +    return true;
> +  }
> +
> +  /// readArcTag - If cursor points to an gcda arc tag then increment the
> +  /// cursor and return true otherwise return false.
> +  bool readArcTag() {
> +    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    if (Tag.empty() ||
> +       Tag[0] != '\0' || Tag[1] != '\0' ||
> +       Tag[2] != '\xa1' || Tag[3] != '\1') {
> +      return false;
> +    }
> +    Cursor += 4;
> +    return true;
> +  }

Why not readTag which returns an enum for what type of tag it saw? In
any case, these functions are too similar to not be refactored.

> +
> +  uint32_t readInt() {
> +    uint32_t Result;
> +    StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
> +    assert (Str.empty() == false && "Unexpected memory buffer end!");

"assert (" --> "assert(".

> +    Cursor += 4;
> +    Result = *(uint32_t *)(Str.data());
> +    return Result;
> +  }
> +
> +  uint64_t readInt64() {
> +    uint64_t Lo = readInt();
> +    uint64_t Hi = readInt();
> +    uint64_t Result = Lo | (Hi << 32);
> +    return Result;
> +  }
> +
> +  StringRef readString() {
> +    uint32_t Len = readInt() * 4;
> +    StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+Len);
> +    Cursor += Len;
> +    return Str;
> +  }
> +
> +  uint64_t getCursor() const { return Cursor; }
> +private:
> +  MemoryBuffer *Buffer;
> +  uint64_t Cursor;
> +};
> +
> +/// GCOVFile - Collects file information.

It collects *source* file information. One GCOVFile is the combination
of both the .gcno and the .gcda...

> +class GCOVFile {
> +public:
> +  GCOVFile() : Format(InvalidGCOV) {}
> +  ~GCOVFile();
> +  bool read(GCOVBuffer &Buffer);
> +  void dump();
> +  void collectLineCounts(FileInfo &FI);
> +private:
> +  enum GCOVFormat Format;

...but, it stores a single format even though read() is supposed to
take either/both the GCNO and GCDA. As far as I can tell, Format can
be hoisted into being a local variable inside read(), because that's
the only method that uses it.

> +  SmallVector<GCOVFunction *, 16> Functions;
> +};
> +
> +/// GCOVFunction - Collects function information.
> +class GCOVFunction {
> +public:
> +  GCOVFunction() : Ident(0), LineNumber(0) {}
> +  ~GCOVFunction();
> +  bool read(GCOVBuffer &Buffer, GCOVFormat Format);
> +  void dump();
> +  void collectLineCounts(FileInfo &FI);
> +private:
> +  uint32_t Ident;
> +  uint32_t LineNumber;
> +  StringRef Name;
> +  StringRef Filename;
> +  SmallVector<GCOVBlock *, 16> Blocks;
> +};
> +
> +/// GCOVBlock - Collects block information.
> +class GCOVBlock {
> +public:
> +  GCOVBlock(uint32_t N) : Number(N), Counter(0) {}
> +  ~GCOVBlock();
> +  void addEdge(uint32_t N) { Edges.push_back(N); }
> +  void addLine(StringRef Filename, uint32_t LineNo);
> +  void addCount(uint64_t N) { Counter = N; }
> +  void dump();
> +  void collectLineCounts(FileInfo &FI);
> +private:
> +  uint32_t Number;
> +  uint64_t Counter;
> +  SmallVector<uint32_t, 16> Edges;
> +  StringMap<GCOVLines *> Lines;
> +};
> +
> +/// GCOVLines - A wrapper around a vector of int to keep track of line nos.
> +class GCOVLines {
> +public:
> +  ~GCOVLines() { Lines.clear(); }
> +  void add(uint32_t N) { Lines.push_back(N); }
> +  void collectLineCounts(FileInfo &FI, StringRef Filename, uint32_t Count);
> +  void dump();
> +
> +private:
> +  SmallVector<uint32_t, 4> Lines;
> +};
> +
> +typedef SmallVector<uint32_t, 16> LineCounts;
> +class FileInfo {
> +public:
> +  void addLineCount(StringRef Filename, uint32_t Line, uint32_t Count);
> +  void print();
> +private:
> +  StringMap<LineCounts> LineInfo;
> +};
> +
> +

Extra newline.

> +}
> +
> +#endif
>
> Added: llvm/trunk/tools/llvm-cov/Makefile
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/Makefile?rev=140712&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/Makefile (added)
> +++ llvm/trunk/tools/llvm-cov/Makefile Wed Sep 28 13:50:00 2011
> @@ -0,0 +1,18 @@
> +##===- tools/llvm-gcov/Makefile ----------------------------*- Makefile -*-===##

"llvm-gcov" --> "llvm-cov" to match the directory it's in now.

> +#
> +#                     The LLVM Compiler Infrastructure
> +#
> +# This file is distributed under the University of Illinois Open Source
> +# License. See LICENSE.TXT for details.
> +#
> +##===----------------------------------------------------------------------===##
> +
> +LEVEL = ../..
> +
> +TOOLNAME = llvm-cov
> +LINK_COMPONENTS := instrumentation
> +
> +# This tool has no plugins, optimize startup time.
> +TOOL_NO_EXPORTS = 1
> +
> +include $(LEVEL)/Makefile.common
>
> Added: llvm/trunk/tools/llvm-cov/llvm-cov.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/llvm-cov.cpp?rev=140712&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/llvm-cov.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/llvm-cov.cpp Wed Sep 28 13:50:00 2011
> @@ -0,0 +1,83 @@
> +//===- tools/llvm-cov/llvm-cov.cpp - LLVM coverage tool -------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +//
> +// llvm-cov is a command line tools to analyze and report coverage information.
> +//
> +//

Extra "//" line before and after.

> +//===----------------------------------------------------------------------===//
> +
> +#include "GCOVReader.h"
> +#include "llvm/ADT/OwningPtr.h"
> +#include "llvm/Support/CommandLine.h"
> +#include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/MemoryObject.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include "llvm/Support/Signals.h"
> +#include "llvm/Support/system_error.h"
> +using namespace llvm;
> +
> +static cl::opt<bool>
> +DumpGCOV("dump", cl::init(false), cl::desc("dump gcov file"));
> +
> +static cl::opt<std::string>
> +InputGCNO("gcno", cl::desc("<input gcno file>"), cl::init(""));
> +
> +static cl::opt<std::string>
> +InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init(""));
> +
> +
> +//===----------------------------------------------------------------------===//
> +int main(int argc, char **argv) {
> +  // Print a stack trace if we signal out.
> +  sys::PrintStackTraceOnErrorSignal();
> +  PrettyStackTraceProgram X(argc, argv);
> +  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
> +
> +  cl::ParseCommandLineOptions(argc, argv, "llvm cov\n");
> +
> +

Extra newline.

> +  GCOVFile GF;
> +  if (InputGCNO.empty())
> +    errs() << " " << argv[0] << ": No gcov input file!\n";
> +
> +  OwningPtr<MemoryBuffer> Buff;
> +  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCNO, Buff)) {
> +    errs() << InputGCNO << ": " << ec.message() << "\n";
> +    return 1;
> +  }
> +  GCOVBuffer GB(Buff.take());

Would you mind naming Buff and GB in a way that indicates they're the
ones for GCNO? And similarly for Buff2 and GB2 being named related to
GCDA?

> +
> +  if (!GF.read(GB)) {
> +    errs() << "Invalid .gcno File!\n";
> +    return 1;
> +  }
> +
> +  if (!InputGCDA.empty()) {
> +    OwningPtr<MemoryBuffer> Buff2;
> +    if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, Buff2)) {
> +      errs() << InputGCDA << ": " << ec.message() << "\n";
> +      return 1;
> +    }
> +    GCOVBuffer GB2(Buff2.take());
> +
> +    if (!GF.read(GB2)) {
> +      errs() << "Invalid .gcda File!\n";
> +      return 1;
> +    }
> +  }
> +
> +

Extra newline.

> +  if (DumpGCOV)
> +    GF.dump();
> +
> +  FileInfo FI;
> +  GF.collectLineCounts(FI);
> +  return 0;
> +}




More information about the llvm-commits mailing list