[reland][flang] Initial debug info support for local variables (#92304)

This is same as #90905 with an added fix. The issue was that we
generated variable info even when user asked for line-tables-only. This
caused llvm dwarf generation code to fail an assertion as it expected an
empty variable list.

Fixed by not generating debug info for variables when user wants only
line table. I also updated a test check for this case.
This commit is contained in:
Abid Qadeer 2024-05-16 09:10:59 +01:00 committed by GitHub
parent dcd32bd65f
commit cd5ee2715e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 361 additions and 47 deletions

View File

@ -13,6 +13,7 @@
#ifndef OPTIMIZER_CODEGEN_CGOPS_H
#define OPTIMIZER_CODEGEN_CGOPS_H
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"

View File

@ -16,6 +16,8 @@
include "mlir/IR/SymbolInterfaces.td"
include "flang/Optimizer/Dialect/FIRTypes.td"
include "flang/Optimizer/Dialect/FIRAttr.td"
include "mlir/IR/BuiltinAttributes.td"
def fircg_Dialect : Dialect {
let name = "fircg";
@ -202,4 +204,36 @@ def fircg_XArrayCoorOp : fircg_Op<"ext_array_coor", [AttrSizedOperandSegments]>
}];
}
// Extended Declare operation.
def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> {
let summary = "for internal conversion only";
let description = [{
Prior to lowering to LLVM IR dialect, a DeclareOp will
be converted to an extended DeclareOp.
}];
let arguments = (ins
AnyRefOrBox:$memref,
Variadic<AnyIntegerType>:$shape,
Variadic<AnyIntegerType>:$shift,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name
);
let results = (outs AnyRefOrBox);
let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`origin` $shift^)? (`typeparams` $typeparams^)?
(`dummy_scope` $dummy_scope^)?
attr-dict `:` functional-type(operands, results)
}];
let extraClassDeclaration = [{
// Shape is optional, but if it exists, it will be at offset 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
}];
}
#endif

View File

@ -47,6 +47,10 @@ def CodeGenRewrite : Pass<"cg-rewrite", "mlir::ModuleOp"> {
let dependentDialects = [
"fir::FIROpsDialect", "fir::FIRCodeGenDialect"
];
let options = [
Option<"preserveDeclare", "preserve-declare", "bool", /*default=*/"false",
"Preserve DeclareOp during pre codegen re-write.">
];
let statistics = [
Statistic<"numDCE", "num-dce'd", "Number of operations eliminated">
];

View File

@ -30,7 +30,8 @@ struct NameUniquer;
/// Prerequiste pass for code gen. Perform intermediate rewrites to perform
/// the code gen (to LLVM-IR dialect) conversion.
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass();
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass(
CodeGenRewriteOptions Options = CodeGenRewriteOptions{});
/// FirTargetRewritePass options.
struct TargetRewriteOptions {
@ -88,7 +89,8 @@ void populateFIRToLLVMConversionPatterns(fir::LLVMTypeConverter &converter,
fir::FIRToLLVMPassOptions &options);
/// Populate the pattern set with the PreCGRewrite patterns.
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns);
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare);
// declarative passes
#define GEN_PASS_REGISTRATION

View File

