From 08dc66eff0c7ad594584a8a6925ef830cd6873a1 Mon Sep 17 00:00:00 2001 From: Momchil Velikov Date: Mon, 12 Feb 2018 16:10:09 +0000 Subject: [PATCH] Re-commit r324489: [DebugInfo] Improvements to representation of enumeration types (PR36168) Differential Revision: https://reviews.llvm.org/D42734 llvm-svn: 324899 --- llvm/include/llvm/Bitcode/LLVMBitCodes.h | 2 +- llvm/include/llvm/IR/DIBuilder.h | 5 +- llvm/include/llvm/IR/DebugInfoFlags.def | 3 +- llvm/include/llvm/IR/DebugInfoMetadata.h | 30 ++-- llvm/lib/AsmParser/LLParser.cpp | 52 ++++++- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 5 +- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 19 +-- llvm/lib/IR/AsmWriter.cpp | 8 +- llvm/lib/IR/DIBuilder.cpp | 10 +- llvm/lib/IR/DebugInfoMetadata.cpp | 8 +- llvm/lib/IR/LLVMContextImpl.h | 10 +- llvm/test/Assembler/DIEnumerator.ll | 85 +++++++++++ llvm/test/DebugInfo/Generic/debug-info-enum.ll | 188 +++++++++++++++++++++++++ llvm/test/DebugInfo/X86/enum-class.ll | 6 +- llvm/unittests/IR/MetadataTest.cpp | 10 +- 16 files changed, 392 insertions(+), 51 deletions(-) create mode 100644 llvm/test/Assembler/DIEnumerator.ll create mode 100644 llvm/test/DebugInfo/Generic/debug-info-enum.ll diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index ab76b0b..1610ac0 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -279,7 +279,7 @@ enum MetadataCodes { METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]] METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num] METADATA_SUBRANGE = 13, // [distinct, count, lo] - METADATA_ENUMERATOR = 14, // [distinct, value, name] + METADATA_ENUMERATOR = 14, // [isUnsigned|distinct, value, name] METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] METADATA_FILE = 16, // [distinct, filename, directory, checksumkind, checksum] METADATA_DERIVED_TYPE = 17, // [distinct, ...] diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 34cc658..0c785f2 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -166,7 +166,7 @@ namespace llvm { DIFile *File); /// Create a single enumerator value. - DIEnumerator *createEnumerator(StringRef Name, int64_t Val); + DIEnumerator *createEnumerator(StringRef Name, int64_t Val, bool IsUnsigned = false); /// Create a DWARF unspecified type. DIBasicType *createUnspecifiedType(StringRef Name); @@ -487,10 +487,11 @@ namespace llvm { /// \param Elements Enumeration elements. /// \param UnderlyingType Underlying type of a C++11/ObjC fixed enum. /// \param UniqueIdentifier A unique identifier for the enum. + /// \param IsFixed Boolean flag indicate if this is C++11/ObjC fixed enum. DICompositeType *createEnumerationType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, DINodeArray Elements, - DIType *UnderlyingType, StringRef UniqueIdentifier = ""); + DIType *UnderlyingType, StringRef UniqueIdentifier = "", bool IsFixed = false); /// Create subroutine type. /// \param ParameterTypes An array of subroutine parameter types. This diff --git a/llvm/include/llvm/IR/DebugInfoFlags.def b/llvm/include/llvm/IR/DebugInfoFlags.def index 96cc3e5..676b978 100644 --- a/llvm/include/llvm/IR/DebugInfoFlags.def +++ b/llvm/include/llvm/IR/DebugInfoFlags.def @@ -45,6 +45,7 @@ HANDLE_DI_FLAG((1 << 20), NoReturn) HANDLE_DI_FLAG((1 << 21), MainSubprogram) HANDLE_DI_FLAG((1 << 22), TypePassByValue) HANDLE_DI_FLAG((1 << 23), TypePassByReference) +HANDLE_DI_FLAG((1 << 24), FixedEnum) // To avoid needing a dedicated value for IndirectVirtualBase, we use // the bitwise or of Virtual and FwdDecl, which does not otherwise @@ -54,7 +55,7 @@ HANDLE_DI_FLAG((1 << 2) | (1 << 5), IndirectVirtualBase) #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 23), Largest) +HANDLE_DI_FLAG((1 << 24), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 591dc84..608a61d 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -396,36 +396,38 @@ class DIEnumerator : public DINode { friend class MDNode; int64_t Value; - DIEnumerator(LLVMContext &C, StorageType Storage, int64_t Value, - ArrayRef Ops) + bool IsUnsigned, ArrayRef Ops) : DINode(C, DIEnumeratorKind, Storage, dwarf::DW_TAG_enumerator, Ops), - Value(Value) {} + Value(Value) { + SubclassData32 = IsUnsigned; + } ~DIEnumerator() = default; static DIEnumerator *getImpl(LLVMContext &Context, int64_t Value, - StringRef Name, StorageType Storage, - bool ShouldCreate = true) { - return getImpl(Context, Value, getCanonicalMDString(Context, Name), Storage, - ShouldCreate); + bool IsUnsigned, StringRef Name, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Value, IsUnsigned, + getCanonicalMDString(Context, Name), Storage, ShouldCreate); } static DIEnumerator *getImpl(LLVMContext &Context, int64_t Value, - MDString *Name, StorageType Storage, - bool ShouldCreate = true); + bool IsUnsigned, MDString *Name, + StorageType Storage, bool ShouldCreate = true); TempDIEnumerator cloneImpl() const { - return getTemporary(getContext(), getValue(), getName()); + return getTemporary(getContext(), getValue(), isUnsigned(), getName()); } public: - DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, StringRef Name), - (Value, Name)) - DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, MDString *Name), - (Value, Name)) + DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, bool IsUnsigned, StringRef Name), + (Value, IsUnsigned, Name)) + DEFINE_MDNODE_GET(DIEnumerator, (int64_t Value, bool IsUnsigned, MDString *Name), + (Value, IsUnsigned, Name)) TempDIEnumerator clone() const { return cloneImpl(); } int64_t getValue() const { return Value; } + bool isUnsigned() const { return SubclassData32; } StringRef getName() const { return getStringOperand(0); } MDString *getRawName() const { return getOperandAs(0); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 2833ef4..209a834 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3636,6 +3636,22 @@ struct MDSignedOrMDField : MDEitherFieldImpl { } }; +struct MDSignedOrUnsignedField + : MDEitherFieldImpl { + MDSignedOrUnsignedField() : ImplTy(MDSignedField(0), MDUnsignedField(0)) {} + + bool isMDSignedField() const { return WhatIs == IsTypeA; } + bool isMDUnsignedField() const { return WhatIs == IsTypeB; } + int64_t getMDSignedValue() const { + assert(isMDSignedField() && "Wrong field type"); + return A.Val; + } + uint64_t getMDUnsignedValue() const { + assert(isMDUnsignedField() && "Wrong field type"); + return B.Val; + } +}; + } // end anonymous namespace namespace llvm { @@ -3913,6 +3929,27 @@ bool LLParser::ParseMDField(LocTy Loc, StringRef Name, } template <> +bool LLParser::ParseMDField(LocTy Loc, StringRef Name, + MDSignedOrUnsignedField &Result) { + if (Lex.getKind() != lltok::APSInt) + return false; + + if (Lex.getAPSIntVal().isSigned()) { + MDSignedField Res = Result.A; + if (ParseMDField(Loc, Name, Res)) + return true; + Result.assign(Res); + return false; + } + + MDUnsignedField Res = Result.B; + if (ParseMDField(Loc, Name, Res)) + return true; + Result.assign(Res); + return false; +} + +template <> bool LLParser::ParseMDField(LocTy Loc, StringRef Name, MDStringField &Result) { LocTy ValueLoc = Lex.getLoc(); std::string S; @@ -4077,15 +4114,24 @@ bool LLParser::ParseDISubrange(MDNode *&Result, bool IsDistinct) { } /// ParseDIEnumerator: -/// ::= !DIEnumerator(value: 30, name: "SomeKind") +/// ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind") bool LLParser::ParseDIEnumerator(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(name, MDStringField, ); \ - REQUIRED(value, MDSignedField, ); + REQUIRED(value, MDSignedOrUnsignedField, ); \ + OPTIONAL(isUnsigned, MDBoolField, (false)); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIEnumerator, (Context, value.Val, name.Val)); + if (isUnsigned.Val && value.isMDSignedField()) + return TokError("unsigned enumerator with negative value"); + + int64_t Value = value.isMDSignedField() + ? value.getMDSignedValue() + : static_cast(value.getMDUnsignedValue()); + Result = + GET_OR_DISTINCT(DIEnumerator, (Context, Value, isUnsigned.Val, name.Val)); + return false; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index c0ec80e..374e315 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1200,10 +1200,11 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( if (Record.size() != 3) return error("Invalid record"); - IsDistinct = Record[0]; + IsDistinct = Record[0] & 1; + bool IsUnsigned = Record[0] & 2; MetadataList.assignValue( GET_OR_DISTINCT(DIEnumerator, (Context, unrotateSign(Record[1]), - getMDString(Record[2]))), + IsUnsigned, getMDString(Record[2]))), NextMetadataNo); NextMetadataNo++; break; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index fd9cde1..8c65e95 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1457,7 +1457,7 @@ void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N, void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N, SmallVectorImpl &Record, unsigned Abbrev) { - Record.push_back(N->isDistinct()); + Record.push_back((N->isUnsigned() << 1) | N->isDistinct()); Record.push_back(rotateSign(N->getValue())); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 0e6ed1c..939d13f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1427,6 +1427,15 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { + const DIType *DTy = resolve(CTy->getBaseType()); + bool IsUnsigned = DTy && isUnsignedDIType(DD, DTy); + if (DTy && DD->getDwarfVersion() >= 3) + addType(Buffer, DTy); + if (DD->getDwarfVersion() >= 4 && (CTy->getFlags() & DINode::FlagFixedEnum)) { + assert(DTy); + addFlag(Buffer, dwarf::DW_AT_enum_class); + } + DINodeArray Elements = CTy->getElements(); // Add enumerators to enumeration type. @@ -1436,16 +1445,10 @@ void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) { DIE &Enumerator = createAndAddDIE(dwarf::DW_TAG_enumerator, Buffer); StringRef Name = Enum->getName(); addString(Enumerator, dwarf::DW_AT_name, Name); - int64_t Value = Enum->getValue(); - addSInt(Enumerator, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, - Value); + auto Value = static_cast(Enum->getValue()); + addConstantValue(Enumerator, IsUnsigned, Value); } } - const DIType *DTy = resolve(CTy->getBaseType()); - if (DTy) { - addType(Buffer, DTy); - addFlag(Buffer, dwarf::DW_AT_enum_class); - } } void DwarfUnit::constructContainingTypeDIEs() { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index d641a63..444a341 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1629,7 +1629,13 @@ static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, Out << "!DIEnumerator("; MDFieldPrinter Printer(Out); Printer.printString("name", N->getName(), /* ShouldSkipEmpty */ false); - Printer.printInt("value", N->getValue(), /* ShouldSkipZero */ false); + if (N->isUnsigned()) { + auto Value = static_cast(N->getValue()); + Printer.printInt("value", Value, /* ShouldSkipZero */ false); + Printer.printBool("isUnsigned", true); + } else { + Printer.printInt("value", N->getValue(), /* ShouldSkipZero */ false); + } Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index ed3e281..f9aca8a 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -233,9 +233,10 @@ DIMacroFile *DIBuilder::createTempMacroFile(DIMacroFile *Parent, return MF; } -DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val) { +DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val, + bool IsUnsigned) { assert(!Name.empty() && "Unable to create enumerator without name"); - return DIEnumerator::get(VMContext, Val, Name); + return DIEnumerator::get(VMContext, Val, IsUnsigned, Name); } DIBasicType *DIBuilder::createUnspecifiedType(StringRef Name) { @@ -492,11 +493,12 @@ DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes, DICompositeType *DIBuilder::createEnumerationType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, DINodeArray Elements, - DIType *UnderlyingType, StringRef UniqueIdentifier) { + DIType *UnderlyingType, StringRef UniqueIdentifier, bool IsFixed) { auto *CTy = DICompositeType::get( VMContext, dwarf::DW_TAG_enumeration_type, Name, File, LineNumber, getNonCompileUnitScope(Scope), UnderlyingType, SizeInBits, AlignInBits, 0, - DINode::FlagZero, Elements, 0, nullptr, nullptr, UniqueIdentifier); + IsFixed ? DINode::FlagFixedEnum : DINode::FlagZero, Elements, 0, nullptr, + nullptr, UniqueIdentifier); AllEnumTypes.push_back(CTy); trackIfUnresolved(CTy); return CTy; diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index c44bc75..a777198 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -263,12 +263,12 @@ DISubrange *DISubrange::getImpl(LLVMContext &Context, Metadata *CountNode, } DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, int64_t Value, - MDString *Name, StorageType Storage, - bool ShouldCreate) { + bool IsUnsigned, MDString *Name, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIEnumerator, (Value, Name)); + DEFINE_GETIMPL_LOOKUP(DIEnumerator, (Value, IsUnsigned, Name)); Metadata *Ops[] = {Name}; - DEFINE_GETIMPL_STORE(DIEnumerator, (Value), Ops); + DEFINE_GETIMPL_STORE(DIEnumerator, (Value, IsUnsigned), Ops); } DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index db7f368..c4cd785 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -354,13 +354,17 @@ template <> struct MDNodeKeyImpl { template <> struct MDNodeKeyImpl { int64_t Value; MDString *Name; + bool IsUnsigned; - MDNodeKeyImpl(int64_t Value, MDString *Name) : Value(Value), Name(Name) {} + MDNodeKeyImpl(int64_t Value, bool IsUnsigned, MDString *Name) + : Value(Value), Name(Name), IsUnsigned(IsUnsigned) {} MDNodeKeyImpl(const DIEnumerator *N) - : Value(N->getValue()), Name(N->getRawName()) {} + : Value(N->getValue()), Name(N->getRawName()), + IsUnsigned(N->isUnsigned()) {} bool isKeyOf(const DIEnumerator *RHS) const { - return Value == RHS->getValue() && Name == RHS->getRawName(); + return Value == RHS->getValue() && IsUnsigned == RHS->isUnsigned() && + Name == RHS->getRawName(); } unsigned getHashValue() const { return hash_combine(Value, Name); } diff --git a/llvm/test/Assembler/DIEnumerator.ll b/llvm/test/Assembler/DIEnumerator.ll new file mode 100644 index 0000000..9dc3d7c --- /dev/null +++ b/llvm/test/Assembler/DIEnumerator.ll @@ -0,0 +1,85 @@ +; Round-trip test for the following program: +; ``` +; enum E0 { A0 = -2147483648, B0 = 2147483647 } x0; +; enum E1 : signed int { A1 = -2147483648, B1 = 2147483647 } x1; +; enum E2 : signed long long { A2 = -9223372036854775807LL - 1, +; B2 = 9223372036854775807LL } x2; +; enum E3 : unsigned long long { A3 = 0x8000000000000000ULL } x3; +; ``` +; Test FixedEnum flag presence/absence, the underlying integer type and +; enumerator values (signed and unsigned, and extreme cases) all survive through +; the round-trip. + +; RUN: llvm-as %s -o - | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +@x0 = global i32 0, align 4, !dbg !0 +@x1 = global i32 0, align 4, !dbg !24 +@x2 = global i64 0, align 8, !dbg !26 +@x3 = global i64 0, align 8, !dbg !28 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!30, !31, !32} +!llvm.ident = !{!33} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "x0", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (/data/src/llvm/tools/clang 697b0cb4c2e712a28767c2f7fe50c90bae7255f5) (/data/src/llvm 5ba8dcca7470b5da405bc92b9681b1f36e5d6772)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !23) +!3 = !DIFile(filename: "e.cc", directory: "/work/build/clang-dev") +!4 = !{!5, !10, !14, !19} + + +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E0", file: !3, line: 1, baseType: !6, size: 32, elements: !7, identifier: "_ZTS2E0") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E0"{{.*}}, baseType: ![[INT:[0-9]+]] +; CHECK-NOT: FixedEnum +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +; CHECK: ![[INT]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{!8, !9} +!8 = !DIEnumerator(name: "A0", value: -2147483648) +!9 = !DIEnumerator(name: "B0", value: 2147483647) +; CHECK: !DIEnumerator(name: "A0", value: -2147483648) +; CHECK: !DIEnumerator(name: "B0", value: 2147483647) + + +!10 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1", file: !3, line: 3, baseType: !6, size: 32, flags: DIFlagFixedEnum, elements: !11, identifier: "_ZTS2E1") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1"{{.*}}, baseType: ![[INT]] +; CHECK-SAME: DIFlagFixedEnum +!11 = !{!12, !13} +!12 = !DIEnumerator(name: "A1", value: -2147483648) +!13 = !DIEnumerator(name: "B1", value: 2147483647) +; CHECK: !DIEnumerator(name: "A1", value: -2147483648) +; CHECK: !DIEnumerator(name: "B1", value: 2147483647) + + +!14 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E2", file: !3, line: 5, baseType: !15, size: 64, flags: DIFlagFixedEnum, elements: !16, identifier: "_ZTS2E2") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E2"{{.*}}, baseType: ![[LONG:[0-9]+]] +; CHECK-SAME: DIFlagFixedEnum +!15 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +; CHECK: ![[LONG]] = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!16 = !{!17, !18} +!17 = !DIEnumerator(name: "A2", value: -9223372036854775808) +!18 = !DIEnumerator(name: "B2", value: 9223372036854775807) +; CHECK: !DIEnumerator(name: "A2", value: -9223372036854775808) +; CHECK: !DIEnumerator(name: "B2", value: 9223372036854775807) + + +!19 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E3", file: !3, line: 7, baseType: !20, size: 64, flags: DIFlagFixedEnum, elements: !21, identifier: "_ZTS2E3") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E3"{{.*}}, baseType: ![[ULONG:[0-9]+]] +; CHECK-SAME: DIFlagFixedEnum +!20 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +; CHECK: ![[ULONG]] = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!21 = !{!22} +!22 = !DIEnumerator(name: "A3", value: 9223372036854775808, isUnsigned: true) +; CHECK: !DIEnumerator(name: "A3", value: 9223372036854775808, isUnsigned: true) + + +!23 = !{!0, !24, !26, !28} +!24 = !DIGlobalVariableExpression(var: !25, expr: !DIExpression()) +!25 = distinct !DIGlobalVariable(name: "x1", scope: !2, file: !3, line: 3, type: !10, isLocal: false, isDefinition: true) +!26 = !DIGlobalVariableExpression(var: !27, expr: !DIExpression()) +!27 = distinct !DIGlobalVariable(name: "x2", scope: !2, file: !3, line: 5, type: !14, isLocal: false, isDefinition: true) +!28 = !DIGlobalVariableExpression(var: !29, expr: !DIExpression()) +!29 = distinct !DIGlobalVariable(name: "x3", scope: !2, file: !3, line: 7, type: !19, isLocal: false, isDefinition: true) +!30 = !{i32 2, !"Dwarf Version", i32 4} +!31 = !{i32 2, !"Debug Info Version", i32 3} +!32 = !{i32 1, !"wchar_size", i32 4} +!33 = !{!"clang version 7.0.0 (/data/src/llvm/tools/clang 697b0cb4c2e712a28767c2f7fe50c90bae7255f5) (/data/src/llvm 5ba8dcca7470b5da405bc92b9681b1f36e5d6772)"} diff --git a/llvm/test/DebugInfo/Generic/debug-info-enum.ll b/llvm/test/DebugInfo/Generic/debug-info-enum.ll new file mode 100644 index 0000000..c380fdc --- /dev/null +++ b/llvm/test/DebugInfo/Generic/debug-info-enum.ll @@ -0,0 +1,188 @@ +; Test enumeration representation in DWARF debug info: +; * test value representation for each possible underlying integer type +; * test the integer type is as expected +; * test the DW_AT_enum_class attribute is present (resp. absent) as expected. + +; RUN: llc -debugger-tune=gdb -dwarf-version=4 -filetype=obj -o %t.o < %s +; RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DW4 +; RUN: llc -debugger-tune=gdb -dwarf-version=2 -filetype=obj -o %t.o < %s +; RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DW2 + +@x0 = global i8 0, align 1, !dbg !0 +@x1 = global i8 0, align 1, !dbg !46 +@x2 = global i16 0, align 2, !dbg !48 +@x3 = global i16 0, align 2, !dbg !50 +@x4 = global i32 0, align 4, !dbg !52 +@x5 = global i32 0, align 4, !dbg !54 +@x6 = global i64 0, align 8, !dbg !56 +@x7 = global i64 0, align 8, !dbg !58 +@x8 = global i32 0, align 4, !dbg !60 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!62} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "x0", scope: !2, file: !3, line: 5, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (/data/src/llvm/tools/clang 0c08d9830124a75675348b4eeb47256f3da6693d) (/data/src/llvm cf29510f52faa77b98510cd53276f564d1f4f41f)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !45) +!3 = !DIFile(filename: "/data/src/llvm-dev/tools/clang/test/CodeGen/debug-info-enum.cpp", directory: "/work/build/clang-dev") +!4 = !{!5, !10, !14, !19, !23, !28, !32, !37, !41} + +; Test enumeration with a fixed "signed char" underlying type. +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E0", file: !3, line: 2, baseType: !6, size: 8, flags: DIFlagFixedEnum, elements: !7, identifier: "_ZTS2E0") +!6 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char) +!7 = !{!8, !9} +!8 = !DIEnumerator(name: "A0", value: -128) +!9 = !DIEnumerator(name: "B0", value: 127) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"signed char" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E0") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A0") +; CHECK-NEXT: DW_AT_const_value (-128) +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("B0") +; CHECK-NEXT: DW_AT_const_value (127) + +; Test enumeration with a fixed "unsigned char" underlying type. +!10 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1", file: !3, line: 12, baseType: !11, size: 8, flags: DIFlagFixedEnum, elements: !12, identifier: "_ZTS2E1") +!11 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!12 = !{!13} +!13 = !DIEnumerator(name: "A1", value: 255, isUnsigned: true) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"unsigned char" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E1") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A1") +; CHECK-NEXT: DW_AT_const_value (255) + +; Test enumeration with a fixed "short" underlying type. +!14 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E2", file: !3, line: 18, baseType: !15, size: 16, flags: DIFlagFixedEnum, elements: !16, identifier: "_ZTS2E2") +!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!16 = !{!17, !18} +!17 = !DIEnumerator(name: "A2", value: -32768) +!18 = !DIEnumerator(name: "B2", value: 32767) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}} "short" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E2") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A2") +; CHECK-NEXT: DW_AT_const_value (-32768) +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("B2") +; CHECK-NEXT: DW_AT_const_value (32767) + +; Test enumeration with a fixed "unsigned short" underlying type. +!19 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E3", file: !3, line: 28, baseType: !20, size: 16, flags: DIFlagFixedEnum, elements: !21, identifier: "_ZTS2E3") +!20 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!21 = !{!22} +!22 = !DIEnumerator(name: "A3", value: 65535, isUnsigned: true) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"unsigned short" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E3") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A3") +; CHECK-NEXT: DW_AT_const_value (65535) + +; Test enumeration with a fixed "int" underlying type. +!23 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E4", file: !3, line: 34, baseType: !24, size: 32, flags: DIFlagFixedEnum, elements: !25, identifier: "_ZTS2E4") +!24 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!25 = !{!26, !27} +!26 = !DIEnumerator(name: "A4", value: -2147483648) +!27 = !DIEnumerator(name: "B4", value: 2147483647) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"int" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E4") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A4") +; CHECK-NEXT: DW_AT_const_value (-2147483648) +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("B4") +; CHECK-NEXT: DW_AT_const_value (2147483647) + +; Test enumeration with a fixed "unsigend int" underlying type. +!28 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E5", file: !3, line: 41, baseType: !29, size: 32, flags: DIFlagFixedEnum, elements: !30, identifier: "_ZTS2E5") +!29 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!30 = !{!31} +!31 = !DIEnumerator(name: "A5", value: 4294967295, isUnsigned: true) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"unsigned int" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E5") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A5") +; CHECK-NEXT: DW_AT_const_value (4294967295) + +; Test enumeration with a fixed "long long" underlying type. +!32 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E6", file: !3, line: 47, baseType: !33, size: 64, flags: DIFlagFixedEnum, elements: !34, identifier: "_ZTS2E6") +!33 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!34 = !{!35, !36} +!35 = !DIEnumerator(name: "A6", value: -9223372036854775808) +!36 = !DIEnumerator(name: "B6", value: 9223372036854775807) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"long long int" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E6") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A6") +; CHECK-NEXT: DW_AT_const_value (-9223372036854775808) +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("B6") +; CHECK-NEXT: DW_AT_const_value (9223372036854775807) + +; Test enumeration with a fixed "unsigned long long" underlying type. +!37 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E7", file: !3, line: 57, baseType: !38, size: 64, flags: DIFlagFixedEnum, elements: !39, identifier: "_ZTS2E7") +!38 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!39 = !{!40} +!40 = !DIEnumerator(name: "A7", value: 18446744073709551615, isUnsigned: true) +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"long long unsigned int" +; CHECK-DW4: DW_AT_enum_class (true) +; CHECK: DW_AT_name ("E7") +; CHECK: DW_TAG_enumerator +; CHECK: DW_AT_name ("A7") +; CHECK-NEXT: DW_AT_const_value (18446744073709551615) + +; Test enumeration without a fixed underlying type. The underlying type should +; still be present (for DWARF >= 3), but the DW_AT_enum_class attribute should +; be absent. +!41 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E8", file: !3, line: 63, baseType: !24, size: 32, elements: !42, identifier: "_ZTS2E8") +!42 = !{!43, !44} +!43 = !DIEnumerator(name: "A8", value: -128) +!44 = !DIEnumerator(name: "B8", value: 127) +!45 = !{!0, !46, !48, !50, !52, !54, !56, !58, !60} +; CHECK: DW_TAG_enumeration_type +; CHECK-DW2-NOT: DW_AT_type +; CHECK-DW4: DW_AT_type{{.*}}"int" +; CHECK-NOT: DW_AT_enum_class +; CHECK: DW_AT_name ("E8") + +!46 = !DIGlobalVariableExpression(var: !47, expr: !DIExpression()) +!47 = distinct !DIGlobalVariable(name: "x1", scope: !2, file: !3, line: 12, type: !10, isLocal: false, isDefinition: true) +!48 = !DIGlobalVariableExpression(var: !49, expr: !DIExpression()) +!49 = distinct !DIGlobalVariable(name: "x2", scope: !2, file: !3, line: 21, type: !14, isLocal: false, isDefinition: true) +!50 = !DIGlobalVariableExpression(var: !51, expr: !DIExpression()) +!51 = distinct !DIGlobalVariable(name: "x3", scope: !2, file: !3, line: 28, type: !19, isLocal: false, isDefinition: true) +!52 = !DIGlobalVariableExpression(var: !53, expr: !DIExpression()) +!53 = distinct !DIGlobalVariable(name: "x4", scope: !2, file: !3, line: 34, type: !23, isLocal: false, isDefinition: true) +!54 = !DIGlobalVariableExpression(var: !55, expr: !DIExpression()) +!55 = distinct !DIGlobalVariable(name: "x5", scope: !2, file: !3, line: 41, type: !28, isLocal: false, isDefinition: true) +!56 = !DIGlobalVariableExpression(var: !57, expr: !DIExpression()) +!57 = distinct !DIGlobalVariable(name: "x6", scope: !2, file: !3, line: 50, type: !32, isLocal: false, isDefinition: true) +!58 = !DIGlobalVariableExpression(var: !59, expr: !DIExpression()) +!59 = distinct !DIGlobalVariable(name: "x7", scope: !2, file: !3, line: 57, type: !37, isLocal: false, isDefinition: true) +!60 = !DIGlobalVariableExpression(var: !61, expr: !DIExpression()) +!61 = distinct !DIGlobalVariable(name: "x8", scope: !2, file: !3, line: 63, type: !41, isLocal: false, isDefinition: true) +!62 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/llvm/test/DebugInfo/X86/enum-class.ll b/llvm/test/DebugInfo/X86/enum-class.ll index 3850f5f..92398c4 100644 --- a/llvm/test/DebugInfo/X86/enum-class.ll +++ b/llvm/test/DebugInfo/X86/enum-class.ll @@ -13,13 +13,13 @@ source_filename = "test/DebugInfo/X86/enum-class.ll" !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 4, type: !3, isLocal: false, isDefinition: true) !2 = !DIFile(filename: "foo.cpp", directory: "/Users/echristo/tmp") -!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !2, line: 1, baseType: !4, size: 32, align: 32, elements: !5) +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !2, line: 1, baseType: !4, size: 32, flags: DIFlagFixedEnum, align: 32, elements: !5) !4 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !5 = !{!6} !6 = !DIEnumerator(name: "A1", value: 1) !7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression()) ; [ DW_TAG_enumerator ] !8 = !DIGlobalVariable(name: "b", scope: null, file: !2, line: 5, type: !9, isLocal: false, isDefinition: true) -!9 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !2, line: 2, baseType: !10, size: 64, align: 64, elements: !11) +!9 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !2, line: 2, baseType: !10, size: 64, flags: DIFlagFixedEnum, align: 64, elements: !11) !10 = !DIBasicType(name: "long unsigned int", size: 64, align: 64, encoding: DW_ATE_unsigned) !11 = !{!12} !12 = !DIEnumerator(name: "B1", value: 1) ; [ DW_TAG_enumerator ] @@ -44,6 +44,6 @@ source_filename = "test/DebugInfo/X86/enum-class.ll" ; CHECK: DW_AT_enum_class [DW_FORM_flag_present] (true) ; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "B") -; CHECK: DW_TAG_enumeration_type [6] +; CHECK: DW_TAG_enumeration_type ; CHECK-NOT: DW_AT_enum_class ; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "C") diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 548456c..6c16951 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -978,14 +978,16 @@ TEST_F(DISubrangeTest, getVariableCount) { typedef MetadataTest DIEnumeratorTest; TEST_F(DIEnumeratorTest, get) { - auto *N = DIEnumerator::get(Context, 7, "name"); + auto *N = DIEnumerator::get(Context, 7, false, "name"); EXPECT_EQ(dwarf::DW_TAG_enumerator, N->getTag()); EXPECT_EQ(7, N->getValue()); + EXPECT_EQ(false, N->isUnsigned()); EXPECT_EQ("name", N->getName()); - EXPECT_EQ(N, DIEnumerator::get(Context, 7, "name")); + EXPECT_EQ(N, DIEnumerator::get(Context, 7, false, "name")); - EXPECT_NE(N, DIEnumerator::get(Context, 8, "name")); - EXPECT_NE(N, DIEnumerator::get(Context, 7, "nam")); + EXPECT_NE(N, DIEnumerator::get(Context, 7, true, "name")); + EXPECT_NE(N, DIEnumerator::get(Context, 8, false, "name")); + EXPECT_NE(N, DIEnumerator::get(Context, 7, false, "nam")); TempDIEnumerator Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); -- 2.7.4