diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -387,7 +387,7 @@ TempDIEnumerator clone() const { return cloneImpl(); } - APInt getValue() const { return Value; } + const APInt &getValue() const { return Value; } bool isUnsigned() const { return SubclassData32; } StringRef getName() const { return getStringOperand(0); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4379,11 +4379,11 @@ if (isUnsigned.Val && value.Val.isSigned()) return TokError("unsigned enumerator with negative value"); - APSInt Value; + APSInt Value(value.Val); + // Add a leading zero so that unsigned values with the msb set are not + // mistaken for negative values when used for signed enumerators. if (value.Val.isUnsigned() && value.Val.isSignBitSet()) - Value = value.Val.zextOrSelf(value.Val.getBitWidth() + 1); - else - Value = value.Val; + Value = Value.zext(Value.getBitWidth() + 1); Result = GET_OR_DISTINCT(DIEnumerator, (Context, Value, isUnsigned.Val, name.Val)); diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -105,6 +105,15 @@ static int64_t unrotateSign(uint64_t U) { return (U & 1) ? ~(U >> 1) : U >> 1; } +static uint64_t decodeSignRotatedValue(uint64_t V) { + if ((V & 1) == 0) + return V >> 1; + if (V != 1) + return -(V >> 1); + // There is no such thing as -0 with integers. "-0" really means MININT. + return 1ULL << 63; +} + class BitcodeReaderMetadataList { /// Array of metadata references. /// @@ -1205,11 +1214,14 @@ APInt Value; if (IsBigInt) { - uint64_t NumWords = Record[1]; - Value = APInt(NumWords * 64, ArrayRef(&Record[3], NumWords)); - } else { + const uint64_t BitWidth = Record[1]; + const unsigned NumWords = Record.size() - 3; + SmallVector Words(NumWords); + transform(makeArrayRef(&Record[3], NumWords), Words.begin(), + decodeSignRotatedValue); + Value = APInt(BitWidth, Words); + } else Value = APInt(64, unrotateSign(Record[1]), !IsUnsigned); - } MetadataList.assignValue( GET_OR_DISTINCT(DIEnumerator, (Context, Value, IsUnsigned, diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1493,17 +1493,25 @@ Record.clear(); } +static void emitSignedInt64(SmallVectorImpl &Vals, uint64_t V) { + if ((int64_t)V >= 0) + Vals.push_back(V << 1); + else + Vals.push_back((-V << 1) | 1); +} + void ModuleBitcodeWriter::writeDIEnumerator(const DIEnumerator *N, SmallVectorImpl &Record, unsigned Abbrev) { - const uint64_t Version = 1 << 2; - Record.push_back(Version | (N->isUnsigned() << 1) | N->isDistinct()); - Record.push_back(N->getValue().getActiveWords()); + const uint64_t IsBigInt = 1 << 2; + Record.push_back(IsBigInt | (N->isUnsigned() << 1) | N->isDistinct()); + Record.push_back(N->getValue().getBitWidth()); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + // Write out only the active words to save some space unsigned NumWords = N->getValue().getActiveWords(); - const uint64_t *WordPtr = N->getValue().getRawData(); + const uint64_t *RawData = N->getValue().getRawData(); for (unsigned i = 0; i < NumWords; i++) - Record.push_back(WordPtr[i]); + emitSignedInt64(Record, RawData[i]); Stream.EmitRecord(bitc::METADATA_ENUMERATOR, Record, Abbrev); Record.clear(); @@ -2233,13 +2241,6 @@ Stream.ExitBlock(); } -static void emitSignedInt64(SmallVectorImpl &Vals, uint64_t V) { - if ((int64_t)V >= 0) - Vals.push_back(V << 1); - else - Vals.push_back((-V << 1) | 1); -} - void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, bool isGlobal) { if (FirstVal == LastVal) return; diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -362,7 +362,8 @@ MDNodeKeyImpl(APInt Value, bool IsUnsigned, MDString *Name) : Value(Value), Name(Name), IsUnsigned(IsUnsigned) {} MDNodeKeyImpl(int64_t Value, bool IsUnsigned, MDString *Name) - : Value(APInt(64, Value, !IsUnsigned)), Name(Name), IsUnsigned(IsUnsigned) {} + : Value(APInt(64, Value, !IsUnsigned)), Name(Name), + IsUnsigned(IsUnsigned) {} MDNodeKeyImpl(const DIEnumerator *N) : Value(N->getValue()), Name(N->getRawName()), IsUnsigned(N->isUnsigned()) {} diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -144,7 +144,12 @@ struct BTF::BTFEnum BTFEnum; BTFEnum.NameOff = BDebug.addString(Enum->getName()); // BTF enum value is 32bit, enforce it. - BTFEnum.Val = static_cast(Enum->getValue()->getLimitedValue()); + uint32_t Value; + if (Enum->isUnsigned()) + Value = static_cast(Enum->getValue().getZExtValue()); + else + Value = static_cast(Enum->getValue().getSExtValue()); + BTFEnum.Val = Value; EnumValues.push_back(BTFEnum); } } diff --git a/llvm/test/Assembler/DIEnumeratorBig.ll b/llvm/test/Assembler/DIEnumeratorBig.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/DIEnumeratorBig.ll @@ -0,0 +1,46 @@ +; Round-trip test for enumeration members using more than 64 bits + +; RUN: llvm-as %s -o - | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 7.0.1-8 (tags/RELEASE_701/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "/tmp/foo.cpp", directory: "/home/lemonboy/code/llvm-project/build") +!2 = !{!3, !8} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E0", file: !1, line: 2, baseType: !4, size: 128, flags: DIFlagEnumClass, elements: !6, identifier: "_ZTS2E0") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E0"{{.*}} +; CHECK-NOT: FixedEnum +!4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int128_t", file: !1, baseType: !5) +!5 = !DIBasicType(name: "__int128", size: 128, encoding: DW_ATE_signed) +; CHECK: !DIBasicType(name: "__int128", size: 128, encoding: DW_ATE_signed) +!6 = !{!7} +!7 = !DIEnumerator(name: "D0", value: 340282366920938463463374607431768211456) +; CHECK: !DIEnumerator(name: "D0", value: 340282366920938463463374607431768211456) +!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1", file: !1, line: 5, baseType: !9, size: 128, flags: DIFlagEnumClass, elements: !11, identifier: "_ZTS2E1") +; CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "E1"{{.*}} +; CHECK-NOT: FixedEnum +!9 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint128_t", file: !1, line: 9, baseType: !10) +!10 = !DIBasicType(name: "unsigned __int128", size: 128, encoding: DW_ATE_unsigned) +; CHECK: !DIBasicType(name: "unsigned __int128", size: 128, encoding: DW_ATE_unsigned) +!11 = !{!12} +!12 = !DIEnumerator(name: "D1", value: 2722258935367507707706996859454145691648, isUnsigned: true) +; CHECK: !DIEnumerator(name: "D1", value: 2722258935367507707706996859454145691648, isUnsigned: true) +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 7.0.1-8 (tags/RELEASE_701/final)"} +!17 = distinct !DISubprogram(name: "enum_test", linkageName: "_Z9enum_test2E0", scope: !1, file: !1, line: 9, type: !18, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !20) +!18 = !DISubroutineType(types: !19) +!19 = !{null, !3} +!20 = !{} +!21 = !DILocalVariable(name: "x", arg: 1, scope: !17, file: !1, line: 9, type: !3) +!22 = !DILocation(line: 9, column: 13, scope: !17) +!23 = !DILocation(line: 9, column: 17, scope: !17) +!24 = distinct !DISubprogram(name: "enum_test", linkageName: "_Z9enum_test2E1", scope: !1, file: !1, line: 10, type: !25, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !20) +!25 = !DISubroutineType(types: !26) +!26 = !{null, !8} +!27 = !DILocalVariable(name: "x", arg: 1, scope: !24, file: !1, line: 10, type: !8) +!28 = !DILocation(line: 10, column: 13, scope: !24) +!29 = !DILocation(line: 10, column: 17, scope: !24) diff --git a/llvm/test/DebugInfo/Generic/debug-info-enum.ll b/llvm/test/DebugInfo/Generic/debug-info-enum.ll --- a/llvm/test/DebugInfo/Generic/debug-info-enum.ll +++ b/llvm/test/DebugInfo/Generic/debug-info-enum.ll @@ -153,7 +153,7 @@ ; CHECK: DW_AT_name ("E7") ; CHECK: DW_TAG_enumerator ; CHECK: DW_AT_name ("A7") -; CHECK-NEXT: DW_AT_const_value (18446744073709551615) +; CHECK-NEXT: DW_AT_const_value (<0x08> ff ff ff ff ff ff ff ff ) ; 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 diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1185,7 +1185,7 @@ TEST_F(DIEnumeratorTest, get) { auto *N = DIEnumerator::get(Context, 7, false, "name"); EXPECT_EQ(dwarf::DW_TAG_enumerator, N->getTag()); - EXPECT_EQ((uint64_t)7, N->getValue().getLimitedValue()); + EXPECT_EQ(7, N->getValue().getSExtValue()); EXPECT_FALSE(N->isUnsigned()); EXPECT_EQ("name", N->getName()); EXPECT_EQ(N, DIEnumerator::get(Context, 7, false, "name")); @@ -1200,7 +1200,7 @@ TEST_F(DIEnumeratorTest, getWithLargeValues) { auto *N = DIEnumerator::get(Context, APInt::getMaxValue(128), false, "val"); - EXPECT_EQ((unsigned)128, N->getValue().countPopulation()); + EXPECT_EQ(128U, N->getValue().countPopulation()); EXPECT_EQ(N, DIEnumerator::get(Context, APInt::getMaxValue(128), false, "val")); EXPECT_NE(N, DIEnumerator::get(Context, APInt::getMinValue(128), false, "val")); }