@ -174,9 +174,11 @@ inline void addMemoryAllocationOpt(mlir::PassManager &pm) {
}
#if !defined(FLANG_EXCLUDE_CODEGEN)
inline void addCodeGenRewritePass(mlir::PassManager &pm) {
addPassConditionally(
pm, disableCodeGenRewrite, fir::createFirCodeGenRewritePass);
inline void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) {
fir::CodeGenRewriteOptions options;
options.preserveDeclare = preserveDeclare;
addPassConditionally(pm, disableCodeGenRewrite,
[&]() { return fir::createFirCodeGenRewritePass(options); });
}
inline void addTargetRewritePass(mlir::PassManager &pm) {
@ -358,7 +360,8 @@ inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
MLIRToLLVMPassPipelineConfig config, llvm::StringRef inputFilename = {}) {
fir::addBoxedProcedurePass(pm);
addNestedPassToAllTopLevelOperations(pm, fir::createAbstractResultOpt);
fir::addCodeGenRewritePass(pm);
fir::addCodeGenRewritePass(
pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
fir::addTargetRewritePass(pm);
fir::addExternalNameConversionPass(pm, config.Underscoring);
fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);

View File

@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"

View File

@ -12,7 +12,7 @@
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"
#include "flang/Optimizer/CodeGen/FIROpPatterns.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
@ -170,6 +170,28 @@ genAllocationScaleSize(OP op, mlir::Type ity,
return nullptr;
}
namespace {
struct DeclareOpConversion : public fir::FIROpConversion<fir::cg::XDeclareOp> {
public:
using FIROpConversion::FIROpConversion;
mlir::LogicalResult
matchAndRewrite(fir::cg::XDeclareOp declareOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
auto memRef = adaptor.getOperands()[0];
if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(declareOp.getLoc())) {
if (auto varAttr =
mlir::dyn_cast_or_null<mlir::LLVM::DILocalVariableAttr>(
fusedLoc.getMetadata())) {
rewriter.create<mlir::LLVM::DbgDeclareOp>(memRef.getLoc(), memRef,
varAttr, nullptr);
}
}
rewriter.replaceOp(declareOp, memRef);
return mlir::success();
}
};
} // namespace
namespace {
/// convert to LLVM IR dialect `alloca`
struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
@ -3714,19 +3736,19 @@ void fir::populateFIRToLLVMConversionPatterns(
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
HasValueOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
MulcOpConversion, NegcOpConversion, NoReassocOpConversion,
SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
ShiftOpConversion, SliceOpConversion, StoreOpConversion,
StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
UndefOpConversion, UnreachableOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DeclareOpConversion,
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
InsertValueOpConversion, IsPresentOpConversion, LenParamIndexOpConversion,
LoadOpConversion, MulcOpConversion, NegcOpConversion,
NoReassocOpConversion, SelectCaseOpConversion, SelectOpConversion,
SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
StoreOpConversion, StringLitOpConversion, SubcOpConversion,
TypeDescOpConversion, TypeInfoOpConversion, UnboxCharOpConversion,
UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
UnrealizedConversionCastOpConversion, XArrayCoorOpConversion,
XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
options);

View File

@ -12,8 +12,8 @@
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "CGOps.h"
#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@ -270,13 +270,43 @@ public:
};
class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
bool preserveDeclare;
public:
using OpRewritePattern::OpRewritePattern;
DeclareOpConversion(mlir::MLIRContext *ctx, bool preserveDecl)
: OpRewritePattern(ctx), preserveDeclare(preserveDecl) {}
mlir::LogicalResult
matchAndRewrite(fir::DeclareOp declareOp,
mlir::PatternRewriter &rewriter) const override {
rewriter.replaceOp(declareOp, declareOp.getMemref());
if (!preserveDeclare) {
rewriter.replaceOp(declareOp, declareOp.getMemref());
return mlir::success();
}
auto loc = declareOp.getLoc();
llvm::SmallVector<mlir::Value> shapeOpers;
llvm::SmallVector<mlir::Value> shiftOpers;
if (auto shapeVal = declareOp.getShape()) {
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
populateShape(shapeOpers, shapeOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp()))
populateShift(shiftOpers, shiftOp);
else
return mlir::failure();
}
// FIXME: Add FortranAttrs and CudaAttrs
auto xDeclOp = rewriter.create<fir::cg::XDeclareOp>(
loc, declareOp.getType(), declareOp.getMemref(), shapeOpers, shiftOpers,
declareOp.getTypeparams(), declareOp.getDummyScope(),
declareOp.getUniqName());
LLVM_DEBUG(llvm::dbgs()
<< "rewriting " << declareOp << " to " << xDeclOp << '\n');
rewriter.replaceOp(declareOp, xDeclOp.getOperation()->getResults());
return mlir::success();
}
};
@ -297,6 +327,7 @@ public:
class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
public:
CodeGenRewrite(fir::CodeGenRewriteOptions opts) : Base(opts) {}
void runOnOperation() override final {
mlir::ModuleOp mod = getOperation();
@ -314,7 +345,7 @@ public:
mlir::cast<fir::BaseBoxType>(embox.getType()).getEleTy()));
});
mlir::RewritePatternSet patterns(&context);
fir::populatePreCGRewritePatterns(patterns);
fir::populatePreCGRewritePatterns(patterns, preserveDeclare);
if (mlir::failed(
mlir::applyPartialConversion(mod, target, std::move(patterns)))) {
mlir::emitError(mlir::UnknownLoc::get(&context),
@ -330,12 +361,14 @@ public:
} // namespace
std::unique_ptr<mlir::Pass> fir::createFirCodeGenRewritePass() {
return std::make_unique<CodeGenRewrite>();
std::unique_ptr<mlir::Pass>
fir::createFirCodeGenRewritePass(fir::CodeGenRewriteOptions Options) {
return std::make_unique<CodeGenRewrite>(Options);
}
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns) {
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare) {
patterns.insert<EmboxConversion, ArrayCoorConversion, ReboxConversion,
DeclareOpConversion, DummyScopeOpConversion>(
patterns.getContext());
DummyScopeOpConversion>(patterns.getContext());
patterns.add<DeclareOpConversion>(patterns.getContext(), preserveDeclare);
}

View File

@ -15,6 +15,7 @@
#include "flang/Common/Version.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@ -45,13 +46,59 @@ namespace fir {
namespace {
class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
void handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen);
public:
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
void runOnOperation() override;
};
static uint32_t getLineFromLoc(mlir::Location loc) {
uint32_t line = 1;
if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
line = fileLoc.getLine();
return line;
}
} // namespace
void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen) {
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
auto result = fir::NameUniquer::deconstruct(declOp.getUniqName());
if (result.first != fir::NameUniquer::NameKind::VARIABLE)
return;
// Only accept local variables.
if (result.second.procs.empty())
return;
// FIXME: There may be cases where an argument is processed a bit before
// DeclareOp is generated. In that case, DeclareOp may point to an
// intermediate op and not to BlockArgument. We need to find those cases and
// walk the chain to get to the actual argument.
unsigned argNo = 0;
if (auto Arg = llvm::dyn_cast<mlir::BlockArgument>(declOp.getMemref()))
argNo = Arg.getArgNumber() + 1;
auto tyAttr = typeGen.convertType(fir::unwrapRefType(declOp.getType()),
fileAttr, scopeAttr, declOp.getLoc());
auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
context, scopeAttr, mlir::StringAttr::get(context, result.second.name),
fileAttr, getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0,
tyAttr);
declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
}
void AddDebugInfoPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
@ -144,14 +191,19 @@ void AddDebugInfoPass::runOnOperation() {
subprogramFlags =
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
}
unsigned line = 1;
if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l))
line = funcLoc.getLine();
unsigned line = getLineFromLoc(l);
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, fileAttr, funcName, fullName,
funcFileAttr, line, line, subprogramFlags, subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
return;
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
handleDeclareOp(declOp, fileAttr, spAttr, typeGen);
});
});
}

