1 //===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/BinaryFormat/Dwarf.h" 10 #include "llvm/IR/DebugInfoMetadata.h" 11 #include "llvm/IR/LLVMContext.h" 12 #include "gtest/gtest.h" 13 using namespace llvm; 14 15 namespace { 16 17 TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) { 18 LLVMContext Context; 19 EXPECT_FALSE(Context.isODRUniquingDebugTypes()); 20 Context.enableDebugTypeODRUniquing(); 21 EXPECT_TRUE(Context.isODRUniquingDebugTypes()); 22 Context.disableDebugTypeODRUniquing(); 23 EXPECT_FALSE(Context.isODRUniquingDebugTypes()); 24 } 25 26 TEST(DebugTypeODRUniquingTest, getODRType) { 27 LLVMContext Context; 28 MDString &UUID = *MDString::get(Context, "string"); 29 30 // Without a type map, this should return null. 31 EXPECT_FALSE(DICompositeType::getODRType( 32 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 33 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, nullptr, 0, nullptr, 34 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); 35 36 // Enable the mapping. There still shouldn't be a type. 37 Context.enableDebugTypeODRUniquing(); 38 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 39 40 // Create some ODR-uniqued type. 41 auto &CT = *DICompositeType::getODRType( 42 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 43 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, nullptr, 0, nullptr, 44 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); 45 EXPECT_EQ(UUID.getString(), CT.getIdentifier()); 46 47 // Check that we get it back, even if we change a field. 48 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); 49 EXPECT_EQ(&CT, DICompositeType::getODRType( 50 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 51 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, 52 nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 53 nullptr, nullptr, nullptr)); 54 EXPECT_EQ(&CT, 55 DICompositeType::getODRType( 56 Context, UUID, dwarf::DW_TAG_class_type, 57 MDString::get(Context, "name"), nullptr, 0, nullptr, nullptr, 0, 58 0, 0, nullptr, 0, DINode::FlagZero, nullptr, 0, nullptr, 59 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); 60 61 // Check that it's discarded with the type map. 62 Context.disableDebugTypeODRUniquing(); 63 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 64 65 // And it shouldn't magically reappear... 66 Context.enableDebugTypeODRUniquing(); 67 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 68 } 69 70 TEST(DebugTypeODRUniquingTest, buildODRType) { 71 LLVMContext Context; 72 Context.enableDebugTypeODRUniquing(); 73 74 // Build an ODR type that's a forward decl. 75 MDString &UUID = *MDString::get(Context, "Type"); 76 auto &CT = *DICompositeType::buildODRType( 77 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 78 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, 79 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); 80 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); 81 EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); 82 83 // Update with another forward decl. This should be a no-op. 84 EXPECT_EQ(&CT, DICompositeType::buildODRType( 85 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 86 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, 87 DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, 88 nullptr, nullptr, nullptr, nullptr, nullptr)); 89 90 EXPECT_FALSE(DICompositeType::buildODRType( 91 Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, 92 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, 93 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); 94 95 // Update with a definition. This time we should see a change. 96 EXPECT_EQ(&CT, DICompositeType::buildODRType( 97 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 98 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, 99 nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, 100 nullptr, nullptr, nullptr)); 101 EXPECT_FALSE(CT.isForwardDecl()); 102 103 // Further updates should be ignored. 104 EXPECT_EQ(&CT, DICompositeType::buildODRType( 105 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 106 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, 107 DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, 108 nullptr, nullptr, nullptr, nullptr, nullptr)); 109 EXPECT_FALSE(CT.isForwardDecl()); 110 EXPECT_EQ(&CT, DICompositeType::buildODRType( 111 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 112 111u, nullptr, nullptr, 0, 0, 0, nullptr, 0, 113 DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, 114 nullptr, nullptr, nullptr, nullptr, nullptr)); 115 EXPECT_NE(111u, CT.getLine()); 116 } 117 118 TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { 119 LLVMContext Context; 120 Context.enableDebugTypeODRUniquing(); 121 122 // Build an ODR type that's a forward decl with no other fields set. 123 MDString &UUID = *MDString::get(Context, "UUID"); 124 auto &CT = *DICompositeType::buildODRType( 125 Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, nullptr, 126 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, nullptr, 127 nullptr, nullptr, nullptr, nullptr); 128 129 // Create macros for running through all the fields except Identifier and Flags. 130 #define FOR_EACH_MDFIELD() \ 131 DO_FOR_FIELD(Name) \ 132 DO_FOR_FIELD(File) \ 133 DO_FOR_FIELD(Scope) \ 134 DO_FOR_FIELD(BaseType) \ 135 DO_FOR_FIELD(Elements) \ 136 DO_FOR_FIELD(VTableHolder) \ 137 DO_FOR_FIELD(TemplateParams) 138 #define FOR_EACH_INLINEFIELD() \ 139 DO_FOR_FIELD(Line) \ 140 DO_FOR_FIELD(SizeInBits) \ 141 DO_FOR_FIELD(AlignInBits) \ 142 DO_FOR_FIELD(OffsetInBits) \ 143 DO_FOR_FIELD(NumExtraInhabitants) \ 144 DO_FOR_FIELD(RuntimeLang) 145 146 // Create all the fields. 147 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X); 148 FOR_EACH_MDFIELD(); 149 #undef DO_FOR_FIELD 150 unsigned NonZeroInit = 0; 151 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit; 152 FOR_EACH_INLINEFIELD(); 153 #undef DO_FOR_FIELD 154 155 // Replace all the fields with new values that are distinct from each other. 156 EXPECT_EQ(&CT, DICompositeType::buildODRType( 157 Context, UUID, 0, Name, File, Line, Scope, BaseType, 158 SizeInBits, AlignInBits, OffsetInBits, nullptr, 159 NumExtraInhabitants, DINode::FlagArtificial, Elements, 160 RuntimeLang, VTableHolder, TemplateParams, nullptr, 161 nullptr, nullptr, nullptr, nullptr, nullptr)); 162 163 // Confirm that all the right fields got updated. 164 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); 165 FOR_EACH_MDFIELD(); 166 #undef DO_FOR_FIELD 167 #undef FOR_EACH_MDFIELD 168 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X()); 169 FOR_EACH_INLINEFIELD(); 170 #undef DO_FOR_FIELD 171 #undef FOR_EACH_INLINEFIELD 172 EXPECT_EQ(DINode::FlagArtificial, CT.getFlags()); 173 EXPECT_EQ(&UUID, CT.getRawIdentifier()); 174 } 175 176 } // end namespace 177