Skip to content

Non constant size and offset in DWARF #141106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 25, 2025

Conversation

tromey
Copy link
Contributor

@tromey tromey commented May 22, 2025

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.

@llvmbot
Copy link
Member

llvmbot commented May 22, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-debuginfo

@llvm/pr-subscribers-llvm-ir

Author: Tom Tromey (tromey)

Changes

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 --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]
@tromey
Copy link
Contributor Author

tromey commented May 22, 2025

Note that I've written this patch as a series of smaller patches. I know it'll all be squashed if it lands, but it may be simpler to review the pieces separately.

@tromey
Copy link
Contributor Author

tromey commented May 27, 2025

I'm fixing up the failures. Sorry about that. Also as a follow-up I may implement the suggestion here: https://discourse.llvm.org/t/rfc-dynamic-sizes-and-field-offsets-in-dwarf/85992/3?u=tromey

@tromey tromey force-pushed the non-constant-size-and-offset branch from 2698846 to 90a46a7 Compare May 28, 2025 18:16
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels May 28, 2025
@tromey
Copy link
Contributor Author

tromey commented May 28, 2025

I rebased this and fixed up the mlir problem. I also changed how the overload resolution was done, so that a later patch that treats nullptr specially can be done without affecting existing call sites.

@tromey
Copy link
Contributor Author

tromey commented May 29, 2025

From what I can tell, those failures don't have anything to do with this patch.

tromey added a commit to tromey/gdb that referenced this pull request May 30, 2025
In Ada, a field can have a dynamic bit offset in its enclosing record.

In DWARF 3, this was handled using a dynamic
DW_AT_data_member_location, combined with a DW_AT_bit_offset -- this
combination worked out ok because in practice GNAT only needs a
dynamic byte offset with a fixed offset within the byte.

However, this approach was deprecated in DWARF 4 and then removed in
DWARF 5.  No replacement approach was given, meaning that in strict
mode there is no way to express this.

This is a DWARF bug, see

    https://dwarfstd.org/issues/250501.1.html

In a discussion on the DWARF mailing list, a couple people mentioned
that compilers could use the obvious extension of a dynamic
DW_AT_data_bit_offset.  I've implemented this for LLVM:

    llvm/llvm-project#141106

In preparation for that landing, this patch implements support for
this construct in gdb.
tromey added a commit to tromey/gdb that referenced this pull request Jun 2, 2025
In Ada, a field can have a dynamic bit offset in its enclosing record.

In DWARF 3, this was handled using a dynamic
DW_AT_data_member_location, combined with a DW_AT_bit_offset -- this
combination worked out ok because in practice GNAT only needs a
dynamic byte offset with a fixed offset within the byte.

However, this approach was deprecated in DWARF 4 and then removed in
DWARF 5.  No replacement approach was given, meaning that in strict
mode there is no way to express this.

This is a DWARF bug, see

    https://dwarfstd.org/issues/250501.1.html

In a discussion on the DWARF mailing list, a couple people mentioned
that compilers could use the obvious extension of a dynamic
DW_AT_data_bit_offset.  I've implemented this for LLVM:

    llvm/llvm-project#141106

In preparation for that landing, this patch implements support for
this construct in gdb.

New in v2: renamed some constants and added a helper method, per
Simon's review.

Approved-By: Simon Marchi <[email protected]>
tromey added a commit to tromey/gdb that referenced this pull request Jun 2, 2025
In Ada, a field can have a dynamic bit offset in its enclosing record.

In DWARF 3, this was handled using a dynamic
DW_AT_data_member_location, combined with a DW_AT_bit_offset -- this
combination worked out ok because in practice GNAT only needs a
dynamic byte offset with a fixed offset within the byte.

However, this approach was deprecated in DWARF 4 and then removed in
DWARF 5.  No replacement approach was given, meaning that in strict
mode there is no way to express this.

This is a DWARF bug, see

    https://dwarfstd.org/issues/250501.1.html

