[llvm] af6d43e - [AsmPrinter][DebugInfo] Create EntryValue mode for DbgVariable

Felipe de Azevedo Piovezan via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 23 09:29:34 PDT 2023


Author: Felipe de Azevedo Piovezan
Date: 2023-08-23T12:29:18-04:00
New Revision: af6d43ea6641917445d8c335952d849d9b00b36a

URL: https://github.com/llvm/llvm-project/commit/af6d43ea6641917445d8c335952d849d9b00b36a
DIFF: https://github.com/llvm/llvm-project/commit/af6d43ea6641917445d8c335952d849d9b00b36a.diff

LOG: [AsmPrinter][DebugInfo] Create EntryValue mode for DbgVariable

With D149881, we converted EntryValue MachineFunction table entries into
`DbgVariables` initialized by a "DbgValue" intrinsic, which can only handle a
single, non-fragment DIExpression. However, it is desirable to handle variables
with multiple fragments and DIExpressions.

To do this, we expand the `DbgVariable` class to handle the EntryValue case.
This class can already operate under three different "modes" (stack slot,
unchanging location described by a dbg value, changing location described by a
loc list). A fourth case is added as a separate class entirely, but a subsequent
patch should redesign `DbgVariable` with four subclasses in order to make the
code more readable.

This patch also exposed a bug in the `beginEntryValueExpression` function, which
was not initializing the `LocationFlags` properly. Note how the
`finalizeEntryValue` function resets that flag. We fix this bug here, as testing
this changing in isolation would be tricky.

Differential Revision: https://reviews.llvm.org/D158458

Added: 
    

Modified: 
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
    llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
    llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 5697037e06e220..938538ef798046 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -882,6 +882,23 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
     return VariableDie;
   }
 
+  if (const std::optional<DbgVariableEntryValue> &EntryValueVar =
+          DV.getEntryValue()) {
+    DIELoc *Loc = new (DIEValueAllocator) DIELoc;
+    DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
+    // Emit each expression as: EntryValue(Register) <other ops> <Fragment>.
+    for (auto [Register, Expr] : EntryValueVar->getEntryValuesInfo()) {
+      DwarfExpr.addFragmentOffset(&Expr);
+      DIExpressionCursor Cursor(Expr.getElements());
+      DwarfExpr.beginEntryValueExpression(Cursor);
+      DwarfExpr.addMachineRegExpression(
+          *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, Register);
+      DwarfExpr.addExpression(std::move(Cursor));
+    }
+    addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
+    return VariableDie;
+  }
+
   // .. else use frame index.
   if (!DV.hasFrameIndexExprs())
     return VariableDie;

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index a5f17a8c2b8832..027bcd4b24320c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1564,21 +1564,16 @@ void DwarfDebug::collectVariableInfoFromMFTable(
                     cast<DILocalVariable>(Var.first), Var.second);
     if (VI.inStackSlot())
       RegVar->initializeMMI(VI.Expr, VI.getStackSlot());
-    else {
-      MachineLocation MLoc(VI.getEntryValueRegister(), /*IsIndirect*/ false);
-      auto LocEntry = DbgValueLocEntry(MLoc);
-      RegVar->initializeDbgValue(DbgValueLoc(VI.Expr, LocEntry));
-    }
+    else
+      RegVar->initializeEntryValue(VI.getEntryValueRegister(), *VI.Expr);
     LLVM_DEBUG(dbgs() << "Created DbgVariable for " << VI.Var->getName()
                       << "\n");
 
     if (DbgVariable *DbgVar = MFVars.lookup(Var)) {
-      if (DbgVar->getValueLoc())
-        LLVM_DEBUG(dbgs() << "Dropping repeated entry value debug info for "
-                             "variable "
-                          << VI.Var->getName() << "\n");
-      else
+      if (DbgVar->hasFrameIndexExprs())
         DbgVar->addMMIEntry(*RegVar);
+      else
+        DbgVar->getEntryValue()->addExpr(VI.getEntryValueRegister(), *VI.Expr);
     } else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) {
       MFVars.insert({Var, RegVar.get()});
       ConcreteEntities.push_back(std::move(RegVar));

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 0fc7aa7bccf3d0..dfbf0d1b7d8987 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -100,6 +100,53 @@ class DbgEntity {
   }
 };
 
+/// Helper class to model a DbgVariable whose location is derived from an
+/// EntryValue.
+/// TODO: split the current implementation of `DbgVariable` into a class per
+/// variant of location that it can represent, and make `DbgVariableEntryValue`
+/// a subclass.
+class DbgVariableEntryValue {
+  struct EntryValueInfo {
+    MCRegister Reg;
+    const DIExpression &Expr;
+
+    /// Operator enabling sorting based on fragment offset.
+    bool operator<(const EntryValueInfo &Other) const {
+      return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits();
+    }
+
+  private:
+    uint64_t getFragmentOffsetInBits() const {
+      std::optional<DIExpression::FragmentInfo> Fragment =
+          Expr.getFragmentInfo();
+      return Fragment ? Fragment->OffsetInBits : 0;
+    }
+  };
+
+  std::set<EntryValueInfo> EntryValues;
+
+public:
+  DbgVariableEntryValue(MCRegister Reg, const DIExpression &Expr) {
+    addExpr(Reg, Expr);
+  };
+
+  // Add the pair Reg, Expr to the list of entry values describing the variable.
+  // If multiple expressions are added, it is the callers responsibility to
+  // ensure they are all non-overlapping fragments.
+  void addExpr(MCRegister Reg, const DIExpression &Expr) {
+    std::optional<const DIExpression *> NonVariadicExpr =
+        DIExpression::convertToNonVariadicExpression(&Expr);
+    assert(NonVariadicExpr && *NonVariadicExpr);
+
+    EntryValues.insert({Reg, **NonVariadicExpr});
+  }
+
+  /// Returns the set of EntryValueInfo.
+  const std::set<EntryValueInfo> &getEntryValuesInfo() const {
+    return EntryValues;
+  }
+};
+
 //===----------------------------------------------------------------------===//
 /// This class is used to track local variable information.
 ///
