[llvm] [DebugInfo] Make DISubprogram's hashing always produce the same result (PR #90770)
Augusto Noronha via llvm-commits
llvm-commits at lists.llvm.org
Wed May 1 14:21:09 PDT 2024
https://github.com/augusto2112 updated https://github.com/llvm/llvm-project/pull/90770
>From aafbf0034d25998195b809f868fc0e545f1d62eb Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Wed, 1 May 2024 13:19:25 -0700
Subject: [PATCH] [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
---
llvm/lib/IR/LLVMContextImpl.h | 16 ++++++---
llvm/unittests/IR/DebugInfoTest.cpp | 52 ++++++++++++++++++++++++++++-
2 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 2713015c266c7e..3be690e486dc2f 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -825,19 +825,25 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
bool isDefinition() const { return SPFlags & DISubprogram::SPFlagDefinition; }
unsigned getHashValue() const {
+ // Use the Scope's linkage name instead of using the scope directly, as the
+ // scope may be a temporary one which can replaced, which would produce a
+ // different hash for the same DISubprogram.
+ llvm::StringRef ScopeLinkageName;
+ if (auto *CT = dyn_cast_or_null<DICompositeType>(Scope))
+ if (auto *ID = CT->getRawIdentifier())
+ ScopeLinkageName = ID->getString();
+
// If this is a declaration inside an ODR type, only hash the type and the
// name. Otherwise the hash will be stronger than
// MDNodeSubsetEqualImpl::isDeclarationOfODRMember().
- if (!isDefinition() && LinkageName)
- if (auto *CT = dyn_cast_or_null<DICompositeType>(Scope))
- if (CT->getRawIdentifier())
- return hash_combine(LinkageName, Scope);
+ if (!isDefinition() && LinkageName && isa_and_nonnull<DICompositeType>(Scope))
+ return hash_combine(LinkageName, ScopeLinkageName);
// Intentionally computes the hash on a subset of the operands for
// performance reason. The subset has to be significant enough to avoid
// collision "most of the time". There is no correctness issue in case of
// collision because of the full check above.
- return hash_combine(Name, Scope, File, Type, Line);
+ return hash_combine(Name, ScopeLinkageName, File, Type, Line);
}
};
diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp
index d06b979bf4a1c4..7d3f0d36bf3cb0 100644
--- a/llvm/unittests/IR/DebugInfoTest.cpp
+++ b/llvm/unittests/IR/DebugInfoTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/DebugInfo.h"
+#include "../lib/IR/LLVMContextImpl.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/DIBuilder.h"
@@ -20,6 +21,7 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Transforms/Utils/Local.h"
+
#include "gtest/gtest.h"
using namespace llvm;
@@ -349,7 +351,7 @@ TEST(MetadataTest, OrderingOfDbgVariableRecords) {
UseNewDbgInfoFormat = OldDbgValueMode;
}
-TEST(DIBuiler, CreateFile) {
+TEST(DIBuilder, CreateFile) {
LLVMContext Ctx;
std::unique_ptr<Module> M(new Module("MyModule", Ctx));
DIBuilder DIB(*M);
@@ -1184,4 +1186,52 @@ TEST(MetadataTest, DbgVariableRecordConversionRoutines) {
UseNewDbgInfoFormat = false;
}
+// Test that the hashing function for DISubprograms produce the same result
+// after replacing the temporary scope.
+TEST(DIBuilder, HashingDISubprogram) {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M(new Module("MyModule", Ctx));
+ DIBuilder DIB(*M);
+
+ DIFile *F = DIB.createFile("main.c", "/");
+ DICompileUnit *CU =
+ DIB.createCompileUnit(dwarf::DW_LANG_C, F, "Test", false, "", 0);
+
+ llvm::TempDIType ForwardDeclaredType =
+ llvm::TempDIType(DIB.createReplaceableCompositeType(
+ llvm::dwarf::DW_TAG_structure_type, "MyType", CU, F, 0, 0, 8, 8, {},
+ "UniqueIdentifier"));
+
+ // The hashing function is different for declarations and definitions, so
+ // create one of each.
+ DISubprogram *Declaration =
+ DIB.createMethod(ForwardDeclaredType.get(), "MethodName", "LinkageName",
+ F, 0, DIB.createSubroutineType({}));
+
+ DISubprogram *Definition = DIB.createFunction(
+ ForwardDeclaredType.get(), "MethodName", "LinkageName", F, 0,
+ DIB.createSubroutineType({}), 0, DINode::FlagZero,
+ llvm::DISubprogram::SPFlagDefinition, nullptr, Declaration);
+
+ // Produce the hash with the temporary scope.
+ unsigned HashDeclaration =
+ MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();
+ unsigned HashDefinition =
+ MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();
+
+ // Instantiate the real scope and replace the temporary one with it.
+ DICompositeType *Type = DIB.createStructType(CU, "MyType", F, 0, 8, 8, {}, {},
+ {}, 0, {}, "UniqueIdentifier");
+ DIB.replaceTemporary(std::move(ForwardDeclaredType), Type);
+
+ // Now make sure the hashing is consistent.
+ unsigned HashDeclarationAfter =
+ MDNodeKeyImpl<DISubprogram>(Declaration).getHashValue();
+ unsigned HashDefinitionAfter =
+ MDNodeKeyImpl<DISubprogram>(Definition).getHashValue();
+
+ EXPECT_EQ(HashDeclaration, HashDeclarationAfter);
+ EXPECT_EQ(HashDefinition, HashDefinitionAfter);
+}
+
} // end namespace
More information about the llvm-commits
mailing list