[llvm] Non constant size and offset in DWARF (PR #141106)
via llvm-commits
llvm-commits at lists.llvm.org
Thu May 22 10:25:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir
Author: Tom Tromey (tromey)
<details>
<summary>Changes</summary>
In Ada, a record type can have a non-constant size, and a field can appear at a non-constant bit offset in a record.
To support this, this patch changes DIType to record the size and offset using metadata, rather than plain integers. In addition to a constant offset, both DIVariable and DIExpression are now supported here.
One thing of note in this patch is the choice of how exactly to represent a non-constant bit offset, with the difficulty being that DWARF 5 does not support this. DWARF 3 did have a way to support a non-constant byte offset, combined with a constant bit offset within the byte, but this was deprecated in DWARF 4 and removed from DWARF 5.
This patch takes a simple approach: a DWARF extension allowing the use of an expression with DW_AT_data_bit_offset. There is a corresponding DWARF issue, see https://dwarfstd.org/issues/250501.1.html. The main reason for this approach is that it keeps API simplicity: just a single value is needed, rather than having separate data describing the byte offset and the bit within the byte.
---
Patch is 124.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/141106.diff
13 Files Affected:
- (modified) llvm/include/llvm/IR/DIBuilder.h (+60)
- (modified) llvm/include/llvm/IR/DebugInfoMetadata.h (+311-122)
- (modified) llvm/lib/AsmParser/LLParser.cpp (+83-27)
- (modified) llvm/lib/Bitcode/Reader/MetadataLoader.cpp (+80-15)
- (modified) llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (+21-14)
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+130-72)
- (modified) llvm/lib/IR/DIBuilder.cpp (+65-23)
- (modified) llvm/lib/IR/DebugInfoMetadata.cpp (+50-51)
- (modified) llvm/lib/IR/LLVMContextImpl.h (+39-37)
- (modified) llvm/lib/IR/Verifier.cpp (+18)
- (added) llvm/test/DebugInfo/dynamic-bitfield.ll (+62)
- (modified) llvm/unittests/IR/DebugInfoTest.cpp (+29)
- (modified) llvm/unittests/IR/DebugTypeODRUniquingTest.cpp (+3-3)
``````````diff
diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index 4ce71bd3dad58..1e1a4cb0af9ba 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -365,6 +365,24 @@ namespace llvm {
uint64_t BaseOffset, uint32_t VBPtrOffset,
DINode::DIFlags Flags);
+ /// Create debugging information entry for a member.
+ /// \param Scope Member scope.
+ /// \param Name Member name.
+ /// \param File File where this member is defined.
+ /// \param LineNo Line number.
+ /// \param SizeInBits Member size.
+ /// \param AlignInBits Member alignment.
+ /// \param OffsetInBits Member offset.
+ /// \param Flags Flags to encode member attribute, e.g. private
+ /// \param Ty Parent type.
+ /// \param Annotations Member annotations.
+ DIDerivedType *createMemberType(DIScope *Scope, StringRef Name,
+ DIFile *File, unsigned LineNo,
+ Metadata *SizeInBits, uint32_t AlignInBits,
+ Metadata *OffsetInBits,
+ DINode::DIFlags Flags, DIType *Ty,
+ DINodeArray Annotations = nullptr);
+
/// Create debugging information entry for a member.
/// \param Scope Member scope.
/// \param Name Member name.
@@ -419,6 +437,25 @@ namespace llvm {
DIDerivedType *createVariantMemberType(DIScope *Scope, DINodeArray Elements,
Constant *Discriminant, DIType *Ty);
+ /// Create debugging information entry for a bit field member.
+ /// \param Scope Member scope.
+ /// \param Name Member name.
+ /// \param File File where this member is defined.
+ /// \param LineNo Line number.
+ /// \param SizeInBits Member size.
+ /// \param OffsetInBits Member offset.
+ /// \param StorageOffsetInBits Member storage offset.
+ /// \param Flags Flags to encode member attribute.
+ /// \param Ty Parent type.
+ /// \param Annotations Member annotations.
+ DIDerivedType *createBitFieldMemberType(DIScope *Scope, StringRef Name,
+ DIFile *File, unsigned LineNo,
+ Metadata *SizeInBits,
+ Metadata *OffsetInBits,
+ uint64_t StorageOffsetInBits,
+ DINode::DIFlags Flags, DIType *Ty,
+ DINodeArray Annotations = nullptr);
+
/// Create debugging information entry for a bit field member.
/// \param Scope Member scope.
/// \param Name Member name.
@@ -510,6 +547,29 @@ namespace llvm {
unsigned RunTimeLang = 0, DIType *VTableHolder = nullptr,
MDNode *TemplateParms = nullptr, StringRef UniqueIdentifier = "");
+ /// Create debugging information entry for a struct.
+ /// \param Scope Scope in which this struct is defined.
+ /// \param Name Struct name.
+ /// \param File File where this member is defined.
+ /// \param LineNumber Line number.
+ /// \param SizeInBits Member size.
+ /// \param AlignInBits Member alignment.
+ /// \param Flags Flags to encode member attribute, e.g. private
+ /// \param Elements Struct elements.
+ /// \param RunTimeLang Optional parameter, Objective-C runtime version.
+ /// \param UniqueIdentifier A unique identifier for the struct.
+ /// \param Specification The type that this type completes. This is used by
+ /// Swift to represent generic types.
+ /// \param NumExtraInhabitants The number of extra inhabitants of the type.
+ /// An extra inhabitant is a bit pattern that does not represent a valid
+ /// value for instances of a given type. This is used by the Swift language.
+ DICompositeType *createStructType(
+ DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
+ Metadata *SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags,
+ DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang = 0,
+ DIType *VTableHolder = nullptr, StringRef UniqueIdentifier = "",
+ DIType *Specification = nullptr, uint32_t NumExtraInhabitants = 0);
+
/// Create debugging information entry for a struct.
/// \param Scope Scope in which this struct is defined.
/// \param Name Struct name.
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index d82c69aebb026..2ab2da60b1b6e 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -711,40 +711,33 @@ std::optional<StringRef> DIScope::getSource() const {
class DIType : public DIScope {
unsigned Line;
DIFlags Flags;
- uint64_t SizeInBits;
- uint64_t OffsetInBits;
uint32_t NumExtraInhabitants;
protected:
+ static constexpr unsigned N_OPERANDS = 5;
+
DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag,
- unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits,
- uint64_t OffsetInBits, uint32_t NumExtraInhabitants, DIFlags Flags,
- ArrayRef<Metadata *> Ops)
+ unsigned Line, uint32_t AlignInBits, uint32_t NumExtraInhabitants,
+ DIFlags Flags, ArrayRef<Metadata *> Ops)
: DIScope(C, ID, Storage, Tag, Ops) {
- init(Line, SizeInBits, AlignInBits, OffsetInBits, NumExtraInhabitants,
- Flags);
+ init(Line, AlignInBits, NumExtraInhabitants, Flags);
}
~DIType() = default;
- void init(unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits,
- uint64_t OffsetInBits, uint32_t NumExtraInhabitants,
+ void init(unsigned Line, uint32_t AlignInBits, uint32_t NumExtraInhabitants,
DIFlags Flags) {
this->Line = Line;
this->Flags = Flags;
- this->SizeInBits = SizeInBits;
this->SubclassData32 = AlignInBits;
- this->OffsetInBits = OffsetInBits;
this->NumExtraInhabitants = NumExtraInhabitants;
}
/// Change fields in place.
- void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits,
- uint32_t AlignInBits, uint64_t OffsetInBits,
+ void mutate(unsigned Tag, unsigned Line, uint32_t AlignInBits,
uint32_t NumExtraInhabitants, DIFlags Flags) {
assert(isDistinct() && "Only distinct nodes can mutate");
setTag(Tag);
- init(Line, SizeInBits, AlignInBits, OffsetInBits, NumExtraInhabitants,
- Flags);
+ init(Line, AlignInBits, NumExtraInhabitants, Flags);
}
public:
@@ -753,10 +746,8 @@ class DIType : public DIScope {
}
unsigned getLine() const { return Line; }
- uint64_t getSizeInBits() const { return SizeInBits; }
uint32_t getAlignInBits() const;
uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; }
- uint64_t getOffsetInBits() const { return OffsetInBits; }
uint32_t getNumExtraInhabitants() const { return NumExtraInhabitants; }
DIFlags getFlags() const { return Flags; }
@@ -766,6 +757,26 @@ class DIType : public DIScope {
Metadata *getRawScope() const { return getOperand(1); }
MDString *getRawName() const { return getOperandAs<MDString>(2); }
+ Metadata *getRawSizeInBits() const { return getOperand(3); }
+ uint64_t getSizeInBits() const {
+ if (auto *MD = dyn_cast_or_null<ConstantAsMetadata>(getRawSizeInBits())) {
+ if (ConstantInt *CI = dyn_cast_or_null<ConstantInt>(MD->getValue())) {
+ return CI->getZExtValue();
+ }
+ }
+ return 0;
+ }
+
+ Metadata *getRawOffsetInBits() const { return getOperand(4); }
+ uint64_t getOffsetInBits() const {
+ if (auto *MD = dyn_cast_or_null<ConstantAsMetadata>(getRawOffsetInBits())) {
+ if (ConstantInt *CI = dyn_cast_or_null<ConstantInt>(MD->getValue())) {
+ return CI->getZExtValue();
+ }
+ }
+ return 0;
+ }
+
/// Returns a new temporary DIType with updated Flags
TempDIType cloneWithFlags(DIFlags NewFlags) const {
auto NewTy = clone();
@@ -831,18 +842,18 @@ class DIBasicType : public DIType {
protected:
DIBasicType(LLVMContext &C, StorageType Storage, unsigned Tag,
- uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
+ uint32_t AlignInBits, unsigned Encoding,
uint32_t NumExtraInhabitants, DIFlags Flags,
ArrayRef<Metadata *> Ops)
- : DIType(C, DIBasicTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0,
+ : DIType(C, DIBasicTypeKind, Storage, Tag, 0, AlignInBits,
NumExtraInhabitants, Flags, Ops),
Encoding(Encoding) {}
DIBasicType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag,
- uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
+ 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),
+ : DIType(C, ID, Storage, Tag, 0, AlignInBits, NumExtraInhabitants, Flags,
+ Ops),
Encoding(Encoding) {}
~DIBasicType() = default;
@@ -859,11 +870,21 @@ class DIBasicType : public DIType {
MDString *Name, uint64_t SizeInBits,
uint32_t AlignInBits, unsigned Encoding,
uint32_t NumExtraInhabitants, DIFlags Flags,
+ StorageType Storage, bool ShouldCreate = true) {
+ auto *SizeInBitsNode = ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
+ return getImpl(Context, Tag, Name, SizeInBitsNode, AlignInBits, Encoding,
+ NumExtraInhabitants, Flags, Storage, ShouldCreate);
+ }
+ static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag,
+ MDString *Name, Metadata *SizeInBits,
+ uint32_t AlignInBits, unsigned Encoding,
+ uint32_t NumExtraInhabitants, DIFlags Flags,
StorageType Storage, bool ShouldCreate = true);
TempDIBasicType cloneImpl() const {
- return getTemporary(getContext(), getTag(), getName(), getSizeInBits(),
- getAlignInBits(), getEncoding(),
+ return getTemporary(getContext(), getTag(), getRawName(),
+ getRawSizeInBits(), getAlignInBits(), getEncoding(),
getNumExtraInhabitants(), getFlags());
}
@@ -896,6 +917,12 @@ class DIBasicType : public DIType {
uint32_t NumExtraInhabitants, DIFlags Flags),
(Tag, Name, SizeInBits, AlignInBits, Encoding,
NumExtraInhabitants, Flags))
+ DEFINE_MDNODE_GET(DIBasicType,
+ (unsigned Tag, MDString *Name, Metadata *SizeInBits,
+ uint32_t AlignInBits, unsigned Encoding,
+ uint32_t NumExtraInhabitants, DIFlags Flags),
+ (Tag, Name, SizeInBits, AlignInBits, Encoding,
+ NumExtraInhabitants, Flags))
TempDIBasicType clone() const { return cloneImpl(); }
@@ -927,29 +954,28 @@ class DIFixedPointType : public DIBasicType {
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),
+ uint32_t AlignInBits, unsigned Encoding, DIFlags Flags,
+ unsigned Kind, int Factor, ArrayRef<Metadata *> Ops)
+ : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, 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),
+ uint32_t AlignInBits, unsigned Encoding, DIFlags Flags,
+ unsigned Kind, APInt Numerator, APInt Denominator,
+ ArrayRef<Metadata *> Ops)
+ : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, 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,
+ 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),
+ : DIBasicType(C, DIFixedPointTypeKind, Storage, Tag, AlignInBits,
+ Encoding, 0, Flags, Ops),
Kind(Kind), Factor(Factor), Numerator(Numerator),
Denominator(Denominator) {}
~DIFixedPointType() = default;
@@ -959,20 +985,42 @@ class DIFixedPointType : public DIBasicType {
uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
DIFlags Flags, unsigned Kind, int Factor, APInt Numerator,
APInt Denominator, StorageType Storage, bool ShouldCreate = true) {
+ auto *SizeInBitsNode = ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
+ return getImpl(Context, Tag, getCanonicalMDString(Context, Name),
+ SizeInBitsNode, AlignInBits, Encoding, Flags, Kind, Factor,
+ Numerator, Denominator, Storage, ShouldCreate);
+ }
+ static DIFixedPointType *
+ getImpl(LLVMContext &Context, unsigned Tag, StringRef Name,
+ Metadata *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,
+ uint32_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
+ DIFlags Flags, unsigned Kind, int Factor, APInt Numerator,
+ APInt Denominator, StorageType Storage, bool ShouldCreate = true) {
+ auto *SizeInBitsNode = ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
+ return getImpl(Context, Tag, Name, SizeInBitsNode, AlignInBits, Encoding,
+ Flags, Kind, Factor, Numerator, Denominator, Storage,
+ ShouldCreate);
+ }
+ static DIFixedPointType *
+ getImpl(LLVMContext &Context, unsigned Tag, MDString *Name,
+ Metadata *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);
+ return getTemporary(getContext(), getTag(), getRawName(),
+ getRawSizeInBits(), getAlignInBits(), getEncoding(),
+ getFlags(), Kind, Factor, Numerator, Denominator);
}
public:
@@ -1003,6 +1051,13 @@ class DIFixedPointType : public DIBasicType {
APInt Denominator),
(Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, Kind,
Factor, Numerator, Denominator))
+ DEFINE_MDNODE_GET(DIFixedPointType,
+ (unsigned Tag, MDString *Name, Metadata *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(); }
@@ -1042,13 +1097,15 @@ class DIStringType : public DIType {
friend class LLVMContextImpl;
friend class MDNode;
+ static constexpr unsigned MY_FIRST_OPERAND = DIType::N_OPERANDS;
+
unsigned Encoding;
DIStringType(LLVMContext &C, StorageType Storage, unsigned Tag,
- uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
+ uint32_t AlignInBits, unsigned Encoding,
ArrayRef<Metadata *> Ops)
- : DIType(C, DIStringTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0,
- 0, FlagZero, Ops),
+ : DIType(C, DIStringTypeKind, Storage, Tag, 0, AlignInBits, 0, FlagZero,
+ Ops),
Encoding(Encoding) {}
~DIStringType() = default;
@@ -1058,8 +1115,10 @@ class DIStringType : public DIType {
uint64_t SizeInBits, uint32_t AlignInBits,
unsigned Encoding, StorageType Storage,
bool ShouldCreate = true) {
+ auto *SizeInBitsNode = ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
return getImpl(Context, Tag, getCanonicalMDString(Context, Name),
- StringLength, StrLenExp, StrLocationExp, SizeInBits,
+ StringLength, StrLenExp, StrLocationExp, SizeInBitsNode,
AlignInBits, Encoding, Storage, ShouldCreate);
}
static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
@@ -1067,12 +1126,24 @@ class DIStringType : public DIType {
Metadata *StrLenExp, Metadata *StrLocationExp,
uint64_t SizeInBits, uint32_t AlignInBits,
unsigned Encoding, StorageType Storage,
+ bool ShouldCreate = true) {
+ auto *SizeInBitsNode = ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
+ return getImpl(Context, Tag, Name, StringLength, StrLenExp, StrLocationExp,
+ SizeInBitsNode, AlignInBits, Encoding, Storage,
+ ShouldCreate);
+ }
+ static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
+ MDString *Name, Metadata *StringLength,
+ Metadata *StrLenExp, Metadata *StrLocationExp,
+ Metadata *SizeInBits, uint32_t AlignInBits,
+ unsigned Encoding, StorageType Storage,
bool ShouldCreate = true);
TempDIStringType cloneImpl() const {
return getTemporary(getContext(), getTag(), getRawName(),
getRawStringLength(), getRawStringLengthExp(),
- getRawStringLocationExp(), getSizeInBits(),
+ getRawStringLocationExp(), getRawSizeInBits(),
...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/141106
More information about the llvm-commits
mailing list