@@ -107,6 +154,10 @@ class DbgEntity {
 /// the MMI table.  Such variables can have multiple expressions and frame
 /// indices.
 ///
+/// Variables can be created from the entry value of registers, in which case
+/// they're generated from the MMI table. Such variables can have either a
+/// single expression or multiple *fragment* expressions.
+///
 /// Variables can be created from \c DBG_VALUE instructions.  Those whose
 /// location changes over time use \a DebugLocListIndex, while those with a
 /// single location use \a ValueLoc and (optionally) a single entry of \a Expr.
@@ -128,6 +179,8 @@ class DbgVariable : public DbgEntity {
   mutable SmallVector<FrameIndexExpr, 1>
       FrameIndexExprs; /// Frame index + expression.
 
+  std::optional<DbgVariableEntryValue> EntryValue;
+
 public:
   /// Construct a DbgVariable.
   ///
@@ -137,7 +190,7 @@ class DbgVariable : public DbgEntity {
       : DbgEntity(V, IA, DbgVariableKind) {}
 
   bool isInitialized() const {
-    return !FrameIndexExprs.empty() || ValueLoc;
+    return !FrameIndexExprs.empty() || ValueLoc || EntryValue;
   }
 
   /// Initialize from the MMI table.
@@ -161,6 +214,17 @@ class DbgVariable : public DbgEntity {
         FrameIndexExprs.push_back({0, E});
   }
 
+  void initializeEntryValue(MCRegister Reg, const DIExpression &Expr) {
+    assert(!isInitialized() && "Already initialized?");
+    EntryValue = DbgVariableEntryValue(Reg, Expr);
+  }
+
+  const std::optional<DbgVariableEntryValue> &getEntryValue() const {
+    return EntryValue;
+  }
+
+  std::optional<DbgVariableEntryValue> &getEntryValue() { return EntryValue; }
+
   /// Initialize from a DBG_VALUE instruction.
   void initializeDbgValue(const MachineInstr *DbgValue);
 

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index 7623b7fb7c5d13..a74d43897d45b3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -414,6 +414,7 @@ void DwarfExpression::beginEntryValueExpression(
 
   SavedLocationKind = LocationKind;
   LocationKind = Register;
+  LocationFlags |= EntryValue;
   IsEmittingEntryValue = true;
   enableTemporaryBuffer();
 }

diff  --git a/llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir b/llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir
index dd29e515366adc..e9b9a6325f3efc 100644
--- a/llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir
+++ b/llvm/test/DebugInfo/AArch64/dbg-entry-value-swiftasync.mir
@@ -3,12 +3,21 @@
 # CHECK:      DW_TAG_variable
 # CHECK-NEXT:   DW_AT_location        (DW_OP_GNU_entry_value(DW_OP_reg22 W22))
 # CHECK-NEXT:   DW_AT_name    ("a")
+# CHECK:      DW_TAG_variable
+# CHECK-NEXT:   DW_AT_location
+# CHECK-SAME:     DW_OP_GNU_entry_value(DW_OP_reg22 W22), DW_OP_piece 0x8,
+# CHECK-SAME:     DW_OP_GNU_entry_value(DW_OP_reg22 W22), DW_OP_plus_uconst 0x2a, DW_OP_piece 0x8)
+# CHECK-NEXT:   DW_AT_name    ("fragmented_var")
 
 
 --- |
   target triple = "aarch64--"
   define void @foo(ptr %unused_arg, ptr swiftasync %async_arg) !dbg !4 {
     call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !10, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !12
+    ; A two fragment variable.
+    ; Fragments intentionally out of order to ensure the code can handle this.
+    call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !10, metadata !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 42, DW_OP_LLVM_fragment, 64, 64)), !dbg !12
+    call void @llvm.dbg.declare(metadata ptr %async_arg, metadata !11, metadata !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_LLVM_fragment, 0, 64)), !dbg !12
     ret void, !dbg !12
   }
   declare void @llvm.dbg.declare(metadata, metadata, metadata)
@@ -22,9 +31,10 @@
   !4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
   !5 = !DISubroutineType(types: !6)
   !6 = !{null, !7, !7, !7}
-  !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
+  !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 128)
   !9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
   !10 = !DILocalVariable(name: "a", scope: !4, file: !1, line: 1, type: !7)
+  !11 = !DILocalVariable(name: "fragmented_var", scope: !4, file: !1, line: 1, type: !7)
   !12 = !DILocation(line: 1, column: 37, scope: !4)
 ...
 ---
@@ -38,6 +48,10 @@ stack:
 entry_values:
   - { entry-value-register: '$x22', debug-info-variable: '!10', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_deref)',
       debug-info-location: '!12' }
+  - { entry-value-register: '$x22', debug-info-variable: '!11', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 42, DW_OP_deref, DW_OP_LLVM_fragment, 64, 64)',
+      debug-info-location: '!12' }
+  - { entry-value-register: '$x22', debug-info-variable: '!11', debug-info-expression: '!DIExpression(DW_OP_LLVM_entry_value, 1,  DW_OP_deref, DW_OP_LLVM_fragment, 0, 64)',
+      debug-info-location: '!12' }
 body:             |
   bb.0 (%ir-block.0):
     liveins: $x0, $x22, $lr


        


More information about the llvm-commits mailing list