[llvm] Allow DWARF expressions to refer to variable values (PR #181028)

via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 11 13:47:13 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Tom Tromey (tromey)

<details>
<summary>Changes</summary>

In Ada, it is possible for a type to refer to the value of local variables.  In many cases this can be described in the DWARF using existing LLVM constructs.  However, in some cases, a DWARF expression that uses multiple variables can be required.

This patch adds a mechanism to allow this.  It adds a new DIVariableExpression class.  This class holds a DIExpression and a list of variables.  When DWARF is emitted, each DW_OP_LLVM_arg in the expression is changed to a DW_OP_GNU_variable_value referencing the variable's DIE.

DW_OP_GNU_variable_value has been in use in GCC for years.  This has also been proposed for DWARF 6, though unfortunately it seems to have stalled:

    http://dwarfstd.org/ShowIssue.php?issue=161109.2

At present this feature is only supported for member offsets and sizes, and the size of a DICompositeType.  These are just the spots that I know are needed by gnat-llvm.

---

Patch is 27.29 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/181028.diff


22 Files Affected:

- (modified) llvm/docs/LangRef.rst (+14) 
- (modified) llvm/include/llvm-c/DebugInfo.h (+1) 
- (modified) llvm/include/llvm/BinaryFormat/Dwarf.def (+4) 
- (modified) llvm/include/llvm/Bitcode/LLVMBitCodes.h (+1) 
- (modified) llvm/include/llvm/IR/DIBuilder.h (+9) 
- (modified) llvm/include/llvm/IR/DebugInfoMetadata.h (+48) 
- (modified) llvm/include/llvm/IR/Metadata.def (+1) 
- (modified) llvm/lib/AsmParser/LLParser.cpp (+14) 
- (modified) llvm/lib/Bitcode/Reader/MetadataLoader.cpp (+13) 
- (modified) llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (+14) 
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+4) 
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp (+5) 
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h (+9) 
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+41) 
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h (+4) 
- (modified) llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp (+1) 
- (modified) llvm/lib/IR/AsmWriter.cpp (+10) 
- (modified) llvm/lib/IR/DIBuilder.cpp (+8) 
- (modified) llvm/lib/IR/DebugInfoMetadata.cpp (+10) 
- (modified) llvm/lib/IR/LLVMContextImpl.h (+16) 
- (modified) llvm/lib/IR/Verifier.cpp (+18-4) 
- (added) llvm/test/DebugInfo/variable-expression.ll (+46) 


``````````diff
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 28edd439b6900..f032b048b58af 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -6980,6 +6980,20 @@ Some examples of expressions:
     !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
     !DIExpression(DW_OP_constu, 42, DW_OP_stack_value)
 
