[llvm] r187213 - Add preliminary support for hashing DIEs and breaking them into

David Blaikie dblaikie at gmail.com
Fri Jul 26 11:17:04 PDT 2013


On Fri, Jul 26, 2013 at 10:02 AM, Eric Christopher <echristo at gmail.com> wrote:
> Author: echristo
> Date: Fri Jul 26 12:02:41 2013
> New Revision: 187213
>
> URL: http://llvm.org/viewvc/llvm-project?rev=187213&view=rev
> Log:
> Add preliminary support for hashing DIEs and breaking them into
> type units.
>
> Initially this support is used in the computation of an ODR checker
> for C++. For now we're attaching it to the DIE, but in the future
> it will be attached to the type unit.
>
> This also starts breaking out types into the separation for type
> units, but without actually splitting the DIEs.
>
> In preparation for hashing the DIEs this adds a DIEString type
> that contains a StringRef with the string contained at the label.
>
> Added:
>     llvm/trunk/test/DebugInfo/generate-odr-hash.ll
> Modified:
>     llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp
>     llvm/trunk/lib/CodeGen/AsmPrinter/DIE.h
>     llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
>     llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
>     llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp?rev=187213&r1=187212&r2=187213&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIE.cpp Fri Jul 26 12:02:41 2013
> @@ -24,6 +24,7 @@
>  #include "llvm/Support/ErrorHandling.h"
>  #include "llvm/Support/Format.h"
>  #include "llvm/Support/FormattedStream.h"
> +#include "llvm/Support/MD5.h"
>  using namespace llvm;
>
>  //===----------------------------------------------------------------------===//
> @@ -322,6 +323,29 @@ void DIEDelta::print(raw_ostream &O) con
>  }
>  #endif
>
> +//===----------------------------------------------------------------------===//
> +// DIEString Implementation
> +//===----------------------------------------------------------------------===//
> +
> +/// EmitValue - Emit string value.
> +///
> +void DIEString::EmitValue(AsmPrinter *AP, unsigned Form) const {
> +  Access->EmitValue(AP, Form);
> +}
> +
> +/// SizeOf - Determine size of delta value in bytes.
> +///
> +unsigned DIEString::SizeOf(AsmPrinter *AP, unsigned Form) const {
> +  return Access->SizeOf(AP, Form);
> +}
> +
> +#ifndef NDEBUG
> +void DIEString::print(raw_ostream &O) const {
> +  O << "String: " << Str << "\tSymbol: ";
> +  Access->print(O);
> +}
> +#endif
> +
>  //===----------------------------------------------------------------------===//
>  // DIEEntry Implementation
>  //===----------------------------------------------------------------------===//
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DIE.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DIE.h?rev=187213&r1=187212&r2=187213&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DIE.h (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DIE.h Fri Jul 26 12:02:41 2013
> @@ -346,6 +346,36 @@ namespace llvm {
>    };
>
>    //===--------------------------------------------------------------------===//
> +  /// DIEString - A container for string values.
> +  ///
> +  class DIEString : public DIEValue {

The addition of DIEString probably could've been a separate commit,
but it's fairly non-invasive anyway.

> +    const DIEValue *Access;
> +    const StringRef Str;
> +
> +  public:
> +    DIEString(const DIEValue *Acc, const StringRef S)
> +        : DIEValue(isString), Access(Acc), Str(S) {}
> +
> +    /// getString - Grab the string out of the object.
> +    StringRef getString() const { return Str; }
> +
> +    /// EmitValue - Emit delta value.
> +    ///
> +    virtual void EmitValue(AsmPrinter *AP, unsigned Form) const;
> +
> +    /// SizeOf - Determine size of delta value in bytes.
> +    ///
> +    virtual unsigned SizeOf(AsmPrinter *AP, unsigned Form) const;
> +
> +    // Implement isa/cast/dyncast.
> +    static bool classof(const DIEValue *D) { return D->getType() == isString; }
> +
> +  #ifndef NDEBUG
> +    virtual void print(raw_ostream &O) const;
> +  #endif
> +  };
> +
> +  //===--------------------------------------------------------------------===//
>    /// DIEEntry - A pointer to another debug information entry.  An instance of
>    /// this class can also be used as a proxy for a debug information entry not
>    /// yet defined (ie. types.)
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp?rev=187213&r1=187212&r2=187213&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp Fri Jul 26 12:02:41 2013
> @@ -132,21 +132,24 @@ void CompileUnit::addSInt(DIE *Die, unsi
>  /// into another table which gets us the static offset into the string
>  /// table.
>  void CompileUnit::addString(DIE *Die, unsigned Attribute, StringRef String) {
> +  DIEValue *Value;
> +  unsigned Form;
>    if (!DD->useSplitDwarf()) {
>      MCSymbol *Symb = DU->getStringPoolEntry(String);
> -    DIEValue *Value;
>      if (Asm->needsRelocationsForDwarfStringPool())
>        Value = new (DIEValueAllocator) DIELabel(Symb);
>      else {
>        MCSymbol *StringPool = DU->getStringPoolSym();
>        Value = new (DIEValueAllocator) DIEDelta(Symb, StringPool);
>      }
> -    Die->addValue(Attribute, dwarf::DW_FORM_strp, Value);
> +    Form = dwarf::DW_FORM_strp;
>    } else {
>      unsigned idx = DU->getStringPoolIndex(String);
> -    DIEValue *Value = new (DIEValueAllocator) DIEInteger(idx);
> -    Die->addValue(Attribute, dwarf::DW_FORM_GNU_str_index, Value);
> +    Value = new (DIEValueAllocator) DIEInteger(idx);
> +    Form = dwarf::DW_FORM_GNU_str_index;
>    }
> +  DIEValue *Str = new (DIEValueAllocator) DIEString(Value, String);
> +  Die->addValue(Attribute, Form, Str);
>  }
>
>  /// addLocalString - Add a string attribute data and value. This is guaranteed
> @@ -878,6 +881,39 @@ void CompileUnit::constructTypeDIE(DIE &
>      addSourceLine(&Buffer, DTy);
>  }
>
> +/// Return true if the type is appropriately scoped to be contained inside
> +/// its own type unit.
> +static bool isTypeUnitScoped(DIType Ty) {

I wonder whether there would be a way to do this by querying the
underlying clang::Type to test the same property (would probably be
more efficient & not require the slightly problematic
DIScope::getContext)

> +  DIScope Parent = Ty.getContext();
> +  while (Parent) {

Could probably write this as:
DIScope Parent = Ty;
while ((Parent = Parent.getContext()))

Probably not actually /better/ as such (& maybe one day we'll want to
be a bit more specific about just which DITypes are DIScopes, rather
than having them all), just an idle thought.

> +    // Don't generate a hash for anything scoped inside a function.
> +    if (Parent.isSubprogram())
> +      return false;
> +    Parent = Parent.getContext();
> +  }
> +  return true;
> +}
> +
> +/// Return true if the type should be split out into a type unit.
> +static bool shouldCreateTypeUnit(DICompositeType CTy) {
> +  unsigned Tag = CTy.getTag();
> +
> +  switch (Tag) {
> +  case dwarf::DW_TAG_structure_type:
> +  case dwarf::DW_TAG_union_type:
> +  case dwarf::DW_TAG_enumeration_type:
> +  case dwarf::DW_TAG_class_type:
> +    // If this is a class, structure, union, or enumeration type
> +    // that is not a declaration, is a type definition, and not scoped
> +    // inside a function then separate this out as a type unit.
> +    if (CTy.isForwardDecl() || !isTypeUnitScoped(CTy))
> +      return 0;
> +    return 1;
> +  default:
> +    return 0;
> +  }
> +}
> +
>  /// constructTypeDIE - Construct type DIE from DICompositeType.
>  void CompileUnit::constructTypeDIE(DIE &Buffer, DICompositeType CTy) {
>    // Get core information.
> @@ -1075,6 +1111,10 @@ void CompileUnit::constructTypeDIE(DIE &
>        addUInt(&Buffer, dwarf::DW_AT_APPLE_runtime_class,
>                dwarf::DW_FORM_data1, RLang);
>    }
> +  // If this is a type applicable to a type unit it then add it to the
> +  // list of types we'll compute a hash for later.
> +  if (shouldCreateTypeUnit(CTy))
> +    DD->addTypeUnitType(&Buffer);
>  }
>
>  /// getOrCreateTemplateTypeParameterDIE - Find existing DIE or create new DIE
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=187213&r1=187212&r2=187213&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Fri Jul 26 12:02:41 2013
> @@ -36,6 +36,7 @@
>  #include "llvm/Support/Debug.h"
>  #include "llvm/Support/ErrorHandling.h"
>  #include "llvm/Support/FormattedStream.h"
> +#include "llvm/Support/MD5.h"
>  #include "llvm/Support/Path.h"
>  #include "llvm/Support/Timer.h"
>  #include "llvm/Support/ValueHandle.h"
> @@ -60,6 +61,11 @@ GenerateDwarfPubNamesSection("generate-d
>                               cl::init(false),
>                               cl::desc("Generate DWARF pubnames section"));
>
> +static cl::opt<bool>
> +GenerateODRHash("generate-odr-hash", cl::Hidden,
> +                cl::desc("Add an ODR hash to external type DIEs."),
> +                cl::init(false));
> +
>  namespace {
>  enum DefaultOnOff {
>    Default,
> @@ -956,6 +962,135 @@ void DwarfDebug::collectDeadVariables()
>    DeleteContainerSeconds(DeadFnScopeMap);
>  }
>
> +// Type Signature computation code.
> +typedef ArrayRef<uint8_t> HashValue;
> +
> +/// \brief Grabs the string in whichever attribute is passed in and returns
> +/// a reference to it.
> +static StringRef getDIEStringAttr(DIE *Die, unsigned Attr) {
> +  const SmallVectorImpl<DIEValue *> &Values = Die->getValues();
> +  const DIEAbbrev &Abbrevs = Die->getAbbrev();
> +
> +  // Iterate through all the attributes until we find the one we're
> +  // looking for, if we can't find it return an empty string.
> +  for (size_t i = 0; i < Values.size(); ++i) {
> +    if (Abbrevs.getData()[i].getAttribute() == Attr) {
> +      DIEValue *V = Values[i];
> +      assert(isa<DIEString>(V) && "String requested. Not a string.");
> +      DIEString *S = cast<DIEString>(V);
> +      return S->getString();
> +    }
> +  }
> +  return StringRef("");

return ""; should be fine, or return StringRef(); (StringRef has no
"null" state so far as I know - just zero-length)

> +}
> +
> +/// \brief Adds the string in \p Str to the hash in \p Hash. This also hashes
> +/// a trailing NULL with the string.
> +static void addStringToHash(MD5 &Hash, StringRef Str) {
> +  DEBUG(dbgs() << "Adding string " << Str << " to hash.\n");
> +  HashValue SVal((const uint8_t *)Str.data(), Str.size());
> +  const uint8_t NB = '\0';
> +  HashValue NBVal((const uint8_t *)&NB, 1);
> +  Hash.update(SVal);
> +  Hash.update(NBVal);
> +}
> +
> +/// \brief Adds the character string in \p Str to the hash in \p Hash. This does
> +/// not hash a trailing NULL on the character.
> +static void addLetterToHash(MD5 &Hash, StringRef Str) {

Seems like a strange name for it - since a StringRef contains things
other than letters and contains more or less than one letter...

Also wondering whether having StringRef APIs for hash would make sense
since these two utility functions (at least the "hash the bytes of
this StringRef") seem like pretty common/basic functionality, having
to go through c-style casts to use them seems a bit lame.

I would expect:
Hash.Update(Str);
Hash.Update('\0');

for the "addStringToHash" (& would call it
"addNullTerminatedStringToHash" or just write those two lines wherever
it matters - it's probably easier to eyeball the fact that it's null
terminating with those two lines than to pick a sufficiently
descriptive function name)

& omit this addLetterToHash function entirely in favor of an update
function that takes a StringRef (or, if it's really not the purview of
the MD5 class to ever consider characters, maybe a free function
update(MD5&, StringRef) in a more general place)

This comes back to hash API design - didn't Chandler have some
proto-C++-standardizable hash API (with function or operator
overloading extensibility to allow for hashing of more/new/different
things). Any reason MD5 wouldn't fit into that? (I vaguely remember
mentioning this before, but don't recall the answer)

> +  DEBUG(dbgs() << "Adding letter " << Str << " to hash.\n");
> +  assert(Str.size() == 1 && "Trying to add a too large letter?");
> +  HashValue SVal((const uint8_t *)Str.data(), Str.size());
> +  Hash.update(SVal);
> +}
> +
> +// FIXME: These are copied and only slightly modified out of LEB128.h.

What's the slight modification? What sort of work will be involved in
generalizing the two uses so they can use common code?

> +
> +/// \brief Adds the unsigned in \p N to the hash in \p Hash. This also encodes
> +/// the unsigned as a ULEB128.
> +static void addULEB128ToHash(MD5 &Hash, uint64_t Value) {
> +  DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n");
> +  do {
> +    uint8_t Byte = Value & 0x7f;
> +    Value >>= 7;
> +    if (Value != 0)
> +      Byte |= 0x80; // Mark this byte to show that more bytes will follow.
> +    Hash.update(Byte);
> +  } while (Value != 0);
> +}
> +
> +/// \brief Including \p Parent adds the context of Parent to \p Hash.
> +static void addParentContextToHash(MD5 &Hash, DIE *Parent) {
> +  unsigned Tag = Parent->getTag();
> +
> +  DEBUG(dbgs() << "Adding parent context to hash...\n");
> +
> +  // For each surrounding type or namespace...

What surrounding things can we expect that aren't namespaces and types?

> +  if (Tag != dwarf::DW_TAG_namespace && Tag != dwarf::DW_TAG_class_type &&
> +      Tag != dwarf::DW_TAG_structure_type)
> +    return;
> +
> +  // ... beginning with the outermost such construct...
> +  if (Parent->getParent() != NULL)
> +    addParentContextToHash(Hash, Parent->getParent());

I'd sort of rather a loop than a recursion, though I realize the
recursion won't be terribly deep.

> +
> +  // Append the letter "C" to the sequence.

No real explanation as to why "C" (I guess 'Context') but if these are
quotes from the DWARF standard, a reference to the chapter/verse at
the start of the sequence of comments would be nice.

> +  addLetterToHash(Hash, "C");
> +
> +  // Followed by the DWARF tag of the construct.
> +  addULEB128ToHash(Hash, Parent->getTag());
> +
> +  // Then the name, taken from the DW_AT_name attribute.
> +  StringRef Name = getDIEStringAttr(Parent, dwarf::DW_AT_name);
> +  if (!Name.empty())
> +    addStringToHash(Hash, Name);

Did we want to push-back any on the issue of hashing null terminators?
That's presumably going to lower the entropy of the hash input
somewhat & not really add anything. I guess it was just a convenience
in GCC that lead to this being the chosen thing to do?

> +}
> +
> +/// This is based on the type signature computation given in section 7.27 of the
> +/// DWARF4 standard. It is the md5 hash of a flattened description of the DIE.
> +static void addDIEODRSignature(MD5 &Hash, CompileUnit *CU, DIE *Die) {
> +
> +  // Add the contexts to the hash.
> +  DIE *Parent = Die->getParent();
> +  if (Parent)

Generally we put the variable in the condition like this:

if (DIE *Parent = Die->getParent())

to reduce scope.

> +    addParentContextToHash(Hash, Parent);
> +
> +  // Add the current DIE information.
> +
> +  // Add the DWARF tag of the DIE.
> +  addULEB128ToHash(Hash, Die->getTag());
> +
> +  // Add the name of the type to the hash.
> +  addStringToHash(Hash, getDIEStringAttr(Die, dwarf::DW_AT_name));

Rather than searching for names repeatedly (do we need to search for
other attributes by name?) would it be worth caching that attribute
specifically in the DIE? (just have a DIEString pointer in the DIE
specifically for the name) Probably not, I guess.

> +
> +  // Now get the result.
> +  MD5::MD5Result Result;
> +  Hash.final(Result);

Weird name for the function - shoudln't it be a verb?

> +
> +  // ... take the least significant 8 bytes and store those as the attribute.
> +  uint64_t Signature;
> +  memcpy(&Signature, &Result[8], 8);

Any discussion on this with the DWARF committee? I assume computing a
big hash & then just taking some of the bytes isn't really the best
way to use a hashing algorithm.

> +
> +  // FIXME: This should be added onto the type unit, not the type, but this
> +  // works as an intermediate stage.
> +  CU->addUInt(Die, dwarf::DW_AT_GNU_odr_signature, dwarf::DW_FORM_data8,
> +              Signature);
> +}
> +
> +/// Return true if the current DIE is contained within an anonymous namespace.
> +static bool isContainedInAnonNamespace(DIE *Die) {
> +  DIE *Parent = Die->getParent();
> +
> +  while (Parent) {
> +    if (Die->getTag() == dwarf::DW_TAG_namespace &&
> +        getDIEStringAttr(Die, dwarf::DW_AT_name) == "")

Should we be representing anonymous namespaces with no name attribute
at all rather than a zero-length string...

Oh, but maybe we are & that's how you're returning invalid from
getDIEStringAttr. Hrm. Personally I kind of like the difference
between "empty string" (which I rarely think should be a special case)
and "no string at all", but I know not everyone agrees & lots of
people are perfectly happy for "empty string" and "no string at all"
to be the same thing. (I certainly don't like "no string at all" to be
built in to string types like StringRef - but instead prefer it to be
added orthogonally with Optional<StringRef> or similar)

> +      return true;
> +    Parent = Parent->getParent();
> +  }
> +
> +  return false;
> +}
> +
>  void DwarfDebug::finalizeModuleInfo() {
>    // Collect info for variables that were optimized out.
>    collectDeadVariables();
> @@ -971,6 +1106,20 @@ void DwarfDebug::finalizeModuleInfo() {
>      TheCU->constructContainingTypeDIEs();
>    }
>
> +  // For types that we'd like to move to type units or ODR check go ahead
> +  // and either move the types out or add the ODR attribute now.
> +  // FIXME: Do type splitting.
> +  for (unsigned i = 0, e = TypeUnits.size(); i != e; ++i) {
> +    MD5 Hash;
> +    DIE *Die = TypeUnits[i];
> +    // If we're in C++ and we want to generate the hash then go ahead and do
> +    // that now.

That phrasing leads to the question "And if we're not in C++ and want
to generate a hash?" - my understanding is that we never want to
generate a hash when we're not in C++ (because C has no ODR-like
thing), but the comment reads a bit oddly if that's the intent. Not
sure of the right wording yet.

> +    if (GenerateODRHash &&
> +        CUMap.begin()->second->getLanguage() == dwarf::DW_LANG_C_plus_plus &&
> +        !isContainedInAnonNamespace(Die))
> +      addDIEODRSignature(Hash, CUMap.begin()->second, Die);
> +  }
> +
>     // Compute DIE offsets and sizes.
>    InfoHolder.computeSizeAndOffsets();
>    if (useSplitDwarf())
>
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h?rev=187213&r1=187212&r2=187213&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h Fri Jul 26 12:02:41 2013
> @@ -428,6 +428,9 @@ class DwarfDebug {
>      ImportedEntityMap;
>    ImportedEntityMap ScopesWithImportedEntities;
>
> +  // Holder for types that are going to be extracted out into a type unit.
> +  std::vector<DIE *> TypeUnits;
> +
>    // DWARF5 Experimental Options
>    bool HasDwarfAccelTables;
>    bool HasSplitDwarf;
> @@ -651,6 +654,10 @@ public:
>    /// \brief Process end of an instruction.
>    void endInstruction(const MachineInstr *MI);
>
> +  /// \brief Add a DIE to the set of types that we're going to pull into
> +  /// type units.
> +  void addTypeUnitType(DIE *Die) { TypeUnits.push_back(Die); }
> +
>    /// \brief Look up the source id with the given directory and source file
>    /// names. If none currently exists, create a new id and insert it in the
>    /// SourceIds map.
>
> Added: llvm/trunk/test/DebugInfo/generate-odr-hash.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/generate-odr-hash.ll?rev=187213&view=auto
> ==============================================================================
> --- llvm/trunk/test/DebugInfo/generate-odr-hash.ll (added)
> +++ llvm/trunk/test/DebugInfo/generate-odr-hash.ll Fri Jul 26 12:02:41 2013
> @@ -0,0 +1,116 @@
> +; REQUIRES: object-emission
> +
> +; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash
> +; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
> +;
> +; Generated from:
> +;
> +; struct bar {};
> +; struct bar b;

Weird to use a prefix on a variable declaration in C++ code (ie: use
"bar b;" rather than "struct bar b;").

> +; void foo(void) {
> +;   struct baz {};
> +;   baz b;
> +; }
> +; namespace echidna {
> +; namespace capybara {
> +; namespace mongoose {

Got a little bored trying to find namespace names? There are lists of
metasyntactic variables to call on you know ;) (also, sometimes we use
a top-level namespace "test1", "test2", etc to separate test cases &
avoid their names polluting each other - though adding namespaces
isn't an irrelevant change in this test case)

> +; class fluffy {
> +;   int a;
> +;   int b;
> +; };
> +; fluffy animal;
> +; }
> +; }
> +; }
> +; namespace {
> +; struct walrus {};
> +; }
> +; walrus w;
> +
> +; Check that we generate a hash for bar, that it is a particular value and
> +; that we don't generate a hash for baz or walrus.

Mightn't hurt to briefly explain /why/ we should/shouldn't have a hash
for each case.

> +; CHECK: DW_TAG_structure_type
> +; CHECK-NEXT: debug_str{{.*}}"bar"
> +; CHECK: DW_AT_GNU_odr_signature [DW_FORM_data8] (0x200520c0d5b90eff)
> +; CHECK: DW_TAG_namespace
> +; CHECK-NEXT: debug_str{{.*}}"echidna"
> +; CHECK: DW_TAG_namespace
> +; CHECK-NEXT: debug_str{{.*}}"capybara"
> +; CHECK: DW_TAG_namespace
> +; CHECK-NEXT: debug_str{{.*}}"mongoose"
> +; CHECK: DW_TAG_class_type
> +; CHECK-NEXT: debug_str{{.*}}"fluffy"
> +; CHECK: DW_AT_GNU_odr_signature [DW_FORM_data8]   (0x9a0124d5a0c21c52)
> +; CHECK: DW_TAG_structure_type
> +; CHECK-NEXT: debug_str{{.*}}"baz"
> +; CHECK-NOT: DW_AT_GNU_odr_signature
> +; FIXME: we may want to generate debug info for walrus, but still no hash.

Why?

> +; CHECK-NOT: debug_str{{.*}}"walrus"
> +
> +
> +%struct.bar = type { i8 }
> +%"class.echidna::capybara::mongoose::fluffy" = type { i32, i32 }
> +%struct.baz = type { i8 }
> +
> + at b = global %struct.bar zeroinitializer, align 1
> + at _ZN7echidna8capybara8mongoose6animalE = global %"class.echidna::capybara::mongoose::fluffy" zeroinitializer, align 4
> +
> +; Function Attrs: nounwind uwtable
> +define void @_Z3foov() #0 {
> +entry:
> +  %b = alloca %struct.baz, align 1
> +  call void @llvm.dbg.declare(metadata !{%struct.baz* %b}, metadata !32), !dbg !40
> +  ret void, !dbg !41
> +}
> +
> +; Function Attrs: nounwind readnone
> +declare void @llvm.dbg.declare(metadata, metadata) #1
> +
> +attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
> +attributes #1 = { nounwind readnone }
> +
> +!llvm.dbg.cu = !{!0}
> +!llvm.module.flags = !{!31}
> +
> +!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.4 (trunk 187152) (llvm/trunk 187150)", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !8, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/usr/local/google/home/echristo/tmp/bar.cpp] [DW_LANG_C_plus_plus]
> +!1 = metadata !{metadata !"bar.cpp", metadata !"/usr/local/google/home/echristo/tmp"}
> +!2 = metadata !{i32 0}
> +!3 = metadata !{metadata !4}
> +!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"_Z3foov", i32 6, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @_Z3foov, null, null, metadata !2, i32 6} ; [ DW_TAG_subprogram ] [line 6] [def] [foo]
> +!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [/usr/local/google/home/echristo/tmp/bar.cpp]
> +!6 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
> +!7 = metadata !{null}
> +!8 = metadata !{metadata !9, metadata !17}
> +!9 = metadata !{i32 786484, i32 0, null, metadata !"b", metadata !"b", metadata !"", metadata !5, i32 4, metadata !10, i32 0, i32 1, %struct.bar* @b, null} ; [ DW_TAG_variable ] [b] [line 4] [def]
> +!10 = metadata !{i32 786451, metadata !1, null, metadata !"bar", i32 1, i64 8, i64 8, i32 0, i32 0, null, metadata !11, i32 0, null, null} ; [ DW_TAG_structure_type ] [bar] [line 1, size 8, align 8, offset 0] [def] [from ]
> +!11 = metadata !{metadata !12}
> +!12 = metadata !{i32 786478, metadata !1, metadata !10, metadata !"bar", metadata !"bar", metadata !"", i32 1, metadata !13, i1 false, i1 false, i32 0, i32 0, null, i32 320, i1 false, null, null, i32 0, metadata !16, i32 1} ; [ DW_TAG_subprogram ] [line 1] [bar]
> +!13 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !14, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
> +!14 = metadata !{null, metadata !15}
> +!15 = metadata !{i32 786447, i32 0, i32 0, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !10} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from bar]
> +!16 = metadata !{i32 786468}
> +!17 = metadata !{i32 786484, i32 0, metadata !18, metadata !"animal", metadata !"animal", metadata !"_ZN7echidna8capybara8mongoose6animalE", metadata !5, i32 20, metadata !21, i32 0, i32 1, %"class.echidna::capybara::mongoose::fluffy"* @_ZN7echidna8capybara8mongoose6animalE, null} ; [ DW_TAG_variable ] [animal] [line 20] [def]
> +!18 = metadata !{i32 786489, metadata !1, metadata !19, metadata !"mongoose", i32 14} ; [ DW_TAG_namespace ] [mongoose] [line 14]
> +!19 = metadata !{i32 786489, metadata !1, metadata !20, metadata !"capybara", i32 13} ; [ DW_TAG_namespace ] [capybara] [line 13]
> +!20 = metadata !{i32 786489, metadata !1, null, metadata !"echidna", i32 12} ; [ DW_TAG_namespace ] [echidna] [line 12]
> +!21 = metadata !{i32 786434, metadata !1, metadata !18, metadata !"fluffy", i32 15, i64 64, i64 32, i32 0, i32 0, null, metadata !22, i32 0, null, null} ; [ DW_TAG_class_type ] [fluffy] [line 15, size 64, align 32, offset 0] [def] [from ]
> +!22 = metadata !{metadata !23, metadata !25, metadata !26}
> +!23 = metadata !{i32 786445, metadata !1, metadata !21, metadata !"a", i32 16, i64 32, i64 32, i64 0, i32 1, metadata !24} ; [ DW_TAG_member ] [a] [line 16, size 32, align 32, offset 0] [private] [from int]
> +!24 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
> +!25 = metadata !{i32 786445, metadata !1, metadata !21, metadata !"b", i32 17, i64 32, i64 32, i64 32, i32 1, metadata !24} ; [ DW_TAG_member ] [b] [line 17, size 32, align 32, offset 32] [private] [from int]
> +!26 = metadata !{i32 786478, metadata !1, metadata !21, metadata !"fluffy", metadata !"fluffy", metadata !"", i32 15, metadata !27, i1 false, i1 false, i32 0, i32 0, null, i32 320, i1 false, null, null, i32 0, metadata !30, i32 15} ; [ DW_TAG_subprogram ] [line 15] [fluffy]
> +!27 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !28, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
> +!28 = metadata !{null, metadata !29}
> +!29 = metadata !{i32 786447, i32 0, i32 0, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !21} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from fluffy]
> +!30 = metadata !{i32 786468}
> +!31 = metadata !{i32 2, metadata !"Dwarf Version", i32 3}
> +!32 = metadata !{i32 786688, metadata !4, metadata !"b", metadata !5, i32 9, metadata !33, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [b] [line 9]
> +!33 = metadata !{i32 786451, metadata !1, metadata !4, metadata !"baz", i32 7, i64 8, i64 8, i32 0, i32 0, null, metadata !34, i32 0, null, null} ; [ DW_TAG_structure_type ] [baz] [line 7, size 8, align 8, offset 0] [def] [from ]
> +!34 = metadata !{metadata !35}
> +!35 = metadata !{i32 786478, metadata !1, metadata !33, metadata !"baz", metadata !"baz", metadata !"", i32 7, metadata !36, i1 false, i1 false, i32 0, i32 0, null, i32 320, i1 false, null, null, i32 0, metadata !39, i32 7} ; [ DW_TAG_subprogram ] [line 7] [baz]
> +!36 = metadata !{i32 786453, i32 0, i32 0, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !37, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
> +!37 = metadata !{null, metadata !38}
> +!38 = metadata !{i32 786447, i32 0, i32 0, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !33} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from baz]
> +!39 = metadata !{i32 786468}
> +!40 = metadata !{i32 9, i32 0, metadata !4, null}
> +!41 = metadata !{i32 10, i32 0, metadata !4, null}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list