[llvm] [llvm][DebugInfo] Add support for _BitInt in DWARFTypePrinter (PR #168382)

Michael Buch via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 17 07:00:03 PST 2025


https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/168382

>From 9b33d9ae5f6ccec648195c722dc5c66de956e3ec Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 17 Nov 2025 14:49:26 +0000
Subject: [PATCH 1/2] [llvm][DebugInfo] Add support for _BitInt in
 DWARFTypePrinter

As of recent, LLVM includes the bit-size as a `DW_AT_bit_size` (and as part of `DW_AT_name`) of `_BitInt`s in DWARF. This allows us to mark `_BitInt`s as "reconstitutable" when compiling with `-gsimple-template-names`.  However, before doing so we need to make sure the `DWARFTypePrinter` can reconstruct template parameter values that have `_BitInt` type. This patch adds support for printing `DW_TAG_template_value_parameter`s that have `_BitInt` type. Since `-gsimple-template-names` only omits template parameters that are `<= 64` bit wide, we don't support `_BitInt`s larger than 64 bits.
---
 .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h   |  44 +++++-
 .../DebugInfo/DWARF/DWARFDieTest.cpp          | 140 ++++++++++++++++++
 2 files changed, 180 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index a760f773055d2..9f6bcfb873b4d 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -13,6 +13,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
 
 #include <string>
 
@@ -78,6 +79,12 @@ template <typename DieType> struct DWARFTypePrinter {
     }
     return false;
   }
+
+  /// If FormValue is a valid constant Form, print into \c OS the integral value
+  /// casted to the type referred to by \c Cast.
+  template <typename FormValueType>
+  void appendCastedValue(const FormValueType &FormValue, DieType Cast,
+                         bool IsUnsigned);
 };
 
 template <typename DieType>
@@ -413,6 +420,31 @@ DieType DWARFTypePrinter<DieType>::appendQualifiedNameBefore(DieType D) {
   return appendUnqualifiedNameBefore(D);
 }
 
+template <typename DieType>
+template <typename FormValueType>
+void DWARFTypePrinter<DieType>::appendCastedValue(
+    const FormValueType &FormValue, DieType Cast, bool IsUnsigned) {
+  std::string ValStr;
+  if (IsUnsigned) {
+    std::optional<uint64_t> UVal = FormValue.getAsUnsignedConstant();
+    if (!UVal)
+      return;
+
+    ValStr = std::to_string(*UVal);
+  } else {
+    std::optional<int64_t> SVal = FormValue.getAsSignedConstant();
+    if (!SVal)
+      return;
+
+    ValStr = std::to_string(*SVal);
+  }
+
+  OS << '(';
+  appendQualifiedName(Cast);
+  OS << ')';
+  OS << std::move(ValStr);
+}
+
 template <typename DieType>
 bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
                                                          bool *FirstParameter) {
@@ -438,13 +470,11 @@ bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
       DieType T = detail::resolveReferencedType(C);
       Sep();
       if (T.getTag() == dwarf::DW_TAG_enumeration_type) {
-        OS << '(';
-        appendQualifiedName(T);
-        OS << ')';
         auto V = C.find(dwarf::DW_AT_const_value);
-        OS << std::to_string(*V->getAsSignedConstant());
+        appendCastedValue(*V, T, /*IsUnsigned=*/false);
         continue;
       }
+
       // /Maybe/ we could do pointer/reference type parameters, looking for the
       // symbol in the ELF symbol table to get back to the variable...
       // but probably not worth it.
@@ -539,6 +569,12 @@ bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
           else
             OS << llvm::format("'\\U%08" PRIx64 "'", Val);
         }
+        // FIXME: Handle _BitInt's larger than 64-bits which are emitted as
+        // block data.
+      } else if (Name.starts_with("_BitInt")) {
+        appendCastedValue(*V, T, /*IsUnsigned=*/false);
+      } else if (Name.starts_with("unsigned _BitInt")) {
+        appendCastedValue(*V, T, /*IsUnsigned=*/true);
       }
       continue;
     }
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
index f566bee170236..a3fafec9e7813 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
@@ -839,4 +839,144 @@ TEST(DWARFDie, DWARFTypePrinterTest) {
   testAppendQualifiedName(Ctx->getDIEForOffset(0x1a), "t1<t3<int> >::t2");
   testAppendQualifiedName(Ctx->getDIEForOffset(0x28), "t3<int>::my_int");
 }
