[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