View File

@ -24,11 +24,6 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m)
LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n");
}
static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return mlir::LLVM::DIBasicTypeAttr::get(
context, llvm::dwarf::DW_TAG_base_type, "void", 32, 1);
}
static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
mlir::StringAttr name,
unsigned bitSize,
@ -37,6 +32,11 @@ static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
context, llvm::dwarf::DW_TAG_base_type, name, bitSize, decoding);
}
static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return genBasicType(context, mlir::StringAttr::get(context, "integer"), 32,
llvm::dwarf::DW_ATE_signed);
}
mlir::LLVM::DITypeAttr
DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope,

View File

@ -1,5 +1,7 @@
// Test rewrite of fir.declare. The result is replaced by the memref operand.
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
// RUN: fir-opt --cg-rewrite="preserve-declare=true" %s -o - | FileCheck %s --check-prefixes DECL
// RUN: fir-opt --cg-rewrite="preserve-declare=false" %s -o - | FileCheck %s --check-prefixes NODECL
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s --check-prefixes NODECL
func.func @test(%arg0: !fir.ref<!fir.array<12x23xi32>>) {
@ -15,9 +17,14 @@ func.func @test(%arg0: !fir.ref<!fir.array<12x23xi32>>) {
func.func private @bar(%arg0: !fir.ref<!fir.array<12x23xi32>>)
// CHECK-LABEL: func.func @test(
// CHECK-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// CHECK-NEXT: fir.call @bar(%[[arg0]]) : (!fir.ref<!fir.array<12x23xi32>>) -> ()
// NODECL-LABEL: func.func @test(
// NODECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// NODECL-NEXT: fir.call @bar(%[[arg0]]) : (!fir.ref<!fir.array<12x23xi32>>) -> ()
// DECL-LABEL: func.func @test(
// DECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
// DECL: fircg.ext_declare
func.func @useless_shape_with_duplicate_extent_operand(%arg0: !fir.ref<!fir.array<3x3xf32>>) {
%c3 = arith.constant 3 : index
@ -26,5 +33,8 @@ func.func @useless_shape_with_duplicate_extent_operand(%arg0: !fir.ref<!fir.arra
return
}
// CHECK-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// CHECK-NEXT: return
// NODECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// NODECL-NEXT: return
// DECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
// DECL: fircg.ext_declare

View File

@ -1,9 +1,14 @@
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
// RUN: fir-opt --cg-rewrite="preserve-declare=true" %s -o - | FileCheck %s --check-prefixes DECL
// RUN: fir-opt --cg-rewrite="preserve-declare=false" %s -o - | FileCheck %s --check-prefixes NODECL
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s --check-prefixes NODECL
func.func @dummy_scope(%arg0: !fir.ref<f32>) {
%scope = fir.dummy_scope : !fir.dscope
%0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
return
}
// CHECK-LABEL: func.func @dummy_scope(
// CHECK-NEXT: return
// DECL-LABEL: func.func @dummy_scope(
// DECL: fircg.ext_declare
// NODECL-LABEL: func.func @dummy_scope(
// NODECL-NEXT: return

View File

@ -0,0 +1,94 @@
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
! RUN: %flang_fc1 -emit-llvm -debug-info-kind=line-tables-only %s -o - | FileCheck --check-prefix=LINEONLY %s
! This tests checks the debug information for local variables in llvm IR.
! CHECK-LABEL: define void @_QQmain
! CHECK-DAG: %[[AL11:.*]] = alloca i32
! CHECK-DAG: %[[AL12:.*]] = alloca i64
! CHECK-DAG: %[[AL13:.*]] = alloca i8
! CHECK-DAG: %[[AL14:.*]] = alloca i32
! CHECK-DAG: %[[AL15:.*]] = alloca float
! CHECK-DAG: %[[AL16:.*]] = alloca double
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL11]], metadata ![[I4:.*]], metadata !DIExpression())
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL12]], metadata ![[I8:.*]], metadata !DIExpression())
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL13]], metadata ![[L1:.*]], metadata !DIExpression())
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL14]], metadata ![[L4:.*]], metadata !DIExpression())
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL15]], metadata ![[R4:.*]], metadata !DIExpression())
! CHECK-DAG: call void @llvm.dbg.declare(metadata ptr %[[AL16]], metadata ![[R8:.*]], metadata !DIExpression())
! CHECK-LABEL: }
! CHECK-LABEL: define {{.*}}i64 @_QFPfn1
! CHECK-SAME: (ptr %[[ARG1:.*]], ptr %[[ARG2:.*]], ptr %[[ARG3:.*]])
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[ARG1]], metadata ![[A1:.*]], metadata !DIExpression())
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[ARG2]], metadata ![[B1:.*]], metadata !DIExpression())
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[ARG3]], metadata ![[C1:.*]], metadata !DIExpression())
! CHECK-DAG: %[[AL2:.*]] = alloca i64
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[AL2]], metadata ![[RES1:.*]], metadata !DIExpression())
! CHECK-LABEL: }
! CHECK-LABEL: define {{.*}}i32 @_QFPfn2
! CHECK-SAME: (ptr %[[FN2ARG1:.*]], ptr %[[FN2ARG2:.*]], ptr %[[FN2ARG3:.*]])
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[FN2ARG1]], metadata ![[A2:.*]], metadata !DIExpression())
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[FN2ARG2]], metadata ![[B2:.*]], metadata !DIExpression())
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[FN2ARG3]], metadata ![[C2:.*]], metadata !DIExpression())
! CHECK-DAG: %[[AL3:.*]] = alloca i32
! CHECK-DAG: tail call void @llvm.dbg.declare(metadata ptr %[[AL3]], metadata ![[RES2:.*]], metadata !DIExpression())
! CHECK-LABEL: }
program mn
! CHECK-DAG: ![[MAIN:.*]] = distinct !DISubprogram(name: "_QQmain", {{.*}})
! CHECK-DAG: ![[TYI32:.*]] = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
! CHECK-DAG: ![[TYI64:.*]] = !DIBasicType(name: "integer", size: 64, encoding: DW_ATE_signed)
! CHECK-DAG: ![[TYL8:.*]] = !DIBasicType(name: "logical", size: 8, encoding: DW_ATE_boolean)
! CHECK-DAG: ![[TYL32:.*]] = !DIBasicType(name: "logical", size: 32, encoding: DW_ATE_boolean)
! CHECK-DAG: ![[TYR32:.*]] = !DIBasicType(name: "real", size: 32, encoding: DW_ATE_float)
! CHECK-DAG: ![[TYR64:.*]] = !DIBasicType(name: "real", size: 64, encoding: DW_ATE_float)
! CHECK-DAG: ![[I4]] = !DILocalVariable(name: "i4", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYI32]])
! CHECK-DAG: ![[I8]] = !DILocalVariable(name: "i8", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYI64]])
! CHECK-DAG: ![[R4]] = !DILocalVariable(name: "r4", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYR32]])
! CHECK-DAG: ![[R8]] = !DILocalVariable(name: "r8", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYR64]])
! CHECK-DAG: ![[L1]] = !DILocalVariable(name: "l1", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYL8]])
! CHECK-DAG: ![[L4]] = !DILocalVariable(name: "l4", scope: ![[MAIN]], file: !{{.*}}, line: [[@LINE+6]], type: ![[TYL32]])
integer(kind=4) :: i4
integer(kind=8) :: i8
real(kind=4) :: r4
real(kind=8) :: r8
logical(kind=1) :: l1
logical(kind=4) :: l4
i8 = fn1(i4, r8, l1)
i4 = fn2(i8, r4, l4)
contains
! CHECK-DAG: ![[FN1:.*]] = distinct !DISubprogram(name: "fn1", {{.*}})
! CHECK-DAG: ![[A1]] = !DILocalVariable(name: "a1", arg: 1, scope: ![[FN1]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYI32]])
! CHECK-DAG: ![[B1]] = !DILocalVariable(name: "b1", arg: 2, scope: ![[FN1]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYR64]])
! CHECK-DAG: ![[C1]] = !DILocalVariable(name: "c1", arg: 3, scope: ![[FN1]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYL8]])
! CHECK-DAG: ![[RES1]] = !DILocalVariable(name: "res1", scope: ![[FN1]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYI64]])
function fn1(a1, b1, c1) result (res1)
integer(kind=4), intent(in) :: a1
real(kind=8), intent(in) :: b1
logical(kind=1), intent(in) :: c1
integer(kind=8) :: res1
res1 = a1 + b1
end function
! CHECK-DAG: ![[FN2:.*]] = distinct !DISubprogram(name: "fn2", {{.*}})
! CHECK-DAG: ![[A2]] = !DILocalVariable(name: "a2", arg: 1, scope: ![[FN2]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYI64]])
! CHECK-DAG: ![[B2]] = !DILocalVariable(name: "b2", arg: 2, scope: ![[FN2]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYR32]])
! CHECK-DAG: ![[C2]] = !DILocalVariable(name: "c2", arg: 3, scope: ![[FN2]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYL32]])
! CHECK-DAG: ![[RES2]] = !DILocalVariable(name: "res2", scope: ![[FN2]], file: !{{.*}}, line: [[@LINE+5]], type: ![[TYI32]])
function fn2(a2, b2, c2) result (res2)
integer(kind=8), intent(in) :: a2
real(kind=4), intent(in) :: b2
logical(kind=4), intent(in) :: c2
integer(kind=4) :: res2
res2 = a2 + b2
end function
end program
LINEONLY-NOT: DILocalVariable