In a discussion on the DWARF mailing list, a couple people mentioned
that compilers could use the obvious extension of a dynamic
DW_AT_data_bit_offset.  I've implemented this for LLVM:

    llvm/llvm-project#141106

In preparation for that landing, this patch implements support for
this construct in gdb.

New in v2: renamed some constants and added a helper method, per
Simon's review.

New in v3: more renamings.

Approved-By: Simon Marchi <[email protected]>
saagarjha pushed a commit to ahjragaas/binutils-gdb that referenced this pull request Jun 3, 2025
In Ada, a field can have a dynamic bit offset in its enclosing record.

In DWARF 3, this was handled using a dynamic
DW_AT_data_member_location, combined with a DW_AT_bit_offset -- this
combination worked out ok because in practice GNAT only needs a
dynamic byte offset with a fixed offset within the byte.

However, this approach was deprecated in DWARF 4 and then removed in
DWARF 5.  No replacement approach was given, meaning that in strict
mode there is no way to express this.

This is a DWARF bug, see

    https://dwarfstd.org/issues/250501.1.html

In a discussion on the DWARF mailing list, a couple people mentioned
that compilers could use the obvious extension of a dynamic
DW_AT_data_bit_offset.  I've implemented this for LLVM:

    llvm/llvm-project#141106

In preparation for that landing, this patch implements support for
this construct in gdb.

New in v2: renamed some constants and added a helper method, per
Simon's review.

New in v3: more renamings.

Approved-By: Simon Marchi <[email protected]>
@tromey tromey force-pushed the non-constant-size-and-offset branch from 90a46a7 to c80072c Compare June 3, 2025 16:28
@tromey
Copy link
Contributor Author

tromey commented Jun 3, 2025

Rebased and adapted to the LLVM_ABI change.

@tromey tromey force-pushed the non-constant-size-and-offset branch from c80072c to 90e7a94 Compare June 4, 2025 14:48
@tromey
Copy link
Contributor Author

tromey commented Jun 4, 2025

Updated to fix a tiny error I'd introduced.

@tromey
Copy link
Contributor Author

tromey commented Jun 10, 2025

Ping.

tromey added 3 commits June 24, 2025 07:34
This patch changes code in DebugInfoMetadata.h to use symbolic
constants to refer to metadata slots.  This makes it a little simpler
(but still not entirely seamless) to add metadata to DIType.
This changes DIType to use metadata for the size and offset
information.  This patch doesn't have any functional changes yet; the
test is in the next patch.
This updates the DWARF writer to emit dynamic offsets and sizes for
members.
@tromey tromey force-pushed the non-constant-size-and-offset branch from 90e7a94 to e265877 Compare June 24, 2025 14:13
@tromey
Copy link
Contributor Author

tromey commented Jun 24, 2025

I've rebased this and addressed the review comments. I am leaving the one sub-thread open since I wasn't sure if I should send a separate PR (I don't have push rights so I can't land something separately on my own) -- just let me know if you'd like that, it's no trouble. Thanks.

Copy link
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's just go with this as a single patch.

Looking closer, in retrospect/for next time, perhaps this could've been a few smaller patches (I guess the strtuct, member, and bit field member are all separate except that they depend on the new MDUnsignedOrMDField - either that could've been included in one of the patches that needed it, and the other two patches dependent on that one arbitrarily chosen - or if that could've been added/tested independently, then all 3 functional patches independently depend on it - (plus the already discussed clang change that could've been done separately - but yeah, annoying to have a dependent patch for such a small change, so probably fine to keep it in in situations like this then just send a tiny PR real quick to go in before the rest once approved)))

This adds some new DIBuilder methods to expose the new dynamic size
and offset functionality.
@tromey tromey force-pushed the non-constant-size-and-offset branch from e265877 to f43c0a1 Compare June 25, 2025 15:10
@dwblaikie dwblaikie merged commit 3b90597 into llvm:main Jun 25, 2025
7 checks passed
@tromey tromey deleted the non-constant-size-and-offset branch June 25, 2025 18:23
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 25, 2025

