[flang-commits] [flang] [flang][acc] Fix separate compilation for module !$acc declare create on allocatables. (PR #202409)

via flang-commits flang-commits at lists.llvm.org
Mon Jun 8 11:48:44 PDT 2026


https://github.com/nvptm updated https://github.com/llvm/llvm-project/pull/202409

>From 7f5b1aab32fa092e90cfaa8ef7d969fe9db9c41e Mon Sep 17 00:00:00 2001
From: nvpm <pmathew at nvidia.com>
Date: Wed, 3 Jun 2026 22:51:28 -0700
Subject: [PATCH 1/2] Fix declare create on module allocatable separate file

---
 flang/include/flang/Lower/OpenACC.h           |  3 ++
 flang/include/flang/Semantics/symbol.h        |  2 +
 flang/lib/Lower/ConvertVariable.cpp           |  3 ++
 flang/lib/Lower/OpenACC.cpp                   | 50 ++++++++++++++++---
 flang/lib/Semantics/resolve-directives.cpp    |  2 +
 ...acc-declare-use-associated-allocatable.f90 | 37 ++++++++++++++
 flang/test/Lower/OpenACC/acc-declare.f90      |  4 +-
 7 files changed, 93 insertions(+), 8 deletions(-)
 create mode 100644 flang/test/Lower/OpenACC/acc-declare-use-associated-allocatable.f90

diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h
index 473cf3013ce8d..c76390a3bb85e 100644
--- a/flang/include/flang/Lower/OpenACC.h
+++ b/flang/include/flang/Lower/OpenACC.h
@@ -86,6 +86,9 @@ void genOpenACCRoutineConstruct(
     AbstractConverter &, mlir::ModuleOp, mlir::func::FuncOp,
     const std::vector<Fortran::semantics::OpenACCRoutineInfo> &);
 
+void declareExternalAccModuleDeclareActionRecipes(AbstractConverter &,
+                                                  fir::FirOpBuilder &,
+                                                  const Fortran::semantics::Symbol &);
 void attachDeclarePostAllocAction(AbstractConverter &, fir::FirOpBuilder &,
                                   const Fortran::semantics::Symbol &);
 void attachDeclarePreDeallocAction(AbstractConverter &, fir::FirOpBuilder &,
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index c794c20abcec5..84b5cd0ddd280 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -881,6 +881,8 @@ class Symbol {
       AccPresent, AccLink, AccDeviceResident, AccDevicePtr, AccUseDevice,
       // OpenACC declare
       AccDeclare,
+      // OpenACC declare on allocatable/pointer needs cross-TU action recipes
+      AccDeclareAction,
       // OpenACC data-movement attribute
       AccDevice, AccHost, AccSelf,
       // OpenACC miscellaneous flags
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 0cbc80cc94285..3527b50e74d1c 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -21,6 +21,7 @@
 #include "flang/Lower/ConvertExprToHLFIR.h"
 #include "flang/Lower/ConvertProcedureDesignator.h"
 #include "flang/Lower/Mangler.h"
+#include "flang/Lower/OpenACC.h"
 #include "flang/Lower/MultiImageFortran.h"
 #include "flang/Lower/PFTBuilder.h"
 #include "flang/Lower/StatementContext.h"
@@ -224,6 +225,8 @@ static fir::GlobalOp declareGlobal(Fortran::lower::AbstractConverter &converter,
       isConstant(ultimate), var.isTarget(), dataAttr,
       /*setDefaultAlignment=*/!isBindC);
   attachAccDeclareAttribute(builder, global, sym);
+  Fortran::lower::declareExternalAccModuleDeclareActionRecipes(converter,
+                                                               builder, sym);
   return global;
 }
 
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 7ee32b31b5e17..a7ef4dd6b0284 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -182,15 +182,20 @@ static mlir::func::FuncOp
 createDeclareFunc(mlir::OpBuilder &modBuilder, fir::FirOpBuilder &builder,
                   mlir::Location loc, llvm::StringRef funcName,
                   llvm::SmallVector<mlir::Type> argsTy = {},
-                  llvm::SmallVector<mlir::Location> locs = {}) {
+                  llvm::SmallVector<mlir::Location> locs = {},
+                  bool linkable = false) {
   auto funcTy = mlir::FunctionType::get(modBuilder.getContext(), argsTy, {});
   auto funcOp = mlir::func::FuncOp::create(modBuilder, loc, funcName, funcTy);
-  funcOp.setVisibility(mlir::SymbolTable::Visibility::Private);
+  funcOp.setVisibility(linkable ? mlir::SymbolTable::Visibility::Public
+                                : mlir::SymbolTable::Visibility::Private);
   builder.createBlock(&funcOp.getRegion(), funcOp.getRegion().end(), argsTy,
                       locs);
   builder.setInsertionPointToEnd(&funcOp.getRegion().back());
   mlir::func::ReturnOp::create(builder, loc);
   builder.setInsertionPointToStart(&funcOp.getRegion().back());
+  if (linkable)
+    funcOp->setAttr(mlir::acc::getDeclareActionAttrName(),
+                    mlir::UnitAttr::get(modBuilder.getContext()));
   return funcOp;
 }
 
@@ -3717,8 +3722,9 @@ static void createDeclareAllocFunc(mlir::OpBuilder &modBuilder,
   std::stringstream registerFuncName;
   registerFuncName << globalOp.getSymName().str()
                    << Fortran::lower::declarePostAllocSuffix.str();
-  auto registerFuncOp =
-      createDeclareFunc(modBuilder, builder, loc, registerFuncName.str());
+  auto registerFuncOp = createDeclareFunc(
+      modBuilder, builder, loc, registerFuncName.str(),
+      /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
 
   fir::AddrOfOp addrOp = fir::AddrOfOp::create(
       builder, loc, fir::ReferenceType::get(globalOp.getType()),
@@ -3757,8 +3763,9 @@ static void createDeclareDeallocFunc(mlir::OpBuilder &modBuilder,
   std::stringstream postDeallocFuncName;
   postDeallocFuncName << globalOp.getSymName().str()
                       << Fortran::lower::declarePostDeallocSuffix.str();
-  auto postDeallocOp =
-      createDeclareFunc(modBuilder, builder, loc, postDeallocFuncName.str());
+  auto postDeallocOp = createDeclareFunc(
+      modBuilder, builder, loc, postDeallocFuncName.str(),
+      /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
 
   fir::AddrOfOp addrOp = fir::AddrOfOp::create(
       builder, loc, fir::ReferenceType::get(globalOp.getType()),
@@ -4715,6 +4722,37 @@ void Fortran::lower::genOpenACCDeclarativeConstruct(
       accDeclConstruct.u);
 }
 
+void Fortran::lower::declareExternalAccModuleDeclareActionRecipes(
+    AbstractConverter &converter, fir::FirOpBuilder &builder,
+    const Fortran::semantics::Symbol &sym) {
+  using Flag = Fortran::semantics::Symbol::Flag;
+  const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
+  if (!ultimate.test(Flag::AccDeclareAction))
+    return;
+
+  mlir::ModuleOp module = builder.getModule();
+  mlir::Location loc = converter.genLocation(sym.name());
+  std::string prefix = converter.mangleName(ultimate);
+
+  auto declareExternalRecipe = [&](llvm::StringRef suffix) {
+    std::string name = prefix + suffix.str();
+    if (module.lookupSymbol<mlir::func::FuncOp>(name))
+      return;
+    auto funcTy = mlir::FunctionType::get(builder.getContext(), {}, {});
+    mlir::OpBuilder modBuilder(module.getBodyRegion());
+    modBuilder.setInsertionPointToEnd(module.getBody());
+    auto funcOp = mlir::func::FuncOp::create(modBuilder, loc, name, funcTy);
+    funcOp.setVisibility(mlir::SymbolTable::Visibility::Private);
+  };
+
+  declareExternalRecipe(declarePostAllocSuffix);
+  if (ultimate.test(Flag::AccCreate) || ultimate.test(Flag::AccCopyIn) ||
+      ultimate.test(Flag::AccCopyInReadOnly) || ultimate.test(Flag::AccCopy) ||
+      ultimate.test(Flag::AccCopyOut) ||
+      ultimate.test(Flag::AccDeviceResident))
+    declareExternalRecipe(declarePostDeallocSuffix);
+}
+
 void Fortran::lower::attachDeclarePostAllocAction(
     AbstractConverter &converter, fir::FirOpBuilder &builder,
     const Fortran::semantics::Symbol &sym) {
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 821724fedc7d4..be5a95025c31e 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1955,6 +1955,8 @@ Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity(
     if (GetContext().directive == llvm::acc::ACCD_declare) {
       object.set(Symbol::Flag::AccDeclare);
       object.set(accFlag);
+      if (IsAllocatableOrObjectPointer(&object))
+        object.set(Symbol::Flag::AccDeclareAction);
     }
   }
   return &object;
diff --git a/flang/test/Lower/OpenACC/acc-declare-use-associated-allocatable.f90 b/flang/test/Lower/OpenACC/acc-declare-use-associated-allocatable.f90
new file mode 100644
index 0000000000000..67171f732be3b
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-declare-use-associated-allocatable.f90
@@ -0,0 +1,37 @@
+! Test separate compilation of !$acc declare create on a module allocatable:
+! - the defining unit exports linkable declare-action recipe definitions
+! - the using unit declares the module global and external recipe symbols so
+!   acc-declare-action-conversion can insert fir.call to the recipes.
+
+! RUN: split-file %s %t
+! RUN: bbc -fopenacc -emit-hlfir %t/mod.f90 -o %t/mod.mlir --module=%t
+! RUN: bbc -fopenacc -emit-hlfir %t/use.f90 -o %t/use.mlir -I %t
+! RUN: FileCheck %s --check-prefix=MOD < %t/mod.mlir
+! RUN: FileCheck %s --check-prefix=USE < %t/use.mlir
+! RUN: fir-opt %t/use.mlir --acc-declare-action-conversion -o - | FileCheck %s --check-prefix=CONV
+
+//--- mod.f90
+module acc_declare_alloc_mod
+  integer, allocatable :: data(:)
+  !$acc declare create(data)
+end module
+
+//--- use.f90
+subroutine use_mod()
+  use acc_declare_alloc_mod
+  implicit none
+  allocate(data(100))
+end subroutine
+
+! MOD: func.func @_QMacc_declare_alloc_modEdata_acc_declare_post_alloc() attributes {acc.declare_action} {
+! MOD: acc.declare_enter
+! MOD: func.func @_QMacc_declare_alloc_modEdata_acc_declare_post_dealloc() attributes {acc.declare_action} {
+
+! USE: func.func @_QPuse_mod() {
+! USE: acc.declare_action = #acc.declare_action<postAlloc = @_QMacc_declare_alloc_modEdata_acc_declare_post_alloc>
+! USE: fir.global @_QMacc_declare_alloc_modEdata {acc.declare = #acc.declare<dataClause = acc_create>
+! USE: func.func private @_QMacc_declare_alloc_modEdata_acc_declare_post_alloc()
+! USE: func.func private @_QMacc_declare_alloc_modEdata_acc_declare_post_dealloc()
+! USE-NOT: acc.declare_enter
+
+! CONV: fir.call @_QMacc_declare_alloc_modEdata_acc_declare_post_alloc()
diff --git a/flang/test/Lower/OpenACC/acc-declare.f90 b/flang/test/Lower/OpenACC/acc-declare.f90
index 206a690e3c951..3339fa31c3d27 100644
--- a/flang/test/Lower/OpenACC/acc-declare.f90
+++ b/flang/test/Lower/OpenACC/acc-declare.f90
@@ -418,14 +418,14 @@ subroutine init_in_data(e)
 ! CHECK:         acc.terminator
 ! CHECK:       }
 
-! CHECK-LABEL: func.func private @_QMacc_declare_allocatable_testEdata1_acc_declare_post_alloc() {
+! CHECK-LABEL: func.func @_QMacc_declare_allocatable_testEdata1_acc_declare_post_alloc() attributes {acc.declare_action} {
 ! CHECK:         %[[GLOBAL_ADDR:.*]] = fir.address_of(@_QMacc_declare_allocatable_testEdata1) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
 ! CHECK:         %[[CREATE_DESC:.*]] = acc.create varPtr(%[[GLOBAL_ADDR]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {implicit = true, name = "data1", structured = false}
 ! CHECK:         acc.declare_enter dataOperands(%[[CREATE_DESC]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
 ! CHECK:         return
 ! CHECK:       }
 
-! CHECK-LABEL: func.func private @_QMacc_declare_allocatable_testEdata1_acc_declare_post_dealloc() {
+! CHECK-LABEL: func.func @_QMacc_declare_allocatable_testEdata1_acc_declare_post_dealloc() attributes {acc.declare_action} {
 ! CHECK:         %[[GLOBAL_ADDR:.*]] = fir.address_of(@_QMacc_declare_allocatable_testEdata1) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
 ! CHECK:         %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[GLOBAL_ADDR]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)   -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {dataClause = #acc<data_clause acc_create>, implicit = true, name = "data1", structured = false}
 ! CHECK:         acc.declare_exit dataOperands(%[[DEVPTR]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)

>From 411d89999b3f855c22feda7f768e29981c6c95fb Mon Sep 17 00:00:00 2001
From: nvpm <pmathew at nvidia.com>
Date: Mon, 8 Jun 2026 11:45:35 -0700
Subject: [PATCH 2/2] Format

---
 flang/include/flang/Lower/OpenACC.h    |  6 +++---
 flang/include/flang/Semantics/symbol.h |  2 +-
 flang/lib/Lower/ConvertVariable.cpp    |  2 +-
 flang/lib/Lower/OpenACC.cpp            | 25 +++++++++++--------------
 4 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h
index c76390a3bb85e..8ba72f356656e 100644
--- a/flang/include/flang/Lower/OpenACC.h
+++ b/flang/include/flang/Lower/OpenACC.h
@@ -86,9 +86,9 @@ void genOpenACCRoutineConstruct(
     AbstractConverter &, mlir::ModuleOp, mlir::func::FuncOp,
     const std::vector<Fortran::semantics::OpenACCRoutineInfo> &);
 
-void declareExternalAccModuleDeclareActionRecipes(AbstractConverter &,
-                                                  fir::FirOpBuilder &,
-                                                  const Fortran::semantics::Symbol &);
+void declareExternalAccModuleDeclareActionRecipes(
+    AbstractConverter &, fir::FirOpBuilder &,
+    const Fortran::semantics::Symbol &);
 void attachDeclarePostAllocAction(AbstractConverter &, fir::FirOpBuilder &,
                                   const Fortran::semantics::Symbol &);
 void attachDeclarePreDeallocAction(AbstractConverter &, fir::FirOpBuilder &,
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 84b5cd0ddd280..5790846d163b1 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -32,7 +32,7 @@ class raw_ostream;
 namespace Fortran::parser {
 struct Expr;
 struct OpenMPDeclarativeConstruct;
-}
+} // namespace Fortran::parser
 
 namespace Fortran::semantics {
 
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 3527b50e74d1c..9e309858deb4c 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -21,8 +21,8 @@
 #include "flang/Lower/ConvertExprToHLFIR.h"
 #include "flang/Lower/ConvertProcedureDesignator.h"
 #include "flang/Lower/Mangler.h"
-#include "flang/Lower/OpenACC.h"
 #include "flang/Lower/MultiImageFortran.h"
+#include "flang/Lower/OpenACC.h"
 #include "flang/Lower/PFTBuilder.h"
 #include "flang/Lower/StatementContext.h"
 #include "flang/Lower/Support/Utils.h"
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index a7ef4dd6b0284..1c51cf7fa6ca5 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -178,12 +178,10 @@ static void addDeclareAttr(fir::FirOpBuilder &builder, mlir::Operation *op,
                                               builder.getContext(), clause)));
 }
 
-static mlir::func::FuncOp
-createDeclareFunc(mlir::OpBuilder &modBuilder, fir::FirOpBuilder &builder,
-                  mlir::Location loc, llvm::StringRef funcName,
-                  llvm::SmallVector<mlir::Type> argsTy = {},
-                  llvm::SmallVector<mlir::Location> locs = {},
-                  bool linkable = false) {
+static mlir::func::FuncOp createDeclareFunc(
+    mlir::OpBuilder &modBuilder, fir::FirOpBuilder &builder, mlir::Location loc,
+    llvm::StringRef funcName, llvm::SmallVector<mlir::Type> argsTy = {},
+    llvm::SmallVector<mlir::Location> locs = {}, bool linkable = false) {
   auto funcTy = mlir::FunctionType::get(modBuilder.getContext(), argsTy, {});
   auto funcOp = mlir::func::FuncOp::create(modBuilder, loc, funcName, funcTy);
   funcOp.setVisibility(linkable ? mlir::SymbolTable::Visibility::Public
@@ -3722,9 +3720,9 @@ static void createDeclareAllocFunc(mlir::OpBuilder &modBuilder,
   std::stringstream registerFuncName;
   registerFuncName << globalOp.getSymName().str()
                    << Fortran::lower::declarePostAllocSuffix.str();
-  auto registerFuncOp = createDeclareFunc(
-      modBuilder, builder, loc, registerFuncName.str(),
-      /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
+  auto registerFuncOp =
+      createDeclareFunc(modBuilder, builder, loc, registerFuncName.str(),
+                        /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
 
   fir::AddrOfOp addrOp = fir::AddrOfOp::create(
       builder, loc, fir::ReferenceType::get(globalOp.getType()),
@@ -3763,9 +3761,9 @@ static void createDeclareDeallocFunc(mlir::OpBuilder &modBuilder,
   std::stringstream postDeallocFuncName;
   postDeallocFuncName << globalOp.getSymName().str()
                       << Fortran::lower::declarePostDeallocSuffix.str();
-  auto postDeallocOp = createDeclareFunc(
-      modBuilder, builder, loc, postDeallocFuncName.str(),
-      /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
+  auto postDeallocOp =
+      createDeclareFunc(modBuilder, builder, loc, postDeallocFuncName.str(),
+                        /*argsTy=*/{}, /*locs=*/{}, /*linkable=*/true);
 
   fir::AddrOfOp addrOp = fir::AddrOfOp::create(
       builder, loc, fir::ReferenceType::get(globalOp.getType()),
@@ -4748,8 +4746,7 @@ void Fortran::lower::declareExternalAccModuleDeclareActionRecipes(
   declareExternalRecipe(declarePostAllocSuffix);
   if (ultimate.test(Flag::AccCreate) || ultimate.test(Flag::AccCopyIn) ||
       ultimate.test(Flag::AccCopyInReadOnly) || ultimate.test(Flag::AccCopy) ||
-      ultimate.test(Flag::AccCopyOut) ||
-      ultimate.test(Flag::AccDeviceResident))
+      ultimate.test(Flag::AccCopyOut) || ultimate.test(Flag::AccDeviceResident))
     declareExternalRecipe(declarePostDeallocSuffix);
 }
 



More information about the flang-commits mailing list