Skip to content
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

[flang][debug] Support assumed shape arrays. #94644

Merged
merged 4 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,73 +35,73 @@ using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *);

/// Get the LLVM IR dialect model for building a particular C++ type, `T`.
template <typename T>
TypeBuilderFunc getModel();
static TypeBuilderFunc getModel();

template <>
TypeBuilderFunc getModel<void *>() {
constexpr TypeBuilderFunc getModel<void *>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::LLVM::LLVMPointerType::get(context);
};
}
template <>
TypeBuilderFunc getModel<unsigned>() {
constexpr TypeBuilderFunc getModel<unsigned>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(unsigned) * 8);
};
}
template <>
TypeBuilderFunc getModel<int>() {
constexpr TypeBuilderFunc getModel<int>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(int) * 8);
};
}
template <>
TypeBuilderFunc getModel<unsigned long>() {
constexpr TypeBuilderFunc getModel<unsigned long>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(unsigned long) * 8);
};
}
template <>
TypeBuilderFunc getModel<unsigned long long>() {
constexpr TypeBuilderFunc getModel<unsigned long long>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8);
};
}
template <>
TypeBuilderFunc getModel<long long>() {
constexpr TypeBuilderFunc getModel<long long>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(long long) * 8);
};
}
template <>
TypeBuilderFunc getModel<Fortran::ISO::CFI_rank_t>() {
constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_rank_t>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context,
sizeof(Fortran::ISO::CFI_rank_t) * 8);
};
}
template <>
TypeBuilderFunc getModel<Fortran::ISO::CFI_type_t>() {
constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_type_t>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context,
sizeof(Fortran::ISO::CFI_type_t) * 8);
};
}
template <>
TypeBuilderFunc getModel<long>() {
constexpr TypeBuilderFunc getModel<long>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
return mlir::IntegerType::get(context, sizeof(long) * 8);
};
}
template <>
TypeBuilderFunc getModel<Fortran::ISO::CFI_dim_t>() {
constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_dim_t>() {
return [](mlir::MLIRContext *context) -> mlir::Type {
auto indexTy = getModel<Fortran::ISO::CFI_index_t>()(context);
return mlir::LLVM::LLVMArrayType::get(indexTy, 3);
};
}
template <>
TypeBuilderFunc
constexpr TypeBuilderFunc
getModel<Fortran::ISO::cfi_internal::FlexibleArray<Fortran::ISO::CFI_dim_t>>() {
return getModel<Fortran::ISO::CFI_dim_t>();
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Optimizer/CodeGen/TypeConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
120 changes: 119 additions & 1 deletion flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <int DescriptorField>
std::uint64_t getComponentOffset(const mlir::DataLayout &dl,
mlir::MLIRContext *context,
mlir::Type llvmFieldType) {
static_assert(DescriptorField > 0 && DescriptorField < 10);
mlir::Type previousFieldType =
getDescFieldTypeModel<DescriptorField - 1>()(context);
std::uint64_t previousOffset =
getComponentOffset<DescriptorField - 1>(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<mlir::DataLayout> dl =
fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/true);
if (!dl) {
mlir::emitError(module.getLoc(), "Missing data layout attribute in module");
tblah marked this conversation as resolved.
Show resolved Hide resolved
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<kDimsPosInBox>()(context);
dimsOffset = getComponentOffset<kDimsPosInBox>(*dl, context, llvmDimsType);
dimsSize = dl->getTypeSize(llvmDimsType);
}

static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
Expand All @@ -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<mlir::LLVM::DIExpressionElemAttr> ops;
auto addOp = [&](unsigned opc, llvm::ArrayRef<uint64_t> 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<mlir::LLVM::DINodeAttr> 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())
Expand Down Expand Up @@ -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<fir::SequenceType>(Ty)) {
return convertSequenceType(seqTy, fileAttr, scope, loc);
} else if (auto boxTy = mlir::dyn_cast_or_null<fir::BoxType>(Ty)) {
auto elTy = boxTy.getElementType();
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(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.
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Optimizer/Transforms/DebugTypeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions flang/test/Integration/debug-assumed-shape-array.f90
Original file line number Diff line number Diff line change
@@ -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))

2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-90683.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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.complex<8>> {fir.bindc_name = "a"} ) {
%0 = fir.declare %arg0 {uniq_name = "_QFfn1Ea"} : (!fir.ref<!fir.complex<8>>) -> !fir.ref<!fir.complex<8>>
%1 = fir.alloca f32 {bindc_name = "abserror", uniq_name = "_QFfn1Eabserror"}
Expand Down
16 changes: 16 additions & 0 deletions flang/test/Transforms/debug-assumed-shape-array.fir
Original file line number Diff line number Diff line change
@@ -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<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : 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.array<?x?xi32>> {fir.bindc_name = "arr"} ) {
%0 = fir.undefined !fir.dscope
%1 = fircg.ext_declare %arg0 dummy_scope %0 {uniq_name = "_QFffEarr"} : (!fir.box<!fir.array<?x?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?x?xi32>> loc(#loc1)
return
} loc(#loc2)
}
#loc1 = loc("test1.f90":1:1)
#loc2 = loc("test1.f90":3:16)

// CHECK: #llvm.di_composite_type<tag = DW_TAG_array_type
// CHECK-SAME: elements = #llvm.di_subrange<lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(24), DW_OP_deref]>, upperBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(32), DW_OP_deref]>>
// CHECK-SAME: #llvm.di_subrange<lowerBound = #llvm.di_expression<[DW_OP_push_object_address, DW_OP_plus_uconst(48), DW_OP_deref]>, 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]>>
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-complex-1.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-fixed-array-type.fir
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-line-table-existing.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Transforms/debug-line-table-inc-file.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-line-table-inc-same-file.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-line-table.fir
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Transforms/debug-module-1.fir
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading