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, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, 34 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, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, 44 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, 50 DICompositeType::getODRType( 51 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, 52 nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, 53 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 54 nullptr)); 55 EXPECT_EQ(&CT, DICompositeType::getODRType( 56 Context, UUID, dwarf::DW_TAG_class_type, 57 MDString::get(Context, "name"), nullptr, 0, nullptr, 58 nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, 59 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 60 nullptr)); 61 62 // Check that it's discarded with the type map. 63 Context.disableDebugTypeODRUniquing(); 64 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 65 66 // And it shouldn't magically reappear... 67 Context.enableDebugTypeODRUniquing(); 68 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 69 } 70 71 TEST(DebugTypeODRUniquingTest, buildODRType) { 72 LLVMContext Context; 73 Context.enableDebugTypeODRUniquing(); 74 75 // Build an ODR type that's a forward decl. 76 MDString &UUID = *MDString::get(Context, "Type"); 77 auto &CT = *DICompositeType::buildODRType( 78 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 79 nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, 80 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); 81 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); 82 EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); 83 84 // Update with another forward decl. This should be a no-op. 85 EXPECT_EQ(&CT, DICompositeType::buildODRType( 86 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 87 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 88 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 89 nullptr, nullptr)); 90 91 EXPECT_FALSE(DICompositeType::buildODRType( 92 Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, 93 nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, 94 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); 95 96 // Update with a definition. This time we should see a change. 97 EXPECT_EQ(&CT, DICompositeType::buildODRType( 98 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 99 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, 100 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 101 nullptr, nullptr)); 102 EXPECT_FALSE(CT.isForwardDecl()); 103 104 // Further updates should be ignored. 105 EXPECT_EQ(&CT, DICompositeType::buildODRType( 106 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 107 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 108 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 109 nullptr, nullptr)); 110 EXPECT_FALSE(CT.isForwardDecl()); 111 EXPECT_EQ(&CT, DICompositeType::buildODRType( 112 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 113 111u, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 114 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 115 nullptr, nullptr)); 116 EXPECT_NE(111u, CT.getLine()); 117 } 118 119 TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { 120 LLVMContext Context; 121 Context.enableDebugTypeODRUniquing(); 122 123 // Build an ODR type that's a forward decl with no other fields set. 124 MDString &UUID = *MDString::get(Context, "UUID"); 125 auto &CT = *DICompositeType::buildODRType( 126 Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, 127 DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, nullptr, 128 nullptr, nullptr, nullptr, nullptr); 129 130 // Create macros for running through all the fields except Identifier and Flags. 131 #define FOR_EACH_MDFIELD() \ 132 DO_FOR_FIELD(Name) \ 133 DO_FOR_FIELD(File) \ 134 DO_FOR_FIELD(Scope) \ 135 DO_FOR_FIELD(BaseType) \ 136 DO_FOR_FIELD(Elements) \ 137 DO_FOR_FIELD(VTableHolder) \ 138 DO_FOR_FIELD(TemplateParams) 139 #define FOR_EACH_INLINEFIELD() \ 140 DO_FOR_FIELD(Line) \ 141 DO_FOR_FIELD(SizeInBits) \ 142 DO_FOR_FIELD(AlignInBits) \ 143 DO_FOR_FIELD(OffsetInBits) \ 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, 157 DICompositeType::buildODRType( 158 Context, UUID, 0, Name, File, Line, Scope, BaseType, SizeInBits, 159 AlignInBits, OffsetInBits, DINode::FlagArtificial, Elements, 160 RuntimeLang, VTableHolder, TemplateParams, nullptr, nullptr, 161 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