LLVM Buildbot has detected a new failure on builder llvm-nvptx64-nvidia-win running on as-builder-8 while building clang,llvm at step 7 "test-build-unified-tree-check-llvm".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/155/builds/10442

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-llvm) failure: test (failure)
******************** TEST 'LLVM :: DebugInfo/dynamic-bitfield.ll' FAILED ********************
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\llc.exe -O0 -filetype=obj -o - C:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\llvm-project\llvm\test\DebugInfo\dynamic-bitfield.ll | c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\llvm-dwarfdump.exe -v -debug-info - | c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\filecheck.exe C:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\llvm-project\llvm\test\DebugInfo\dynamic-bitfield.ll
# executed command: 'c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\llc.exe' -O0 -filetype=obj -o - 'C:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\llvm-project\llvm\test\DebugInfo\dynamic-bitfield.ll'
# .---command stderr------------
# | c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\llc.exe: error: createMCCodeEmitter failed
# `-----------------------------
# error: command failed with exit status: 1
# executed command: 'c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\llvm-dwarfdump.exe' -v -debug-info -
# .---command stderr------------
# | error: -: The file was not recognized as a valid object file
# `-----------------------------
# error: command failed with exit status: 1
# executed command: 'c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\filecheck.exe' 'C:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\llvm-project\llvm\test\DebugInfo\dynamic-bitfield.ll'
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  c:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\build\bin\filecheck.exe C:\buildbot\as-builder-8\llvm-nvptx64-nvidia-win\llvm-project\llvm\test\DebugInfo\dynamic-bitfield.ll
# `-----------------------------
# error: command failed with exit status: 2

--

********************


@vvereschaka
Copy link
Contributor

Hi @tromey,

LLVM Buildbot has detected a new failure on builder llvm-nvptx64-nvidia-win running on as-builder-8 while building clang,llvm at step 7 "test-build-unified-tree-check-llvm".

there is the same problem with the dynamic-bitfield.ll test on llvm-nvptx-nvidia-win builder
https://lab.llvm.org/buildbot/#/builders/54/builds/10317

@dwblaikie
Copy link
Collaborator

Hi @tromey,

LLVM Buildbot has detected a new failure on builder llvm-nvptx64-nvidia-win running on as-builder-8 while building clang,llvm at step 7 "test-build-unified-tree-check-llvm".

there is the same problem with the dynamic-bitfield.ll test on llvm-nvptx-nvidia-win builder https://lab.llvm.org/buildbot/#/builders/54/builds/10317

#145797

If anyone wants to stamp that & I'll commit it once the presubmit checks run - hopefully that's adequate to address the nvptx issue - just at a very rough guess.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 26, 2025

LLVM Buildbot has detected a new failure on builder llvm-nvptx64-nvidia-ubuntu running on as-builder-7 while building clang,llvm at step 6 "test-build-unified-tree-check-llvm".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/160/builds/19862

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-llvm) failure: test (failure)
******************** TEST 'LLVM :: DebugInfo/dynamic-bitfield.ll' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
/home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/llc -O0 -filetype=obj -o - /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll | /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/llvm-dwarfdump -v -debug-info - | /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll # RUN: at line 1
+ /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/llc -O0 -filetype=obj -o - /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll
+ /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/llvm-dwarfdump -v -debug-info -
+ /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll
/home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/llc: error: createMCCodeEmitter failed
error: -: The file was not recognized as a valid object file
FileCheck error: '<stdin>' is empty.
FileCheck command line:  /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx64-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll

--

********************


@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 26, 2025

