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/IR/DebugInfoMetadata.h" 10 #include "llvm/IR/LLVMContext.h" 11 #include "gtest/gtest.h" 12 using namespace llvm; 13 14 namespace { 15 16 TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) { 17 LLVMContext Context; 18 EXPECT_FALSE(Context.isODRUniquingDebugTypes()); 19 Context.enableDebugTypeODRUniquing(); 20 EXPECT_TRUE(Context.isODRUniquingDebugTypes()); 21 Context.disableDebugTypeODRUniquing(); 22 EXPECT_FALSE(Context.isODRUniquingDebugTypes()); 23 } 24 25 TEST(DebugTypeODRUniquingTest, getODRType) { 26 LLVMContext Context; 27 MDString &UUID = *MDString::get(Context, "string"); 28 29 // Without a type map, this should return null. 30 EXPECT_FALSE(DICompositeType::getODRType( 31 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 32 nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, 33 nullptr, nullptr, nullptr, nullptr, nullptr)); 34 35 // Enable the mapping. There still shouldn't be a type. 36 Context.enableDebugTypeODRUniquing(); 37 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); 38 39 // Create some ODR-uniqued type. 40 auto &CT = *DICompositeType::getODRType( 41 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, 42 nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr, 43 nullptr, nullptr, nullptr, nullptr, nullptr); 44 EXPECT_EQ(UUID.getString(), CT.getIdentifier()); 45 46 // Check that we get it back, even if we change a field. 47 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); 48 EXPECT_EQ(&CT, 49 DICompositeType::getODRType( 50 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, 51 nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, 52 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 53 nullptr)); 54 EXPECT_EQ(&CT, DICompositeType::getODRType( 55 Context, UUID, dwarf::DW_TAG_class_type, 56 MDString::get(Context, "name"), nullptr, 0, nullptr, 57 nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, 58 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 59 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, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, 79 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, DINode::FlagFwdDecl, nullptr, 87 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 88 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, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, 93 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, DINode::FlagZero, nullptr, 0, 99 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 100 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, DINode::FlagFwdDecl, nullptr, 107 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 108 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, DINode::FlagZero, nullptr, 113 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 114 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, 126 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(RuntimeLang) 144 145 // Create all the fields. 146 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X); 147 FOR_EACH_MDFIELD(); 148 #undef DO_FOR_FIELD 149 unsigned NonZeroInit = 0; 150 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit; 151 FOR_EACH_INLINEFIELD(); 152 #undef DO_FOR_FIELD 153 154 // Replace all the fields with new values that are distinct from each other. 155 EXPECT_EQ(&CT, 156 DICompositeType::buildODRType( 157 Context, UUID, 0, Name, File, Line, Scope, BaseType, SizeInBits, 158 AlignInBits, OffsetInBits, DINode::FlagArtificial, Elements, 159 RuntimeLang, VTableHolder, TemplateParams, nullptr, nullptr, 160 nullptr, nullptr, nullptr, nullptr)); 161 162 // Confirm that all the right fields got updated. 163 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); 164 FOR_EACH_MDFIELD(); 165 #undef DO_FOR_FIELD 166 #undef FOR_EACH_MDFIELD 167 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X()); 168 FOR_EACH_INLINEFIELD(); 169 #undef DO_FOR_FIELD 170 #undef FOR_EACH_INLINEFIELD 171 EXPECT_EQ(DINode::FlagArtificial, CT.getFlags()); 172 EXPECT_EQ(&UUID, CT.getRawIdentifier()); 173 } 174 175 } // end namespace 176