+
+TEST(DWARFDie, DWARFTypePrinterTest_BitInt) {
+  // Make sure we can reconstruct the case where a template value parameter
+  // is a _BitInt.
+
+  // DW_TAG_compile_unit
+  //   DW_TAG_base_type
+  //     DW_AT_name      ("_BitInt(2)")
+  //     DW_AT_bit_size ("2")
+  //   DW_TAG_base_type
+  //     DW_AT_name      ("_BitInt(65)")
+  //     DW_AT_bit_size ("65")
+  //   DW_TAG_base_type
+  //     DW_AT_name      ("unsigned _BitInt(2)")
+  //     DW_AT_bit_size ("2")
+  //   DW_TAG_base_type
+  //     DW_AT_name      ("unsigned _BitInt(65)")
+  //     DW_AT_bit_size ("65")
+  //   DW_TAG_structure_type
+  //     DW_AT_name      ("foo")
+  //     DW_TAG_template_value_parameter
+  //       DW_AT_type    ("_BitInt(2)")
+  //       DW_AT_const_value (DW_FORM_sdata "-1")
+  //     DW_TAG_template_value_parameter
+  //       DW_AT_type    ("unsigned _BitInt(2)")
+  //       DW_AT_const_value (DW_FORM_udata "12")
+  //     DW_TAG_template_value_parameter
+  //       DW_AT_type    ("_BitInt(65)")
+  //       DW_AT_const_value (DW_FORM_block1 "1")
+  //     DW_TAG_template_value_parameter
+  //       DW_AT_type    ("unsigned _BitInt(65)")
+  //       DW_AT_const_value (DW_FORM_block1 "1")
+  //     NULL
+  //   NULL
+  const char *yamldata = R"(
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+        - Code:            0x2
+          Tag:             DW_TAG_base_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x3
+          Tag:             DW_TAG_structure_type
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+        - Code:            0x4
+          Tag:             DW_TAG_template_value_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_const_value
+              Form:            DW_FORM_sdata
+        - Code:            0x5
+          Tag:             DW_TAG_template_value_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_const_value
+              Form:            DW_FORM_udata
+        - Code:            0x6
+          Tag:             DW_TAG_template_value_parameter
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_const_value
+              Form:            DW_FORM_block1
+  debug_info:
+    - Version:         4
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xDEADBEEFDEADBEEF
+              CStr:            _BitInt(2)
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xDEADBEEFDEADBEEF
+              CStr:            _BitInt(65)
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xDEADBEEFDEADBEEF
+              CStr:            unsigned _BitInt(2)
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xDEADBEEFDEADBEEF
+              CStr:            unsigned _BitInt(65)
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0xDEADBEEFDEADBEEF
+              CStr:            foo
+        - AbbrCode:        0x4
+          Values:
+            - Value:            0x0000000c
+            - Value:            0xffffffffffffffff
+        - AbbrCode:        0x5
+          Values:
+            - Value:            0x00000025
+            - Value:            12
+        - AbbrCode:        0x6
+          Values:
+            - Value:            0x00000018
+            - Value:            0x0F
+              BlockData:       [ 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                                 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]     
+        - AbbrCode:        0x6
+          Values:
+            - Value:            0x0000003a
+            - Value:            0x0F
+              BlockData:       [ 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                                 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]     
+        - AbbrCode:        0x0
+        - AbbrCode:        0x0
+)";
+  Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
+      DWARFYAML::emitDebugSections(StringRef(yamldata),
+                                   /*IsLittleEndian=*/true,
+                                   /*Is64BitAddrSize=*/true);
+  ASSERT_THAT_EXPECTED(Sections, Succeeded());
+  std::unique_ptr<DWARFContext> Ctx =
+      DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true);
+
+  // FIXME: support _BitInt's with block forms. Currently they are just omitted.
+  // Will be necessary once -gsimple-template-names emit template value
+  // parameters with bit-width larger than 64.
+  testAppendAndTerminateTemplateParameters(
+      Ctx->getDIEForOffset(0x50),
+      "<(_BitInt(2))-1, (unsigned _BitInt(2))12, , >");
+}
 } // end anonymous namespace

>From 59fb0bd36c519781fc0506e29fba21fa673ac993 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 17 Nov 2025 14:59:44 +0000
Subject: [PATCH 2/2] fixup! remove redundant header

---
 llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index 9f6bcfb873b4d..9108c718c4794 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -13,7 +13,6 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/Support/Error.h"
-#include "llvm/Support/FormatVariadic.h"
 
 #include <string>
 



More information about the llvm-commits mailing list