summaryrefslogtreecommitdiff
path: root/unittests/IR/DebugTypeODRUniquingTest.cpp
blob: 2133d8236adea6d1929827f635e2b0e044ef4f5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/DebugInfoMetadata.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));

  // 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);
  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));
  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));

  // 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);
  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_structure_type, nullptr, nullptr, 0, nullptr,
      nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr));
  EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());

  // Update with a definition.  This time we should see a change.
  EXPECT_EQ(&CT, DICompositeType::buildODRType(
      Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
      nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr));
  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());

  // 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));
  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
  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));
  EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
}

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);

// 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(Tag)                                                            \
  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, Tag, Name, File, Line, Scope, BaseType,
                SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial,
                Elements, RuntimeLang, VTableHolder, TemplateParams));

  // 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