LLVM Buildbot has detected a new failure on builder llvm-nvptx-nvidia-ubuntu running on as-builder-7 while building clang,llvm at step 6 "test-build-unified-tree-check-llvm".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/180/builds/20005

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-llvm) failure: test (failure)
******************** TEST 'LLVM :: DebugInfo/dynamic-bitfield.ll' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
/home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/llc -O0 -filetype=obj -o - /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll | /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/llvm-dwarfdump -v -debug-info - | /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll # RUN: at line 1
+ /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/llc -O0 -filetype=obj -o - /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll
+ /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/llvm-dwarfdump -v -debug-info -
+ /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll
/home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/llc: error: createMCCodeEmitter failed
error: -: The file was not recognized as a valid object file
FileCheck error: '<stdin>' is empty.
FileCheck command line:  /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/build/bin/FileCheck /home/buildbot/worker/as-builder-7/llvm-nvptx-nvidia-ubuntu/llvm-project/llvm/test/DebugInfo/dynamic-bitfield.ll

--

********************


searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Jun 26, 2025
Need dbg team to land this patch

This reverts commit 3b90597.
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
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.
@brendandahl
Copy link
Contributor

brendandahl commented Jun 26, 2025

It looks like this PR is causing failures in emscripten's LTO builds. I haven't looked into it yet, but if you have any thoughts on what may be the issue it would be helpful.

wasm-ld: /b/s/w/ir/cache/builder/emscripten-releases/llvm-project/llvm/include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From *) [To = llvm::MDNode, From = llvm::Metadata]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
 #0 0x0000577663876d28 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x1b8cd28)
 #1 0x00005776638747b5 llvm::sys::RunSignalHandlers() (/b/s/w/ir/x/w/install/bin/wasm-ld+0x1b8a7b5)
 #2 0x0000577663877576 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x0000742536842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007425368969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007425368969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007425368969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x0000742536842476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007425368287f3 abort ./stdlib/abort.c:81:7
 #9 0x000074253682871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x0000742536839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00005776662f46a4 (/b/s/w/ir/x/w/install/bin/wasm-ld+0x460a6a4)
