summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2013-10-22 18:14:41 +0000
committerDavid Blaikie <dblaikie@gmail.com>2013-10-22 18:14:41 +0000
commitf196208900e690fe2d3bb1c6ca393d3fcd64226d (patch)
tree8061602901d3c45944cc0cfce3a569a8538d7db1
parent51ec77d880ce53cbc8a48168185edc085df9b6d9 (diff)
downloadllvm-f196208900e690fe2d3bb1c6ca393d3fcd64226d.tar.gz
llvm-f196208900e690fe2d3bb1c6ca393d3fcd64226d.tar.bz2
llvm-f196208900e690fe2d3bb1c6ca393d3fcd64226d.tar.xz
DWARF type hashing: pointers to members
Includes a test case/FIXME demonstrating a bug/limitation in pointer to member hashing. To be honest I'm not sure why we don't just always use summary hashing for referenced types... but perhaps I'm missing something. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193175 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/AsmPrinter/DIEHash.cpp25
-rw-r--r--unittests/CodeGen/DIEHashTest.cpp178
2 files changed, 192 insertions, 11 deletions
diff --git a/lib/CodeGen/AsmPrinter/DIEHash.cpp b/lib/CodeGen/AsmPrinter/DIEHash.cpp
index 64a8fd50ed..9a1f966c8d 100644
--- a/lib/CodeGen/AsmPrinter/DIEHash.cpp
+++ b/lib/CodeGen/AsmPrinter/DIEHash.cpp
@@ -192,6 +192,7 @@ void DIEHash::collectAttributes(DIE *Die, DIEAttrs &Attrs) {
void DIEHash::hashAttribute(AttrEntry Attr, dwarf::Tag Tag) {
const DIEValue *Value = Attr.Val;
const DIEAbbrevData *Desc = Attr.Desc;
+ dwarf::Attribute Attribute = Desc->getAttribute();
// 7.27 Step 3
// ... An attribute that refers to another type entry T is processed as
@@ -200,14 +201,16 @@ void DIEHash::hashAttribute(AttrEntry Attr, dwarf::Tag Tag) {
DIE *Entry = EntryAttr->getEntry();
// Step 5
- // If the tag in Step 3 is one of ...
- if (Tag == dwarf::DW_TAG_pointer_type ||
- Tag == dwarf::DW_TAG_reference_type ||
- Tag == dwarf::DW_TAG_rvalue_reference_type) {
- // ... and the referenced type (via the DW_AT_type or DW_AT_friend
- // attribute) ...
- assert(Desc->getAttribute() == dwarf::DW_AT_type ||
- Desc->getAttribute() == dwarf::DW_AT_friend);
+ // If the tag in Step 3 is one of [the below tags]
+ if ((Tag == dwarf::DW_TAG_pointer_type ||
+ Tag == dwarf::DW_TAG_reference_type ||
+ Tag == dwarf::DW_TAG_rvalue_reference_type ||
+ Tag == dwarf::DW_TAG_ptr_to_member_type) &&
+ // and the referenced type (via the [below attributes])
+ // FIXME: This seems overly restrictive, and causes hash mismatches
+ // there's a decl/def difference in the containing type of a
+ // ptr_to_member_type.
+ Attribute == dwarf::DW_AT_type) {
// [FIXME] ... has a DW_AT_name attribute,
// append the letter 'N'
addULEB128('N');
@@ -238,7 +241,7 @@ void DIEHash::hashAttribute(AttrEntry Attr, dwarf::Tag Tag) {
// 'R' as the marker
addULEB128('R');
- addULEB128(Desc->getAttribute());
+ addULEB128(Attribute);
// and use the unsigned LEB128 encoding of [the index of T in the
// list] as the attribute value;
@@ -249,7 +252,7 @@ void DIEHash::hashAttribute(AttrEntry Attr, dwarf::Tag Tag) {
// otherwise, b) use the letter 'T' as a the marker, ...
addULEB128('T');
- addULEB128(Desc->getAttribute());
+ addULEB128(Attribute);
// ... process the type T recursively by performing Steps 2 through 7, and
// use the result as the attribute value.
@@ -261,7 +264,7 @@ void DIEHash::hashAttribute(AttrEntry Attr, dwarf::Tag Tag) {
// Other attribute values use the letter 'A' as the marker, ...
addULEB128('A');
- addULEB128(Desc->getAttribute());
+ addULEB128(Attribute);
// ... and the value consists of the form code (encoded as an unsigned LEB128
// value) followed by the encoding of the value according to the form code. To
diff --git a/unittests/CodeGen/DIEHashTest.cpp b/unittests/CodeGen/DIEHashTest.cpp
index 1ac8b3df6e..32030c1509 100644
--- a/unittests/CodeGen/DIEHashTest.cpp
+++ b/unittests/CodeGen/DIEHashTest.cpp
@@ -264,4 +264,182 @@ TEST(DIEHashTest, RValueReference) {
ASSERT_EQ(0xad211c8c3b31e57ULL, MD5Res);
}
+
+// struct foo { foo foo::*mem; };
+TEST(DIEHashTest, PtrToMember) {
+ DIE Foo(dwarf::DW_TAG_structure_type);
+ DIEInteger Eight(8);
+ Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight);
+ DIEString FooStr(&Eight, "foo");
+ Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr);
+
+ DIE *Mem = new DIE(dwarf::DW_TAG_member);
+ DIEString MemStr(&Eight, "mem");
+ Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr);
+ DIEInteger Zero(0);
+ Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero);
+
+ DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type);
+ DIEEntry FooEntry(&Foo);
+ PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooEntry);
+ PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, &FooEntry);
+
+ DIEEntry PtrToFooMemRef(&PtrToFooMem);
+ Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef);
+
+ Foo.addChild(Mem);
+
+ uint64_t MD5Res = DIEHash().computeTypeSignature(&Foo);
+
+ ASSERT_EQ(0x852e0c9ff7c04ebULL, MD5Res);
+}
+
+// Check that the hash for a pointer-to-member matches regardless of whether the
+// pointed-to type is a declaration or a definition.
+//
+// struct bar; // { };
+// struct foo { bar foo::*mem; };
+TEST(DIEHashTest, PtrToMemberDeclDefMatch) {
+ DIEInteger Zero(0);
+ DIEInteger One(1);
+ DIEInteger Eight(8);
+ DIEString FooStr(&Eight, "foo");
+ DIEString BarStr(&Eight, "bar");
+ DIEString MemStr(&Eight, "mem");
+ uint64_t MD5ResDecl;
+ {
+ DIE Bar(dwarf::DW_TAG_structure_type);
+ Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr);
+ Bar.addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One);
+
+ DIE Foo(dwarf::DW_TAG_structure_type);
+ Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight);
+ Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr);
+
+ DIE *Mem = new DIE(dwarf::DW_TAG_member);
+ Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr);
+ Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
+ &Zero);
+
+ DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type);
+ DIEEntry BarEntry(&Bar);
+ PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry);
+ DIEEntry FooEntry(&Foo);
+ PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
+ &FooEntry);
+
+ DIEEntry PtrToFooMemRef(&PtrToFooMem);
+ Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef);
+
+ Foo.addChild(Mem);
+
+ MD5ResDecl = DIEHash().computeTypeSignature(&Foo);
+ }
+ uint64_t MD5ResDef;
+ {
+ DIE Bar(dwarf::DW_TAG_structure_type);
+ Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr);
+ Bar.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One);
+
+ DIE Foo(dwarf::DW_TAG_structure_type);
+ Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight);
+ Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr);
+
+ DIE *Mem = new DIE(dwarf::DW_TAG_member);
+ Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr);
+ Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
+ &Zero);
+
+ DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type);
+ DIEEntry BarEntry(&Bar);
+ PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry);
+ DIEEntry FooEntry(&Foo);
+ PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
+ &FooEntry);
+
+ DIEEntry PtrToFooMemRef(&PtrToFooMem);
+ Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef);
+
+ Foo.addChild(Mem);
+
+ MD5ResDef = DIEHash().computeTypeSignature(&Foo);
+ }
+ ASSERT_EQ(MD5ResDef, MD5ResDecl);
+}
+
+// Check that the hash for a pointer-to-member matches regardless of whether the
+// pointed-to type is a declaration or a definition.
+//
+// struct bar; // { };
+// struct foo { bar bar::*mem; };
+TEST(DIEHashTest, PtrToMemberDeclDefMisMatch) {
+ DIEInteger Zero(0);
+ DIEInteger One(1);
+ DIEInteger Eight(8);
+ DIEString FooStr(&Eight, "foo");
+ DIEString BarStr(&Eight, "bar");
+ DIEString MemStr(&Eight, "mem");
+ uint64_t MD5ResDecl;
+ {
+ DIE Bar(dwarf::DW_TAG_structure_type);
+ Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr);
+ Bar.addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One);
+
+ DIE Foo(dwarf::DW_TAG_structure_type);
+ Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight);
+ Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr);
+
+ DIE *Mem = new DIE(dwarf::DW_TAG_member);
+ Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr);
+ Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
+ &Zero);
+
+ DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type);
+ DIEEntry BarEntry(&Bar);
+ PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry);
+ PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
+ &BarEntry);
+
+ DIEEntry PtrToFooMemRef(&PtrToFooMem);
+ Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef);
+
+ Foo.addChild(Mem);
+
+ MD5ResDecl = DIEHash().computeTypeSignature(&Foo);
+ }
+ uint64_t MD5ResDef;
+ {
+ DIE Bar(dwarf::DW_TAG_structure_type);
+ Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr);
+ Bar.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One);
+
+ DIE Foo(dwarf::DW_TAG_structure_type);
+ Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight);
+ Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr);
+
+ DIE *Mem = new DIE(dwarf::DW_TAG_member);
+ Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr);
+ Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
+ &Zero);
+
+ DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type);
+ DIEEntry BarEntry(&Bar);
+ PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry);
+ PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
+ &BarEntry);
+
+ DIEEntry PtrToFooMemRef(&PtrToFooMem);
+ Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef);
+
+ Foo.addChild(Mem);
+
+ MD5ResDef = DIEHash().computeTypeSignature(&Foo);
+ }
+ // FIXME: This seems to be a bug in the DWARF type hashing specification that
+ // only uses the brief name hashing for types referenced via DW_AT_type. In
+ // this case the type is referenced via DW_AT_containing_type and full hashing
+ // causes a hash to differ when the containing type is a declaration in one TU
+ // and a definition in another.
+ ASSERT_NE(MD5ResDef, MD5ResDecl);
+}
}