[flang-commits] [flang] [flang][debug] Add fake use ops for dynamic array dimension variables (PR #200061)
via flang-commits
flang-commits at lists.llvm.org
Mon Jun 15 08:04:03 PDT 2026
https://github.com/timsmith78 updated https://github.com/llvm/llvm-project/pull/200061
>From 144098d6858732f30bb3c7a1992484af32a90989 Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Fri, 15 May 2026 15:17:51 -0500
Subject: [PATCH] Add fake use ops for dynamic array dimension variables
In cases where the upper or lower bounds of a dynamic array are not
explicitly referenced in code, flang can optimize away the internal
variables that represent these values. This causes missing values to
appear in the debugger when examining the dynamic array's type. Adding
an llvm.fake.use op for each bound preserves it for use by a debugger,
similar to the fix for #185432.
Resolves #119474
---
.../flang/Optimizer/Transforms/Passes.td | 4 +-
flang/lib/Optimizer/Passes/Pipelines.cpp | 2 +-
.../lib/Optimizer/Transforms/AddDebugInfo.cpp | 63 +++++--
.../debug-fake-use-multiple-dimensions.fir | 165 ++++++++++++++++++
.../debug-fake-use-multiple-returns.fir | 125 +++++++++++++
flang/test/Transforms/debug-fake-use.fir | 52 +++++-
6 files changed, 391 insertions(+), 20 deletions(-)
create mode 100644 flang/test/Transforms/debug-fake-use-multiple-dimensions.fir
create mode 100644 flang/test/Transforms/debug-fake-use-multiple-returns.fir
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index d9072e7aab4f7..8c082fb073451 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -267,9 +267,9 @@ def AddDebugInfo : Pass<"add-debug-info", "mlir::ModuleOp"> {
Option<"dwarfDebugFlags", "dwarf-debug-flags",
"std::string", /*default=*/"std::string{}",
"Command-line flags to append to DWARF producer">,
- Option<"emitFakeUseForArguments", "emit-fake-use-for-arguments",
+ Option<"emitFakeUseForDebugVars", "emit-fake-use-for-debug-vars",
"bool", /*default=*/"false",
- "Emit fake use for function arguments to extend their lifetime">
+ "Emit fake use for debug variables to extend their lifetime">
];
}
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index c6d531ce50762..c677962f30199 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -113,7 +113,7 @@ void addDebugInfoPass(mlir::PassManager &pm,
options.dwarfVersion = config.DwarfVersion;
options.splitDwarfFile = config.SplitDwarfFile;
options.dwarfDebugFlags = config.DwarfDebugFlags;
- options.emitFakeUseForArguments =
+ options.emitFakeUseForDebugVars =
(config.OptLevel == llvm::OptimizationLevel::O0) &&
!disableArgumentFakeUse;
addPassConditionally(pm, disableDebugInfo,
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index e0b570a908521..e5c1fc8279630 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -291,6 +291,27 @@ bool AddDebugInfoPass::createCommonBlockGlobal(
return true;
}
+// Create fake uses for compiler-generated internal variables that represent
+// values needed by a debugger. This prevents values from being optimized out
+// such as the count and lower bound of dynamic arrays.
+template <typename Op>
+static void InsertFakeUseForDebugVar(mlir::OpBuilder &builder, Op declOp,
+ mlir::Value var) {
+ if (auto funcOp = declOp->template getParentOfType<mlir::func::FuncOp>()) {
+ if (declOp->getBlock() == &funcOp.getBody().front()) {
+ for (mlir::Block &block : funcOp.getBody()) {
+ if (auto returnOp =
+ mlir::dyn_cast<mlir::func::ReturnOp>(block.getTerminator())) {
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.setInsertionPoint(returnOp);
+ if (!fir::getIntIfConstant(var))
+ fir::FakeUseOp::create(builder, declOp.getLoc(), var);
+ }
+ }
+ }
+ }
+}
+
template <typename Op>
void AddDebugInfoPass::handleLocalVariable(Op declOp, llvm::StringRef name,
mlir::LLVM::DIFileAttr fileAttr,
@@ -307,22 +328,9 @@ void AddDebugInfoPass::handleLocalVariable(Op declOp, llvm::StringRef name,
if (dummyScope && declOp.getDummyScope() == dummyScope) {
if (auto argNoOpt = declOp.getDummyArgNo()) {
argNo = *argNoOpt;
- if (emitFakeUseForArguments) {
+ if (emitFakeUseForDebugVars) {
if constexpr (std::is_same_v<Op, fir::cg::XDeclareOp>) {
- if (auto funcOp =
- declOp->template getParentOfType<mlir::func::FuncOp>()) {
- if (declOp->getBlock() == &funcOp.getBody().front()) {
- for (mlir::Block &block : funcOp.getBody()) {
- if (auto returnOp = mlir::dyn_cast<mlir::func::ReturnOp>(
- block.getTerminator())) {
- mlir::OpBuilder::InsertionGuard guard(builder);
- builder.setInsertionPoint(returnOp);
- fir::FakeUseOp::create(builder, declOp.getLoc(),
- declOp.getMemref());
- }
- }
- }
- }
+ InsertFakeUseForDebugVar(builder, declOp, declOp.getMemref());
}
}
}
@@ -331,6 +339,31 @@ void AddDebugInfoPass::handleLocalVariable(Op declOp, llvm::StringRef name,
auto tyAttr =
typeGen.convertType(typeToConvert, fileAttr, scopeAttr, typeGenDeclOp);
+ if (emitFakeUseForDebugVars) {
+ // Create fake uses for internal variables that represent count and lower
+ // bound of dynamic arrays to ensure they are not optimized out.
+ if (auto arrayTy =
+ mlir::dyn_cast<mlir::LLVM::DICompositeTypeAttr>(tyAttr)) {
+ if (arrayTy.getTag() == llvm::dwarf::DW_TAG_array_type) {
+ if constexpr (std::is_same_v<Op, fir::cg::XDeclareOp>) {
+ // Count is represented as a value in the shape attribute
+ for (auto val : declOp.getShape())
+ InsertFakeUseForDebugVar(builder, declOp, val);
+ // Lower bound is represented as a value in the shift attribute
+ for (auto val : declOp.getShift())
+ InsertFakeUseForDebugVar(builder, declOp, val);
+ }
+ }
+ }
+
+ // Create fake uses for the length of character arrays to ensure they
+ // are not optimized out.
+ if constexpr (std::is_same_v<Op, fir::cg::XDeclareOp>) {
+ for (auto val : declOp.getTypeparams())
+ InsertFakeUseForDebugVar(builder, declOp, val);
+ }
+ }
+
auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
context, scopeAttr, mlir::StringAttr::get(context, name), fileAttr,
getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0, tyAttr,
diff --git a/flang/test/Transforms/debug-fake-use-multiple-dimensions.fir b/flang/test/Transforms/debug-fake-use-multiple-dimensions.fir
new file mode 100644
index 0000000000000..e97cf1df67c2f
--- /dev/null
+++ b/flang/test/Transforms/debug-fake-use-multiple-dimensions.fir
@@ -0,0 +1,165 @@
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=true" %s | FileCheck %s --check-prefix=FAKE-USE
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=false" %s | FileCheck %s --check-prefix=NO-FAKE-USE
+
+// Test that fir.fake_use ops are inserted for count and lower bound variables
+// in each dimension of a multi-dimensional dynamic array.
+
+// FAKE-USE-LABEL: func.func @test_2d_dynamic_array
+// FAKE-USE: fircg.ext_declare %arg0(%[[COUNT1:.*]], %[[COUNT2:.*]]) origin %[[LB1:.*]], %[[LB2:.*]] dummy_scope
+// FAKE-USE: fir.call @foo() : () -> ()
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: fir.fake_use %[[COUNT1]]
+// FAKE-USE: fir.fake_use %[[COUNT2]]
+// FAKE-USE: fir.fake_use %[[LB1]]
+// FAKE-USE: fir.fake_use %[[LB2]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_2d_dynamic_array
+// NO-FAKE-USE: fircg.ext_declare %arg0(%{{.*}}, %{{.*}}) origin %{{.*}}, %{{.*}} dummy_scope
+// NO-FAKE-USE: fir.call @foo() : () -> ()
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+// FAKE-USE-LABEL: func.func @test_3d_dynamic_array
+// FAKE-USE: fircg.ext_declare %arg0(%[[C1:.*]], %[[C2:.*]], %[[C3:.*]]) origin %[[L1:.*]], %[[L2:.*]], %[[L3:.*]] dummy_scope
+// FAKE-USE: fir.call @foo() : () -> ()
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: fir.fake_use %[[C1]]
+// FAKE-USE: fir.fake_use %[[C2]]
+// FAKE-USE: fir.fake_use %[[C3]]
+// FAKE-USE: fir.fake_use %[[L1]]
+// FAKE-USE: fir.fake_use %[[L2]]
+// FAKE-USE: fir.fake_use %[[L3]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_3d_dynamic_array
+// NO-FAKE-USE: fircg.ext_declare %arg0(%{{.*}}, %{{.*}}, %{{.*}}) origin %{{.*}}, %{{.*}}, %{{.*}} dummy_scope
+// NO-FAKE-USE: fir.call @foo() : () -> ()
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+// FAKE-USE-LABEL: func.func @test_2d_dynamic_array_multi_ret
+// FAKE-USE: fircg.ext_declare %arg0(%[[MR_COUNT1:.*]], %[[MR_COUNT2:.*]]) origin %[[MR_LB1:.*]], %[[MR_LB2:.*]] dummy_scope
+// FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// FAKE-USE: ^bb1:
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: fir.fake_use %[[MR_COUNT1]]
+// FAKE-USE: fir.fake_use %[[MR_COUNT2]]
+// FAKE-USE: fir.fake_use %[[MR_LB1]]
+// FAKE-USE: fir.fake_use %[[MR_LB2]]
+// FAKE-USE: return
+// FAKE-USE: ^bb2:
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: fir.fake_use %[[MR_COUNT1]]
+// FAKE-USE: fir.fake_use %[[MR_COUNT2]]
+// FAKE-USE: fir.fake_use %[[MR_LB1]]
+// FAKE-USE: fir.fake_use %[[MR_LB2]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_2d_dynamic_array_multi_ret
+// NO-FAKE-USE: fircg.ext_declare %arg0(%{{.*}}, %{{.*}}) origin %{{.*}}, %{{.*}} dummy_scope
+// NO-FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// NO-FAKE-USE: ^bb1:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+// NO-FAKE-USE: ^bb2:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+#loc1 = loc("debug-fake-use-multiple-dimensions.f90":1:1)
+#loc3 = loc("debug-fake-use-multiple-dimensions.f90":3:14)
+#loc4 = loc("debug-fake-use-multiple-dimensions.f90":4:14)
+#loc5 = loc("debug-fake-use-multiple-dimensions.f90":5:1)
+#loc6 = loc("debug-fake-use-multiple-dimensions.f90":6:1)
+#loc = loc("debug-fake-use-multiple-dimensions.f90":0:0)
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<i128 = dense<128> : vector<2xi64>, f80 = dense<128> : vector<2xi64>, i1 = dense<8> : vector<2xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i64 = dense<64> : vector<2xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, i32 = dense<32> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, i8 = dense<8> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, "dlti.stack_alignment" = 128 : i64, "dlti.mangling_mode" = "e", "dlti.endianness" = "little">, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", fir.target_cpu = "x86-64", 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", llvm.ident = "flang", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+ func.func private @foo()
+
+ // 2D dynamically-sized array with a single return.
+ func.func @test_2d_dynamic_array(%arg0: !fir.ref<!fir.array<?x?xi32>> {fir.bindc_name = "arr"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg1: !fir.ref<i32> {fir.bindc_name = "n1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg2: !fir.ref<i32> {fir.bindc_name = "lb1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg3: !fir.ref<i32> {fir.bindc_name = "n2"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg4: !fir.ref<i32> {fir.bindc_name = "lb2"} loc("debug-fake-use-multiple-dimensions.f90":1:1)) attributes {fir.internal_name = "_QPtest_2d_dynamic_array"} {
+ %c0 = arith.constant 0 : index
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_2d_dynamic_arrayEn1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %2 = fircg.ext_declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_2d_dynamic_arrayElb1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %3 = fircg.ext_declare %arg3 dummy_scope %0 arg 4 {uniq_name = "_QFtest_2d_dynamic_arrayEn2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %4 = fircg.ext_declare %arg4 dummy_scope %0 arg 5 {uniq_name = "_QFtest_2d_dynamic_arrayElb2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %5 = fir.load %1 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = arith.cmpi sgt, %6, %c0 : index
+ %8 = arith.select %7, %6, %c0 : index
+ %9 = fir.load %2 : !fir.ref<i32>
+ %10 = fir.convert %9 : (i32) -> index
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> index
+ %13 = arith.cmpi sgt, %12, %c0 : index
+ %14 = arith.select %13, %12, %c0 : index
+ %15 = fir.load %4 : !fir.ref<i32>
+ %16 = fir.convert %15 : (i32) -> index
+ %17 = fircg.ext_declare %arg0(%8, %14) origin %10, %16 dummy_scope %0 arg 1 {uniq_name = "_QFtest_2d_dynamic_arrayEarr"} : (!fir.ref<!fir.array<?x?xi32>>, index, index, index, index, !fir.dscope) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ return loc(#loc5)
+ } loc(#loc1)
+
+ // 3D dynamically-sized array with a single return.
+ func.func @test_3d_dynamic_array(%arg0: !fir.ref<!fir.array<?x?x?xi32>> {fir.bindc_name = "arr"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg1: !fir.ref<i32> {fir.bindc_name = "n1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg2: !fir.ref<i32> {fir.bindc_name = "lb1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg3: !fir.ref<i32> {fir.bindc_name = "n2"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg4: !fir.ref<i32> {fir.bindc_name = "lb2"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg5: !fir.ref<i32> {fir.bindc_name = "n3"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg6: !fir.ref<i32> {fir.bindc_name = "lb3"} loc("debug-fake-use-multiple-dimensions.f90":1:1)) attributes {fir.internal_name = "_QPtest_3d_dynamic_array"} {
+ %c0 = arith.constant 0 : index
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_3d_dynamic_arrayEn1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %2 = fircg.ext_declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_3d_dynamic_arrayElb1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %3 = fircg.ext_declare %arg3 dummy_scope %0 arg 4 {uniq_name = "_QFtest_3d_dynamic_arrayEn2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %4 = fircg.ext_declare %arg4 dummy_scope %0 arg 5 {uniq_name = "_QFtest_3d_dynamic_arrayElb2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %5 = fircg.ext_declare %arg5 dummy_scope %0 arg 6 {uniq_name = "_QFtest_3d_dynamic_arrayEn3"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %6 = fircg.ext_declare %arg6 dummy_scope %0 arg 7 {uniq_name = "_QFtest_3d_dynamic_arrayElb3"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %7 = fir.load %1 : !fir.ref<i32>
+ %8 = fir.convert %7 : (i32) -> index
+ %9 = arith.cmpi sgt, %8, %c0 : index
+ %10 = arith.select %9, %8, %c0 : index
+ %11 = fir.load %2 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> index
+ %13 = fir.load %3 : !fir.ref<i32>
+ %14 = fir.convert %13 : (i32) -> index
+ %15 = arith.cmpi sgt, %14, %c0 : index
+ %16 = arith.select %15, %14, %c0 : index
+ %17 = fir.load %4 : !fir.ref<i32>
+ %18 = fir.convert %17 : (i32) -> index
+ %19 = fir.load %5 : !fir.ref<i32>
+ %20 = fir.convert %19 : (i32) -> index
+ %21 = arith.cmpi sgt, %20, %c0 : index
+ %22 = arith.select %21, %20, %c0 : index
+ %23 = fir.load %6 : !fir.ref<i32>
+ %24 = fir.convert %23 : (i32) -> index
+ %25 = fircg.ext_declare %arg0(%10, %16, %22) origin %12, %18, %24 dummy_scope %0 arg 1 {uniq_name = "_QFtest_3d_dynamic_arrayEarr"} : (!fir.ref<!fir.array<?x?x?xi32>>, index, index, index, index, index, index, !fir.dscope) -> !fir.ref<!fir.array<?x?x?xi32>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ return loc(#loc5)
+ } loc(#loc1)
+
+ // 2D dynamically-sized array with multiple returns.
+ func.func @test_2d_dynamic_array_multi_ret(%arg0: !fir.ref<!fir.array<?x?xi32>> {fir.bindc_name = "arr"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg1: !fir.ref<i32> {fir.bindc_name = "n1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg2: !fir.ref<i32> {fir.bindc_name = "lb1"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg3: !fir.ref<i32> {fir.bindc_name = "n2"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg4: !fir.ref<i32> {fir.bindc_name = "lb2"} loc("debug-fake-use-multiple-dimensions.f90":1:1), %arg5: i1 loc("debug-fake-use-multiple-dimensions.f90":1:1)) attributes {fir.internal_name = "_QPtest_2d_dynamic_array_multi_ret"} {
+ %c0 = arith.constant 0 : index
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_2d_dynamic_array_multi_retEn1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %2 = fircg.ext_declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_2d_dynamic_array_multi_retElb1"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %3 = fircg.ext_declare %arg3 dummy_scope %0 arg 4 {uniq_name = "_QFtest_2d_dynamic_array_multi_retEn2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %4 = fircg.ext_declare %arg4 dummy_scope %0 arg 5 {uniq_name = "_QFtest_2d_dynamic_array_multi_retElb2"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %5 = fir.load %1 : !fir.ref<i32>
+ %6 = fir.convert %5 : (i32) -> index
+ %7 = arith.cmpi sgt, %6, %c0 : index
+ %8 = arith.select %7, %6, %c0 : index
+ %9 = fir.load %2 : !fir.ref<i32>
+ %10 = fir.convert %9 : (i32) -> index
+ %11 = fir.load %3 : !fir.ref<i32>
+ %12 = fir.convert %11 : (i32) -> index
+ %13 = arith.cmpi sgt, %12, %c0 : index
+ %14 = arith.select %13, %12, %c0 : index
+ %15 = fir.load %4 : !fir.ref<i32>
+ %16 = fir.convert %15 : (i32) -> index
+ %17 = fircg.ext_declare %arg0(%8, %14) origin %10, %16 dummy_scope %0 arg 1 {uniq_name = "_QFtest_2d_dynamic_array_multi_retEarr"} : (!fir.ref<!fir.array<?x?xi32>>, index, index, index, index, !fir.dscope) -> !fir.ref<!fir.array<?x?xi32>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ cf.cond_br %arg5, ^bb1, ^bb2
+ ^bb1:
+ return loc(#loc5)
+ ^bb2:
+ return loc(#loc6)
+ } loc(#loc1)
+} loc(#loc)
diff --git a/flang/test/Transforms/debug-fake-use-multiple-returns.fir b/flang/test/Transforms/debug-fake-use-multiple-returns.fir
new file mode 100644
index 0000000000000..fdd90dbcb809d
--- /dev/null
+++ b/flang/test/Transforms/debug-fake-use-multiple-returns.fir
@@ -0,0 +1,125 @@
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=true" %s | FileCheck %s --check-prefix=FAKE-USE
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=false" %s | FileCheck %s --check-prefix=NO-FAKE-USE
+
+// Test that fir.fake_use ops are inserted before every return in functions with
+// multiple return locations.
+
+// FAKE-USE-LABEL: func.func @test_dummy_arg_multi_ret
+// FAKE-USE: %[[UNDEF:.*]] = fir.undefined !fir.dscope
+// FAKE-USE: %[[DECL:.*]] = fircg.ext_declare %arg0 dummy_scope %[[UNDEF]] arg 1
+// FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// FAKE-USE: ^bb1:
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: return
+// FAKE-USE: ^bb2:
+// FAKE-USE: fir.fake_use %arg0
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_dummy_arg_multi_ret
+// NO-FAKE-USE: %[[UNDEF:.*]] = fir.undefined !fir.dscope
+// NO-FAKE-USE: %[[DECL:.*]] = fircg.ext_declare %arg0 dummy_scope %[[UNDEF]] arg 1
+// NO-FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// NO-FAKE-USE: ^bb1:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+// NO-FAKE-USE: ^bb2:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+// FAKE-USE-LABEL: func.func @test_dynamic_array_multi_ret
+// FAKE-USE: fircg.ext_declare %arg0(%[[COUNT:.*]]) origin %[[LB:.*]] dummy_scope
+// FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// FAKE-USE: ^bb1:
+// FAKE-USE: fir.fake_use %[[COUNT]]
+// FAKE-USE: fir.fake_use %[[LB]]
+// FAKE-USE: return
+// FAKE-USE: ^bb2:
+// FAKE-USE: fir.fake_use %[[COUNT]]
+// FAKE-USE: fir.fake_use %[[LB]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_dynamic_array_multi_ret
+// NO-FAKE-USE: fircg.ext_declare %arg0(%{{.*}}) origin %{{.*}} dummy_scope
+// NO-FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// NO-FAKE-USE: ^bb1:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+// NO-FAKE-USE: ^bb2:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+// FAKE-USE-LABEL: func.func @test_char_array_multi_ret
+// FAKE-USE: fircg.ext_declare %arg0 typeparams %[[LEN:.*]] dummy_scope
+// FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// FAKE-USE: ^bb1:
+// FAKE-USE: fir.fake_use %[[LEN]]
+// FAKE-USE: return
+// FAKE-USE: ^bb2:
+// FAKE-USE: fir.fake_use %[[LEN]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_char_array_multi_ret
+// NO-FAKE-USE: fircg.ext_declare %arg0 typeparams %{{.*}} dummy_scope
+// NO-FAKE-USE: cf.cond_br %{{.*}}, ^bb1, ^bb2
+// NO-FAKE-USE: ^bb1:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+// NO-FAKE-USE: ^bb2:
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+#loc1 = loc("debug-fake-use-multiple-returns.f90":1:1)
+#loc3 = loc("debug-fake-use-multiple-returns.f90":3:14)
+#loc4 = loc("debug-fake-use-multiple-returns.f90":4:14)
+#loc5 = loc("debug-fake-use-multiple-returns.f90":5:1)
+#loc6 = loc("debug-fake-use-multiple-returns.f90":6:1)
+#loc = loc("debug-fake-use-multiple-returns.f90":0:0)
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<i128 = dense<128> : vector<2xi64>, f80 = dense<128> : vector<2xi64>, i1 = dense<8> : vector<2xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i64 = dense<64> : vector<2xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, i32 = dense<32> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, i8 = dense<8> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, "dlti.stack_alignment" = 128 : i64, "dlti.mangling_mode" = "e", "dlti.endianness" = "little">, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", fir.target_cpu = "x86-64", 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", llvm.ident = "flang", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+ func.func private @foo()
+
+ // Function with a dummy argument and multiple returns.
+ func.func @test_dummy_arg_multi_ret(%arg0: !fir.ref<i32> {fir.bindc_name = "expected"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg1: i1 loc("debug-fake-use-multiple-returns.f90":1:1)) attributes {fir.internal_name = "_QPtest_dummy_arg_multi_ret"} {
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg0 dummy_scope %0 arg 1 {uniq_name = "_QFtest_dummy_arg_multi_retEexpected"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ fir.call @foo() : () -> ()
+ cf.cond_br %arg1, ^bb1, ^bb2
+ ^bb1:
+ return loc(#loc5)
+ ^bb2:
+ return loc(#loc6)
+ } loc(#loc1)
+
+ // Function with a dynamically-sized array and multiple returns.
+ func.func @test_dynamic_array_multi_ret(%arg0: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "arr"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg1: !fir.ref<i32> {fir.bindc_name = "n"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg2: !fir.ref<i32> {fir.bindc_name = "lb"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg3: i1 loc("debug-fake-use-multiple-returns.f90":1:1)) attributes {fir.internal_name = "_QPtest_dynamic_array_multi_ret"} {
+ %c0 = arith.constant 0 : index
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_dynamic_array_multi_retEn"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %2 = fircg.ext_declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_dynamic_array_multi_retElb"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %3 = fir.load %1 : !fir.ref<i32>
+ %4 = fir.convert %3 : (i32) -> index
+ %5 = arith.cmpi sgt, %4, %c0 : index
+ %6 = arith.select %5, %4, %c0 : index
+ %7 = fir.load %2 : !fir.ref<i32>
+ %8 = fir.convert %7 : (i32) -> index
+ %9 = fircg.ext_declare %arg0(%6) origin %8 dummy_scope %0 arg 1 {uniq_name = "_QFtest_dynamic_array_multi_retEarr"} : (!fir.ref<!fir.array<?xi32>>, index, index, !fir.dscope) -> !fir.ref<!fir.array<?xi32>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ cf.cond_br %arg3, ^bb1, ^bb2
+ ^bb1:
+ return loc(#loc5)
+ ^bb2:
+ return loc(#loc6)
+ } loc(#loc1)
+
+ // Function with a dynamically-sized character array and multiple returns.
+ func.func @test_char_array_multi_ret(%arg0: !fir.ref<!fir.char<1,?>> {fir.bindc_name = "str"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg1: index {fir.bindc_name = "n"} loc("debug-fake-use-multiple-returns.f90":1:1), %arg2: i1 loc("debug-fake-use-multiple-returns.f90":1:1)) attributes {fir.internal_name = "_QPtest_char_array_multi_ret"} {
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg0 typeparams %arg1 dummy_scope %0 arg 1 {uniq_name = "_QFtest_char_array_multi_retEstr"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> !fir.ref<!fir.char<1,?>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ cf.cond_br %arg2, ^bb1, ^bb2
+ ^bb1:
+ return loc(#loc5)
+ ^bb2:
+ return loc(#loc6)
+ } loc(#loc1)
+} loc(#loc)
diff --git a/flang/test/Transforms/debug-fake-use.fir b/flang/test/Transforms/debug-fake-use.fir
index d86cc9b3afee4..770286197ed4b 100644
--- a/flang/test/Transforms/debug-fake-use.fir
+++ b/flang/test/Transforms/debug-fake-use.fir
@@ -1,5 +1,5 @@
-// RUN: fir-opt --add-debug-info="emit-fake-use-for-arguments=true" %s | FileCheck %s --check-prefix=FAKE-USE
-// RUN: fir-opt --add-debug-info="emit-fake-use-for-arguments=false" %s | FileCheck %s --check-prefix=NO-FAKE-USE
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=true" %s | FileCheck %s --check-prefix=FAKE-USE
+// RUN: fir-opt --add-debug-info="emit-fake-use-for-debug-vars=false" %s | FileCheck %s --check-prefix=NO-FAKE-USE
// FAKE-USE-LABEL: func.func @test_
// FAKE-USE: %[[UNDEF:.*]] = fir.undefined !fir.dscope
@@ -31,6 +31,31 @@
// NO-FAKE-USE-NOT: fir.fake_use
// NO-FAKE-USE: return
+// FAKE-USE-LABEL: func.func @test_dynamic_array
+// FAKE-USE: fircg.ext_declare %arg0(%[[COUNT:.*]]) origin %[[LB:.*]] dummy_scope
+// FAKE-USE: fir.call @foo() : () -> ()
+// FAKE-USE: fir.fake_use %[[COUNT]]
+// FAKE-USE: fir.fake_use %[[LB]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_dynamic_array
+// NO-FAKE-USE: fircg.ext_declare %arg0(%{{.*}}) origin %{{.*}} dummy_scope
+// NO-FAKE-USE: fir.call @foo() : () -> ()
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
+// FAKE-USE-LABEL: func.func @test_char_array
+// FAKE-USE: fircg.ext_declare %arg0 typeparams %[[LEN:.*]] dummy_scope
+// FAKE-USE: fir.call @foo() : () -> ()
+// FAKE-USE: fir.fake_use %[[LEN]]
+// FAKE-USE: return
+
+// NO-FAKE-USE-LABEL: func.func @test_char_array
+// NO-FAKE-USE: fircg.ext_declare %arg0 typeparams %{{.*}} dummy_scope
+// NO-FAKE-USE: fir.call @foo() : () -> ()
+// NO-FAKE-USE-NOT: fir.fake_use
+// NO-FAKE-USE: return
+
#loc1 = loc("debug-fake-use.f90":1:1)
#loc3 = loc("debug-fake-use.f90":3:14)
#loc4 = loc("debug-fake-use.f90":4:14)
@@ -53,4 +78,27 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i128 = dense<128> : vector<2xi64
fir.call @foo() : () -> ()
return loc(#loc5)
} loc(#loc1)
+
+ func.func @test_dynamic_array(%arg0: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "arr"} loc("debug-fake-use.f90":1:1), %arg1: !fir.ref<i32> {fir.bindc_name = "n"} loc("debug-fake-use.f90":1:1), %arg2: !fir.ref<i32> {fir.bindc_name = "lb"} loc("debug-fake-use.f90":1:1)) attributes {fir.internal_name = "_QPtest_dynamic_array"} {
+ %c0 = arith.constant 0 : index
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {uniq_name = "_QFtest_dynamic_arrayEn"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc3)
+ %2 = fircg.ext_declare %arg2 dummy_scope %0 arg 3 {uniq_name = "_QFtest_dynamic_arrayElb"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc4)
+ %3 = fir.load %1 : !fir.ref<i32>
+ %4 = fir.convert %3 : (i32) -> index
+ %5 = arith.cmpi sgt, %4, %c0 : index
+ %6 = arith.select %5, %4, %c0 : index
+ %7 = fir.load %2 : !fir.ref<i32>
+ %8 = fir.convert %7 : (i32) -> index
+ %9 = fircg.ext_declare %arg0(%6) origin %8 dummy_scope %0 arg 1 {uniq_name = "_QFtest_dynamic_arrayEarr"} : (!fir.ref<!fir.array<?xi32>>, index, index, !fir.dscope) -> !fir.ref<!fir.array<?xi32>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ return loc(#loc5)
+ } loc(#loc1)
+
+ func.func @test_char_array(%arg0: !fir.ref<!fir.char<1,?>> {fir.bindc_name = "str"} loc("debug-fake-use.f90":1:1), %arg1: index {fir.bindc_name = "n"} loc("debug-fake-use.f90":1:1)) attributes {fir.internal_name = "_QPtest_char_array"} {
+ %0 = fir.undefined !fir.dscope loc(#loc1)
+ %1 = fircg.ext_declare %arg0 typeparams %arg1 dummy_scope %0 arg 1 {uniq_name = "_QFtest_char_arrayEstr"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> !fir.ref<!fir.char<1,?>> loc(#loc3)
+ fir.call @foo() : () -> ()
+ return loc(#loc5)
+ } loc(#loc1)
} loc(#loc)
More information about the flang-commits
mailing list