[flang-commits] [flang] [flang][cuda] Exclude device variables from host debug info (PR #222241)

via flang-commits flang-commits at lists.llvm.org
Tue Sep 8 22:46:18 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-codegen

Author: jiel-nv

<details>
<summary>Changes</summary>

Filter out variables whose storage is not addressable by the host when generating debug info for a host procedure.

---
Full diff: https://github.com/llvm/llvm-project/pull/222241.diff


6 Files Affected:

- (modified) flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.h (+1) 
- (modified) flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td (+2) 
- (modified) flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp (+2-2) 
- (modified) flang/lib/Optimizer/Dialect/FIRCG/CMakeLists.txt (+1) 
- (modified) flang/lib/Optimizer/Transforms/AddDebugInfo.cpp (+35) 
- (added) flang/test/Transforms/debug-cuf-device-variable.fir (+63) 


``````````diff
diff --git a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.h b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.h
index e2795d8a136b8..67c14e944ec56 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.h
@@ -13,6 +13,7 @@
 #ifndef OPTIMIZER_DIALECT_FIRCG_CGOPS_H
 #define OPTIMIZER_DIALECT_FIRCG_CGOPS_H
 
+#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "mlir/Dialect/Func/IR/FuncOps.h"
 
diff --git a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td
index f3c72eaf44958..5a7c85e7883fa 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRCG/CGOps.td
@@ -15,6 +15,7 @@
 #define FORTRAN_DIALECT_FIRCG_OPS
 
 include "mlir/IR/SymbolInterfaces.td"
+include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.td"
 include "flang/Optimizer/Dialect/FIRTypes.td"
 include "flang/Optimizer/Dialect/FIRAttr.td"
 include "mlir/IR/BuiltinAttributes.td"
@@ -236,6 +237,7 @@ def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> {
       Optional<AnyReferenceLike>:$storage,
       DefaultValuedAttr<UI64Attr, "0">:$storage_offset,
       Builtin_StringAttr:$uniq_name,
+      OptionalAttr<cuf_DataAttributeAttr>:$data_attr,
       OptionalAttr<UI32Attr>:$dummy_arg_no);
   let results = (outs AnyRefOrBox);
 
diff --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
index ee3b8362b5ef6..f4ae6841afc12 100644
--- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
@@ -388,12 +388,12 @@ class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
     mlir::IntegerAttr dummyArgNoAttr;
     if (auto attr = declareOp->getAttrOfType<mlir::IntegerAttr>("dummy_arg_no"))
       dummyArgNoAttr = attr;
-    // FIXME: Add FortranAttrs and CudaAttrs
+    // FIXME: Add FortranAttrs
     auto xDeclOp = fir::cg::XDeclareOp::create(
         rewriter, loc, declareOp.getType(), declareOp.getMemref(), shapeOpers,
         shiftOpers, declareOp.getTypeparams(), declareOp.getDummyScope(),
         declareOp.getStorage(), declareOp.getStorageOffset(),
-        declareOp.getUniqName(), dummyArgNoAttr);
+        declareOp.getUniqName(), declareOp.getDataAttrAttr(), dummyArgNoAttr);
     LLVM_DEBUG(llvm::dbgs()
                << "rewriting " << declareOp << " to " << xDeclOp << '\n');
     rewriter.replaceOp(declareOp, xDeclOp.getOperation()->getResults());
