|  | //===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/BinaryFormat/Dwarf.h" | 
|  | #include "llvm/IR/DebugInfoMetadata.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "gtest/gtest.h" | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) { | 
|  | LLVMContext Context; | 
|  | EXPECT_FALSE(Context.isODRUniquingDebugTypes()); | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  | EXPECT_TRUE(Context.isODRUniquingDebugTypes()); | 
|  | Context.disableDebugTypeODRUniquing(); | 
|  | EXPECT_FALSE(Context.isODRUniquingDebugTypes()); | 
|  | } | 
|  |  | 
|  | TEST(DebugTypeODRUniquingTest, getODRType) { | 
|  | LLVMContext Context; | 
|  | MDString &UUID = *MDString::get(Context, "string"); | 
|  |  | 
|  | // Without a type map, this should return null. | 
|  | EXPECT_FALSE(DICompositeType::getODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, | 
|  | nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr)); | 
|  |  | 
|  | // Enable the mapping.  There still shouldn't be a type. | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  | EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); | 
|  |  | 
|  | // Create some ODR-uniqued type. | 
|  | auto &CT = *DICompositeType::getODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, | 
|  | nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr); | 
|  | EXPECT_EQ(UUID.getString(), CT.getIdentifier()); | 
|  |  | 
|  | // Check that we get it back, even if we change a field. | 
|  | EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); | 
|  | EXPECT_EQ(&CT, | 
|  | DICompositeType::getODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, | 
|  | nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr)); | 
|  | EXPECT_EQ(&CT, DICompositeType::getODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, | 
|  | MDString::get(Context, "name"), nullptr, 0, nullptr, | 
|  | nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr)); | 
|  |  | 
|  | // Check that it's discarded with the type map. | 
|  | Context.disableDebugTypeODRUniquing(); | 
|  | EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); | 
|  |  | 
|  | // And it shouldn't magically reappear... | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  | EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); | 
|  | } | 
|  |  | 
|  | TEST(DebugTypeODRUniquingTest, buildODRType) { | 
|  | LLVMContext Context; | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  |  | 
|  | // Build an ODR type that's a forward decl. | 
|  | MDString &UUID = *MDString::get(Context, "Type"); | 
|  | auto &CT = *DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, | 
|  | nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); | 
|  | EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); | 
|  | EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); | 
|  |  | 
|  | // Update with another forward decl.  This should be a no-op. | 
|  | EXPECT_EQ(&CT, DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, | 
|  | 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, | 
|  | 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr)); | 
|  |  | 
|  | EXPECT_FALSE(DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, | 
|  | nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); | 
|  |  | 
|  | // Update with a definition.  This time we should see a change. | 
|  | EXPECT_EQ(&CT, DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, | 
|  | 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, | 
|  | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr)); | 
|  | EXPECT_FALSE(CT.isForwardDecl()); | 
|  |  | 
|  | // Further updates should be ignored. | 
|  | EXPECT_EQ(&CT, DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, | 
|  | 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, | 
|  | 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr)); | 
|  | EXPECT_FALSE(CT.isForwardDecl()); | 
|  | EXPECT_EQ(&CT, DICompositeType::buildODRType( | 
|  | Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, | 
|  | 111u, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, | 
|  | 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr)); | 
|  | EXPECT_NE(111u, CT.getLine()); | 
|  | } | 
|  |  | 
|  | TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { | 
|  | LLVMContext Context; | 
|  | Context.enableDebugTypeODRUniquing(); | 
|  |  | 
|  | // Build an ODR type that's a forward decl with no other fields set. | 
|  | MDString &UUID = *MDString::get(Context, "UUID"); | 
|  | auto &CT = *DICompositeType::buildODRType( | 
|  | Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, | 
|  | DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr); | 
|  |  | 
|  | // Create macros for running through all the fields except Identifier and Flags. | 
|  | #define FOR_EACH_MDFIELD()                                                     \ | 
|  | DO_FOR_FIELD(Name)                                                           \ | 
|  | DO_FOR_FIELD(File)                                                           \ | 
|  | DO_FOR_FIELD(Scope)                                                          \ | 
|  | DO_FOR_FIELD(BaseType)                                                       \ | 
|  | DO_FOR_FIELD(Elements)                                                       \ | 
|  | DO_FOR_FIELD(VTableHolder)                                                   \ | 
|  | DO_FOR_FIELD(TemplateParams) | 
|  | #define FOR_EACH_INLINEFIELD()                                                 \ | 
|  | DO_FOR_FIELD(Line)                                                           \ | 
|  | DO_FOR_FIELD(SizeInBits)                                                     \ | 
|  | DO_FOR_FIELD(AlignInBits)                                                    \ | 
|  | DO_FOR_FIELD(OffsetInBits)                                                   \ | 
|  | DO_FOR_FIELD(RuntimeLang) | 
|  |  | 
|  | // Create all the fields. | 
|  | #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X); | 
|  | FOR_EACH_MDFIELD(); | 
|  | #undef DO_FOR_FIELD | 
|  | unsigned NonZeroInit = 0; | 
|  | #define DO_FOR_FIELD(X) auto X = ++NonZeroInit; | 
|  | FOR_EACH_INLINEFIELD(); | 
|  | #undef DO_FOR_FIELD | 
|  |  | 
|  | // Replace all the fields with new values that are distinct from each other. | 
|  | EXPECT_EQ(&CT, | 
|  | DICompositeType::buildODRType( | 
|  | Context, UUID, 0, Name, File, Line, Scope, BaseType, SizeInBits, | 
|  | AlignInBits, OffsetInBits, DINode::FlagArtificial, Elements, | 
|  | RuntimeLang, VTableHolder, TemplateParams, nullptr, nullptr, | 
|  | nullptr, nullptr, nullptr, nullptr)); | 
|  |  | 
|  | // Confirm that all the right fields got updated. | 
|  | #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); | 
|  | FOR_EACH_MDFIELD(); | 
|  | #undef DO_FOR_FIELD | 
|  | #undef FOR_EACH_MDFIELD | 
|  | #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X()); | 
|  | FOR_EACH_INLINEFIELD(); | 
|  | #undef DO_FOR_FIELD | 
|  | #undef FOR_EACH_INLINEFIELD | 
|  | EXPECT_EQ(DINode::FlagArtificial, CT.getFlags()); | 
|  | EXPECT_EQ(&UUID, CT.getRawIdentifier()); | 
|  | } | 
|  |  | 
|  | } // end namespace |