Skip to content

Commit 89e419e

Browse files
committed
[DebugInfo] Make DISubprogram's hashing always produce the same result
A DISubprogram's hashing algorithm takes into account its Scope. A Scope can be a temporary though which can be replaced later on during compilation. This means that the hashing algorithm for a DISubprogram could produce a different hash before/after the Scope has changed. Fix this by checking the Scope's linkage name instead, which should always be the same. rdar://127004707 (cherry picked from commit 0f47349)
1 parent 5dc3fbd commit 89e419e

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

llvm/lib/IR/LLVMContextImpl.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -843,19 +843,26 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
843843
bool isDefinition() const { return SPFlags & DISubprogram::SPFlagDefinition; }
844844

845845
unsigned getHashValue() const {
846+
// Use the Scope's linkage name instead of using the scope directly, as the
847+
// scope may be a temporary one which can replaced, which would produce a
848+
// different hash for the same DISubprogram.
849+
llvm::StringRef ScopeLinkageName;
850+
if (auto *CT = dyn_cast_or_null<DICompositeType>(Scope))
851+
if (auto *ID = CT->getRawIdentifier())
852+
ScopeLinkageName = ID->getString();
853+
846854
// If this is a declaration inside an ODR type, only hash the type and the
847855
// name. Otherwise the hash will be stronger than
848856
// MDNodeSubsetEqualImpl::isDeclarationOfODRMember().
849-
if (!isDefinition() && LinkageName)
850-
if (auto *CT = dyn_cast_or_null<DICompositeType>(Scope))
851-
if (CT->getRawIdentifier())
852-
return hash_combine(LinkageName, Scope);
857+
if (!isDefinition() && LinkageName &&
858+
isa_and_nonnull<DICompositeType>(Scope))
859+
return hash_combine(LinkageName, ScopeLinkageName);
853860

854861
// Intentionally computes the hash on a subset of the operands for
855862
// performance reason. The subset has to be significant enough to avoid
856863
// collision "most of the time". There is no correctness issue in case of
857864
// collision because of the full check above.
858-
return hash_combine(Name, Scope, File, Type, Line);
865+
return hash_combine(Name, ScopeLinkageName, File, Type, Line);
859866
}
860867
};
861868

llvm/unittests/IR/DebugInfoTest.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/IR/DebugInfo.h"
10+
#include "../lib/IR/LLVMContextImpl.h"
1011
#include "llvm/ADT/APSInt.h"
1112
#include "llvm/AsmParser/Parser.h"
1213
#include "llvm/IR/DIBuilder.h"
@@ -19,6 +20,7 @@
1920
#include "llvm/IR/Verifier.h"
2021
#include "llvm/Support/SourceMgr.h"
2122
#include "llvm/Transforms/Utils/Local.h"
23+
2224
#include "gtest/gtest.h"
2325

2426
using namespace llvm;
@@ -231,7 +233,7 @@ TEST(DbgVariableIntrinsic, EmptyMDIsKillLocation) {
231233
EXPECT_TRUE(DbgDeclare->isKillLocation());
232234
}
233235

234-
TEST(DIBuiler, CreateFile) {
236+
TEST(DIBuilder, CreateFile) {
235237
LLVMContext Ctx;
236238
std::unique_ptr<Module> M(new Module("MyModule", Ctx));
237239
DIBuilder DIB(*M);
@@ -730,4 +732,51 @@ TEST(AssignmentTrackingTest, InstrMethods) {
730732
}
731733
}
732734

735+
// Test that the hashing function for DISubprograms produce the same result
736+
// after replacing the temporary scope.
737+
TEST(DIBuilder, HashingDISubprogram) {
738+
LLVMContext Ctx;
739+
std::unique_ptr<Module> M = std::make_unique<Module>("MyModule", Ctx);
740+
DIBuilder DIB(*M);
741+
742+
DIFile *F = DIB.createFile("main.c", "/");
743+
DICompileUnit *CU =
744+
DIB.createCompileUnit(dwarf::DW_LANG_C, F, "Test", false, "", 0);
745+
746+
llvm::TempDIType ForwardDeclaredType =
747+
llvm::TempDIType(DIB.createReplaceableCompositeType(
748+
llvm::dwarf::DW_TAG_structure_type, "MyType", CU, F, 0, 0, 8, 8, {},
749+
"UniqueIdentifier"));
750+
751+
// The hashing function is different for declarations and definitions, so
752+
// create one of each.
753+
DISubprogram *Declaration =
754+
DIB.createMethod(ForwardDeclaredType.get(), "MethodName", "LinkageName",
755+
F, 0, DIB.createSubroutineType({}));
756+
757+
DISubprogram *Definition = DIB.createFunction(
758+
ForwardDeclaredType.get(), "MethodName", "LinkageName", F, 0,
759+
DIB.createSubroutineType({}), 0, DINode::FlagZero,
760+
llvm::DISubprogram::SPFlagDefinition, nullptr, Declaration);
761+
762+
// Produce the hash with the temporary scope.
763+
unsigned HashDeclaration =
764+
MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();
765+
unsigned HashDefinition =
766+
MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();
767+
768+
// Instantiate the real scope and replace the temporary one with it.
769+
DICompositeType *Type = DIB.createStructType(CU, "MyType", F, 0, 8, 8, {}, {},
770+
{}, 0, {}, "UniqueIdentifier");
771+
DIB.replaceTemporary(std::move(ForwardDeclaredType), Type);
772+
773+
// Now make sure the hashing is consistent.
774+
unsigned HashDeclarationAfter =
775+
MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();
776+
unsigned HashDefinitionAfter =
777+
MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();
778+
779+
EXPECT_EQ(HashDeclaration, HashDeclarationAfter);
780+
EXPECT_EQ(HashDefinition, HashDefinitionAfter);
781+
}
733782
} // end namespace

0 commit comments

Comments
 (0)