diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 33c85c7ba9d29..32b62bbdb59ad 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6210,6 +6210,35 @@ following: DW_ATE_unsigned = 7 DW_ATE_unsigned_char = 8 +.. _DIFixedPointType: + +DIFixedPointType +"""""""""""""""" + +``DIFixedPointType`` nodes represent fixed-point types. A fixed-point +type is conceptually an integer with a scale factor. +``DIFixedPointType`` is derived from ``DIBasicType`` and inherits its +attributes. However, only certain encodings are accepted: + +.. code-block:: text + + DW_ATE_signed_fixed = 13 + DW_ATE_unsigned_fixed = 14 + +There are three kinds of fixed-point type: binary, where the scale +factor is a power of 2; decimal, where the scale factor is a power of +10; and rational, where the scale factor is an arbitrary rational +number. + +.. code-block:: text + + !0 = !DIFixedPointType(name: "decimal", size: 8, encoding: DW_ATE_signed_fixed, + kind: Decimal, factor: -4) + !1 = !DIFixedPointType(name: "binary", size: 8, encoding: DW_ATE_unsigned_fixed, + kind: Binary, factor: -16) + !2 = !DIFixedPointType(name: "rational", size: 8, encoding: DW_ATE_signed_fixed, + kind: Rational, numerator: 1234, denominator: 5678) + .. _DISubroutineType: DISubroutineType diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 9d0875a4ed8d8..3ecd642e08958 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -171,6 +171,7 @@ enum { LLVMDISubrangeMetadataKind, LLVMDIEnumeratorMetadataKind, LLVMDIBasicTypeMetadataKind, + LLVMDIFixedPointTypeMetadataKind, LLVMDIDerivedTypeMetadataKind, LLVMDISubrangeTypeMetadataKind, LLVMDICompositeTypeMetadataKind, diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index 81b9929b1fab8..a8f9c71781701 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -494,6 +494,7 @@ enum Kind { DwarfCC, // DW_CC_foo EmissionKind, // lineTablesOnly NameTableKind, // GNU + FixedPointKind, // Fixed point DwarfOp, // DW_OP_foo DIFlag, // DIFlagFoo DISPFlag, // DISPFlagFoo diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index ec2535ac85966..92b6e68d9d0a7 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -386,6 +386,7 @@ enum MetadataCodes { METADATA_ARG_LIST = 46, // [n x [type num, value num]] METADATA_ASSIGN_ID = 47, // [distinct, ...] METADATA_SUBRANGE_TYPE = 48, // [distinct, ...] + METADATA_FIXED_POINT_TYPE = 49, // [distinct, ...] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 92a0b7a16d039..2e624b8d816ae 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -215,6 +215,42 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, uint32_t NumExtraInhabitants = 0); + /// Create debugging information entry for a binary fixed-point type. + /// \param Name Type name. + /// \param Encoding DWARF encoding code, either + /// dwarf::DW_ATE_signed_fixed or DW_ATE_unsigned_fixed. + /// \param Flags Optional DWARF attributes, e.g., DW_AT_endianity. + /// \param Factor Binary scale factor. + DIFixedPointType * + createBinaryFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, int Factor); + + /// Create debugging information entry for a decimal fixed-point type. + /// \param Name Type name. + /// \param Encoding DWARF encoding code, either + /// dwarf::DW_ATE_signed_fixed or DW_ATE_unsigned_fixed. + /// \param Flags Optional DWARF attributes, e.g., DW_AT_endianity. + /// \param Factor Decimal scale factor. + DIFixedPointType * + createDecimalFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, int Factor); + + /// Create debugging information entry for an arbitrary rational + /// fixed-point type. + /// \param Name Type name. + /// \param Encoding DWARF encoding code, either + /// dwarf::DW_ATE_signed_fixed or DW_ATE_unsigned_fixed. + /// \param Flags Optional DWARF attributes, e.g., DW_AT_endianity. + /// \param Numerator Numerator of scale factor. + /// \param Denominator Denominator of scale factor. + DIFixedPointType * + createRationalFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, APInt Numerator, + APInt Denominator); + /// Create debugging information entry for a string /// type. /// \param Name Type name. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 7826514cd3e44..1e91265332ef5 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -199,6 +199,7 @@ class DINode : public MDNode { case DISubrangeKind: case DIEnumeratorKind: case DIBasicTypeKind: + case DIFixedPointTypeKind: case DIStringTypeKind: case DISubrangeTypeKind: case DIDerivedTypeKind: @@ -547,6 +548,7 @@ class DIScope : public DINode { default: return false; case DIBasicTypeKind: + case DIFixedPointTypeKind: case DIStringTypeKind: case DISubrangeTypeKind: case DIDerivedTypeKind: @@ -806,6 +808,7 @@ class DIType : public DIScope { default: return false; case DIBasicTypeKind: + case DIFixedPointTypeKind: case DIStringTypeKind: case DISubrangeTypeKind: case DIDerivedTypeKind: @@ -826,6 +829,7 @@ class DIBasicType : public DIType { unsigned Encoding; +protected: DIBasicType(LLVMContext &C, StorageType Storage, unsigned Tag, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, uint32_t NumExtraInhabitants, DIFlags Flags, @@ -833,6 +837,13 @@ class DIBasicType : public DIType { : DIType(C, DIBasicTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0, NumExtraInhabitants, Flags, Ops), Encoding(Encoding) {} + DIBasicType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + uint32_t NumExtraInhabitants, DIFlags Flags, + ArrayRef Ops) + : DIType(C, ID, Storage, Tag, 0, SizeInBits, AlignInBits, 0, + NumExtraInhabitants, Flags, Ops), + Encoding(Encoding) {} ~DIBasicType() = default; static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, @@ -897,7 +908,132 @@ class DIBasicType : public DIType { std::optional getSignedness() const; static bool classof(const Metadata *MD) { - return MD->getMetadataID() == DIBasicTypeKind; + return MD->getMetadataID() == DIBasicTypeKind || + MD->getMetadataID() == DIFixedPointTypeKind; + } +}; + +/// Fixed-point type. +class DIFixedPointType : public DIBasicType { + friend class LLVMContextImpl; + friend class MDNode; + + // Actually FixedPointKind. + unsigned Kind; + // Used for binary and decimal. + int Factor; + // Used for rational. + APInt Numerator; + APInt Denominator; + + DIFixedPointType(LLVMContext &C, StorageType Storage, unsigned Tag, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + DIFlags Flags, unsigned Kind, int Factor, + ArrayRef Ops) + : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, SizeInBits, + AlignInBits, Encoding, 0, Flags, Ops), + Kind(Kind), Factor(Factor) { + assert(Kind == FixedPointBinary || Kind == FixedPointDecimal); + } + DIFixedPointType(LLVMContext &C, StorageType Storage, unsigned Tag, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + DIFlags Flags, unsigned Kind, APInt Numerator, + APInt Denominator, ArrayRef Ops) + : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, SizeInBits, + AlignInBits, Encoding, 0, Flags, Ops), + Kind(Kind), Factor(0), Numerator(Numerator), Denominator(Denominator) { + assert(Kind == FixedPointRational); + } + DIFixedPointType(LLVMContext &C, StorageType Storage, unsigned Tag, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + DIFlags Flags, unsigned Kind, int Factor, APInt Numerator, + APInt Denominator, ArrayRef Ops) + : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, SizeInBits, + AlignInBits, Encoding, 0, Flags, Ops), + Kind(Kind), Factor(Factor), Numerator(Numerator), + Denominator(Denominator) {} + ~DIFixedPointType() = default; + + static DIFixedPointType * + getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + DIFlags Flags, unsigned Kind, int Factor, APInt Numerator, + APInt Denominator, StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Tag, getCanonicalMDString(Context, Name), + SizeInBits, AlignInBits, Encoding, Flags, Kind, Factor, + Numerator, Denominator, Storage, ShouldCreate); + } + static DIFixedPointType * + getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + DIFlags Flags, unsigned Kind, int Factor, APInt Numerator, + APInt Denominator, StorageType Storage, bool ShouldCreate = true); + + TempDIFixedPointType cloneImpl() const { + return getTemporary(getContext(), getTag(), getName(), getSizeInBits(), + getAlignInBits(), getEncoding(), getFlags(), Kind, + Factor, Numerator, Denominator); + } + +public: + enum FixedPointKind : unsigned { + /// Scale factor 2^Factor. + FixedPointBinary, + /// Scale factor 10^Factor. + FixedPointDecimal, + /// Arbitrary rational scale factor. + FixedPointRational, + LastFixedPointKind = FixedPointRational, + }; + + static std::optional getFixedPointKind(StringRef Str); + static const char *fixedPointKindString(FixedPointKind); + + DEFINE_MDNODE_GET(DIFixedPointType, + (unsigned Tag, MDString *Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags, + unsigned Kind, int Factor, APInt Numerator, + APInt Denominator), + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, Kind, + Factor, Numerator, Denominator)) + DEFINE_MDNODE_GET(DIFixedPointType, + (unsigned Tag, StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, DIFlags Flags, + unsigned Kind, int Factor, APInt Numerator, + APInt Denominator), + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, Kind, + Factor, Numerator, Denominator)) + + TempDIFixedPointType clone() const { return cloneImpl(); } + + bool isBinary() const { return Kind == FixedPointBinary; } + bool isDecimal() const { return Kind == FixedPointDecimal; } + bool isRational() const { return Kind == FixedPointRational; } + + bool isSigned() const; + + FixedPointKind getKind() const { return static_cast(Kind); } + + int getFactorRaw() const { return Factor; } + int getFactor() const { + assert(Kind == FixedPointBinary || Kind == FixedPointDecimal); + return Factor; + } + + const APInt &getNumeratorRaw() const { return Numerator; } + const APInt &getNumerator() const { + assert(Kind == FixedPointRational); + return Numerator; + } + + const APInt &getDenominatorRaw() const { return Denominator; } + const APInt &getDenominator() const { + assert(Kind == FixedPointRational); + return Denominator; + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIFixedPointTypeKind; } }; diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def index 7cb257fefbc38..511bf48707f00 100644 --- a/llvm/include/llvm/IR/Metadata.def +++ b/llvm/include/llvm/IR/Metadata.def @@ -119,6 +119,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubrangeType) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIFixedPointType) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index fd0a50d25e714..4d25b12c9ab06 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -1024,6 +1024,11 @@ lltok::Kind LLLexer::LexIdentifier() { return lltok::NameTableKind; } + if (Keyword == "Binary" || Keyword == "Decimal" || Keyword == "Rational") { + StrVal.assign(Keyword.begin(), Keyword.end()); + return lltok::FixedPointKind; + } + // Check for [us]0x[0-9A-Fa-f]+ which are Hexadecimal constant generated by // the CFE to avoid forcing it to deal with 64-bit numbers. if ((TokStart[0] == 'u' || TokStart[0] == 's') && diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 777bf5f7bb386..4298aff0dcd70 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4750,6 +4750,11 @@ struct EmissionKindField : public MDUnsignedField { EmissionKindField() : MDUnsignedField(0, DICompileUnit::LastEmissionKind) {} }; +struct FixedPointKindField : public MDUnsignedField { + FixedPointKindField() + : MDUnsignedField(0, DIFixedPointType::LastFixedPointKind) {} +}; + struct NameTableKindField : public MDUnsignedField { NameTableKindField() : MDUnsignedField( @@ -4993,6 +4998,25 @@ bool LLParser::parseMDField(LocTy Loc, StringRef Name, return false; } +template <> +bool LLParser::parseMDField(LocTy Loc, StringRef Name, + FixedPointKindField &Result) { + if (Lex.getKind() == lltok::APSInt) + return parseMDField(Loc, Name, static_cast(Result)); + + if (Lex.getKind() != lltok::FixedPointKind) + return tokError("expected fixed-point kind"); + + auto Kind = DIFixedPointType::getFixedPointKind(Lex.getStrVal()); + if (!Kind) + return tokError("invalid fixed-point kind" + Twine(" '") + Lex.getStrVal() + + "'"); + assert(*Kind <= Result.Max && "Expected valid fixed-point kind"); + Result.assign(*Kind); + Lex.Lex(); + return false; +} + template <> bool LLParser::parseMDField(LocTy Loc, StringRef Name, NameTableKindField &Result) { @@ -5515,6 +5539,33 @@ bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) { return false; } +/// parseDIFixedPointType: +/// ::= !DIFixedPointType(tag: DW_TAG_base_type, name: "xyz", size: 32, +/// align: 32, encoding: DW_ATE_signed_fixed, +/// flags: 0, kind: Rational, factor: 3, numerator: 1, +/// denominator: 8) +bool LLParser::parseDIFixedPointType(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_base_type)); \ + OPTIONAL(name, MDStringField, ); \ + OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \ + OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \ + OPTIONAL(encoding, DwarfAttEncodingField, ); \ + OPTIONAL(flags, DIFlagField, ); \ + OPTIONAL(kind, FixedPointKindField, ); \ + OPTIONAL(factor, MDSignedField, ); \ + OPTIONAL(numerator, MDAPSIntField, ); \ + OPTIONAL(denominator, MDAPSIntField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DIFixedPointType, + (Context, tag.Val, name.Val, size.Val, align.Val, + encoding.Val, flags.Val, kind.Val, factor.Val, + numerator.Val, denominator.Val)); + return false; +} + /// parseDIStringType: /// ::= !DIStringType(name: "character(4)", size: 32, align: 32) bool LLParser::parseDIStringType(MDNode *&Result, bool IsDistinct) { diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 1baf0a9214e00..7e078f6f7f044 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1542,6 +1542,39 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( NextMetadataNo++; break; } + case bitc::METADATA_FIXED_POINT_TYPE: { + if (Record.size() < 11) + return error("Invalid record"); + + IsDistinct = Record[0]; + DINode::DIFlags Flags = static_cast(Record[6]); + + size_t Offset = 9; + + auto ReadWideInt = [&]() { + uint64_t Encoded = Record[Offset++]; + unsigned NumWords = Encoded >> 32; + unsigned BitWidth = Encoded & 0xffffffff; + auto Value = readWideAPInt(ArrayRef(&Record[Offset], NumWords), BitWidth); + Offset += NumWords; + return Value; + }; + + APInt Numerator = ReadWideInt(); + APInt Denominator = ReadWideInt(); + + if (Offset != Record.size()) + return error("Invalid record"); + + MetadataList.assignValue( + GET_OR_DISTINCT(DIFixedPointType, + (Context, Record[1], getMDString(Record[2]), Record[3], + Record[4], Record[5], Flags, Record[7], Record[8], + Numerator, Denominator)), + NextMetadataNo); + NextMetadataNo++; + break; + } case bitc::METADATA_STRING_TYPE: { if (Record.size() > 9 || Record.size() < 8) return error("Invalid record"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 440a2c9ace8a3..91d1f931fce39 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -323,6 +323,9 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase { SmallVectorImpl &Record, unsigned Abbrev); void writeDIBasicType(const DIBasicType *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIFixedPointType(const DIFixedPointType *N, + SmallVectorImpl &Record, + unsigned Abbrev); void writeDIStringType(const DIStringType *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIDerivedType(const DIDerivedType *N, @@ -1888,6 +1891,35 @@ void ModuleBitcodeWriter::writeDIBasicType(const DIBasicType *N, Record.clear(); } +void ModuleBitcodeWriter::writeDIFixedPointType( + const DIFixedPointType *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getEncoding()); + Record.push_back(N->getFlags()); + Record.push_back(N->getKind()); + Record.push_back(N->getFactorRaw()); + + auto WriteWideInt = [&](const APInt &Value) { + // Write an encoded word that holds the number of active words and + // the number of bits. + uint64_t NumWords = Value.getActiveWords(); + uint64_t Encoded = (NumWords << 32) | Value.getBitWidth(); + Record.push_back(Encoded); + emitWideAPInt(Record, Value); + }; + + WriteWideInt(N->getNumeratorRaw()); + WriteWideInt(N->getDenominatorRaw()); + + Stream.EmitRecord(bitc::METADATA_FIXED_POINT_TYPE, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDIStringType(const DIStringType *N, SmallVectorImpl &Record, unsigned Abbrev) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index b77ecf1372405..3f3c6e4138050 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -615,7 +615,9 @@ DIE *DwarfUnit::createTypeDIE(const DIScope *Context, DIE &ContextDIE, return &TyDIE; } construct(CTy); - } else if (auto *BT = dyn_cast(Ty)) + } else if (auto *FPT = dyn_cast(Ty)) + construct(FPT); + else if (auto *BT = dyn_cast(Ty)) construct(BT); else if (auto *ST = dyn_cast(Ty)) construct(ST); @@ -760,6 +762,30 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { NumExtraInhabitants); } +void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIFixedPointType *BTy) { + // Base type handling. + constructTypeDIE(Buffer, static_cast(BTy)); + + if (BTy->isBinary()) + addSInt(Buffer, dwarf::DW_AT_binary_scale, dwarf::DW_FORM_sdata, + BTy->getFactor()); + else if (BTy->isDecimal()) + addSInt(Buffer, dwarf::DW_AT_decimal_scale, dwarf::DW_FORM_sdata, + BTy->getFactor()); + else { + assert(BTy->isRational()); + DIE *ContextDIE = getOrCreateContextDIE(BTy->getScope()); + DIE &Constant = createAndAddDIE(dwarf::DW_TAG_constant, *ContextDIE); + + addInt(Constant, dwarf::DW_AT_GNU_numerator, BTy->getNumerator(), + !BTy->isSigned()); + addInt(Constant, dwarf::DW_AT_GNU_denominator, BTy->getDenominator(), + !BTy->isSigned()); + + addDIEEntry(Buffer, dwarf::DW_AT_small, Constant); + } +} + void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) { // Get core information. StringRef Name = STy->getName(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 5b0da7b09d31c..055d7173daec5 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -343,6 +343,7 @@ class DwarfUnit : public DIEUnit { void addIntAsBlock(DIE &Die, dwarf::Attribute Attribute, const APInt &Val); void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy); + void constructTypeDIE(DIE &Buffer, const DIFixedPointType *BTy); void constructTypeDIE(DIE &Buffer, const DIStringType *BTy); void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy); void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 238898c3b2e2f..ae1e2a558e5d1 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1890,6 +1890,7 @@ struct MDFieldPrinter { void printEmissionKind(StringRef Name, DICompileUnit::DebugEmissionKind EK); void printNameTableKind(StringRef Name, DICompileUnit::DebugNameTableKind NTK); + void printFixedPointKind(StringRef Name, DIFixedPointType::FixedPointKind V); }; } // end anonymous namespace @@ -2026,6 +2027,11 @@ void MDFieldPrinter::printNameTableKind(StringRef Name, Out << FS << Name << ": " << DICompileUnit::nameTableKindString(NTK); } +void MDFieldPrinter::printFixedPointKind(StringRef Name, + DIFixedPointType::FixedPointKind V) { + Out << FS << Name << ": " << DIFixedPointType::fixedPointKindString(V); +} + template void MDFieldPrinter::printDwarfEnum(StringRef Name, IntTy Value, Stringifier toString, bool ShouldSkipZero) { @@ -2198,6 +2204,29 @@ static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N, Out << ")"; } +static void writeDIFixedPointType(raw_ostream &Out, const DIFixedPointType *N, + AsmWriterContext &) { + Out << "!DIFixedPointType("; + MDFieldPrinter Printer(Out); + if (N->getTag() != dwarf::DW_TAG_base_type) + Printer.printTag(N); + Printer.printString("name", N->getName()); + Printer.printInt("size", N->getSizeInBits()); + Printer.printInt("align", N->getAlignInBits()); + Printer.printDwarfEnum("encoding", N->getEncoding(), + dwarf::AttributeEncodingString); + Printer.printDIFlags("flags", N->getFlags()); + Printer.printFixedPointKind("kind", N->getKind()); + if (N->isRational()) { + bool IsUnsigned = !N->isSigned(); + Printer.printAPInt("numerator", N->getNumerator(), IsUnsigned, false); + Printer.printAPInt("denominator", N->getDenominator(), IsUnsigned, false); + } else { + Printer.printInt("factor", N->getFactor()); + } + Out << ")"; +} + static void writeDIStringType(raw_ostream &Out, const DIStringType *N, AsmWriterContext &WriterCtx) { Out << "!DIStringType("; diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index f127ca8d94295..3aaa4b4432437 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -272,6 +272,37 @@ DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits, 0, Encoding, NumExtraInhabitants, Flags); } +DIFixedPointType * +DIBuilder::createBinaryFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, int Factor) { + return DIFixedPointType::get(VMContext, dwarf::DW_TAG_base_type, Name, + SizeInBits, AlignInBits, Encoding, Flags, + DIFixedPointType::FixedPointBinary, Factor, + APInt(), APInt()); +} + +DIFixedPointType * +DIBuilder::createDecimalFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, int Factor) { + return DIFixedPointType::get(VMContext, dwarf::DW_TAG_base_type, Name, + SizeInBits, AlignInBits, Encoding, Flags, + DIFixedPointType::FixedPointDecimal, Factor, + APInt(), APInt()); +} + +DIFixedPointType * +DIBuilder::createRationalFixedPointType(StringRef Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, + DINode::DIFlags Flags, APInt Numerator, + APInt Denominator) { + return DIFixedPointType::get(VMContext, dwarf::DW_TAG_base_type, Name, + SizeInBits, AlignInBits, Encoding, Flags, + DIFixedPointType::FixedPointRational, 0, + Numerator, Denominator); +} + DIStringType *DIBuilder::createStringType(StringRef Name, uint64_t SizeInBits) { assert(!Name.empty() && "Unable to create type without name"); return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name, diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index f975d4ca33ad9..83b07be9a2d2d 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -721,15 +721,58 @@ std::optional DIBasicType::getSignedness() const { switch (getEncoding()) { case dwarf::DW_ATE_signed: case dwarf::DW_ATE_signed_char: + case dwarf::DW_ATE_signed_fixed: return Signedness::Signed; case dwarf::DW_ATE_unsigned: case dwarf::DW_ATE_unsigned_char: + case dwarf::DW_ATE_unsigned_fixed: return Signedness::Unsigned; default: return std::nullopt; } } +DIFixedPointType * +DIFixedPointType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, unsigned Kind, + int Factor, APInt Numerator, APInt Denominator, + StorageType Storage, bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DIFixedPointType, + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, + Kind, Factor, Numerator, Denominator)); + Metadata *Ops[] = {nullptr, nullptr, Name}; + DEFINE_GETIMPL_STORE(DIFixedPointType, + (Tag, SizeInBits, AlignInBits, Encoding, Flags, Kind, + Factor, Numerator, Denominator), + Ops); +} + +bool DIFixedPointType::isSigned() const { + return getEncoding() == dwarf::DW_ATE_signed_fixed; +} + +std::optional +DIFixedPointType::getFixedPointKind(StringRef Str) { + return StringSwitch>(Str) + .Case("Binary", FixedPointBinary) + .Case("Decimal", FixedPointDecimal) + .Case("Rational", FixedPointRational) + .Default(std::nullopt); +} + +const char *DIFixedPointType::fixedPointKindString(FixedPointKind V) { + switch (V) { + case FixedPointBinary: + return "Binary"; + case FixedPointDecimal: + return "Decimal"; + case FixedPointRational: + return "Rational"; + } + return nullptr; +} + DIStringType *DIStringType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *StringLength, Metadata *StringLengthExp, diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 72ea3104cc7d5..4dfe89ed3aac8 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -494,6 +494,43 @@ template <> struct MDNodeKeyImpl { } }; +template <> struct MDNodeKeyImpl { + unsigned Tag; + MDString *Name; + uint64_t SizeInBits; + uint32_t AlignInBits; + unsigned Encoding; + unsigned Flags; + unsigned Kind; + int Factor; + APInt Numerator; + APInt Denominator; + + MDNodeKeyImpl(unsigned Tag, MDString *Name, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned Encoding, unsigned Flags, + unsigned Kind, int Factor, APInt Numerator, APInt Denominator) + : Tag(Tag), Name(Name), SizeInBits(SizeInBits), AlignInBits(AlignInBits), + Encoding(Encoding), Flags(Flags), Kind(Kind), Factor(Factor), + Numerator(Numerator), Denominator(Denominator) {} + MDNodeKeyImpl(const DIFixedPointType *N) + : Tag(N->getTag()), Name(N->getRawName()), SizeInBits(N->getSizeInBits()), + AlignInBits(N->getAlignInBits()), Encoding(N->getEncoding()), + Flags(N->getFlags()), Kind(N->getKind()), Factor(N->getFactorRaw()), + Numerator(N->getNumeratorRaw()), Denominator(N->getDenominatorRaw()) {} + + bool isKeyOf(const DIFixedPointType *RHS) const { + return Name == RHS->getRawName() && SizeInBits == RHS->getSizeInBits() && + AlignInBits == RHS->getAlignInBits() && Kind == RHS->getKind() && + (RHS->isRational() ? (Numerator == RHS->getNumerator() && + Denominator == RHS->getDenominator()) + : Factor == RHS->getFactor()); + } + + unsigned getHashValue() const { + return hash_combine(Name, Flags, Kind, Factor, Numerator, Denominator); + } +}; + template <> struct MDNodeKeyImpl { unsigned Tag; MDString *Name; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 3477e2bfe0b2b..758e03dd47e34 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1239,6 +1239,25 @@ void Verifier::visitDIBasicType(const DIBasicType &N) { "invalid tag", &N); } +void Verifier::visitDIFixedPointType(const DIFixedPointType &N) { + visitDIBasicType(N); + + CheckDI(N.getTag() == dwarf::DW_TAG_base_type, "invalid tag", &N); + CheckDI(N.getEncoding() == dwarf::DW_ATE_signed_fixed || + N.getEncoding() == dwarf::DW_ATE_unsigned_fixed, + "invalid encoding", &N); + CheckDI(N.getKind() == DIFixedPointType::FixedPointBinary || + N.getKind() == DIFixedPointType::FixedPointDecimal || + N.getKind() == DIFixedPointType::FixedPointRational, + "invalid kind", &N); + CheckDI(N.getKind() != DIFixedPointType::FixedPointRational || + N.getFactorRaw() == 0, + "factor should be 0 for rationals", &N); + CheckDI(N.getKind() == DIFixedPointType::FixedPointRational || + (N.getNumeratorRaw() == 0 && N.getDenominatorRaw() == 0), + "numerator and denominator should be 0 for non-rationals", &N); +} + void Verifier::visitDIStringType(const DIStringType &N) { CheckDI(N.getTag() == dwarf::DW_TAG_string_type, "invalid tag", &N); CheckDI(!(N.isBigEndian() && N.isLittleEndian()), "has conflicting flags", diff --git a/llvm/test/Bitcode/fixedpoint_type.ll b/llvm/test/Bitcode/fixedpoint_type.ll new file mode 100644 index 0000000000000..bbe1fdac9a4e6 --- /dev/null +++ b/llvm/test/Bitcode/fixedpoint_type.ll @@ -0,0 +1,29 @@ +;; This test checks generation of DIFixedPointType. + +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +;; Test whether DIFixedPointType is generated. +; CHECK: !DIFixedPointType(name: "fp__decimal", size: 32, align: 32, encoding: DW_ATE_signed_fixed, kind: Decimal, factor: -4) +; CHECK: !DIFixedPointType(name: "fp__rational", size: 32, align: 32, encoding: DW_ATE_unsigned_fixed, kind: Rational, numerator: 1234, denominator: 5678) +; CHECK: !DIFixedPointType(name: "fp__binary", size: 64, encoding: DW_ATE_unsigned_fixed, kind: Binary, factor: -16) + +; ModuleID = 'fixedpoint_type.ll' +source_filename = "/dir/fixedpoint_type.adb" + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = !{i32 2, !"Dwarf Version", i32 4} +!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "GNAT/LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4) +!3 = !DIFile(filename: "fixedpoint_type.adb", directory: "/dir") +!4 = !{} +!5 = !{!11, !12, !13} +!6 = distinct !DISubprogram(name: "fp", scope: !3, file: !3, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !9) +!7 = !DISubroutineType(types: !8) +!8 = !{null} +!9 = !{!10} +!10 = !DILocalVariable(name: "x", scope: !6, file: !3, line: 3, type: !11, align: 32) +!11 = !DIFixedPointType(name: "fp__decimal", size: 32, align: 32, encoding: DW_ATE_signed_fixed, kind: Decimal, factor: -4) +!12 = !DIFixedPointType(name: "fp__rational", size: 32, align: 32, encoding: DW_ATE_unsigned_fixed, kind: Rational, numerator: 1234, denominator: 5678) +!13 = !DIFixedPointType(name: "fp__binary", size: 64, align: 0, encoding: DW_ATE_unsigned_fixed, kind: Binary, factor: -16) diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp index c632bd6d3cbb5..3d68bd59b670f 100644 --- a/llvm/unittests/IR/DebugInfoTest.cpp +++ b/llvm/unittests/IR/DebugInfoTest.cpp @@ -483,6 +483,40 @@ TEST(DIBuilder, DIEnumerator) { EXPECT_FALSE(E2); } +TEST(DIBuilder, FixedPointType) { + LLVMContext Ctx; + std::unique_ptr M(new Module("MyModule", Ctx)); + DIBuilder DIB(*M); + + DIFixedPointType *Ty = DIB.createBinaryFixedPointType( + {}, 32, 0, dwarf::DW_ATE_signed_fixed, DINode::FlagZero, -4); + EXPECT_TRUE(Ty); + EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointBinary); + EXPECT_TRUE(Ty->getFactor() == -4); + EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_signed_fixed); + EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type); + + Ty = DIB.createDecimalFixedPointType({}, 32, 0, dwarf::DW_ATE_unsigned_fixed, + DINode::FlagZero, -7); + EXPECT_TRUE(Ty); + EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointDecimal); + EXPECT_TRUE(Ty->getFactor() == -7); + EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_unsigned_fixed); + EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type); + + APSInt Num(APInt(32, 1)); + APSInt Denom(APInt(33, 72)); + Ty = DIB.createRationalFixedPointType({}, 32, 0, dwarf::DW_ATE_unsigned_fixed, + DINode::FlagZero, Num, Denom); + EXPECT_TRUE(Ty); + EXPECT_TRUE(Ty->getKind() == DIFixedPointType::FixedPointRational); + EXPECT_TRUE(Ty->getFactorRaw() == 0); + EXPECT_TRUE(Ty->getNumerator() == Num); + EXPECT_TRUE(Ty->getDenominator() == Denom); + EXPECT_TRUE(Ty->getEncoding() == dwarf::DW_ATE_unsigned_fixed); + EXPECT_TRUE(Ty->getTag() == dwarf::DW_TAG_base_type); +} + TEST(DbgAssignIntrinsicTest, replaceVariableLocationOp) { LLVMContext C; std::unique_ptr M = parseIR(C, R"(