+DIVariableExpression
+""""""""""""""""""""
+
+``DIVariableExpression`` holds a ``DIExpression`` and a list of
+references to other variables.  When DWARF is emitted for this sort of
+object, each instance of ``DW_OP_LLVM_arg`` in the expression is
+replaced with the DWARF extension operator
+``DW_OP_GNU_variable_value``.
+
+A ``DIVariableExpression`` is useful when a type depends on a
+variable's value.  Currently it can be used as the bit size or bit
+offset of a member of a type, or the bit size of a
+``DICompositeType``.
+
 DIAssignID
 """"""""""
 
diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h
index 70da3a61a46d8..6fbc6d9e73d79 100644
--- a/llvm/include/llvm-c/DebugInfo.h
+++ b/llvm/include/llvm-c/DebugInfo.h
@@ -200,6 +200,7 @@ enum {
   LLVMDIAssignIDMetadataKind,
   LLVMDISubrangeTypeMetadataKind,
   LLVMDIFixedPointTypeMetadataKind,
+  LLVMDIVariableExpressionMetadataKind,
 };
 typedef unsigned LLVMMetadataKind;
 
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index fbf22cc6f760b..529d35a2c5d91 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -926,6 +926,10 @@ HANDLE_DW_OP(0xf8, PGI_omp_thread_num, -1, -1, 0, PGI)
 HANDLE_DW_OP(0xfb, GNU_addr_index, 1, 0, 0, GNU)
 HANDLE_DW_OP(0xfc, GNU_const_index, 1, 0, 0, GNU)
 
+// Allow an expression to use the value of a variable.
+// http://dwarfstd.org/ShowIssue.php?issue=161109.2
+HANDLE_DW_OP (0xfd, GNU_variable_value, 1, 0, 0, GNU)
+
 // DW_OP_LLVM_user has two operands:
 //   (1) An unsigned LEB128 "LLVM Vendor Extension Opcode".
 //   (2) Zero or more literal operands, the number and type of which are
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 811116a3e1756..aa8cfa81a0e2f 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -393,6 +393,7 @@ enum MetadataCodes {
   METADATA_ASSIGN_ID = 47,        // [distinct, ...]
   METADATA_SUBRANGE_TYPE = 48,    // [distinct, ...]
   METADATA_FIXED_POINT_TYPE = 49, // [distinct, ...]
+  METADATA_VARIABLE_EXPR = 50,    // [distinct, ...]
 };
 
 // The constants block (CONSTANTS_BLOCK_ID) describes emission for each
diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index 9753c363166d9..1c027c9b9ad85 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -942,6 +942,15 @@ namespace llvm {
           VMContext, {dwarf::DW_OP_constu, Val, dwarf::DW_OP_stack_value});
     }
 
+    /// Create an expression that involves the value of one or more
+    /// variables.  Each instance of DW_OP_LLVM_arg in \c Expr is
+    /// replaced with the appropriate variable from \c Vars.
+    /// \param Expr        The expression.
+    /// \param Vars        The variables to substitute.
+    DIVariableExpression *
+    createExpressionWithVariables(ArrayRef<uint64_t> Expr,
+                                  ArrayRef<Metadata *> Vars);
+
     /// Create a new descriptor for the specified subprogram.
     /// See comments in DISubprogram* for descriptions of these fields.
     /// \param Scope         Function scope.
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 3ce899db66217..bd772c377ee09 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -4681,6 +4681,54 @@ class DIArgList : public Metadata, ReplaceableMetadataImpl {
   LLVM_ABI void handleChangedOperand(void *Ref, Metadata *New);
 };
 
+/// This holds a DIExpression and a list of variables that are
+/// referenced by that expression.
+class DIVariableExpression : public MDNode {
+  friend class LLVMContextImpl;
+  friend class MDNode;
+
+  DIVariableExpression(LLVMContext &C, StorageType Storage,
+                       ArrayRef<Metadata *> Ops)
+      : MDNode(C, DIVariableExpressionKind, Storage, Ops) {}
+
+  static DIVariableExpression *getImpl(LLVMContext &Context, DIExpression *Expr,
+                                       DINodeArray VarArray,
+                                       StorageType Storage,
+                                       bool ShouldCreate = true) {
+    return getImpl(Context, static_cast<Metadata *>(Expr), VarArray.get(), Storage, ShouldCreate);
+  }
+  static DIVariableExpression *getImpl(LLVMContext &Context, Metadata *Expr,
+                                       Metadata *VarArray, StorageType Storage,
+                                       bool ShouldCreate = true);
+
+  TempDIVariableExpression cloneImpl() const {
+    return getTemporary(getContext(), getExpression(), getVariableArray());
+  }
+
+public:
+  DEFINE_MDNODE_GET(DIVariableExpression,
+                    (DIExpression * Expr, DINodeArray Vars),
+                    (Expr, Vars))
+  DEFINE_MDNODE_GET(DIVariableExpression, (Metadata * Expr, Metadata *Vars),
+                    (Expr, Vars))
+
+  DIExpression *getExpression() const {
+    return cast<DIExpression>(getRawExpression());
+  }
+
+  Metadata *getRawExpression() const { return getOperand(0); }
+
+  DINodeArray getVariableArray() const {
+    return cast_or_null<MDTuple>(getRawVariableArray());
+  }
+
+  Metadata *getRawVariableArray() const { return getOperand(1); }
+
+  static bool classof(const Metadata *MD) {
+    return MD->getMetadataID() == DIVariableExpressionKind;
+  }
+};
+
 /// Identifies a unique instance of a variable.
 ///
 /// Storage for identifying a potentially inlined instance of a variable,
diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def
index 511bf48707f00..7417514c34134 100644
--- a/llvm/include/llvm/IR/Metadata.def
+++ b/llvm/include/llvm/IR/Metadata.def
@@ -120,6 +120,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubrangeType)
 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIFixedPointType)
+HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIVariableExpression)
 
 #undef HANDLE_METADATA
 #undef HANDLE_METADATA_LEAF
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 5b916711690ec..3f61f264fa602 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -6477,6 +6477,20 @@ bool LLParser::parseDIArgList(Metadata *&MD, PerFunctionState *PFS) {
   return false;
 }
 
+/// parseDIVariableExpression:
+///   ::= !DIVariableExpression(expr: !0, vars: !1)
+bool LLParser::parseDIVariableExpression(MDNode *&Result, bool IsDistinct) {
+#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED)                                    \
+  REQUIRED(expr, MDField, );                                                   \
+  REQUIRED(vars, MDField, );
+  PARSE_MD_FIELDS();
+#undef VISIT_MD_FIELDS
+
+  Result = GET_OR_DISTINCT(DIVariableExpression,
+                           (Context, expr.Val, vars.Val));
+  return false;
+}
+
 /// parseDIGlobalVariableExpression:
 ///   ::= !DIGlobalVariableExpression(var: !0, expr: !1)
 bool LLParser::parseDIGlobalVariableExpression(MDNode *&Result,
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 4bc55232a6df6..3174b4a043abf 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -2367,6 +2367,19 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
     NextMetadataNo++;
     break;
   }
+  case bitc::METADATA_VARIABLE_EXPR: {
+    if (Record.size() != 3)
+      return error("Invalid record");
+
+    IsDistinct = Record[0];
+    Metadata *Expr = getMDOrNull(Record[1]);
+    Metadata *Vars = getMDOrNull(Record[2]);
+    MetadataList.assignValue(
+        GET_OR_DISTINCT(DIVariableExpression, (Context, Expr, Vars)),
+        NextMetadataNo);
+    NextMetadataNo++;
+    break;
+  }
   case bitc::METADATA_GLOBAL_VAR_EXPR: {
     if (Record.size() != 3)
       return error("Invalid record");
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 2566b2a292300..11564c9d18c49 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -401,6 +401,9 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase {
                     SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
   void writeDIExpression(const DIExpression *N,
                          SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
+  void writeDIVariableExpression(const DIVariableExpression *N,
+                                 SmallVectorImpl<uint64_t> &Record,
+                                 unsigned Abbrev);
   void writeDIGlobalVariableExpression(const DIGlobalVariableExpression *N,
                                        SmallVectorImpl<uint64_t> &Record,
                                        unsigned Abbrev);
@@ -2389,6 +2392,17 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N,
   Record.clear();
 }
 
+void ModuleBitcodeWriter::writeDIVariableExpression(
+    const DIVariableExpression *N, SmallVectorImpl<uint64_t> &Record,
+    unsigned Abbrev) {
+  Record.push_back(N->isDistinct());
+  Record.push_back(VE.getMetadataOrNullID(N->getExpression()));
+  Record.push_back(VE.getMetadataOrNullID(N->getVariableArray().get()));
+
+  Stream.EmitRecord(bitc::METADATA_VARIABLE_EXPR, Record, Abbrev);
+  Record.clear();
+}
+
 void ModuleBitcodeWriter::writeDIGlobalVariableExpression(
     const DIGlobalVariableExpression *N, SmallVectorImpl<uint64_t> &Record,
     unsigned Abbrev) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f8c2c753b91ce..2ab2cbb535f34 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -199,6 +199,10 @@ void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
   getActiveStreamer().emitULEB128(Idx, Twine(Idx), ULEB128PadSize);
 }
 
+void DebugLocDwarfExpression::emitDIERef(DIE &Ref) {
+  getActiveStreamer().emitDIERef(Ref);
+}
+
 bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
                                               llvm::Register MachineReg) {
   // This information is not available while emitting .debug_loc entries.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index d6b06b83207c7..cfc3c1eb46ad4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -40,6 +40,11 @@ void DwarfExpression::emitConstu(uint64_t Value) {
   }
 }
 
+void DwarfExpression::addVariableReference(DIE &Ref) {
+  emitOp(llvm::dwarf::DW_OP_GNU_variable_value);
+  emitDIERef(Ref);
+}
+
 void DwarfExpression::addReg(int64_t DwarfReg, const char *Comment) {
   assert(DwarfReg >= 0 && "invalid negative dwarf register number");
   assert((isUnknownLocation() || isRegisterLocation()) &&
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
index c4929aed1c197..4de24343358fe 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -134,6 +134,9 @@ class DwarfExpression {
 
   virtual void emitBaseTypeRef(uint64_t Idx) = 0;
 
+  /// Emit a reference to the given DIE.
+  virtual void emitDIERef(DIE &Ref) = 0;
+
   /// Start emitting data to the temporary buffer. The data stored in the
   /// temporary buffer can be committed to the main output using
   /// commitTemporaryBuffer().
@@ -270,6 +273,10 @@ class DwarfExpression {
                                llvm::Register MachineReg,
                                unsigned FragmentOffsetInBits = 0);
 
+  /// Add a reference to the variable indicated by the given DIE.  A
+  /// DW_OP_GNU_variable_value operation is emitted first.
+  void addVariableReference(DIE &);
+
   /// Begin emission of an entry value dwarf operation. The entry value's
   /// first operand is the size of the DWARF block (its second operand),
   /// which needs to be calculated at time of emission, so we don't emit
@@ -327,6 +334,7 @@ class DebugLocDwarfExpression final : public DwarfExpression {
   void emitUnsigned(uint64_t Value) override;
   void emitData1(uint8_t Value) override;
   void emitBaseTypeRef(uint64_t Idx) override;
+  void emitDIERef(DIE &Ref) override;
 
   void enableTemporaryBuffer() override;
   void disableTemporaryBuffer() override;
@@ -357,6 +365,7 @@ class DIEDwarfExpression final : public DwarfExpression {
   void emitUnsigned(uint64_t Value) override;
   void emitData1(uint8_t Value) override;
   void emitBaseTypeRef(uint64_t Idx) override;
+  void emitDIERef(DIE &Ref) override;
 
   void enableTemporaryBuffer() override;
   void disableTemporaryBuffer() override;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index baffd81b4f336..198c02afd61e6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -61,6 +61,10 @@ void DIEDwarfExpression::emitBaseTypeRef(uint64_t Idx) {
   CU.addBaseTypeRef(getActiveDIE(), Idx);
 }
 
+void DIEDwarfExpression::emitDIERef(DIE &Ref) {
+  CU.addDIEEntry(getActiveDIE(), dwarf::DW_FORM_ref_addr, Ref);
+}
+
 void DIEDwarfExpression::enableTemporaryBuffer() {
   assert(!IsBuffering && "Already buffering?");
   IsBuffering = true;
@@ -389,6 +393,10 @@ void DwarfUnit::addDIEEntry(DIE &Die, dwarf::Attribute Attribute, DIE &Entry) {
   addDIEEntry(Die, Attribute, DIEEntry(Entry));
 }
 
+void DwarfUnit::addDIEEntry(DIEValueList &Die, dwarf::Form Form, DIE &Entry) {
+  addAttribute(Die, (dwarf::Attribute)0, Form, DIEEntry(Entry));
+}
+
 void DwarfUnit::addDIETypeSignature(DIE &Die, uint64_t Signature) {
   // Flag the type unit reference as a declaration so that if it contains
   // members (implicit special members, static data member definitions, member
@@ -450,6 +458,30 @@ void DwarfUnit::addBlock(DIE &Die, dwarf::Attribute Attribute,
   addBlock(Die, Attribute, DwarfExpr.finalize());
 }
 
+void DwarfUnit::addBlock(DIE &Die, dwarf::Attribute Attribute,
+                         const DIVariableExpression *Expr) {
+  // Emitting a DIVariableExpression normally involves an extension
+  // operator, so just drop this in strict mode.
+  // See http://dwarfstd.org/ShowIssue.php?issue=161109.2.
+  if (Asm->TM.Options.DebugStrictDwarf)
+    return;
+
+  DIELoc *Loc = new (DIEValueAllocator) DIELoc;
+  DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc);
+  DwarfExpr.setMemoryLocationKind();
+  DINodeArray Vars = Expr->getVariableArray();
+  DwarfExpr.addExpression(
+      Expr->getExpression(),
+      [&](unsigned Idx, DIExpressionCursor &Cursor) -> bool {
+        if (auto *VarDie = getDIE(Vars[Idx])) {
+          DwarfExpr.addVariableReference(*VarDie);
+          return true;
+        }
+        return false;
+      });
+  addBlock(Die, Attribute, DwarfExpr.finalize());
+}
+
 void DwarfUnit::addSourceLine(DIE &Die, unsigned Line, unsigned Column,
                               const DIFile *File) {
   if (Line == 0)
@@ -1208,6 +1240,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
     } else if (auto *Exp =
                    dyn_cast_or_null<DIExpression>(CTy->getRawSizeInBits())) {
       addBlock(Buffer, dwarf::DW_AT_bit_size, Exp);
+    } else if (auto *VarExp = dyn_cast_or_null<DIVariableExpression>(
+                   CTy->getRawSizeInBits())) {
+      addBlock(Buffer, dwarf::DW_AT_bit_size, VarExp);
     } else {
       uint64_t Size = CTy->getSizeInBits() >> 3;
       // Add size if non-zero (derived types might be zero-sized.)
@@ -1890,6 +1925,9 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
         addDIEEntry(MemberDie, dwarf::DW_AT_bit_size, *VarDIE);
     } else if (auto *Exp = dyn_cast<DIExpression>(DT->getRawSizeInBits())) {
       addBlock(MemberDie, dwarf::DW_AT_bit_size, Exp);
+    } else if (auto *VarExp = dyn_cast_or_null<DIVariableExpression>(
+                   DT->getRawSizeInBits())) {
+      addBlock(MemberDie, dwarf::DW_AT_bit_size, VarExp);
     } else {
       Size = DT->getSizeInBits();
       FieldSize = DD->getBaseTypeSize(DT);
@@ -1915,6 +1953,9 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
       if (!Asm->TM.Options.DebugStrictDwarf || DD->getDwarfVersion() >= 6) {
         addBlock(MemberDie, dwarf::DW_AT_data_bit_offset, Expr);
       }
+    } else if (auto *VarExp = dyn_cast_or_null<DIVariableExpression>(
+                   DT->getRawOffsetInBits())) {
+      addBlock(MemberDie, dwarf::DW_AT_data_bit_offset, VarExp);
     } else {
       uint32_t AlignInBytes = DT->getAlignInBytes();
       uint64_t OffsetInBytes;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 22eef85a1dffa..2053b4241048d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -205,6 +205,9 @@ class DwarfUnit : public DIEUnit {
   /// Add a DIE attribute data and value.
   void addDIEEntry(DIE &Die, dwarf::Attribute Attribute, DIEEntry Entry);
 
+  /// Add a reference to Entry using the indicated form.
+  void addDIEEntry(DIEValueList &Die, dwarf::Form Form, DIE &Entry);
+
   /// Add a type's DW_AT_signature and set the  declaration flag.
   void addDIETypeSignature(DIE &Die, uint64_t Signature);
 
@@ -218,6 +221,7 @@ class DwarfUnit : public DIEUnit {
 
   /// Add an expression as block data.
   void addBlock(DIE &Die, dwarf::Attribute Attribute, const DIExpression *Expr);
+  void addBlock(DIE &Die, dwarf::Attribute Attribute, const DIVariableExpression *Expr);
 
   /// Add location information to specified debug information entry.
   void addSourceLine(DIE &Die, unsigned Line, unsigned Column,
diff --git a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
index 61bd6fcb65bfa..f154d0126b3c8 100644
--- a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
@@ -101,6 +101,7 @@ static std::vector<Desc> getOpDescriptions() {
   Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_GNU_variable_value] = Desc(Op::Dwarf4, Op::SizeRefAddr);
   Descriptions[DW_OP_GNU_implicit_pointer] =
       Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB);
   // This Description acts as a marker that getSubOpDesc must be called
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index b3e0323fd8633..565979cfc2f3d 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -2645,6 +2645,16 @@ static void writeDIExpression(raw_ostream &Out, const DIExpression *N,
   Out << ")";
 }
 
+static void writeDIVariableExpression(raw_ostream &Out,
+                                      const DIVariableExpression *N,
+                                      AsmWriterContext &WriterCtx) {
+  Out << "!DIVariableExpression(";
+  MDFieldPrinter Printer(Out, WriterCtx);
+  Printer.printMetadata("expr", N->getRawExpression());
+  Printer.printMetadata("vars", N->getRawVariableArray());
+  Out << ")";
+}
+
 static void writeDIArgList(raw_ostream &Out, const DIArgList *N,
                            AsmWriterContext &WriterCtx,
                            bool FromValue = false) {
diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp
index 38cf3f552b83d..327f794964618 100644
--- a/llvm/lib/IR/DIBuilder.cpp
+++ b/llvm/lib/IR/DIBuilder.cpp
@@ -918,6 +918,14 @@ static void checkGlobalVariableScope(DIScope *Context) {
 #endif
 }
 
+DIVariableExpression *
+DIBuilder::createExpressionWithVariables(ArrayRef<uint64_t> Expr,
+                                         ArrayRef<Metadata *> Vars) {
+  DIExpression *EX = DIExpress...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/181028


More information about the llvm-commits mailing list