[Lldb-commits] [llvm] [lldb] Fix size in bytes of type DIEs when size in bits is not a multiple of 8 (PR #69741)

Augusto Noronha via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 10 10:41:12 PST 2023


https://github.com/augusto2112 updated https://github.com/llvm/llvm-project/pull/69741

>From 997da625fda1efebde43ec965c23c1a8ef9c0132 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <augusto2112 at me.com>
Date: Fri, 10 Nov 2023 10:40:05 -0800
Subject: [PATCH] Emit DIE's size in bits when size is not a multiple of 8

The existing code will always round down the size in bits when
calculating the size in bytes (for example, a types with 1-7 bits will
be emitted as 0 bytes long). Fix this by emitting the size in bits if
the size is not aligned to a byte.
---
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 25 +++++--
 llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp     | 30 +++++---
 .../AArch64/non_standard_bit_sizes.ll         | 69 +++++++++++++++++++
 3 files changed, 110 insertions(+), 14 deletions(-)
 create mode 100644 llvm/test/DebugInfo/AArch64/non_standard_bit_sizes.ll

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 3174c18c97d888c..928033ea48e890c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -298,6 +298,12 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
       byte_size = form_value.Unsigned();
       break;
 
+    case DW_AT_bit_size:
+      // Convert the bit size to byte size, and round it up to the minimum
+      // amount of bytes that will fit the bits.
+      byte_size = (form_value.Unsigned() + 7) / 8;
+      break;
+
     case DW_AT_byte_stride:
       byte_stride = form_value.Unsigned();
       break;
@@ -2134,6 +2140,16 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
          template_param_infos.hasParameterPack();
 }
 
+/// Reads the bit size from a die, by trying both the byte size and bit size
+/// attributes.
+static uint64_t GetSizeInBitsFromDie(const DWARFDIE &die) {
+  const uint64_t byte_size =
+      die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
+  if (byte_size != UINT64_MAX)
+    return byte_size * 8;
+  return die.GetAttributeValueAsUnsigned(DW_AT_bit_size, UINT64_MAX);
+}
+
 bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
                                              lldb_private::Type *type,
                                              CompilerType &clang_type) {
@@ -2211,8 +2227,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
     if (type)
       layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8;
     if (layout_info.bit_size == 0)
-      layout_info.bit_size =
-          die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;
+      layout_info.bit_size = GetSizeInBitsFromDie(die);
 
     clang::CXXRecordDecl *record_decl =
         m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
@@ -2864,10 +2879,8 @@ void DWARFASTParserClang::ParseSingleMember(
   ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
   const dw_tag_t tag = die.Tag();
   // Get the parent byte size so we can verify any members will fit
-  const uint64_t parent_byte_size =
-      parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
-  const uint64_t parent_bit_size =
-      parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8;
+  uint64_t parent_bit_size = GetSizeInBitsFromDie(parent_die);
+  ;
 
   // FIXME: Remove the workarounds below and make this const.
   MemberAttributes attrs(die, parent_die, module_sp);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index a5960a5d4a09a17..9633e3b19ec0d63 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -687,6 +687,16 @@ std::string DwarfUnit::getParentContextString(const DIScope *Context) const {
   return CS;
 }
 
+/// Returns the most appropriate dwarf size attribute (bits or bytes) and size
+/// to be used with it, given the input size in bits.
+static std::pair<dwarf::Attribute, uint64_t>
+getMostAppropriateRepresentationAndSize(uint64_t SizeInBits) {
+  if (SizeInBits % 8 == 0) {
+    return {dwarf::DW_AT_byte_size, SizeInBits / 8};
+  }
+  return {dwarf::DW_AT_bit_size, SizeInBits};
+}
+
 void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
   // Get core information.
   StringRef Name = BTy->getName();
@@ -702,8 +712,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
     addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
             BTy->getEncoding());
 
-  uint64_t Size = BTy->getSizeInBits() >> 3;
-  addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
+  auto [SizeAttribute, Size] =
+      getMostAppropriateRepresentationAndSize(BTy->getSizeInBits());
+  addUInt(Buffer, SizeAttribute, std::nullopt, Size);
 
   if (BTy->isBigEndian())
     addUInt(Buffer, dwarf::DW_AT_endianity, std::nullopt, dwarf::DW_END_big);
@@ -731,8 +742,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
     DwarfExpr.addExpression(Expr);
     addBlock(Buffer, dwarf::DW_AT_string_length, DwarfExpr.finalize());
   } else {
-    uint64_t Size = STy->getSizeInBits() >> 3;
-    addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
+    auto [SizeAttributte, Size] =
+        getMostAppropriateRepresentationAndSize(STy->getSizeInBits());
+    addUInt(Buffer, SizeAttributte, std::nullopt, Size);
   }
 
   if (DIExpression *Expr = STy->getStringLocationExp()) {
@@ -755,7 +767,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
 void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
   // Get core information.
   StringRef Name = DTy->getName();
-  uint64_t Size = DTy->getSizeInBits() >> 3;
+  auto [SizeAttribute, Size] =
+      getMostAppropriateRepresentationAndSize(DTy->getSizeInBits());
   uint16_t Tag = Buffer.getTag();
 
   // Map to main type, void will not have a type.
@@ -783,7 +796,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
            && Tag != dwarf::DW_TAG_ptr_to_member_type
            && Tag != dwarf::DW_TAG_reference_type
            && Tag != dwarf::DW_TAG_rvalue_reference_type)
