186 lines · cpp
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-exception6//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"13using namespace llvm;14 15namespace {16 17TEST(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 26TEST(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, std::nullopt,34 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,35 nullptr));36 37 // Enable the mapping. There still shouldn't be a type.38 Context.enableDebugTypeODRUniquing();39 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));40 41 // Create some ODR-uniqued type.42 auto &CT = *DICompositeType::getODRType(43 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,44 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, nullptr, 0, std::nullopt,45 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,46 nullptr);47 EXPECT_EQ(UUID.getString(), CT.getIdentifier());48 49 // Check that we get it back, even if we change a field.50 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));51 EXPECT_EQ(&CT, DICompositeType::getODRType(52 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,53 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero,54 nullptr, 0, std::nullopt, nullptr, nullptr, nullptr,55 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));56 EXPECT_EQ(&CT, DICompositeType::getODRType(57 Context, UUID, dwarf::DW_TAG_class_type,58 MDString::get(Context, "name"), nullptr, 0, nullptr,59 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero, nullptr, 0,60 std::nullopt, nullptr, nullptr, nullptr, nullptr, nullptr,61 nullptr, nullptr, nullptr, nullptr));62 63 // Check that it's discarded with the type map.64 Context.disableDebugTypeODRUniquing();65 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));66 67 // And it shouldn't magically reappear...68 Context.enableDebugTypeODRUniquing();69 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));70}71 72TEST(DebugTypeODRUniquingTest, buildODRType) {73 LLVMContext Context;74 Context.enableDebugTypeODRUniquing();75 76 // Build an ODR type that's a forward decl.77 MDString &UUID = *MDString::get(Context, "Type");78 auto &CT = *DICompositeType::buildODRType(79 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,80 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl, nullptr, 0,81 std::nullopt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,82 nullptr, nullptr, nullptr);83 EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));84 EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());85 86 // Update with another forward decl. This should be a no-op.87 EXPECT_EQ(&CT,88 DICompositeType::buildODRType(89 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0,90 nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl,91 nullptr, 0, std::nullopt, nullptr, nullptr, nullptr, nullptr,92 nullptr, nullptr, nullptr, nullptr, nullptr));93 94 EXPECT_FALSE(DICompositeType::buildODRType(95 Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,96 nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl, nullptr, 0,97 std::nullopt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,98 nullptr, nullptr, nullptr));99 100 // Update with a definition. This time we should see a change.101 EXPECT_EQ(&CT, DICompositeType::buildODRType(102 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,103 0, nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero,104 nullptr, 0, std::nullopt, nullptr, nullptr, nullptr,105 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));106 EXPECT_FALSE(CT.isForwardDecl());107 108 // Further updates should be ignored.109 EXPECT_EQ(&CT,110 DICompositeType::buildODRType(111 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0,112 nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagFwdDecl,113 nullptr, 0, std::nullopt, nullptr, nullptr, nullptr, nullptr,114 nullptr, nullptr, nullptr, nullptr, nullptr));115 EXPECT_FALSE(CT.isForwardDecl());116 EXPECT_EQ(&CT,117 DICompositeType::buildODRType(118 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 111u,119 nullptr, nullptr, 0, 0, 0, nullptr, 0, DINode::FlagZero,120 nullptr, 0, std::nullopt, nullptr, nullptr, nullptr, nullptr,121 nullptr, nullptr, nullptr, nullptr, nullptr));122 EXPECT_NE(111u, CT.getLine());123}124 125TEST(DebugTypeODRUniquingTest, buildODRTypeFields) {126 LLVMContext Context;127 Context.enableDebugTypeODRUniquing();128 129 // Build an ODR type that's a forward decl with no other fields set.130 MDString &UUID = *MDString::get(Context, "UUID");131 auto &CT = *DICompositeType::buildODRType(132 Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, nullptr,133 0, DINode::FlagFwdDecl, nullptr, 0, std::nullopt, nullptr, nullptr,134 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);135 136// Create macros for running through all the fields except Identifier and Flags.137#define FOR_EACH_MDFIELD() \138 DO_FOR_FIELD(Name) \139 DO_FOR_FIELD(File) \140 DO_FOR_FIELD(Scope) \141 DO_FOR_FIELD(BaseType) \142 DO_FOR_FIELD(Elements) \143 DO_FOR_FIELD(VTableHolder) \144 DO_FOR_FIELD(TemplateParams) \145 DO_FOR_FIELD(SizeInBits) \146 DO_FOR_FIELD(OffsetInBits)147#define FOR_EACH_INLINEFIELD() \148 DO_FOR_FIELD(Line) \149 DO_FOR_FIELD(AlignInBits) \150 DO_FOR_FIELD(NumExtraInhabitants) \151 DO_FOR_FIELD(RuntimeLang) \152 DO_FOR_FIELD(EnumKind)153 154// Create all the fields.155#define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);156 FOR_EACH_MDFIELD();157#undef DO_FOR_FIELD158 unsigned NonZeroInit = 0;159#define DO_FOR_FIELD(X) auto X = ++NonZeroInit;160 FOR_EACH_INLINEFIELD();161#undef DO_FOR_FIELD162 163 // Replace all the fields with new values that are distinct from each other.164 EXPECT_EQ(&CT,165 DICompositeType::buildODRType(166 Context, UUID, 0, Name, File, Line, Scope, BaseType, SizeInBits,167 AlignInBits, OffsetInBits, nullptr, NumExtraInhabitants,168 DINode::FlagArtificial, Elements, RuntimeLang, EnumKind,169 VTableHolder, TemplateParams, nullptr, nullptr, nullptr,170 nullptr, nullptr, nullptr, nullptr));171 172 // Confirm that all the right fields got updated.173#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());174 FOR_EACH_MDFIELD();175#undef DO_FOR_FIELD176#undef FOR_EACH_MDFIELD177#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());178 FOR_EACH_INLINEFIELD();179#undef DO_FOR_FIELD180#undef FOR_EACH_INLINEFIELD181 EXPECT_EQ(DINode::FlagArtificial, CT.getFlags());182 EXPECT_EQ(&UUID, CT.getRawIdentifier());183}184 185} // end namespace186