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 `, 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 ` or :ref:`subrange descriptors +`, 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 `, 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(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(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}