Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. LLVM Metadata Extensions for Debugging Fortran Version 0.2 This document describes the extensions to LLVM debug metadata that have been implemented to support standard DWARF constructed used to represent Fortran. These changes are committed to in flang-compiler/llvm but not yet committed to llvm.org/llvm. This document does not cover all the changes required to support debug metadata generation for Fortran. There is a companion document that is used for discussion of proposed changes to LLVM to support LLVM metadata changes for Fortran. Extensions to LLVM Metadata This document describes the extensions that PGI has added to LLVM to support debugging Fortran programs. Work In Progress Array stride information is not implemented in the extended metadata described in this document. The implication is that arrays will have single-unit stride, which is often, but not always, the case with Flang array parameters. CHARACTER Type There is no analog in C or C++ for the Fortran CHARACTER type. The runtime representation of Fortran CHARACTER type is significantly different from C strings and C char VLAs. The Fortran CHARACTER type maps to the DWARF DW_TAG_string_type. DW_TAG_string_type: DW_AT_name: "character(5)" DW_AT_byte_size: 5 A new named DI was implemented to generate this DWARF information: !21 = !DIStringType(name: "character(5)", size: 40) CHARACTER Type with Deferred Length CHARACTER types can also have deferred length. The Fortran CHARACTER type with a deferred length maps to the following DWARF: DW_TAG_string_type: DW_AT_name: character(*)!1 DW_AT_string_length: 0x9b (location list) DW_AT_byte_size: 4 This is supported in the new metadata as follows. !22 = !DIStringType(name: "character(*)!1, size: 32, stringLength: !23, stringLengthExpression: !24) !23 = !DILocalVariable(scope: !3, arg: 4, file: !4, type: !5, flags: DIFlagArtificial) !24 = !DIExpression() Fortran Array Types and Bounds Fortran arrays have multiple dimensions. Generally, Fortran arrays are described using descriptors which includes the number of dimensions, the upper and lower bound for each dimension, the stride, and the element size. Explicit array dimensions An array may be given a constant size as in the following example. The example shows a two-dimensional array, named array, that has indices from 1 to 10 for the rows and 2 to 11 for the columns.TYPE(t) :: array(10,2:11) For this declaration, the compiler generates the following LLVM metadata. !100 = !DIFortranArrayType(baseType: !7, elements: !101) !101 = !{ !102, !103 } !102 = !DIFortranSubrange(constLowerBound: 1, constUpperBound: 10) !103 = !DIFortranSubrange(constLowerBound: 2, constUpperBound: 11) The DWARF generated for this is as follows. DW_TAG_array_type: DW_AT_name: array DW_AT_type: 4d08 ;TYPE(t) DW_TAG_subrange_type: DW_AT_type: int DW_AT_lower_bound: 1 DW_AT_upper_bound: 10 DW_TAG_subrange_type: DW_AT_type: int DW_AT_lower_bound: 2 DW_AT_upper_bound: 11 Adjustable arrays An adjustable array is an array that is a local array or argument array with one or more of its dimensions or bounds as an expression of variables that are either dummy arguments or in a common block. SUBROUTINE subr2(array2,N) INTEGER :: N TYPE(t) :: array2(N) In this case, we want to be able to express the !DISubrange as an expression that references the dummy argument, N. call void @llvm.dbg.declare(metadata i64* %N, metadata !113, metadata !114) ... !110 = !DIFortranArrayType(baseType: !7, elements: !111) !111 = !{ !112 } !112 = !DIFortranSubrange(lowerBound: 1, upperBound: !113, upperBoundExpression: !114) !113 = !DILocalVariable(scope: !2, name: "zb1", file: !3, type: !4, flags: DIFlagArtificial) !114 = !DIExpression() It turns out the gdb does not properly interpret location lists or variable references in the DW_AT_lower_bound and DW_AT_upper_bound attribute forms, so we must generate either a constant or a block with the DW_OP operations for each of them. DW_TAG_array_type: DW_AT_name: array2 DW_AT_type: 4d08 ;TYPE(t) DW_TAG_subrange_type: DW_AT_type: int DW_AT_lower_bound: 1 DW_AT_upper_bound: 2 byte block: 91 70 Assumed size arrays An assumed size array leaves the last dimension of the array unspecified. SUBROUTINE subr3(array3) TYPE(t):: array3(*) We want the compiler to generate DWARF information without an upper bound, such as in this snippet. DW_TAG_array_type DW_AT_name: array3 DW_TAG_subrange_type DW_AT_type = int DW_AT_lower_bound = 1 This DWARF is produced by omission of the upper bound information. !122 = !DIFortranSubrange(lowerBound: 1) Assumed shape arrays Fortran also has assumed shape arrays, which allow extra state to be passed into the procedure to describe the shape of the array dummy argument. This extra information is the array descriptor, generated by the compiler, and passed as a hidden argument.SUBROUTINE subr4(array4) TYPE(t) :: array4(:,:) In this case, we want to be able to generate DWARF expressions to access the results of the procedure's usage of the array descriptor argument when it computes the lower bound (DW_AT_lower_bound) and upper bound (DW_AT_upper_bound). ... call void @llvm.dbg.declare(metadata i64* %4, metadata !134, metadata !135) call void @llvm.dbg.declare(metadata i64* %8, metadata !136, metadata !135) call void @llvm.dbg.declare(metadata i64* %9, metadata !137, metadata !138) call void @llvm.dbg.declare(metadata i64* %13, metadata !139, metadata !138) ... !130 = !DIFortranArrayType(baseType: !80, elements: !131) !131 = !{ !132, !133 } !132 = !DISubrange(lowerBound: !134, lowerBoundExpression: !135, upperBound: !136, upperBoundExpression: !135) !133 = !DISubrange(lowerBound: !137, lowerBoundExpression: !138, upperBound: !139, upperBoundExpression: !138) !134 = !DILocalVariable(scope: !2, name: "zb1", file: !3, type: !9, flags: DIArtificial) !135 = !DIExpression() !136 = !DILocalVariable(scope: !2, name: "zb3", file: !3, type: !9, flags: DIArtificial) !137 = !DILocalVariable(scope: !2, name: "zb4", file: !3, type: !9, flags: DIArtificial) !138 = !DIExpression(DW_OP_deref) !139 = !DILocalVariable(scope: !2, name: "zb5", file: !3, type: !9, flags: DIArtificial) The DWARF generated for this is as follows. DW_TAG_array_type: DW_AT_name: array4 DW_AT_type: 4d08 ;TYPE(t) DW_TAG_subrange_type: DW_AT_type: int DW_AT_lower_bound: 2 byte block: 91 78 DW_AT_upper_bound: 2 byte block: 91 70 DW_TAG_subrange_type: DW_AT_type: int DW_AT_lower_bound: 2 byte block: 91 68 DW_AT_upper_bound: 2 byte block: 91 60 Elemental, Pure, and Recursive Procedures DWARF 4 defines attributes for the Fortran function specifiers ELEMENTAL, PURE, and RECURSIVE: DW_AT_elemental, DW_AT_pure, DW_AT_recursive, resp. LLVM has an existing way of informing the DWARF generator of simple boolean attributes in the metadata. We have added these to the collection of flags. !60 = !DISubprogram(..., flags: DIFlagElemental) !61 = !DISubprogram(..., flags: DIFlagPure) !62 = !DISubprogram(..., flags: DIFlagRecursive) The Fortran 2018 standard defines a new attribute, NON_RECURSIVE. DWARF does not yet have a way to represent NON_RECURSIVE.