View File

@ -0,0 +1,54 @@
! RUN: %flang_fc1 -emit-fir -debug-info-kind=standalone -mmlir --mlir-print-debuginfo %s -o - | \
! RUN: fir-opt --cg-rewrite="preserve-declare=true" --mlir-print-debuginfo | fir-opt --add-debug-info --mlir-print-debuginfo | FileCheck %s
! CHECK-DAG: #[[INT8:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 64, encoding = DW_ATE_signed>
! CHECK-DAG: #[[INT4:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 32, encoding = DW_ATE_signed>
! CHECK-DAG: #[[REAL8:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real", sizeInBits = 64, encoding = DW_ATE_float>
! CHECK-DAG: #[[LOG1:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "logical", sizeInBits = 8, encoding = DW_ATE_boolean>
! CHECK-DAG: #[[REAL4:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "real", sizeInBits = 32, encoding = DW_ATE_float>
! CHECK-DAG: #[[LOG4:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "logical", sizeInBits = 32, encoding = DW_ATE_boolean>
! CHECK-DAG: #[[MAIN:.*]] = #llvm.di_subprogram<{{.*}}name = "_QQmain"{{.*}}>
! CHECK-DAG: #[[FN1:.*]] = #llvm.di_subprogram<{{.*}}name = "fn1"{{.*}}>
! CHECK-DAG: #[[FN2:.*]] = #llvm.di_subprogram<{{.*}}name = "fn2"{{.*}}>
program mn
! CHECK-DAG: #[[I4:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "i4", file = #{{.*}}, line = [[@LINE+6]], type = #[[INT4]]>
! CHECK-DAG: #[[I8:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "i8", file = #{{.*}}, line = [[@LINE+6]], type = #[[INT8]]>
! CHECK-DAG: #[[R4:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "r4", file = #{{.*}}, line = [[@LINE+6]], type = #[[REAL4]]>
! CHECK-DAG: #[[R8:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "r8", file = #{{.*}}, line = [[@LINE+6]], type = #[[REAL8]]>
! CHECK-DAG: #[[L1:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "l1", file = #{{.*}}, line = [[@LINE+6]], type = #[[LOG1]]>
! CHECK-DAG: #[[L4:.*]] = #llvm.di_local_variable<scope = #[[MAIN]], name = "l4", file = #{{.*}}, line = [[@LINE+6]], type = #[[LOG4]]>
integer(kind=4) :: i4
integer(kind=8) :: i8
real(kind=4) :: r4
real(kind=8) :: r8
logical(kind=1) :: l1
logical(kind=4) :: l4
i8 = fn1(i4, r8, l1)
i4 = fn2(i8, r4, l4)
contains
function fn1(a1, b1, c1) result (res1)
! CHECK-DAG: #[[A1:.*]] = #llvm.di_local_variable<scope = #[[FN1]], name = "a1", file = #{{.*}}, line = [[@LINE+4]], arg = 1, type = #[[INT4]]>
! CHECK-DAG: #[[B1:.*]] = #llvm.di_local_variable<scope = #[[FN1]], name = "b1", file = #{{.*}}, line = [[@LINE+4]], arg = 2, type = #[[REAL8]]>
! CHECK-DAG: #[[C1:.*]] = #llvm.di_local_variable<scope = #[[FN1]], name = "c1", file = #{{.*}}, line = [[@LINE+4]], arg = 3, type = #[[LOG1]]>
! CHECK-DAG: #[[RES1:.*]] = #llvm.di_local_variable<scope = #[[FN1]], name = "res1", file = #{{.*}}, line = [[@LINE+4]], type = #[[INT8]]>
integer(kind=4), intent(in) :: a1
real(kind=8), intent(in) :: b1
logical(kind=1), intent(in) :: c1
integer(kind=8) :: res1
res1 = a1 + b1
end function
function fn2(a2, b2, c2) result (res2)
implicit none
! CHECK-DAG: #[[A2:.*]] = #llvm.di_local_variable<scope = #[[FN2]], name = "a2", file = #{{.*}}, line = [[@LINE+4]], arg = 1, type = #[[INT8]]>
! CHECK-DAG: #[[B2:.*]] = #llvm.di_local_variable<scope = #[[FN2]], name = "b2", file = #{{.*}}, line = [[@LINE+4]], arg = 2, type = #[[REAL4]]>
! CHECK-DAG: #[[C2:.*]] = #llvm.di_local_variable<scope = #[[FN2]], name = "c2", file = #{{.*}}, line = [[@LINE+4]], arg = 3, type = #[[LOG4]]>
! CHECK-DAG: #[[RES2:.*]] = #llvm.di_local_variable<scope = #[[FN2]], name = "res2", file = #{{.*}}, line = [[@LINE+4]], type = #[[INT4]]>
integer(kind=8), intent(in) :: a2
real(kind=4), intent(in) :: b2
logical(kind=4), intent(in) :: c2
integer(kind=4) :: res2
res2 = a2 + b2
end function
end program