[flang-commits] [flang] [flang] Avoid invalid declare_value for promoted dummy-scope variables (PR #202498)

Zhen Wang via flang-commits flang-commits at lists.llvm.org
Mon Jun 8 20:47:37 PDT 2026


https://github.com/wangzpgi created https://github.com/llvm/llvm-project/pull/202498

This fixes a verifier failure in mem2reg after inlining a CUDA device procedure. When a promoted FIR alloca had an associated fir.declare with a dummy_scope, mem2reg could create a fir.declare_value at a loop header where the original dummy scope did not dominate.

Skip creating block-argument fir.declare_value ops for such declarations, matching the existing replaced-value handling. Add a FIR mem2reg regression test for the loop-header block argument case.

>From b4721c64a7fb673d7b7e219b1633478cb8654a1e Mon Sep 17 00:00:00 2001
From: Zhen Wang <zhenw at nvidia.com>
Date: Mon, 8 Jun 2026 20:45:03 -0700
Subject: [PATCH] Avoid invalid declare_value for promoted dummy-scope
 variables

---
 flang/lib/Optimizer/Dialect/FIROps.cpp |  6 +++++-
 flang/test/Fir/mem2reg.mlir            | 27 ++++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index c3c6397c16fca..fc44f20b5a675 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -271,11 +271,15 @@ void fir::AllocaOp::handleBlockArgument(const mlir::MemorySlot &slot,
   // no-ops like fir.declare (i.e., to replace the FIR specific
   // isSlotOrDeclaredSlot).
   for (mlir::Operation *user : getOperation()->getUsers())
-    if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(user))
+    if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(user)) {
+      // Inlined dummy scopes may not dominate block-argument debug values.
+      if (declareOp.getDummyScope())
+        continue;
       fir::DeclareValueOp::create(
           builder, declareOp.getLoc(), argument, declareOp.getDummyScope(),
           declareOp.getUniqNameAttr(), declareOp.getFortranAttrsAttr(),
           declareOp.getDataAttrAttr(), declareOp.getDummyArgNoAttr());
+    }
 }
 
 std::optional<mlir::PromotableAllocationOpInterface>
diff --git a/flang/test/Fir/mem2reg.mlir b/flang/test/Fir/mem2reg.mlir
index 41f894a2f9473..154580c626e7c 100644
--- a/flang/test/Fir/mem2reg.mlir
+++ b/flang/test/Fir/mem2reg.mlir
@@ -233,3 +233,30 @@ func.func @dummy_scope(%arg : i32) {
   fir.call @use(%result) : (i32) -> ()
   return
 }
+
+// -----
+
+// Do not create block-argument fir.declare_value ops with non-dominating
+// dummy scopes.
+
+// CHECK-LABEL: func.func @dummy_scope_block_argument(
+// CHECK: ^bb1(%{{.*}}: i32):
+// CHECK-NOT: fir.declare_value
+func.func @dummy_scope_block_argument(%arg : i32, %cond : i1) {
+  %c1 = arith.constant 1 : i32
+  %alloca = fir.alloca i32 {adapt.valuebyref}
+  fir.store %arg to %alloca : !fir.ref<i32>
+  cf.br ^loop
+^loop:
+  %result = fir.load %alloca : !fir.ref<i32>
+  cf.cond_br %cond, ^body, ^exit
+^body:
+  %scope = fir.dummy_scope : !fir.dscope
+  %declare = fir.declare %alloca dummy_scope %scope arg 1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "foo"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32>
+  %next = arith.addi %result, %c1 : i32
+  fir.store %next to %alloca : !fir.ref<i32>
+  cf.br ^loop
+^exit:
+  fir.call @use(%result) : (i32) -> ()
+  return
+}



More information about the flang-commits mailing list