diff --git a/flang/lib/Optimizer/Dialect/FIRCG/CMakeLists.txt b/flang/lib/Optimizer/Dialect/FIRCG/CMakeLists.txt
index cd5865fc8766a..24b62f3b23b36 100644
--- a/flang/lib/Optimizer/Dialect/FIRCG/CMakeLists.txt
+++ b/flang/lib/Optimizer/Dialect/FIRCG/CMakeLists.txt
@@ -3,6 +3,7 @@ add_flang_library(FIRCodeGenDialect
 
   DEPENDS
   CGOpsIncGen
+  CUFAttrsIncGen
 
   LINK_LIBS
   FIRDialect
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index c911827b72a7c..d5313d9cbb6dc 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
 #include "flang/Optimizer/Dialect/FIRCG/CGOps.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FIROps.h"
@@ -199,6 +200,35 @@ static bool isModuleLevelName(const fir::NameUniquer::DeconstructedName &name) {
   return name.procs.empty() && !name.modules.empty();
 }
 
+// Check if the storage of a variable with the given CUDA Fortran data
+// attribute can be addressed by the host.
+static bool isHostAddressable(cuf::DataAttributeAttr dataAttr) {
+  if (!dataAttr)
+    return true;
+  switch (dataAttr.getValue()) {
+  case cuf::DataAttribute::Constant:
+  case cuf::DataAttribute::Device:
+  case cuf::DataAttribute::Shared:
+    return false;
+  case cuf::DataAttribute::Managed:
+  case cuf::DataAttribute::Pinned:
+  case cuf::DataAttribute::Unified:
+    return true;
+  }
+  llvm_unreachable("unknown CUDA Fortran data attribute");
+}
+
+// Check if the operation belongs to a procedure that is compiled for the
+// device, whose debug info is generated separately.
+static bool isInDeviceProcedure(mlir::Operation *op) {
+  auto funcOp = op->getParentOfType<mlir::func::FuncOp>();
+  if (!funcOp)
+    return false;
+  auto procAttr =
+      funcOp->getAttrOfType<cuf::ProcAttributeAttr>(cuf::getProcAttrName());
+  return procAttr && procAttr.getValue() != cuf::ProcAttribute::Host;
+}
+
 // Check if a global represents a data object declared in a module.
 static bool isModuleDataObject(fir::GlobalOp globalOp) {
   std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName());
@@ -337,6 +367,11 @@ void AddDebugInfoPass::handleLocalVariable(Op declOp, llvm::StringRef name,
                                            mlir::Value dummyScope,
                                            mlir::Type typeToConvert,
                                            fir::cg::XDeclareOp typeGenDeclOp) {
+  // Exclude variables that the host cannot address.
+  if (!isInDeviceProcedure(declOp) &&
+      !isHostAddressable(declOp.getDataAttrAttr()))
+    return;
+
   mlir::MLIRContext *context = &getContext();
   mlir::OpBuilder builder(context);
 
diff --git a/flang/test/Transforms/debug-cuf-device-variable.fir b/flang/test/Transforms/debug-cuf-device-variable.fir
new file mode 100644
index 0000000000000..52b365533187b
--- /dev/null
+++ b/flang/test/Transforms/debug-cuf-device-variable.fir
@@ -0,0 +1,63 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo --mlir-print-local-scope %s | FileCheck %s
+
+module {
+  func.func @_QPhost(%arg0: !fir.ref<i32> {fir.bindc_name = "a"}, %arg1: !fir.ref<i32> {fir.bindc_name = "a_d", cuf.data_attr = #cuf.cuda<device>}) {
+    %0 = fir.undefined !fir.dscope
+    %1 = fircg.ext_declare %arg0 dummy_scope %0 arg 1 {uniq_name = "_QFhostEa"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc1)
+    %2 = fircg.ext_declare %arg1 dummy_scope %0 arg 2 {data_attr = #cuf.cuda<device>, uniq_name = "_QFhostEa_d"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc2)
+    return
+  } loc(#loc3)
+
+  func.func @_QPhostlocals() {
+    %0 = fir.alloca i32 {uniq_name = "_QFhostlocalsEd"}
+    %1 = fircg.ext_declare %0 {data_attr = #cuf.cuda<device>, uniq_name = "_QFhostlocalsEd"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc4)
+    %2 = fir.alloca i32 {uniq_name = "_QFhostlocalsEc"}
+    %3 = fircg.ext_declare %2 {data_attr = #cuf.cuda<constant>, uniq_name = "_QFhostlocalsEc"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc5)
+    %4 = fir.alloca i32 {uniq_name = "_QFhostlocalsEm"}
+    %5 = fircg.ext_declare %4 {data_attr = #cuf.cuda<managed>, uniq_name = "_QFhostlocalsEm"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc6)
+    %6 = fir.alloca i32 {uniq_name = "_QFhostlocalsEp"}
+    %7 = fircg.ext_declare %6 {data_attr = #cuf.cuda<pinned>, uniq_name = "_QFhostlocalsEp"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc7)
+    %8 = fir.alloca i32 {uniq_name = "_QFhostlocalsEu"}
+    %9 = fircg.ext_declare %8 {data_attr = #cuf.cuda<unified>, uniq_name = "_QFhostlocalsEu"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc8)
+    return
+  } loc(#loc9)
+
+  func.func @_QPkernel(%arg0: !fir.ref<i32> {fir.bindc_name = "k_d", cuf.data_attr = #cuf.cuda<device>}) attributes {cuf.proc_attr = #cuf.cuda_proc<global>} {
+    %0 = fir.undefined !fir.dscope
+    %1 = fircg.ext_declare %arg0 dummy_scope %0 arg 1 {data_attr = #cuf.cuda<device>, uniq_name = "_QFkernelEk_d"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#loc10)
+    %2 = fir.alloca i32 {uniq_name = "_QFkernelEs"}
+    %3 = fircg.ext_declare %2 {data_attr = #cuf.cuda<shared>, uniq_name = "_QFkernelEs"} : (!fir.ref<i32>) -> !fir.ref<i32> loc(#loc11)
+    return
+  } loc(#loc12)
+}
+
+#loc1 = loc("test.cuf":3:1)
+#loc2 = loc("test.cuf":4:1)
+#loc3 = loc("test.cuf":2:1)
+#loc4 = loc("test.cuf":9:1)
+#loc5 = loc("test.cuf":10:1)
+#loc6 = loc("test.cuf":11:1)
+#loc7 = loc("test.cuf":12:1)
+#loc8 = loc("test.cuf":13:1)
+#loc9 = loc("test.cuf":8:1)
+#loc10 = loc("test.cuf":18:1)
+#loc11 = loc("test.cuf":19:1)
+#loc12 = loc("test.cuf":17:1)
+
+// A variable that gets debug info ends up with a fused loc carrying
+// #llvm.di_local_variable, while a filtered one keeps its plain source loc.
+
+// CHECK-LABEL: func.func @_QPhost
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostEa"{{.*}}loc(fused<#llvm.di_local_variable<
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostEa_d"{{.*}}loc("test.cuf":4:1)
+
+// CHECK-LABEL: func.func @_QPhostlocals
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostlocalsEd"{{.*}}loc("test.cuf":9:1)
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostlocalsEc"{{.*}}loc("test.cuf":10:1)
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostlocalsEm"{{.*}}loc(fused<#llvm.di_local_variable<
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostlocalsEp"{{.*}}loc(fused<#llvm.di_local_variable<
+// CHECK: ext_declare{{.*}}uniq_name = "_QFhostlocalsEu"{{.*}}loc(fused<#llvm.di_local_variable<
+
+// CHECK-LABEL: func.func @_QPkernel
+// CHECK: ext_declare{{.*}}uniq_name = "_QFkernelEk_d"{{.*}}loc(fused<#llvm.di_local_variable<
+// CHECK: ext_declare{{.*}}uniq_name = "_QFkernelEs"{{.*}}loc(fused<#llvm.di_local_variable<

``````````

</details>


https://github.com/llvm/llvm-project/pull/222241


More information about the flang-commits mailing list