[flang-commits] [flang] [CUF] Fix CompilerGeneratedNamesConversion renaming managed companion globals (PR #198161)

via flang-commits flang-commits at lists.llvm.org
Sun May 17 02:39:44 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Kareem Ergawy (ergawy)

<details>
<summary>Changes</summary>

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@<!-- -->anthropic.com>

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


5 Files Affected:

- (modified) flang/include/flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h (+7) 
- (modified) flang/lib/Optimizer/Transforms/CUDA/CUFAddConstructor.cpp (+4) 
- (modified) flang/lib/Optimizer/Transforms/CompilerGeneratedNames.cpp (+3-1) 
- (modified) flang/test/Fir/CUDA/cuda-constructor-2.f90 (+2-2) 
- (added) flang/test/Fir/CUDA/cuda-managed-ptr-companion.mlir (+51) 


``````````diff
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 &region = ptrGlobal.getRegion();
   mlir::Block *block = builder.createBlock(&region);
   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>
+  }
+}

``````````

</details>


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


More information about the flang-commits mailing list