Add support for fixed-point types (#129596)

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.
This commit is contained in:
Tom Tromey
2025-03-31 08:42:21 -06:00
committed by GitHub
parent 4007de00a0
commit 68947342b7
20 changed files with 577 additions and 2 deletions

View File

@@ -6212,6 +6212,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

View File

@@ -173,6 +173,7 @@ enum {
LLVMDISubrangeMetadataKind,
LLVMDIEnumeratorMetadataKind,
LLVMDIBasicTypeMetadataKind,
LLVMDIFixedPointTypeMetadataKind,
LLVMDIDerivedTypeMetadataKind,
LLVMDICompositeTypeMetadataKind,
LLVMDISubroutineTypeMetadataKind,

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -199,6 +199,7 @@ public:
case DISubrangeKind:
case DIEnumeratorKind:
case DIBasicTypeKind:
case DIFixedPointTypeKind:
case DIStringTypeKind:
case DISubrangeTypeKind:
case DIDerivedTypeKind:
@@ -547,6 +548,7 @@ public:
default:
return false;
case DIBasicTypeKind:
case DIFixedPointTypeKind:
case DIStringTypeKind:
case DISubrangeTypeKind:
case DIDerivedTypeKind:
@@ -806,6 +808,7 @@ public:
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 @@ public:
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;
}
};

View File

@@ -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

View File

@@ -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') &&

View File

@@ -4751,6 +4751,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(
@@ -4994,6 +4999,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) {
@@ -5516,6 +5540,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) {

View File

@@ -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");

View File

@@ -323,6 +323,9 @@ private:
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,
@@ -1887,6 +1890,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) {

View File

@@ -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();

View File

@@ -343,6 +343,7 @@ private:
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);

View File

@@ -1894,6 +1894,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
@@ -2030,6 +2031,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) {
@@ -2199,6 +2205,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(";

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;

View File

@@ -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",

View File

@@ -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)

View File

@@ -501,6 +501,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"(