#12 0x00005776662eb044 llvm::MetadataLoader::MetadataLoaderImpl::resolveForwardRefsAndPlaceholders((anonymous namespace)::(anonymous namespace)::PlaceholderQueue&) MetadataLoader.cpp:0:0
#13 0x00005776662f3a48 llvm::MetadataLoader::MetadataLoaderImpl::getMetadataFwdRefOrLoad(unsigned int) MetadataLoader.cpp:0:0
#14 0x00005776662ea465 llvm::MetadataLoader::MetadataLoaderImpl::parseGlobalObjectAttachment(llvm::GlobalObject&, llvm::ArrayRef<unsigned long>) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x4600465)
#15 0x00005776662ea02e llvm::MetadataLoader::MetadataLoaderImpl::loadGlobalDeclAttachments() (/b/s/w/ir/x/w/install/bin/wasm-ld+0x460002e)
#16 0x00005776662ea875 llvm::MetadataLoader::MetadataLoaderImpl::parseMetadata(bool) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x4600875)
#17 0x00005776662f4fbc llvm::MetadataLoader::parseMetadata(bool) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x460afbc)
#18 0x00005776662bd30b (anonymous namespace)::BitcodeReader::materializeMetadata() BitcodeReader.cpp:0:0
#19 0x0000577666518e76 llvm::Module::materializeMetadata() (/b/s/w/ir/x/w/install/bin/wasm-ld+0x482ee76)
#20 0x0000577664f35910 llvm::FunctionImporter::importFunctions(llvm::Module&, llvm::FunctionImporter::ImportMapTy const&) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x324b910)
#21 0x00005776642b69f7 llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, bool, std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, std::__2::vector<unsigned char, std::__2::allocator<unsigned char>> const&) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x25cc9f7)
#22 0x00005776642a82b2 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::__2::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::__2::less<unsigned long>, std::__2::allocator<std::__2::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>)::operator()(std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>) const LTO.cpp:0:0
#23 0x00005776642a7523 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::__2::function<llvm::Expected<std::__2::unique_ptr<llvm::CachedFileStream, std::__2::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::__2::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::__2::less<unsigned long>, std::__2::allocator<std::__2::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&) LTO.cpp:0:0
#24 0x00005776642a7e44 void std::__2::__function::__policy_func<void ()>::__call_func[abi:nn210000]<std::__2::__bind<(anonymous namespace)::InProcessThinBackend::start(unsigned int, llvm::BitcodeModule, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::__2::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::__2::less<unsigned long>, std::__2::allocator<std::__2::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::__2::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::__2::less<unsigned long>, std::__2::allocator<std::__2::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&), llvm::BitcodeModule&, std::__2::reference_wrapper<llvm::ModuleSummaryIndex>, std::__2::reference_wrapper<llvm::FunctionImporter::ImportMapTy const>, std::__2::reference_wrapper<llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const>, std::__2::reference_wrapper<std::__2::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::__2::less<unsigned long>, std::__2::allocator<std::__2::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const>, std::__2::reference_wrapper<llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const>, std::__2::reference_wrapper<llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::__2::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>>>>(std::__2::__function::__policy_storage const*) LTO.cpp:0:0
#25 0x0000577663bf898e std::__2::__deferred_assoc_state<void, std::__2::__async_func<std::__2::function<void ()>>>::__execute() BalancedPartitioning.cpp:0:0
#26 0x0000577663bff4ed llvm::StdThreadPool::processTasks(llvm::ThreadPoolTaskGroup*) (/b/s/w/ir/x/w/install/bin/wasm-ld+0x1f154ed)
#27 0x0000577663c00f5e void* llvm::thread::ThreadProxy<std::__2::tuple<llvm::StdThreadPool::grow(int)::$_0>>(void*) ThreadPool.cpp:0:0
#28 0x0000742536894ac3 start_thread ./nptl/pthread_create.c:442:8
#29 0x0000742536926850 ./misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:83:0
@nathanchance
Copy link
Member

I am seeing an assertion failure when building the Linux kernel for aarch64 with LTO enabled. cvise spits out:

$ cat hda_bind.i
void snd_hda_codec_shutdown();
void hda_codec_driver_shutdown() { snd_hda_codec_shutdown(); }

$ cat hda_codec.i
struct {
  int mfg;
} hda_set_power_state_codec;
void snd_hda_codec_shutdown() {}

$ clang --target=aarch64-linux-gnu -flto=thin -fsplit-lto-unit -fvisibility=hidden -g -O2 -c hda_bind.i

$ clang --target=aarch64-linux-gnu -flto=thin -fsplit-lto-unit -fvisibility=hidden -g -O2 -c hda_codec.i

$ ld.lld -EL -maarch64elf -r -o /dev/null hda_{bind,codec}.o
ld.lld: llvm/include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From *) [To = llvm::MDNode, From = llvm::Metadata]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
 #0 0x0000000001de7f88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (lld+0x1de7f88)
 #1 0x0000000001de5d90 llvm::sys::RunSignalHandlers() (lld+0x1de5d90)
 #2 0x0000000001de8820 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x0000ffffae6a0868 (linux-vdso.so.1+0x868)
 #4 0x0000ffffae0af71c __pthread_kill_implementation (/lib64/libc.so.6+0x8f71c)
 #5 0x0000ffffae05b63c gsignal (/lib64/libc.so.6+0x3b63c)
 #6 0x0000ffffae045b88 abort (/lib64/libc.so.6+0x25b88)
 #7 0x0000ffffae0540a0 __assert_fail_base (/lib64/libc.so.6+0x340a0)
 #8 0x0000000004801710 (anonymous namespace)::BitcodeReaderMetadataList::getMetadataFwdRef(unsigned int) MetadataLoader.cpp:0:0
 #9 0x00000000047f9524 llvm::MetadataLoader::MetadataLoaderImpl::resolveForwardRefsAndPlaceholders((anonymous namespace)::(anonymous namespace)::PlaceholderQueue&) MetadataLoader.cpp:0:0
