[llvm] Add support for fixed-point types (PR #129596)
Tom Tromey via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 6 09:58:41 PST 2025
https://github.com/tromey updated https://github.com/llvm/llvm-project/pull/129596
>From ca2cf87c319baee70b8be002aa4d9997936fa9de Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey at adacore.com>
Date: Wed, 29 Jan 2025 08:13:14 -0700
Subject: [PATCH] Add support for fixed-point types
This adds DWARF generation for fixed-point types. This feature is
needed by Ada.
Note that a pre-existing GNU extension is used in one case. This has
been emitted by GCC for years, and is needed because standard DWARF is
otherwise incapable of representing these types.
---
llvm/docs/LangRef.rst | 29 +++++
llvm/include/llvm-c/DebugInfo.h | 1 +
llvm/include/llvm/AsmParser/LLToken.h | 1 +
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 +
llvm/include/llvm/IR/DIBuilder.h | 36 ++++++
llvm/include/llvm/IR/DebugInfoMetadata.h | 138 ++++++++++++++++++++-
llvm/include/llvm/IR/Metadata.def | 1 +
llvm/lib/AsmParser/LLLexer.cpp | 5 +
llvm/lib/AsmParser/LLParser.cpp | 51 ++++++++
llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 33 +++++
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 32 +++++
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 28 ++++-
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 1 +
llvm/lib/IR/AsmWriter.cpp | 29 +++++
llvm/lib/IR/DIBuilder.cpp | 31 +++++
llvm/lib/IR/DebugInfoMetadata.cpp | 43 +++++++
llvm/lib/IR/LLVMContextImpl.h | 37 ++++++
llvm/lib/IR/Verifier.cpp | 19 +++
llvm/test/Bitcode/fixedpoint_type.ll | 29 +++++
llvm/unittests/IR/DebugInfoTest.cpp | 34 +++++
20 files changed, 577 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Bitcode/fixedpoint_type.ll
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<Metadata *> 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<Signedness> 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<Metadata *> 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<Metadata *> 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<Metadata *> 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<FixedPointKind> 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<FixedPointKind>(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<MDUnsignedField &>(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<DINode::DIFlags>(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<uint64_t> &Record, unsigned Abbrev);
void writeDIBasicType(const DIBasicType *N, SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev);
+ void writeDIFixedPointType(const DIFixedPointType *N,
+ SmallVectorImpl<uint64_t> &Record,
+ unsigned Abbrev);
void writeDIStringType(const DIStringType *N,
SmallVectorImpl<uint64_t> &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<uint64_t> &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<uint64_t> &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<DIBasicType>(Ty))
+ } else if (auto *FPT = dyn_cast<DIFixedPointType>(Ty))
+ construct(FPT);
+ else if (auto *BT = dyn_cast<DIBasicType>(Ty))
construct(BT);
else if (auto *ST = dyn_cast<DIStringType>(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<const DIBasicType *>(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 <class IntTy, class Stringifier>
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::Signedness> 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::FixedPointKind>
+DIFixedPointType::getFixedPointKind(StringRef Str) {
+ return StringSwitch<std::optional<FixedPointKind>>(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<DIBasicType> {
}
};
+template <> struct MDNodeKeyImpl<DIFixedPointType> {
+ 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<DIStringType> {
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<Module> 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<Module> M = parseIR(C, R"(
More information about the llvm-commits
mailing list