-    addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
+    addUInt(Buffer, SizeAttribute, std::nullopt, Size);
 
   if (Tag == dwarf::DW_TAG_ptr_to_member_type)
     addDIEEntry(Buffer, dwarf::DW_AT_containing_type,
@@ -873,7 +886,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
   // Add name if not anonymous or intermediate type.
   StringRef Name = CTy->getName();
 
-  uint64_t Size = CTy->getSizeInBits() >> 3;
+  auto [SizeAttribute, Size] =
+      getMostAppropriateRepresentationAndSize(CTy->getSizeInBits());
   uint16_t Tag = Buffer.getTag();
 
   switch (Tag) {
@@ -1017,7 +1031,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
     // TODO: Do we care about size for enum forward declarations?
     if (Size &&
         (!CTy->isForwardDecl() || Tag == dwarf::DW_TAG_enumeration_type))
-      addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
+      addUInt(Buffer, SizeAttribute, std::nullopt, Size);
     else if (!CTy->isForwardDecl())
       // Add zero size if it is not a forward declaration.
       addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, 0);
diff --git a/llvm/test/DebugInfo/AArch64/non_standard_bit_sizes.ll b/llvm/test/DebugInfo/AArch64/non_standard_bit_sizes.ll
new file mode 100644
index 000000000000000..2e6afc9068151ff
--- /dev/null
+++ b/llvm/test/DebugInfo/AArch64/non_standard_bit_sizes.ll
@@ -0,0 +1,69 @@
+; RUN: llc -mtriple arm64-apple-darwin -filetype=obj %s -o %t
+; RUN: llvm-dwarfdump -all %t | FileCheck %s
+
+; Checks that bit sizes that are not byte aligned are rounded up.
+
+; Check that a 1 bit sized type gets emitted as 1 bit long.
+; CHECK: DW_AT_name	("one_bit_int")
+; CHECK-NEXT: DW_AT_encoding	(DW_ATE_signed)
+; CHECK-NEXT: DW_AT_bit_size	(0x01)
+
+; Check that a 9 bit sized type gets emitted as 2 bytes long.
+; CHECK: DW_AT_name	("nine_bit_double")
+; CHECK-NEXT: DW_AT_encoding	(DW_ATE_float)
+; CHECK-NEXT: DW_AT_bit_size	(0x09)
+
+; Check that a 7 bit sized type gets emitted as 1 bytes long.
+; CHECK: DW_AT_name	("seven_bit_float")
+; CHECK-NEXT: DW_AT_encoding	(DW_ATE_float)
+; CHECK-NEXT: DW_AT_bit_size	(0x07)
+
+; Check that a byte aligned bit size is emitted with the same byte size.
+; CHECK: DW_AT_name	("four_byte_S")
+; CHECK-NEXT: DW_AT_byte_size	(0x04)
+
+%struct.S = type { i32 }
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define void @func(i32 noundef %a, double noundef %b, float noundef %c, i64 %s.coerce) !dbg !10 {
+entry:
+  %s = alloca %struct.S, align 4
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca double, align 8
+  %c.addr = alloca float, align 4
+  call void @llvm.dbg.declare(metadata ptr %a.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  call void @llvm.dbg.declare(metadata ptr %b.addr, metadata !22, metadata !DIExpression()), !dbg !23
+  call void @llvm.dbg.declare(metadata ptr %c.addr, metadata !24, metadata !DIExpression()), !dbg !25
+  call void @llvm.dbg.declare(metadata ptr %s, metadata !26, metadata !DIExpression()), !dbg !27
+  ret void, !dbg !28
+}
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare void @llvm.dbg.declare(metadata, metadata, metadata) 
+
+!llvm.module.flags = !{!2}
+!llvm.dbg.cu = !{!7}
+
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!8 = !DIFile(filename: "t.c", directory: "")
+!10 = distinct !DISubprogram(name: "func", scope: !8, file: !8, line: 6, type: !11, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !19)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13, !14, !15, !16}
+!13 = !DIBasicType(name: "one_bit_int", size: 1, encoding: DW_ATE_signed)
+!14 = !DIBasicType(name: "nine_bit_double", size: 9, encoding: DW_ATE_float)
+!15 = !DIBasicType(name: "seven_bit_float", size: 7, encoding: DW_ATE_float)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "four_byte_S", file: !8, line: 2, size: 32, elements: !17)
+!17 = !{!18}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "field", scope: !16, file: !8, line: 3, baseType: !13, size: 32)
+!19 = !{}
+!20 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !8, line: 6, type: !13)
+!21 = !DILocation(line: 6, column: 15, scope: !10)
+!22 = !DILocalVariable(name: "b", arg: 2, scope: !10, file: !8, line: 6, type: !14)
+!23 = !DILocation(line: 6, column: 25, scope: !10)
+!24 = !DILocalVariable(name: "c", arg: 3, scope: !10, file: !8, line: 6, type: !15)
+!25 = !DILocation(line: 6, column: 34, scope: !10)
+!26 = !DILocalVariable(name: "s", arg: 4, scope: !10, file: !8, line: 6, type: !16)
+!27 = !DILocation(line: 6, column: 46, scope: !10)
+!28 = !DILocation(line: 7, column: 1, scope: !10)
+



More information about the lldb-commits mailing list