[flang-commits] [flang] [CUF] Fix CompilerGeneratedNamesConversion renaming managed companion globals (PR #198161)
Kareem Ergawy via flang-commits
flang-commits at lists.llvm.org
Sun May 17 02:39:12 PDT 2026
https://github.com/ergawy created https://github.com/llvm/llvm-project/pull/198161
CUFAddConstructor creates a companion pointer global (e.g. foo.managed.ptr) for each non-allocatable managed variable. When CompilerGeneratedNamesConversion ran after CUFAddConstructor, it replaced the dots with 'X', so CUFOpConversionLate could no longer find the companion by name and fell back to CUFGetDeviceAddress with the wrong host pointer, causing cudaErrorInvalidSymbol.
Fix: mark the companion global with a cuf.managed_ptr unit attribute in CUFAddConstructor and skip it in CompilerGeneratedNamesConversionPass.
Co-authored-by: Claude Sonnet 4.6 <noreply at anthropic.com>
>From d926f39d949937c6172cef7098f41fa4dc3fdef7 Mon Sep 17 00:00:00 2001
From: ergawy <kareem.ergawy at gmail.com>
Date: Fri, 15 May 2026 21:38:56 -0700
Subject: [PATCH] [CUF] Fix CompilerGeneratedNamesConversion renaming managed
companion globals
CUFAddConstructor creates a companion pointer global (e.g. foo.managed.ptr)
for each non-allocatable managed variable. When CompilerGeneratedNamesConversion
ran after CUFAddConstructor, it replaced the dots with 'X',
so CUFOpConversionLate could no longer find the companion by name and fell back
to CUFGetDeviceAddress with the wrong host pointer, causing cudaErrorInvalidSymbol.
Fix: mark the companion global with a cuf.managed_ptr unit attribute in
CUFAddConstructor and skip it in CompilerGeneratedNamesConversionPass.
Co-authored-by: Claude Sonnet 4.6 <noreply at anthropic.com>
---
.../Dialect/CUF/Attributes/CUFAttr.h | 7 +++
.../Transforms/CUDA/CUFAddConstructor.cpp | 4 ++
.../Transforms/CompilerGeneratedNames.cpp | 4 +-
flang/test/Fir/CUDA/cuda-constructor-2.f90 | 4 +-
.../Fir/CUDA/cuda-managed-ptr-companion.mlir | 51 +++++++++++++++++++
5 files changed, 67 insertions(+), 3 deletions(-)
create mode 100644 flang/test/Fir/CUDA/cuda-managed-ptr-companion.mlir
diff --git a/flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h b/flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h
index 88a47749b8808..310930d011d9c 100644
--- a/flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h
+++ b/flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h
@@ -36,6 +36,13 @@ static constexpr llvm::StringRef dataAttrName = "data_attr";
static constexpr llvm::StringRef getDataAttrName() { return "cuf.data_attr"; }
static constexpr llvm::StringRef getProcAttrName() { return "cuf.proc_attr"; }
+/// Attribute to mark a global as a managed-memory companion pointer.
+/// Prevents CompilerGeneratedNamesConversionPass from renaming it, which
+/// would break the name lookup in CUFOpConversionLate.
+static constexpr llvm::StringRef getManagedPtrAttrName() {
+ return "cuf.managed_ptr";
+}
+
/// Attribute to carry CUDA launch_bounds values.
static constexpr llvm::StringRef getLaunchBoundsAttrName() {
return "cuf.launch_bounds";
diff --git a/flang/lib/Optimizer/Transforms/CUDA/CUFAddConstructor.cpp b/flang/lib/Optimizer/Transforms/CUDA/CUFAddConstructor.cpp
index 466d65d16aadf..892e0ccd35331 100644
--- a/flang/lib/Optimizer/Transforms/CUDA/CUFAddConstructor.cpp
+++ b/flang/lib/Optimizer/Transforms/CUDA/CUFAddConstructor.cpp
@@ -13,6 +13,7 @@
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/CodeGen/Target.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
+#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
#include "flang/Optimizer/Dialect/CUF/CUFOps.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
@@ -68,6 +69,9 @@ static fir::GlobalOp createManagedPointerGlobal(fir::FirOpBuilder &builder,
/*isTarget=*/false, ptrTy, initAttr,
/*linkName=*/builder.createInternalLinkage(), attrs);
+ ptrGlobal->setAttr(cuf::getManagedPtrAttrName(),
+ mlir::UnitAttr::get(ctx));
+
mlir::Region ®ion = ptrGlobal.getRegion();
mlir::Block *block = builder.createBlock(®ion);
builder.setInsertionPointToStart(block);
diff --git a/flang/lib/Optimizer/Transforms/CompilerGeneratedNames.cpp b/flang/lib/Optimizer/Transforms/CompilerGeneratedNames.cpp
index f92c60908b149..9e21e72e91279 100644
--- a/flang/lib/Optimizer/Transforms/CompilerGeneratedNames.cpp
+++ b/flang/lib/Optimizer/Transforms/CompilerGeneratedNames.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
@@ -49,7 +50,8 @@ void CompilerGeneratedNamesConversionPass::runOnOperation() {
mlir::SymbolTable::getSymbolAttrName());
auto deconstructedName = fir::NameUniquer::deconstruct(symName);
if (deconstructedName.first != fir::NameUniquer::NameKind::NOT_UNIQUED &&
- !fir::NameUniquer::isExternalFacingUniquedName(deconstructedName)) {
+ !fir::NameUniquer::isExternalFacingUniquedName(deconstructedName) &&
+ !op.hasAttr(cuf::getManagedPtrAttrName())) {
std::string newName =
fir::NameUniquer::replaceSpecialSymbols(symName.getValue().str());
if (newName != symName) {
diff --git a/flang/test/Fir/CUDA/cuda-constructor-2.f90 b/flang/test/Fir/CUDA/cuda-constructor-2.f90
index bb2a98c294558..734b9dc78d118 100644
--- a/flang/test/Fir/CUDA/cuda-constructor-2.f90
+++ b/flang/test/Fir/CUDA/cuda-constructor-2.f90
@@ -139,8 +139,8 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<
}
}
-// Pointer global should be created with section attribute.
-// CHECK: fir.global internal @_QMtestEmanx.managed.ptr {section = "__nv_managed_data__"} : !fir.llvm_ptr<i8>
+// Pointer global should be created with section and cuf.managed_ptr attributes.
+// CHECK: fir.global internal @_QMtestEmanx.managed.ptr {cuf.managed_ptr, section = "__nv_managed_data__"} : !fir.llvm_ptr<i8>
// CHECK: fir.zero_bits !fir.llvm_ptr<i8>
// Constructor should register with CUFRegisterManagedVariable then init module.
diff --git a/flang/test/Fir/CUDA/cuda-managed-ptr-companion.mlir b/flang/test/Fir/CUDA/cuda-managed-ptr-companion.mlir
new file mode 100644
index 0000000000000..10c7d70a423a5
--- /dev/null
+++ b/flang/test/Fir/CUDA/cuda-managed-ptr-companion.mlir
@@ -0,0 +1,51 @@
+// RUN: fir-opt --split-input-file --cuf-add-constructor %s | FileCheck %s --check-prefix=CONSTRUCTOR
+// RUN: fir-opt --split-input-file --compiler-generated-names %s | FileCheck %s --check-prefix=NAMES
+
+// Test 1 (CONSTRUCTOR): CUFAddConstructor attaches the cuf.managed_ptr unit
+// attribute to the companion pointer global it creates for non-allocatable
+// managed variables. This attribute is required so that downstream passes
+// (CompilerGeneratedNamesConversionPass) can identify and exempt the global.
+
+// Test 2 (NAMES): CompilerGeneratedNamesConversionPass does NOT rename a
+// global that carries the cuf.managed_ptr attribute, leaving the dotted
+// companion name intact so that CUFOpConversionLate can look it up.
+
+// -----
+
+// CONSTRUCTOR-LABEL: fir.global internal @_QMtestEmanx.managed.ptr
+// CONSTRUCTOR-SAME: cuf.managed_ptr
+// CONSTRUCTOR-SAME: section = "__nv_managed_data__"
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f32, dense<32> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, 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.target_triple = "x86_64-unknown-linux-gnu"} {
+
+ fir.global @_QMtestEmanx {data_attr = #cuf.cuda<managed>} : !fir.array<100xi32> {
+ %0 = fir.zero_bits !fir.array<100xi32>
+ fir.has_value %0 : !fir.array<100xi32>
+ }
+
+ gpu.module @cuda_device_mod {
+ gpu.func @_QMtestPkernel() kernel {
+ gpu.return
+ }
+ fir.global @_QMtestEmanx {data_attr = #cuf.cuda<managed>} : !fir.array<100xi32> {
+ %0 = fir.zero_bits !fir.array<100xi32>
+ fir.has_value %0 : !fir.array<100xi32>
+ }
+ }
+}
+
+// -----
+
+// A companion pointer global bearing cuf.managed_ptr must not have its name
+// mangled by CompilerGeneratedNamesConversionPass. Without the exemption the
+// dots would be replaced with 'X', breaking the lookup in CUFOpConversionLate.
+
+// NAMES: fir.global internal @_QMtestEmanx.managed.ptr
+// NAMES-NOT: @_QMtestEmanxXmanagedXptr
+
+module {
+ fir.global internal @_QMtestEmanx.managed.ptr {cuf.managed_ptr, section = "__nv_managed_data__"} : !fir.llvm_ptr<i8> {
+ %0 = fir.zero_bits !fir.llvm_ptr<i8>
+ fir.has_value %0 : !fir.llvm_ptr<i8>
+ }
+}
More information about the flang-commits
mailing list