Two fixes for DISubrangeType (#130345)

My previous patch to add DISubrangeType (#126772) had a couple of minor
errors. This patch corrects them.

1. When using a DISubrangeType as an array index type, the wrong tag was
written into the DIE.

2. I'd intended for subranges to use bit strides, not byte strides --
but neglected to actually implement this. Ada needs bit strides.

This patch adds a new test that checks both these things.

Finally, this patch adds some documentation for DISubrangeType.
This commit is contained in:
Tom Tromey
2025-03-07 15:23:05 -07:00
committed by GitHub
parent d90423e310
commit 993cbead9e
3 changed files with 103 additions and 17 deletions

View File

@@ -6319,21 +6319,24 @@ The following ``tag:`` values are valid:
DW_TAG_union_type = 23
For ``DW_TAG_array_type``, the ``elements:`` should be :ref:`subrange
descriptors <DISubrange>`, each representing the range of subscripts at that
level of indexing. The ``DIFlagVector`` flag to ``flags:`` indicates that an
array type is a native packed vector. The optional ``dataLocation`` is a
DIExpression that describes how to get from an object's address to the actual
raw data, if they aren't equivalent. This is only supported for array types,
particularly to describe Fortran arrays, which have an array descriptor in
addition to the array data. Alternatively it can also be DIVariable which
has the address of the actual raw data. The Fortran language supports pointer
arrays which can be attached to actual arrays, this attachment between pointer
and pointee is called association. The optional ``associated`` is a
DIExpression that describes whether the pointer array is currently associated.
The optional ``allocated`` is a DIExpression that describes whether the
allocatable array is currently allocated. The optional ``rank`` is a
DIExpression that describes the rank (number of dimensions) of fortran assumed
rank array (rank is known at runtime).
descriptors <DISubrange>` or :ref:`subrange descriptors
<DISubrangeType>`, each representing the range of subscripts at that
level of indexing. The ``DIFlagVector`` flag to ``flags:`` indicates
that an array type is a native packed vector. The optional
``dataLocation`` is a DIExpression that describes how to get from an
object's address to the actual raw data, if they aren't
equivalent. This is only supported for array types, particularly to
describe Fortran arrays, which have an array descriptor in addition to
the array data. Alternatively it can also be DIVariable which has the
address of the actual raw data. The Fortran language supports pointer
arrays which can be attached to actual arrays, this attachment between
pointer and pointee is called association. The optional
``associated`` is a DIExpression that describes whether the pointer
array is currently associated. The optional ``allocated`` is a
DIExpression that describes whether the allocatable array is currently
allocated. The optional ``rank`` is a DIExpression that describes the
rank (number of dimensions) of fortran assumed rank array (rank is
known at runtime).
For ``DW_TAG_enumeration_type``, the ``elements:`` should be :ref:`enumerator
descriptors <DIEnumerator>`, each representing the definition of an enumeration
@@ -6378,6 +6381,50 @@ DISubrange
!12 = !DIGlobalVariable(name: "count", scope: !8, file: !6, line: 22, type: !9)
!13 = !DISubrange(count: !12, lowerBound: 0)
.. _DISubrangeType:
DISubrangeType
""""""""""""""
``DISubrangeType`` is similar to ``DISubrange``, but it is also a
``DIType``. It may be used as the type of an object, but could also
be used as an array index.
Like ``DISubrange``, it can hold a lower bound and count, or a lower
bound and upper bound. A ``DISubrangeType`` refers to the underlying
type of which it is a subrange; this type can be an integer type or an
enumeration type.
A ``DISubrangeType`` may also have a stride -- unlike ``DISubrange``,
this stride is a bit stride. The stride is only useful when a
``DISubrangeType`` is used as an array index type.
Finally, ``DISubrangeType`` may have a bias. In Ada, a program can
request that a subrange value be stored in the minimum number of bits
required. In this situation, the stored value is biased by the lower
bound -- e.g., a range ``-7 .. 0`` may take 3 bits in memory, and the
value -5 would be stored as 2 (a bias of -7).
.. code-block:: text
; Scopes used in rest of example
!0 = !DIFile(filename: "vla.c", directory: "/path/to/file")
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !0)
!2 = distinct !DISubprogram(name: "foo", scope: !1, file: !0, line: 5)
; Base type used in example.
!3 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
; A simple subrange with a name.
!4 = !DISubrange(name: "subrange", file: !0, line: 17, size: 32,
align: 32, baseType: !3, lowerBound: 18, count: 12)
; A subrange with a bias.
!5 = !DISubrange(name: "biased", lowerBound: -7, upperBound: 0,
bias: -7, size: 3)
; A subrange with a bit stride.
!6 = !DISubrange(name: "biased", lowerBound: 0, upperBound: 7,
stride: 3)
.. _DIEnumerator:
DIEnumerator

View File

@@ -1478,7 +1478,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &DW_Subrange, const DISubrangeType *SR,
AddBoundTypeEntry(dwarf::DW_AT_upper_bound, SR->getUpperBound());
AddBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride());
AddBoundTypeEntry(dwarf::DW_AT_bit_stride, SR->getStride());
AddBoundTypeEntry(dwarf::DW_AT_GNU_bias, SR->getBias());
}
@@ -1670,7 +1670,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
DINodeArray Elements = CTy->getElements();
for (DINode *E : Elements) {
if (auto *Element = dyn_cast_or_null<DISubrangeType>(E)) {
DIE &TyDIE = createAndAddDIE(CTy->getTag(), Buffer, CTy);
DIE &TyDIE = createAndAddDIE(Element->getTag(), Buffer, CTy);
constructSubrangeDIE(TyDIE, Element, true);
} else if (auto *Element = dyn_cast_or_null<DISubrange>(E))
constructSubrangeDIE(Buffer, Element);

View File

@@ -0,0 +1,39 @@
;; Check output of DISubrangeType.
; RUN: %llc_dwarf -filetype=obj -O0 < %s | llvm-dwarfdump -debug-info - | FileCheck %s
; CHECK: DW_TAG_array_type
; CHECK-TYPE: DW_AT_type{{.*}}"unsigned int"
; CHECK-NOT: NULL
; CHECK: DW_TAG_subrange_type
; CHECK-NOT: NULL
; CHECK: DW_AT_lower_bound (-7)
; CHECK-NEXT: DW_AT_upper_bound (0)
; CHECK-NEXT: DW_AT_bit_stride (6)
; ModuleID = 'subrange_type.ll'
source_filename = "/dir/subrange_type.adb"
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 2, !"Dwarf Version", i32 4}
!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "GNAT/LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
!3 = !DIFile(filename: "subrange_type.adb", directory: "/dir")
!4 = !{}
!5 = !{!29}
!6 = distinct !DISubprogram(name: "sr", scope: !3, file: !3, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !9)
!7 = !DISubroutineType(types: !8)
!8 = !{null}
!9 = !{!10}
!10 = !DILocalVariable(name: "x", scope: !6, file: !3, line: 3, type: !31, align: 32)
!11 = !DISubrangeType(name: "sr__int_range", file: !3, line: 2, size: 32, align: 32, baseType: !12, lowerBound: i64 -7, upperBound: i64 0, stride: 6)
!12 = !DIBasicType(name: "sr__Tint_rangeB", size: 32, encoding: DW_ATE_signed)
!13 = !DILocation(line: 3, column: 4, scope: !6)
!14 = !DILocation(line: 6, column: 5, scope: !6)
!29 = !DICompositeType(tag: DW_TAG_array_type, size: 64, align: 32, file: !3, scope: !6, baseType: !31, elements: !32)
!31 = !DIBasicType(tag: DW_TAG_base_type, name: "unsigned int", size: 32, align: 32, encoding: DW_ATE_unsigned)
!32 = !{!11}