Debug info: Support DWARF4 bitfields via DW_AT_data_bit_offset.
The DWARF2 specification of DW_AT_bit_offset was written from the perspective of
a big-endian machine with unclear semantics for other systems. DWARF4
deprecated DW_AT_bit_offset and introduced a new attribute DW_AT_data_bit_offset
that simply counts the number of bits from the beginning of the containing
entity regardless of endianness.
After this patch LLVM emits DW_AT_bit_offset for DWARF 2 or 3 and
DW_AT_data_bit_offset when DWARF 4 or later is requested.
llvm-svn: 267895
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 91c490f..08800f4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1395,41 +1395,43 @@
// Handle bitfield, assume bytes are 8 bits.
addUInt(MemberDie, dwarf::DW_AT_byte_size, None, FieldSize/8);
addUInt(MemberDie, dwarf::DW_AT_bit_size, None, Size);
- //
- // The DWARF 2 DW_AT_bit_offset is counting the bits between the most
- // significant bit of the aligned storage unit containing the bit field to
- // the most significan bit of the bit field.
- //
- // FIXME: DWARF 4 states that DW_AT_data_bit_offset (which
- // counts from the beginning, regardless of endianness) should
- // be used instead.
- //
- //
- // Struct Align Align Align
- // v v v v
- // +-----------+-----*-----+-----*-----+--
- // | ... |b1|b2|b3|b4|
- // +-----------+-----*-----+-----*-----+--
- // | | |<-- Size ->| |
- // |<---- Offset --->| |<--->|
- // | | | \_ DW_AT_bit_offset (little endian)
- // | |<--->|
- // |<--------->| \_ StartBitOffset = DW_AT_bit_offset (big endian)
- // \ = DW_AT_data_bit_offset (biendian)
- // \_ OffsetInBytes
+
uint64_t Offset = DT->getOffsetInBits();
uint64_t Align = DT->getAlignInBits() ? DT->getAlignInBits() : FieldSize;
uint64_t AlignMask = ~(Align - 1);
// The bits from the start of the storage unit to the start of the field.
uint64_t StartBitOffset = Offset - (Offset & AlignMask);
- // The endian-dependent DWARF 2 offset.
- uint64_t DwarfBitOffset = Asm->getDataLayout().isLittleEndian()
- ? OffsetToAlignment(Offset + Size, Align)
- : StartBitOffset;
-
// The byte offset of the field's aligned storage unit inside the struct.
OffsetInBytes = (Offset - StartBitOffset) / 8;
- addUInt(MemberDie, dwarf::DW_AT_bit_offset, None, DwarfBitOffset);
+
+ if (DD->getDwarfVersion() >= 4)
+ addUInt(MemberDie, dwarf::DW_AT_data_bit_offset, None, Offset);
+ else {
+ //
+ // The DWARF 2 DW_AT_bit_offset is counting the bits between the most
+ // significant bit of the aligned storage unit containing the bit field
+ // to
+ // the most significan bit of the bit field.
+ //
+ // Struct Align Align Align
+ // v v v v
+ // +-----------+-----*-----+-----*-----+--
+ // | ... |b1|b2|b3|b4|
+ // +-----------+-----*-----+-----*-----+--
+ // | | |<-- Size ->| |
+ // |<---- Offset --->| |<--->|
+ // | | | \_ DW_AT_bit_offset (little endian)
+ // | |<--->|
+ // |<--------->| \_ StartBitOffset = DW_AT_bit_offset (big endian)
+ // \ = DW_AT_data_bit_offset (biendian)
+ // \_ OffsetInBytes
+ // The endian-dependent DWARF 2 offset.
+ uint64_t DwarfBitOffset = Asm->getDataLayout().isLittleEndian()
+ ? OffsetToAlignment(Offset + Size, Align)
+ : StartBitOffset;
+
+ addUInt(MemberDie, dwarf::DW_AT_bit_offset, None, DwarfBitOffset);
+ }
} else
// This is not a bitfield.
OffsetInBytes = DT->getOffsetInBits() / 8;