Skip to content

Two fixes for DISubrangeType #130345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2025
Merged

Conversation

tromey
Copy link
Contributor

@tromey tromey commented Mar 7, 2025

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.

My previous patch to add DISubrangeType (llvm#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.
@llvmbot
Copy link
Member

llvmbot commented Mar 7, 2025

@llvm/pr-subscribers-debuginfo

Author: Tom Tromey (tromey)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/130345.diff

3 Files Affected:

  • (modified) llvm/docs/LangRef.rst (+62-15)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+2-2)
  • (added) llvm/test/DebugInfo/Generic/subrange_type.ll (+39)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 8f80344b854ee..b0de05da2fd1f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -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
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index b77ecf1372405..383fbfb3fbd2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -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);
diff --git a/llvm/test/DebugInfo/Generic/subrange_type.ll b/llvm/test/DebugInfo/Generic/subrange_type.ll
new file mode 100644
index 0000000000000..28fd70eab5d72
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/subrange_type.ll
@@ -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}

@llvmbot
Copy link
Member

llvmbot commented Mar 7, 2025

@llvm/pr-subscribers-llvm-ir

Author: Tom Tromey (tromey)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/130345.diff

3 Files Affected:

  • (modified) llvm/docs/LangRef.rst (+62-15)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+2-2)
  • (added) llvm/test/DebugInfo/Generic/subrange_type.ll (+39)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 8f80344b854ee..b0de05da2fd1f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -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
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index b77ecf1372405..383fbfb3fbd2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -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);
diff --git a/llvm/test/DebugInfo/Generic/subrange_type.ll b/llvm/test/DebugInfo/Generic/subrange_type.ll
new file mode 100644
index 0000000000000..28fd70eab5d72
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/subrange_type.ll
@@ -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}

@dwblaikie dwblaikie merged commit 993cbea into llvm:main Mar 7, 2025
13 of 15 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 7, 2025

LLVM Buildbot has detected a new failure on builder llvm-nvptx-nvidia-win running on as-builder-8 while building llvm at step 7 "test-build-unified-tree-check-llvm".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/54/builds/7107

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-llvm) failure: test (failure)
******************** TEST 'LLVM-Unit :: Support/./SupportTests.exe/51/87' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:C:\buildbot\as-builder-8\llvm-nvptx-nvidia-win\build\unittests\Support\.\SupportTests.exe-LLVM-Unit-31144-51-87.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=87 GTEST_SHARD_INDEX=51 C:\buildbot\as-builder-8\llvm-nvptx-nvidia-win\build\unittests\Support\.\SupportTests.exe
--

Script:
--
C:\buildbot\as-builder-8\llvm-nvptx-nvidia-win\build\unittests\Support\.\SupportTests.exe --gtest_filter=Caching.NoCommit
--
C:\buildbot\as-builder-8\llvm-nvptx-nvidia-win\llvm-project\llvm\unittests\Support\Caching.cpp(142): error: Value of: AddStream
  Actual: false
Expected: true


C:\buildbot\as-builder-8\llvm-nvptx-nvidia-win\llvm-project\llvm\unittests\Support\Caching.cpp:142
Value of: AddStream
  Actual: false
Expected: true



********************


@tromey tromey deleted the fixup-subrange-type branch March 10, 2025 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants