mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-15 01:46:46 +00:00

n Rust, an enum that carries data in the variants is, essentially, a discriminated union. Furthermore, the Rust compiler will perform space optimizations on such enums in some situations. Previously, DWARF for these constructs was emitted using a hack (a magic field name); but this approach stopped working when more space optimizations were added in https://github.com/rust-lang/rust/pull/45225. This patch changes LLVM to allow discriminated unions to be represented in DWARF. It adds createDiscriminatedUnionType and createDiscriminatedMemberType to DIBuilder and then arranges for this to be emitted using DWARF's DW_TAG_variant_part and DW_TAG_variant. Note that DWARF requires that a discriminated union be represented as a structure with a variant part. However, as Rust only needs to emit pure discriminated unions, this is what I chose to expose on DIBuilder. Patch by Tom Tromey! Differential Revision: https://reviews.llvm.org/D42082 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@324426 91177308-0d34-0410-b5e6-96231b3b80d8
160 lines
7.0 KiB
C++
160 lines
7.0 KiB
C++
//===- 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/DebugInfoMetadata.h"
|
|
#include "llvm/IR/LLVMContext.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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, nullptr));
|
|
|
|
// 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
|