[flang-commits] [flang] [flang][cuda] Avoid false positive on multi device symbol with components (PR #192513)

Valentin Clement バレンタイン クレメン via flang-commits flang-commits at lists.llvm.org
Thu Apr 16 11:50:07 PDT 2026


https://github.com/clementval created https://github.com/llvm/llvm-project/pull/192513

Semantic was wrongly flagging derived-type components as two device resident object. Update how we collect symbols and count the number of device resident object.

>From 86cdb692a8ba59698918602ea50a406295d7ae94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?=
 =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?=
 =?UTF-8?q?=E3=83=B3=29?= <clementval at gmail.com>
Date: Wed, 15 Apr 2026 15:24:35 -0700
Subject: [PATCH] [flang][cuda] Avoid false positive on multi device symbol
 with components (#192177)

Semantic was wrongly flagging derived-type components as two device
resident object. Update how we collect symbols and count the number of
device resident object.
---
 flang/include/flang/Evaluate/tools.h         | 10 +++++
 flang/lib/Evaluate/tools.cpp                 | 37 ++++++++++++++++++
 flang/lib/Semantics/check-cuda.cpp           |  2 +-
 flang/test/Lower/CUDA/cuda-data-transfer.cuf | 41 ++++++++++++++++++++
 4 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index cab6ddbb6b27c..944494823d8a2 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1299,6 +1299,13 @@ bool CheckForCoindexedObject(parser::ContextualMessages &,
     const std::optional<ActualArgument> &, const std::string &procName,
     const std::string &argName);
 
+// Get the symbol vectors of the expression where symbols are grouped together
+// if they are part of the same component expression.
+//
+// Example: a%b + c%d
+// Will be grouped as: [(a, b), (c, d)]
+std::vector<SymbolVector> GetSymbolVectors(const Expr<SomeType> &expr);
+
 bool IsCUDADeviceSymbol(const Symbol &sym);
 bool IsCUDADeviceOnlySymbol(const Symbol &sym);
 
@@ -1348,6 +1355,9 @@ template <typename A> inline int GetNbOfCUDADeviceSymbols(const A &expr) {
   return symbols.size();
 }
 
+// Get the number of unique symbols with CUDA device attribute.
+int GetNbOfUniqueCUDADeviceSymbols(const Expr<SomeType> &expr);
+
 // Get the number of distinct symbols with CUDA managed or unified
 // attribute in the expression.
 template <typename A>
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 8aff09aa84c13..259fe49c06f58 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1130,6 +1130,43 @@ template semantics::UnorderedSymbolSet CollectCudaSymbols(
 template semantics::UnorderedSymbolSet CollectCudaSymbols(
     const Expr<SubscriptInteger> &);
 
+std::vector<SymbolVector> GetSymbolVectors(const Expr<SomeType> &expr) {
+  SymbolVector symbols{GetSymbolVector(expr)};
+  std::reverse(symbols.begin(), symbols.end());
+
+  std::vector<SymbolVector> symbolVectors;
+
+  SymbolVector crtSymbols;
+  for (const Symbol &sym : symbols) {
+    bool isComponent{sym.owner().IsDerivedType()};
+    if (isComponent) {
+      crtSymbols.push_back(sym);
+    } else {
+      crtSymbols.push_back(sym);
+      symbolVectors.push_back(crtSymbols);
+      crtSymbols.clear();
+    }
+  }
+  return symbolVectors;
+}
+
+int GetNbOfUniqueCUDADeviceSymbols(const Expr<SomeType> &expr) {
+  std::vector<SymbolVector> symbolVectors{evaluate::GetSymbolVectors(expr)};
+  semantics::UnorderedSymbolSet symbols;
+  semantics::UnorderedSymbolSet cudaSymbols{CollectCudaSymbols(expr)};
+  for (const auto &symbolVector : symbolVectors) {
+    for (const auto &sym : symbolVector) {
+      if (cudaSymbols.find(sym) != cudaSymbols.end()) {
+        if (IsCUDADeviceSymbol(*sym)) {
+          symbols.insert(sym);
+          break;
+        }
+      }
+    }
+  }
+  return symbols.size();
+}
+
 bool HasCUDAImplicitTransfer(const Expr<SomeType> &expr) {
   semantics::UnorderedSymbolSet hostSymbols;
   semantics::UnorderedSymbolSet deviceSymbols;
diff --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp
index 62ece9e57b5d6..acf685088fd29 100644
--- a/flang/lib/Semantics/check-cuda.cpp
+++ b/flang/lib/Semantics/check-cuda.cpp
@@ -795,7 +795,7 @@ void CUDAChecker::Enter(const parser::AssignmentStmt &x) {
   }
 
   int nbLhs{evaluate::GetNbOfCUDADeviceSymbols(assign->lhs)};
-  int nbRhs{evaluate::GetNbOfCUDADeviceSymbols(assign->rhs)};
+  int nbRhs{evaluate::GetNbOfUniqueCUDADeviceSymbols(assign->rhs)};
   int nbRhsManaged{evaluate::GetNbOfCUDAManagedOrUnifiedSymbols(assign->rhs)};
 
   // device to host transfer with more than one device object on the rhs is not
diff --git a/flang/test/Lower/CUDA/cuda-data-transfer.cuf b/flang/test/Lower/CUDA/cuda-data-transfer.cuf
index 1d0e510c110ee..593827ae28fca 100644
--- a/flang/test/Lower/CUDA/cuda-data-transfer.cuf
+++ b/flang/test/Lower/CUDA/cuda-data-transfer.cuf
@@ -673,3 +673,44 @@ end subroutine
 
 ! CHECK-LABEL: func.func @_QPsub37()
 ! CHECK: cuf.data_transfer
+
+subroutine sub38()
+  type :: bar
+    integer, device, allocatable :: m(:)
+  end type
+  type(bar), unified :: a
+  type(bar), managed :: ma
+  integer :: lm(5)
+
+
+  lm(1:5) = a%m(1:5)
+  lm(1:5) = ma%m(1:5)
+end subroutine
+
+subroutine sub39()
+  type :: foo
+    integer, device, allocatable :: m(:)
+  end type
+  type :: bar
+    type(foo) :: f
+  end type
+  type(bar) :: a
+  integer :: lm(5)
+
+  lm(1:5) = a%f%m(1:5)
+end subroutine
+
+function sub40_call(x, y, n) result(z)
+  integer :: n
+  real, device :: x(n)
+  real, device :: y(n)
+  real :: z
+  z = 0.0
+end function
+
+subroutine sub40()
+  real, device :: x(10)
+  real, device :: y(10)
+  real :: res
+  res = sub40_call(x, y, 10)
+end subroutine



More information about the flang-commits mailing list