diff --git a/flang/lib/Optimizer/CodeGen/DescriptorModel.h b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h similarity index 88% rename from flang/lib/Optimizer/CodeGen/DescriptorModel.h rename to flang/include/flang/Optimizer/CodeGen/DescriptorModel.h index ed35caef930149..ff0cf29e8073e6 100644 --- a/flang/lib/Optimizer/CodeGen/DescriptorModel.h +++ b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h @@ -35,73 +35,73 @@ using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); /// Get the LLVM IR dialect model for building a particular C++ type, `T`. template -TypeBuilderFunc getModel(); +static TypeBuilderFunc getModel(); template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::LLVM::LLVMPointerType::get(context); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(unsigned) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(int) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(unsigned long) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(long long) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(Fortran::ISO::CFI_rank_t) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(Fortran::ISO::CFI_type_t) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(context, sizeof(long) * 8); }; } template <> -TypeBuilderFunc getModel() { +constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { auto indexTy = getModel()(context); return mlir::LLVM::LLVMArrayType::get(indexTy, 3); }; } template <> -TypeBuilderFunc +constexpr TypeBuilderFunc getModel>() { return getModel(); } diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp index 07d3bd713ce45d..501a36f5b68ba6 100644 --- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp @@ -13,9 +13,9 @@ #define DEBUG_TYPE "flang-type-conversion" #include "flang/Optimizer/CodeGen/TypeConverter.h" -#include "DescriptorModel.h" #include "flang/Common/Fortran.h" #include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done +#include "flang/Optimizer/CodeGen/DescriptorModel.h" #include "flang/Optimizer/CodeGen/TBAABuilder.h" #include "flang/Optimizer/CodeGen/Target.h" #include "flang/Optimizer/Dialect/FIRType.h" diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index a174f2c2bc4bfd..53745d10fe9e4d 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -13,15 +13,55 @@ #define DEBUG_TYPE "flang-debug-type-generator" #include "DebugTypeGenerator.h" +#include "flang/Optimizer/CodeGen/DescriptorModel.h" +#include "flang/Optimizer/CodeGen/TypeConverter.h" +#include "flang/Optimizer/Support/DataLayout.h" +#include "mlir/Pass/Pass.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Debug.h" namespace fir { +/// Calculate offset of any field in the descriptor. +template +std::uint64_t getComponentOffset(const mlir::DataLayout &dl, + mlir::MLIRContext *context, + mlir::Type llvmFieldType) { + static_assert(DescriptorField > 0 && DescriptorField < 10); + mlir::Type previousFieldType = + getDescFieldTypeModel()(context); + std::uint64_t previousOffset = + getComponentOffset(dl, context, previousFieldType); + std::uint64_t offset = previousOffset + dl.getTypeSize(previousFieldType); + std::uint64_t fieldAlignment = dl.getTypeABIAlignment(llvmFieldType); + return llvm::alignTo(offset, fieldAlignment); +} +template <> +std::uint64_t getComponentOffset<0>(const mlir::DataLayout &dl, + mlir::MLIRContext *context, + mlir::Type llvmFieldType) { + return 0; +} + DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m) : module(m), kindMapping(getKindMapping(m)) { LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n"); + + std::optional dl = + fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/true); + if (!dl) { + mlir::emitError(module.getLoc(), "Missing data layout attribute in module"); + return; + } + + mlir::MLIRContext *context = module.getContext(); + + // The debug information requires the offset of certain fields in the + // descriptors like lower_bound and extent for each dimension. + mlir::Type llvmDimsType = getDescFieldTypeModel()(context); + dimsOffset = getComponentOffset(*dl, context, llvmDimsType); + dimsSize = dl->getTypeSize(llvmDimsType); } static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context, @@ -37,10 +77,82 @@ static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) { llvm::dwarf::DW_ATE_signed); } +mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType( + fir::SequenceType seqTy, mlir::LLVM::DIFileAttr fileAttr, + mlir::LLVM::DIScopeAttr scope, mlir::Location loc, bool genAllocated, + bool genAssociated) { + + mlir::MLIRContext *context = module.getContext(); + // FIXME: Assumed rank arrays not supported yet + if (seqTy.hasUnknownShape()) + return genPlaceholderType(context); + + llvm::SmallVector ops; + auto addOp = [&](unsigned opc, llvm::ArrayRef vals) { + ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(context, opc, vals)); + }; + + addOp(llvm::dwarf::DW_OP_push_object_address, {}); + addOp(llvm::dwarf::DW_OP_deref, {}); + + // dataLocation = *base_addr + mlir::LLVM::DIExpressionAttr dataLocation = + mlir::LLVM::DIExpressionAttr::get(context, ops); + addOp(llvm::dwarf::DW_OP_lit0, {}); + addOp(llvm::dwarf::DW_OP_ne, {}); + + // allocated = associated = (*base_addr != 0) + mlir::LLVM::DIExpressionAttr valid = + mlir::LLVM::DIExpressionAttr::get(context, ops); + mlir::LLVM::DIExpressionAttr associated = genAllocated ? valid : nullptr; + mlir::LLVM::DIExpressionAttr allocated = genAssociated ? valid : nullptr; + ops.clear(); + + llvm::SmallVector elements; + mlir::LLVM::DITypeAttr elemTy = + convertType(seqTy.getEleTy(), fileAttr, scope, loc); + unsigned offset = dimsOffset; + const unsigned indexSize = dimsSize / 3; + for ([[maybe_unused]] auto _ : seqTy.getShape()) { + // For each dimension, find the offset of count and lower bound in the + // descriptor and generate the dwarf expression to extract it. + // FIXME: If `indexSize` happens to be bigger than address size on the + // system then we may have to change 'DW_OP_deref' here. + addOp(llvm::dwarf::DW_OP_push_object_address, {}); + addOp(llvm::dwarf::DW_OP_plus_uconst, + {offset + (indexSize * kDimExtentPos)}); + addOp(llvm::dwarf::DW_OP_deref, {}); + // count[i] = *(base_addr + offset + (indexSize * kDimExtentPos)) + // where 'offset' is dimsOffset + (i * dimsSize) + mlir::LLVM::DIExpressionAttr countAttr = + mlir::LLVM::DIExpressionAttr::get(context, ops); + ops.clear(); + + addOp(llvm::dwarf::DW_OP_push_object_address, {}); + addOp(llvm::dwarf::DW_OP_plus_uconst, + {offset + (indexSize * kDimLowerBoundPos)}); + addOp(llvm::dwarf::DW_OP_deref, {}); + // lower_bound[i] = *(base_addr + offset + (indexSize * kDimLowerBoundPos)) + mlir::LLVM::DIExpressionAttr lowerAttr = + mlir::LLVM::DIExpressionAttr::get(context, ops); + ops.clear(); + + offset += dimsSize; + mlir::LLVM::DISubrangeAttr subrangeTy = mlir::LLVM::DISubrangeAttr::get( + context, nullptr, lowerAttr, countAttr, nullptr); + elements.push_back(subrangeTy); + } + return mlir::LLVM::DICompositeTypeAttr::get( + context, llvm::dwarf::DW_TAG_array_type, /*recursive id*/ {}, + /* name */ nullptr, /* file */ nullptr, /* line */ 0, + /* scope */ nullptr, elemTy, mlir::LLVM::DIFlags::Zero, + /* sizeInBits */ 0, /*alignInBits*/ 0, elements, dataLocation, + /* rank */ nullptr, allocated, associated); +} + mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType( fir::SequenceType seqTy, mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scope, mlir::Location loc) { - mlir::MLIRContext *context = module.getContext(); // FIXME: Only fixed sizes arrays handled at the moment. if (seqTy.hasDynamicExtents()) @@ -112,6 +224,12 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, bitWidth * 2, llvm::dwarf::DW_ATE_complex_float); } else if (auto seqTy = mlir::dyn_cast_or_null(Ty)) { return convertSequenceType(seqTy, fileAttr, scope, loc); + } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { + auto elTy = boxTy.getElementType(); + if (auto seqTy = mlir::dyn_cast_or_null(elTy)) + return convertBoxedSequenceType(seqTy, fileAttr, scope, loc, false, + false); + return genPlaceholderType(context); } else { // FIXME: These types are currently unhandled. We are generating a // placeholder type to allow us to test supported bits. diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h index 963c919d66825c..11515d11dfed63 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h @@ -35,8 +35,20 @@ class DebugTypeGenerator { mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scope, mlir::Location loc); + + /// The 'genAllocated' is true when we want to generate 'allocated' field + /// in the DICompositeType. It is needed for the allocatable arrays. + /// Similarly, 'genAssociated' is used with 'pointer' type to generate + /// 'associated' field. + mlir::LLVM::DITypeAttr + convertBoxedSequenceType(fir::SequenceType seqTy, + mlir::LLVM::DIFileAttr fileAttr, + mlir::LLVM::DIScopeAttr scope, mlir::Location loc, + bool genAllocated, bool genAssociated); mlir::ModuleOp module; KindMapping kindMapping; + std::uint64_t dimsSize; + std::uint64_t dimsOffset; }; } // namespace fir diff --git a/flang/test/Integration/debug-assumed-shape-array.f90 b/flang/test/Integration/debug-assumed-shape-array.f90 new file mode 100644 index 00000000000000..7b0801c12dba11 --- /dev/null +++ b/flang/test/Integration/debug-assumed-shape-array.f90 @@ -0,0 +1,13 @@ +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s + +subroutine ff(arr) + implicit none + integer :: arr(:, :) + return arr(1,1) +end subroutine ff + +! CHECK-DAG: !DICompositeType(tag: DW_TAG_array_type{{.*}}elements: ![[ELEMS:[0-9]+]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref)) +! CHECK-DAG: ![[ELEMS]] = !{![[ELEM1:[0-9]+]], ![[ELEM2:[0-9]+]]} +! CHECK-DAG: ![[ELEM1]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 24, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 32, DW_OP_deref)) +! CHECK-DAG: ![[ELEM2]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref)) + diff --git a/flang/test/Transforms/debug-90683.fir b/flang/test/Transforms/debug-90683.fir index 9da0e5347d3f8f..cc6929c10411f8 100644 --- a/flang/test/Transforms/debug-90683.fir +++ b/flang/test/Transforms/debug-90683.fir @@ -2,7 +2,7 @@ // This test checks that debug information for fir.real type works ok. -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QPfn1(%arg0: !fir.ref> {fir.bindc_name = "a"} ) { %0 = fir.declare %arg0 {uniq_name = "_QFfn1Ea"} : (!fir.ref>) -> !fir.ref> %1 = fir.alloca f32 {bindc_name = "abserror", uniq_name = "_QFfn1Eabserror"} diff --git a/flang/test/Transforms/debug-assumed-shape-array.fir b/flang/test/Transforms/debug-assumed-shape-array.fir new file mode 100644 index 00000000000000..00dec9b318c811 --- /dev/null +++ b/flang/test/Transforms/debug-assumed-shape-array.fir @@ -0,0 +1,16 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry, dense<64> : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>, #dlti.dl_entry<"dlti.endianness", "little">>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} { + func.func @ff_(%arg0: !fir.box> {fir.bindc_name = "arr"} ) { + %0 = fir.undefined !fir.dscope + %1 = fircg.ext_declare %arg0 dummy_scope %0 {uniq_name = "_QFffEarr"} : (!fir.box>, !fir.dscope) -> !fir.box> loc(#loc1) + return + } loc(#loc2) +} +#loc1 = loc("test1.f90":1:1) +#loc2 = loc("test1.f90":3:16) + +// CHECK: #llvm.di_composite_type, upperBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(32), DW_OP_deref]>> +// CHECK-SAME: #llvm.di_subrange, upperBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(56), DW_OP_deref]>> +// CHECK-SAME: dataLocation = <[DW_OP_push_object_address, DW_OP_deref]>> diff --git a/flang/test/Transforms/debug-complex-1.fir b/flang/test/Transforms/debug-complex-1.fir index a3cbd767d8a58e..cc742d3b183bbf 100644 --- a/flang/test/Transforms/debug-complex-1.fir +++ b/flang/test/Transforms/debug-complex-1.fir @@ -3,7 +3,7 @@ // check conversion of complex type of different size. Both fir and mlir // variants are checked. -module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "native"} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @test1(%x : !fir.complex<4>) -> !fir.complex<8> { %1 = fir.convert %x : (!fir.complex<4>) -> !fir.complex<8> return %1 : !fir.complex<8> diff --git a/flang/test/Transforms/debug-fixed-array-type.fir b/flang/test/Transforms/debug-fixed-array-type.fir index 401c725411831e..d4ed0b97020898 100644 --- a/flang/test/Transforms/debug-fixed-array-type.fir +++ b/flang/test/Transforms/debug-fixed-array-type.fir @@ -1,6 +1,6 @@ // RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QQmain() attributes {fir.bindc_name = "mn"} { %c7 = arith.constant 7 : index %c8 = arith.constant 8 : index diff --git a/flang/test/Transforms/debug-line-table-existing.fir b/flang/test/Transforms/debug-line-table-existing.fir index 534278ebc972d3..0e006303c8a81d 100644 --- a/flang/test/Transforms/debug-line-table-existing.fir +++ b/flang/test/Transforms/debug-line-table-existing.fir @@ -3,7 +3,7 @@ // REQUIRES: system-linux // Test that there are no changes to a function with existed fused loc debug -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QPs1() { return loc(#loc1) } loc(#loc2) diff --git a/flang/test/Transforms/debug-line-table-inc-file.fir b/flang/test/Transforms/debug-line-table-inc-file.fir index 9370c138fd42ff..065039b59c5ae8 100644 --- a/flang/test/Transforms/debug-line-table-inc-file.fir +++ b/flang/test/Transforms/debug-line-table-inc-file.fir @@ -3,7 +3,7 @@ // REQUIRES: system-linux // Test for included functions that have a different debug location than the current file -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QPsinc() { return loc(#loc2) } loc(#loc1) @@ -19,7 +19,7 @@ module attributes {} { #loc4 = loc("/home/user01/llvm-project/build_release/simple.f90":4:3) #loc5 = loc("/home/user01/llvm-project/build_release/simple.f90":5:1) -// CHECK: module { +// CHECK: module // CHECK: func.func @_QPsinc() { // CHECK: } loc(#[[FUSED_LOC_INC_FILE:.*]]) // CHECK: func.func @_QQmain() { diff --git a/flang/test/Transforms/debug-line-table-inc-same-file.fir b/flang/test/Transforms/debug-line-table-inc-same-file.fir index 4836f2e21dd9db..bcaf4497982310 100644 --- a/flang/test/Transforms/debug-line-table-inc-same-file.fir +++ b/flang/test/Transforms/debug-line-table-inc-same-file.fir @@ -4,7 +4,7 @@ // Test that there is only one FileAttribute generated for multiple functions // in the same file. -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QPs1() { return loc(#loc2) } loc(#loc1) diff --git a/flang/test/Transforms/debug-line-table.fir b/flang/test/Transforms/debug-line-table.fir index 8a72ca2a856a70..d6e54fd1ac467e 100644 --- a/flang/test/Transforms/debug-line-table.fir +++ b/flang/test/Transforms/debug-line-table.fir @@ -3,7 +3,7 @@ // RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=LINETABLE // RUN: fir-opt --add-debug-info="is-optimized=true" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=OPT -module attributes { fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", llvm.target_triple = "aarch64-unknown-linux-gnu"} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { func.func @_QPsb() { return loc(#loc_sb) } loc(#loc_sb) diff --git a/flang/test/Transforms/debug-module-1.fir b/flang/test/Transforms/debug-module-1.fir index 822ae01b99aa78..71457d32b15960 100644 --- a/flang/test/Transforms/debug-module-1.fir +++ b/flang/test/Transforms/debug-module-1.fir @@ -1,7 +1,7 @@ // RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s -module attributes {} { +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { fir.global @_QMhelperEgli : i32 { %0 = fir.zero_bits i32 fir.has_value %0 : i32