#10 0x0000000004800ca4 llvm::MetadataLoader::MetadataLoaderImpl::getMetadataFwdRefOrLoad(unsigned int) MetadataLoader.cpp:0:0
#11 0x00000000047f8ae4 llvm::MetadataLoader::MetadataLoaderImpl::parseGlobalObjectAttachment(llvm::GlobalObject&, llvm::ArrayRef<unsigned long>) (lld+0x47f8ae4)
#12 0x00000000047f86d0 llvm::MetadataLoader::MetadataLoaderImpl::loadGlobalDeclAttachments() (lld+0x47f86d0)
#13 0x00000000047f90e8 llvm::MetadataLoader::MetadataLoaderImpl::parseMetadata(bool) (lld+0x47f90e8)
#14 0x00000000047cfe78 (anonymous namespace)::BitcodeReader::materializeMetadata() BitcodeReader.cpp:0:0
#15 0x00000000034c3d80 llvm::FunctionImporter::importFunctions(llvm::Module&, llvm::FunctionImporter::ImportMapTy const&) (lld+0x34c3d80)
#16 0x00000000028f0ee4 llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, bool, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, std::vector<unsigned char, std::allocator<unsigned char>> const&) (lld+0x28f0ee4)
#17 0x00000000028e4798 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>)::operator()(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>) const LTO.cpp:0:0
#18 0x00000000028e3c98 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&) LTO.cpp:0:0
#19 0x00000000028e4384 std::_Function_handler<void (), std::_Bind<(anonymous namespace)::InProcessThinBackend::start(unsigned int, llvm::BitcodeModule, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&) (llvm::BitcodeModule, std::reference_wrapper<llvm::ModuleSummaryIndex>, std::reference_wrapper<llvm::FunctionImporter::ImportMapTy const>, std::reference_wrapper<llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const>, std::reference_wrapper<std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const>, std::reference_wrapper<llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const>, std::reference_wrapper<llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>>)>>::_M_invoke(std::_Any_data const&) LTO.cpp:0:0
#20 0x000000000212dde8 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<std::function<void ()>>>, void>>::_M_invoke(std::_Any_data const&) BalancedPartitioning.cpp:0:0
#21 0x0000000001e284f4 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) Driver.cpp:0:0
#22 0x0000ffffae0b3260 __pthread_once_slow.isra.0 (/lib64/libc.so.6+0x93260)
#23 0x0000ffffae0b3324 pthread_once@@GLIBC_2.34 (/lib64/libc.so.6+0x93324)
#24 0x000000000212e148 std::__future_base::_Deferred_state<std::thread::_Invoker<std::tuple<std::function<void ()>>>, void>::_M_complete_async() BalancedPartitioning.cpp:0:0
#25 0x000000000212e1e0 std::_Function_handler<void (), std::shared_future<void> llvm::ThreadPoolInterface::asyncImpl<void>(std::function<void ()>, llvm::ThreadPoolTaskGroup*)::'lambda'()>::_M_invoke(std::_Any_data const&) BalancedPartitioning.cpp:0:0
#26 0x000000000213503c llvm::StdThreadPool::processTasks(llvm::ThreadPoolTaskGroup*) (lld+0x213503c)
#27 0x00000000021363e4 void* llvm::thread::ThreadProxy<std::tuple<llvm::StdThreadPool::grow(int)::$_0>>(void*) ThreadPool.cpp:0:0
#28 0x0000ffffae0ad894 start_thread (/lib64/libc.so.6+0x8d894)
#29 0x0000ffffae11860c thread_start (/lib64/libc.so.6+0xf860c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category debuginfo llvm:codegen llvm:ir
7 participants