[flang-commits] [flang] [acc][flang] lowering of acc declare on	COMMON variables (PR #163676)
    Susan Tan ス-ザン タン via flang-commits 
    flang-commits at lists.llvm.org
       
    Fri Oct 17 10:34:17 PDT 2025
    
    
  
https://github.com/SusanTan updated https://github.com/llvm/llvm-project/pull/163676
>From 3582fd5f7b4588bae0100f068a56c32ad92a790b Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 15 Oct 2025 15:36:14 -0700
Subject: [PATCH 1/6] initial implementation
---
 flang/lib/Lower/OpenACC.cpp | 274 +++++++++++++++++++++++++++++++++++-
 1 file changed, 268 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index cfb18914e8126..9e940743bd377 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -4112,12 +4112,26 @@ static void createDeclareGlobalOp(mlir::OpBuilder &modBuilder,
     DeclareOp::create(builder, loc, mlir::Value{},
                       mlir::ValueRange(entryOp.getAccVar()));
   if constexpr (std::is_same_v<GlobalOp, mlir::acc::GlobalDestructorOp>) {
-    ExitOp::create(builder, entryOp.getLoc(), entryOp.getAccVar(),
-                   entryOp.getBounds(), entryOp.getAsyncOperands(),
-                   entryOp.getAsyncOperandsDeviceTypeAttr(),
-                   entryOp.getAsyncOnlyAttr(), entryOp.getDataClause(),
-                   /*structured=*/false, /*implicit=*/false,
-                   builder.getStringAttr(*entryOp.getName()));
+    if constexpr (std::is_same_v<ExitOp, mlir::acc::DeclareLinkOp>) {
+      // No destructor emission for declare link in this path to avoid
+      // complex var/varType/varPtrPtr signatures. The ctor registers the link.
+    } else if constexpr (std::is_same_v<ExitOp, mlir::acc::CopyoutOp> ||
+                         std::is_same_v<ExitOp, mlir::acc::UpdateHostOp>) {
+      ExitOp::create(builder, entryOp.getLoc(), entryOp.getAccVar(),
+                     entryOp.getVar(), entryOp.getVarType(),
+                     entryOp.getBounds(), entryOp.getAsyncOperands(),
+                     entryOp.getAsyncOperandsDeviceTypeAttr(),
+                     entryOp.getAsyncOnlyAttr(), entryOp.getDataClause(),
+                     /*structured=*/false, /*implicit=*/false,
+                     builder.getStringAttr(*entryOp.getName()));
+    } else {
+      ExitOp::create(builder, entryOp.getLoc(), entryOp.getAccVar(),
+                     entryOp.getBounds(), entryOp.getAsyncOperands(),
+                     entryOp.getAsyncOperandsDeviceTypeAttr(),
+                     entryOp.getAsyncOnlyAttr(), entryOp.getDataClause(),
+                     /*structured=*/false, /*implicit=*/false,
+                     builder.getStringAttr(*entryOp.getName()));
+    }
   }
   mlir::acc::TerminatorOp::create(builder, loc);
   modBuilder.setInsertionPointAfter(declareGlobalOp);
@@ -4329,6 +4343,58 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           createClause->v;
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
+      // Emit module-level declare for COMMON symbols in this clause.
+      for (const auto &obj : accObjectList.v) {
+        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+            Fortran::semantics::FindCommonBlockContaining(sym)) {
+          std::string globalName = converter.mangleName(sym);
+          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+          if (!globalOp) {
+            if (Fortran::semantics::FindEquivalenceSet(sym)) {
+              for (Fortran::semantics::EquivalenceObject eqObj :
+                   *Fortran::semantics::FindEquivalenceSet(sym)) {
+                std::string eqName = converter.mangleName(eqObj.symbol);
+                globalOp = builder.getNamedGlobal(eqName);
+                if (globalOp)
+                  break;
+              }
+            }
+          }
+          if (!globalOp)
+            llvm::report_fatal_error("could not retrieve global symbol");
+          std::stringstream ctorName;
+          ctorName << globalName << "_acc_ctor";
+          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+                  ctorName.str())) {
+            mlir::Location operandLocation = genOperandLocation(converter, obj);
+            addDeclareAttr(builder, globalOp.getOperation(),
+                mlir::acc::DataClause::acc_create);
+            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+            modBuilder.setInsertionPointAfter(globalOp);
+            std::stringstream asFortran;
+            asFortran << sym.name().ToString();
+            auto savedIP = builder.saveInsertionPoint();
+            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                  mlir::acc::CreateOp,
+                                  mlir::acc::DeclareEnterOp,
+                                  mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_create, ctorName.str(),
+                    /*implicit=*/false, asFortran);
+            std::stringstream dtorName;
+            dtorName << globalName << "_acc_dtor";
+            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                  mlir::acc::GetDevicePtrOp,
+                                  mlir::acc::DeclareExitOp,
+                                  mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_create, dtorName.str(),
+                    /*implicit=*/false, asFortran);
+            builder.restoreInsertionPoint(savedIP);
+          }
+        }
+      }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::CreateOp, mlir::acc::DeleteOp>(
           accObjectList, converter, semanticsContext, stmtCtx,
@@ -4349,6 +4415,61 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
                                   dataClauseOperands.end());
     } else if (const auto *copyinClause =
                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
+      // Emit module-level declare for COMMON symbols in this clause.
+      const auto &listWithModifier = copyinClause->v;
+      const auto ©inObjs =
+          std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
+      for (const auto &obj : copyinObjs.v) {
+        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+            Fortran::semantics::FindCommonBlockContaining(sym)) {
+          std::string globalName = converter.mangleName(sym);
+          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+          if (!globalOp) {
+            if (Fortran::semantics::FindEquivalenceSet(sym)) {
+              for (Fortran::semantics::EquivalenceObject eqObj :
+                   *Fortran::semantics::FindEquivalenceSet(sym)) {
+                std::string eqName = converter.mangleName(eqObj.symbol);
+                globalOp = builder.getNamedGlobal(eqName);
+                if (globalOp)
+                  break;
+              }
+            }
+          }
+          if (!globalOp)
+            llvm::report_fatal_error("could not retrieve global symbol");
+          std::stringstream ctorName;
+          ctorName << globalName << "_acc_ctor";
+          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+                  ctorName.str())) {
+            mlir::Location operandLocation = genOperandLocation(converter, obj);
+            addDeclareAttr(builder, globalOp.getOperation(),
+                mlir::acc::DataClause::acc_copyin);
+            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+            modBuilder.setInsertionPointAfter(globalOp);
+            std::stringstream asFortran;
+            asFortran << sym.name().ToString();
+            auto savedIP = builder.saveInsertionPoint();
+            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                  mlir::acc::CopyinOp,
+                                  mlir::acc::DeclareEnterOp,
+                                  mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_copyin, ctorName.str(),
+                    /*implicit=*/false, asFortran);
+            std::stringstream dtorName;
+            dtorName << globalName << "_acc_dtor";
+            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                  mlir::acc::GetDevicePtrOp,
+                                  mlir::acc::DeclareExitOp,
+                                  mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_copyin, dtorName.str(),
+                    /*implicit=*/false, asFortran);
+            builder.restoreInsertionPoint(savedIP);
+          }
+        }
+      }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperationsWithModifier<mlir::acc::CopyinOp,
                                                   mlir::acc::DeleteOp>(
@@ -4365,6 +4486,58 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           copyoutClause->v;
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
+      // Emit module-level declare for COMMON symbols in this clause.
+      for (const auto &obj : accObjectList.v) {
+        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+            Fortran::semantics::FindCommonBlockContaining(sym)) {
+          std::string globalName = converter.mangleName(sym);
+          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+          if (!globalOp) {
+            if (Fortran::semantics::FindEquivalenceSet(sym)) {
+              for (Fortran::semantics::EquivalenceObject eqObj :
+                   *Fortran::semantics::FindEquivalenceSet(sym)) {
+                std::string eqName = converter.mangleName(eqObj.symbol);
+                globalOp = builder.getNamedGlobal(eqName);
+                if (globalOp)
+                  break;
+              }
+            }
+          }
+          if (!globalOp)
+            llvm::report_fatal_error("could not retrieve global symbol");
+          std::stringstream ctorName;
+          ctorName << globalName << "_acc_ctor";
+          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+                  ctorName.str())) {
+            mlir::Location operandLocation = genOperandLocation(converter, obj);
+            addDeclareAttr(builder, globalOp.getOperation(),
+                mlir::acc::DataClause::acc_copyout);
+            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+            modBuilder.setInsertionPointAfter(globalOp);
+            std::stringstream asFortran;
+            asFortran << sym.name().ToString();
+            auto savedIP = builder.saveInsertionPoint();
+            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                  mlir::acc::CreateOp,
+                                  mlir::acc::DeclareEnterOp,
+                                  mlir::acc::CopyoutOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_copyout, ctorName.str(),
+                    /*implicit=*/false, asFortran);
+            std::stringstream dtorName;
+            dtorName << globalName << "_acc_dtor";
+            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                  mlir::acc::GetDevicePtrOp,
+                                  mlir::acc::DeclareExitOp,
+                                  mlir::acc::CopyoutOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_copyout, dtorName.str(),
+                    /*implicit=*/false, asFortran);
+            builder.restoreInsertionPoint(savedIP);
+          }
+        }
+      }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::CreateOp,
                                       mlir::acc::CopyoutOp>(
@@ -4383,6 +4556,50 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           /*structured=*/true, /*implicit=*/false);
     } else if (const auto *linkClause =
                    std::get_if<Fortran::parser::AccClause::Link>(&clause.u)) {
+      // Emit module-level declare for COMMON symbols in this clause.
+      const auto &linkObjs = linkClause->v;
+      for (const auto &obj : linkObjs.v) {
+        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+            Fortran::semantics::FindCommonBlockContaining(sym)) {
+          std::string globalName = converter.mangleName(sym);
+          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+          if (!globalOp) {
+            if (Fortran::semantics::FindEquivalenceSet(sym)) {
+              for (Fortran::semantics::EquivalenceObject eqObj :
+                   *Fortran::semantics::FindEquivalenceSet(sym)) {
+                std::string eqName = converter.mangleName(eqObj.symbol);
+                globalOp = builder.getNamedGlobal(eqName);
+                if (globalOp)
+                  break;
+              }
+            }
+          }
+          if (!globalOp)
+            llvm::report_fatal_error("could not retrieve global symbol");
+          std::stringstream ctorName;
+          ctorName << globalName << "_acc_ctor";
+          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+                  ctorName.str())) {
+            mlir::Location operandLocation = genOperandLocation(converter, obj);
+            addDeclareAttr(builder, globalOp.getOperation(),
+                mlir::acc::DataClause::acc_declare_link);
+            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+            modBuilder.setInsertionPointAfter(globalOp);
+            std::stringstream asFortran;
+            asFortran << sym.name().ToString();
+            auto savedIP = builder.saveInsertionPoint();
+            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                  mlir::acc::DeclareLinkOp,
+                                  mlir::acc::DeclareEnterOp,
+                                  mlir::acc::DeclareLinkOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_declare_link, ctorName.str(),
+                    /*implicit=*/false, asFortran);
+            builder.restoreInsertionPoint(savedIP);
+          }
+        }
+      }
       genDeclareDataOperandOperations<mlir::acc::DeclareLinkOp,
                                       mlir::acc::DeclareLinkOp>(
           linkClause->v, converter, semanticsContext, stmtCtx,
@@ -4391,6 +4608,51 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
     } else if (const auto *deviceResidentClause =
                    std::get_if<Fortran::parser::AccClause::DeviceResident>(
                        &clause.u)) {
+      // Emit module-level declare for COMMON symbols in this clause.
+      const auto &devResObjs = deviceResidentClause->v;
+      for (const auto &obj : devResObjs.v) {
+        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+            Fortran::semantics::FindCommonBlockContaining(sym)) {
+          std::string globalName = converter.mangleName(sym);
+          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+          if (!globalOp) {
+            if (Fortran::semantics::FindEquivalenceSet(sym)) {
+              for (Fortran::semantics::EquivalenceObject eqObj :
+                   *Fortran::semantics::FindEquivalenceSet(sym)) {
+                std::string eqName = converter.mangleName(eqObj.symbol);
+                globalOp = builder.getNamedGlobal(eqName);
+                if (globalOp)
+                  break;
+              }
+            }
+          }
+          if (!globalOp)
+            llvm::report_fatal_error("could not retrieve global symbol");
+          std::stringstream ctorName;
+          ctorName << globalName << "_acc_ctor";
+          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+                  ctorName.str())) {
+            mlir::Location operandLocation = genOperandLocation(converter, obj);
+            addDeclareAttr(builder, globalOp.getOperation(),
+                mlir::acc::DataClause::acc_declare_device_resident);
+            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+            modBuilder.setInsertionPointAfter(globalOp);
+            std::stringstream asFortran;
+            asFortran << sym.name().ToString();
+            auto savedIP = builder.saveInsertionPoint();
+            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                  mlir::acc::DeclareDeviceResidentOp,
+                                  mlir::acc::DeclareEnterOp,
+                                  mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp,
+                    mlir::acc::DataClause::acc_declare_device_resident,
+                    ctorName.str(),
+                    /*implicit=*/false, asFortran);
+            builder.restoreInsertionPoint(savedIP);
+          }
+        }
+      }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::DeclareDeviceResidentOp,
                                       mlir::acc::DeleteOp>(
>From c6ee3b92db518a4e121203556e17b06fb5516825 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 15 Oct 2025 15:56:11 -0700
Subject: [PATCH 2/6] refactor
---
 flang/lib/Lower/OpenACC.cpp | 342 ++++++++++++------------------------
 1 file changed, 117 insertions(+), 225 deletions(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 9e940743bd377..37abcffc683d9 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -3398,6 +3398,7 @@ genACCHostDataOp(Fortran::lower::AbstractConverter &converter,
 
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
 
+
   for (const Fortran::parser::AccClause &clause : accClauseList.v) {
     mlir::Location clauseLocation = converter.genLocation(clause.source);
     if (const auto *ifClause =
@@ -4326,6 +4327,50 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
   Fortran::lower::StatementContext stmtCtx;
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
 
+  // Inline helper to emit module-level declare for COMMON symbols in a clause.
+  auto emitCommonGlobal = [&](const Fortran::parser::AccObject &obj,
+                              mlir::acc::DataClause clause,
+                              auto emitCtorDtor) {
+    Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+    if (!(sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+          Fortran::semantics::FindCommonBlockContaining(sym)))
+      return;
+
+    std::string globalName = converter.mangleName(sym);
+    fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+    if (!globalOp) {
+      if (Fortran::semantics::FindEquivalenceSet(sym)) {
+        for (Fortran::semantics::EquivalenceObject eqObj :
+             *Fortran::semantics::FindEquivalenceSet(sym)) {
+          std::string eqName = converter.mangleName(eqObj.symbol);
+          globalOp = builder.getNamedGlobal(eqName);
+          if (globalOp)
+            break;
+        }
+      }
+    }
+    if (!globalOp)
+      llvm::report_fatal_error("could not retrieve global symbol");
+
+    std::stringstream ctorName;
+    ctorName << globalName << "_acc_ctor";
+    if (builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+            ctorName.str()))
+      return;
+
+    mlir::Location operandLocation = genOperandLocation(converter, obj);
+    addDeclareAttr(builder, globalOp.getOperation(), clause);
+    mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+    modBuilder.setInsertionPointAfter(globalOp);
+    std::stringstream asFortran;
+    asFortran << sym.name().ToString();
+
+    auto savedIP = builder.saveInsertionPoint();
+    emitCtorDtor(modBuilder, operandLocation, globalOp, clause, asFortran,
+                 ctorName.str());
+    builder.restoreInsertionPoint(savedIP);
+  };
+
   for (const Fortran::parser::AccClause &clause : accClauseList.v) {
     if (const auto *copyClause =
             std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
@@ -4343,57 +4388,26 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           createClause->v;
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
-      // Emit module-level declare for COMMON symbols in this clause.
       for (const auto &obj : accObjectList.v) {
-        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-            Fortran::semantics::FindCommonBlockContaining(sym)) {
-          std::string globalName = converter.mangleName(sym);
-          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-          if (!globalOp) {
-            if (Fortran::semantics::FindEquivalenceSet(sym)) {
-              for (Fortran::semantics::EquivalenceObject eqObj :
-                   *Fortran::semantics::FindEquivalenceSet(sym)) {
-                std::string eqName = converter.mangleName(eqObj.symbol);
-                globalOp = builder.getNamedGlobal(eqName);
-                if (globalOp)
-                  break;
-              }
-            }
-          }
-          if (!globalOp)
-            llvm::report_fatal_error("could not retrieve global symbol");
-          std::stringstream ctorName;
-          ctorName << globalName << "_acc_ctor";
-          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-                  ctorName.str())) {
-            mlir::Location operandLocation = genOperandLocation(converter, obj);
-            addDeclareAttr(builder, globalOp.getOperation(),
-                mlir::acc::DataClause::acc_create);
-            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-            modBuilder.setInsertionPointAfter(globalOp);
-            std::stringstream asFortran;
-            asFortran << sym.name().ToString();
-            auto savedIP = builder.saveInsertionPoint();
-            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                  mlir::acc::CreateOp,
-                                  mlir::acc::DeclareEnterOp,
-                                  mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_create, ctorName.str(),
+        emitCommonGlobal(obj, mlir::acc::DataClause::acc_create,
+            [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
+                fir::GlobalOp globalOp, mlir::acc::DataClause clause,
+                std::stringstream &asFortran, const std::string &ctorName) {
+              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                    mlir::acc::CreateOp,
+                                    mlir::acc::DeclareEnterOp,
+                                    mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, ctorName,
                     /*implicit=*/false, asFortran);
-            std::stringstream dtorName;
-            dtorName << globalName << "_acc_dtor";
-            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                  mlir::acc::GetDevicePtrOp,
-                                  mlir::acc::DeclareExitOp,
-                                  mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_create, dtorName.str(),
+              std::stringstream dtorName;
+              dtorName << globalOp.getSymName().str() << "_acc_dtor";
+              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                    mlir::acc::GetDevicePtrOp,
+                                    mlir::acc::DeclareExitOp,
+                                    mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, dtorName.str(),
                     /*implicit=*/false, asFortran);
-            builder.restoreInsertionPoint(savedIP);
-          }
-        }
+            });
       }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::CreateOp, mlir::acc::DeleteOp>(
@@ -4415,60 +4429,29 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
                                   dataClauseOperands.end());
     } else if (const auto *copyinClause =
                    std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
-      // Emit module-level declare for COMMON symbols in this clause.
       const auto &listWithModifier = copyinClause->v;
       const auto ©inObjs =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
       for (const auto &obj : copyinObjs.v) {
-        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-            Fortran::semantics::FindCommonBlockContaining(sym)) {
-          std::string globalName = converter.mangleName(sym);
-          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-          if (!globalOp) {
-            if (Fortran::semantics::FindEquivalenceSet(sym)) {
-              for (Fortran::semantics::EquivalenceObject eqObj :
-                   *Fortran::semantics::FindEquivalenceSet(sym)) {
-                std::string eqName = converter.mangleName(eqObj.symbol);
-                globalOp = builder.getNamedGlobal(eqName);
-                if (globalOp)
-                  break;
-              }
-            }
-          }
-          if (!globalOp)
-            llvm::report_fatal_error("could not retrieve global symbol");
-          std::stringstream ctorName;
-          ctorName << globalName << "_acc_ctor";
-          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-                  ctorName.str())) {
-            mlir::Location operandLocation = genOperandLocation(converter, obj);
-            addDeclareAttr(builder, globalOp.getOperation(),
-                mlir::acc::DataClause::acc_copyin);
-            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-            modBuilder.setInsertionPointAfter(globalOp);
-            std::stringstream asFortran;
-            asFortran << sym.name().ToString();
-            auto savedIP = builder.saveInsertionPoint();
-            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                  mlir::acc::CopyinOp,
-                                  mlir::acc::DeclareEnterOp,
-                                  mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_copyin, ctorName.str(),
+        emitCommonGlobal(obj, mlir::acc::DataClause::acc_copyin,
+            [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
+                fir::GlobalOp globalOp, mlir::acc::DataClause clause,
+                std::stringstream &asFortran, const std::string &ctorName) {
+              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                    mlir::acc::CopyinOp,
+                                    mlir::acc::DeclareEnterOp,
+                                    mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, ctorName,
                     /*implicit=*/false, asFortran);
-            std::stringstream dtorName;
-            dtorName << globalName << "_acc_dtor";
-            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                  mlir::acc::GetDevicePtrOp,
-                                  mlir::acc::DeclareExitOp,
-                                  mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_copyin, dtorName.str(),
+              std::stringstream dtorName;
+              dtorName << globalOp.getSymName().str() << "_acc_dtor";
+              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                    mlir::acc::GetDevicePtrOp,
+                                    mlir::acc::DeclareExitOp,
+                                    mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, dtorName.str(),
                     /*implicit=*/false, asFortran);
-            builder.restoreInsertionPoint(savedIP);
-          }
-        }
+            });
       }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperationsWithModifier<mlir::acc::CopyinOp,
@@ -4486,57 +4469,26 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           copyoutClause->v;
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
-      // Emit module-level declare for COMMON symbols in this clause.
       for (const auto &obj : accObjectList.v) {
-        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-            Fortran::semantics::FindCommonBlockContaining(sym)) {
-          std::string globalName = converter.mangleName(sym);
-          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-          if (!globalOp) {
-            if (Fortran::semantics::FindEquivalenceSet(sym)) {
-              for (Fortran::semantics::EquivalenceObject eqObj :
-                   *Fortran::semantics::FindEquivalenceSet(sym)) {
-                std::string eqName = converter.mangleName(eqObj.symbol);
-                globalOp = builder.getNamedGlobal(eqName);
-                if (globalOp)
-                  break;
-              }
-            }
-          }
-          if (!globalOp)
-            llvm::report_fatal_error("could not retrieve global symbol");
-          std::stringstream ctorName;
-          ctorName << globalName << "_acc_ctor";
-          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-                  ctorName.str())) {
-            mlir::Location operandLocation = genOperandLocation(converter, obj);
-            addDeclareAttr(builder, globalOp.getOperation(),
-                mlir::acc::DataClause::acc_copyout);
-            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-            modBuilder.setInsertionPointAfter(globalOp);
-            std::stringstream asFortran;
-            asFortran << sym.name().ToString();
-            auto savedIP = builder.saveInsertionPoint();
-            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                  mlir::acc::CreateOp,
-                                  mlir::acc::DeclareEnterOp,
-                                  mlir::acc::CopyoutOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_copyout, ctorName.str(),
+        emitCommonGlobal(obj, mlir::acc::DataClause::acc_copyout,
+            [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
+                fir::GlobalOp globalOp, mlir::acc::DataClause clause,
+                std::stringstream &asFortran, const std::string &ctorName) {
+              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                    mlir::acc::CreateOp,
+                                    mlir::acc::DeclareEnterOp,
+                                    mlir::acc::CopyoutOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, ctorName,
                     /*implicit=*/false, asFortran);
-            std::stringstream dtorName;
-            dtorName << globalName << "_acc_dtor";
-            createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                  mlir::acc::GetDevicePtrOp,
-                                  mlir::acc::DeclareExitOp,
-                                  mlir::acc::CopyoutOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_copyout, dtorName.str(),
+              std::stringstream dtorName;
+              dtorName << globalOp.getSymName().str() << "_acc_dtor";
+              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
+                                    mlir::acc::GetDevicePtrOp,
+                                    mlir::acc::DeclareExitOp,
+                                    mlir::acc::CopyoutOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, dtorName.str(),
                     /*implicit=*/false, asFortran);
-            builder.restoreInsertionPoint(savedIP);
-          }
-        }
+            });
       }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::CreateOp,
@@ -4556,49 +4508,19 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
           /*structured=*/true, /*implicit=*/false);
     } else if (const auto *linkClause =
                    std::get_if<Fortran::parser::AccClause::Link>(&clause.u)) {
-      // Emit module-level declare for COMMON symbols in this clause.
       const auto &linkObjs = linkClause->v;
       for (const auto &obj : linkObjs.v) {
-        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-            Fortran::semantics::FindCommonBlockContaining(sym)) {
-          std::string globalName = converter.mangleName(sym);
-          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-          if (!globalOp) {
-            if (Fortran::semantics::FindEquivalenceSet(sym)) {
-              for (Fortran::semantics::EquivalenceObject eqObj :
-                   *Fortran::semantics::FindEquivalenceSet(sym)) {
-                std::string eqName = converter.mangleName(eqObj.symbol);
-                globalOp = builder.getNamedGlobal(eqName);
-                if (globalOp)
-                  break;
-              }
-            }
-          }
-          if (!globalOp)
-            llvm::report_fatal_error("could not retrieve global symbol");
-          std::stringstream ctorName;
-          ctorName << globalName << "_acc_ctor";
-          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-                  ctorName.str())) {
-            mlir::Location operandLocation = genOperandLocation(converter, obj);
-            addDeclareAttr(builder, globalOp.getOperation(),
-                mlir::acc::DataClause::acc_declare_link);
-            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-            modBuilder.setInsertionPointAfter(globalOp);
-            std::stringstream asFortran;
-            asFortran << sym.name().ToString();
-            auto savedIP = builder.saveInsertionPoint();
-            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                  mlir::acc::DeclareLinkOp,
-                                  mlir::acc::DeclareEnterOp,
-                                  mlir::acc::DeclareLinkOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_declare_link, ctorName.str(),
+        emitCommonGlobal(obj, mlir::acc::DataClause::acc_declare_link,
+            [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
+                fir::GlobalOp globalOp, mlir::acc::DataClause clause,
+                std::stringstream &asFortran, const std::string &ctorName) {
+              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                    mlir::acc::DeclareLinkOp,
+                                    mlir::acc::DeclareEnterOp,
+                                    mlir::acc::DeclareLinkOp>(modBuilder,
+                    builder, operandLocation, globalOp, clause, ctorName,
                     /*implicit=*/false, asFortran);
-            builder.restoreInsertionPoint(savedIP);
-          }
-        }
+            });
       }
       genDeclareDataOperandOperations<mlir::acc::DeclareLinkOp,
                                       mlir::acc::DeclareLinkOp>(
@@ -4608,50 +4530,20 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
     } else if (const auto *deviceResidentClause =
                    std::get_if<Fortran::parser::AccClause::DeviceResident>(
                        &clause.u)) {
-      // Emit module-level declare for COMMON symbols in this clause.
       const auto &devResObjs = deviceResidentClause->v;
       for (const auto &obj : devResObjs.v) {
-        Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-        if (sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-            Fortran::semantics::FindCommonBlockContaining(sym)) {
-          std::string globalName = converter.mangleName(sym);
-          fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-          if (!globalOp) {
-            if (Fortran::semantics::FindEquivalenceSet(sym)) {
-              for (Fortran::semantics::EquivalenceObject eqObj :
-                   *Fortran::semantics::FindEquivalenceSet(sym)) {
-                std::string eqName = converter.mangleName(eqObj.symbol);
-                globalOp = builder.getNamedGlobal(eqName);
-                if (globalOp)
-                  break;
-              }
-            }
-          }
-          if (!globalOp)
-            llvm::report_fatal_error("could not retrieve global symbol");
-          std::stringstream ctorName;
-          ctorName << globalName << "_acc_ctor";
-          if (!builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-                  ctorName.str())) {
-            mlir::Location operandLocation = genOperandLocation(converter, obj);
-            addDeclareAttr(builder, globalOp.getOperation(),
-                mlir::acc::DataClause::acc_declare_device_resident);
-            mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-            modBuilder.setInsertionPointAfter(globalOp);
-            std::stringstream asFortran;
-            asFortran << sym.name().ToString();
-            auto savedIP = builder.saveInsertionPoint();
-            createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                  mlir::acc::DeclareDeviceResidentOp,
-                                  mlir::acc::DeclareEnterOp,
-                                  mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp,
-                    mlir::acc::DataClause::acc_declare_device_resident,
-                    ctorName.str(),
+        emitCommonGlobal(obj,
+            mlir::acc::DataClause::acc_declare_device_resident,
+            [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
+                fir::GlobalOp globalOp, mlir::acc::DataClause clause,
+                std::stringstream &asFortran, const std::string &ctorName) {
+              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
+                                    mlir::acc::DeclareDeviceResidentOp,
+                                    mlir::acc::DeclareEnterOp,
+                                    mlir::acc::DeleteOp>(modBuilder, builder,
+                    operandLocation, globalOp, clause, ctorName,
                     /*implicit=*/false, asFortran);
-            builder.restoreInsertionPoint(savedIP);
-          }
-        }
+            });
       }
       auto crtDataStart = dataClauseOperands.size();
       genDeclareDataOperandOperations<mlir::acc::DeclareDeviceResidentOp,
>From 3592903f21135f6117623d07634c5d95c8ae6c26 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 15 Oct 2025 17:24:56 -0700
Subject: [PATCH 3/6] more refactor
---
 flang/lib/Lower/OpenACC.cpp | 83 ++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 48 deletions(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 37abcffc683d9..e493198fd2b51 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -4138,6 +4138,29 @@ static void createDeclareGlobalOp(mlir::OpBuilder &modBuilder,
   modBuilder.setInsertionPointAfter(declareGlobalOp);
 }
 
+// Small helper to emit a constructor/destructor pair for a given global
+// declare Entry/Exit Op combination.
+template <typename EntryOp, typename ExitOp>
+static void emitCtorDtorPair(mlir::OpBuilder &modBuilder,
+                             fir::FirOpBuilder &builder,
+                             mlir::Location operandLocation,
+                             fir::GlobalOp globalOp,
+                             mlir::acc::DataClause clause,
+                             std::stringstream &asFortran,
+                             const std::string &ctorName) {
+  createDeclareGlobalOp<mlir::acc::GlobalConstructorOp, EntryOp,
+                        mlir::acc::DeclareEnterOp, ExitOp>(
+      modBuilder, builder, operandLocation, globalOp, clause, ctorName,
+      /*implicit=*/false, asFortran);
+
+  std::stringstream dtorName;
+  dtorName << globalOp.getSymName().str() << "_acc_dtor";
+  createDeclareGlobalOp<mlir::acc::GlobalDestructorOp, mlir::acc::GetDevicePtrOp,
+                        mlir::acc::DeclareExitOp, ExitOp>(
+      modBuilder, builder, operandLocation, globalOp, clause, dtorName.str(),
+      /*implicit=*/false, asFortran);
+}
+
 template <typename EntryOp>
 static void createDeclareAllocFunc(mlir::OpBuilder &modBuilder,
                                    fir::FirOpBuilder &builder,
@@ -4393,20 +4416,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
-              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                    mlir::acc::CreateOp,
-                                    mlir::acc::DeclareEnterOp,
-                                    mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, ctorName,
-                    /*implicit=*/false, asFortran);
-              std::stringstream dtorName;
-              dtorName << globalOp.getSymName().str() << "_acc_dtor";
-              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                    mlir::acc::GetDevicePtrOp,
-                                    mlir::acc::DeclareExitOp,
-                                    mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, dtorName.str(),
-                    /*implicit=*/false, asFortran);
+              emitCtorDtorPair<mlir::acc::CreateOp, mlir::acc::DeleteOp>(
+                  modBuilder, builder, operandLocation, globalOp, clause,
+                  asFortran, ctorName);
             });
       }
       auto crtDataStart = dataClauseOperands.size();
@@ -4437,20 +4449,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
-              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                    mlir::acc::CopyinOp,
-                                    mlir::acc::DeclareEnterOp,
-                                    mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, ctorName,
-                    /*implicit=*/false, asFortran);
-              std::stringstream dtorName;
-              dtorName << globalOp.getSymName().str() << "_acc_dtor";
-              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                    mlir::acc::GetDevicePtrOp,
-                                    mlir::acc::DeclareExitOp,
-                                    mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, dtorName.str(),
-                    /*implicit=*/false, asFortran);
+              emitCtorDtorPair<mlir::acc::CopyinOp, mlir::acc::DeleteOp>(
+                  modBuilder, builder, operandLocation, globalOp, clause,
+                  asFortran, ctorName);
             });
       }
       auto crtDataStart = dataClauseOperands.size();
@@ -4474,20 +4475,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
-              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                    mlir::acc::CreateOp,
-                                    mlir::acc::DeclareEnterOp,
-                                    mlir::acc::CopyoutOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, ctorName,
-                    /*implicit=*/false, asFortran);
-              std::stringstream dtorName;
-              dtorName << globalOp.getSymName().str() << "_acc_dtor";
-              createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
-                                    mlir::acc::GetDevicePtrOp,
-                                    mlir::acc::DeclareExitOp,
-                                    mlir::acc::CopyoutOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, dtorName.str(),
-                    /*implicit=*/false, asFortran);
+              emitCtorDtorPair<mlir::acc::CreateOp, mlir::acc::CopyoutOp>(
+                  modBuilder, builder, operandLocation, globalOp, clause,
+                  asFortran, ctorName);
             });
       }
       auto crtDataStart = dataClauseOperands.size();
@@ -4537,12 +4527,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
-              createDeclareGlobalOp<mlir::acc::GlobalConstructorOp,
-                                    mlir::acc::DeclareDeviceResidentOp,
-                                    mlir::acc::DeclareEnterOp,
-                                    mlir::acc::DeleteOp>(modBuilder, builder,
-                    operandLocation, globalOp, clause, ctorName,
-                    /*implicit=*/false, asFortran);
+              emitCtorDtorPair<mlir::acc::DeclareDeviceResidentOp,
+                               mlir::acc::DeleteOp>(modBuilder, builder,
+                  operandLocation, globalOp, clause, asFortran, ctorName);
             });
       }
       auto crtDataStart = dataClauseOperands.size();
>From c76338c64ee5b7c452ffb5eba816ae560511a2b4 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Wed, 15 Oct 2025 18:38:03 -0700
Subject: [PATCH 4/6] add a test
---
 flang/lib/Lower/OpenACC.cpp                   |  9 +++++
 .../acc-declare-common-in-function.f90        | 40 +++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index e493198fd2b51..f2afc75b7f6b3 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -726,6 +726,10 @@ static void genDeclareDataOperandOperations(
     std::stringstream asFortran;
     mlir::Location operandLocation = genOperandLocation(converter, accObject);
     Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject);
+    // Skip COMMON/global symbols: handled via global ctor/dtor path in declare.
+    if (symbol.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+        Fortran::semantics::FindCommonBlockContaining(symbol))
+      continue;
     Fortran::semantics::MaybeExpr designator = Fortran::common::visit(
         [&](auto &&s) { return ea.Analyze(s); }, accObject.u);
     fir::factory::AddrAndBoundsInfo info =
@@ -4547,6 +4551,11 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
     }
   }
 
+  // If no structured operands were generated (all objects were COMMON),
+  // do not create a declare region.
+  if (dataClauseOperands.empty())
+    return;
+
   mlir::func::FuncOp funcOp = builder.getFunction();
   auto ops = funcOp.getOps<mlir::acc::DeclareEnterOp>();
   mlir::Value declareToken;
diff --git a/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90 b/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
new file mode 100644
index 0000000000000..bffbe304c7078
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
@@ -0,0 +1,40 @@
+! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
+
+! Verify that a COMMON block declared with OpenACC declare inside a function
+! is lowered as a global declare (acc.global_ctor/dtor) rather than a
+! structured declare.
+
+program p
+  implicit none
+  real :: pi
+  integer :: i
+  common /RIEMANN_COM/ pi
+!$acc declare copyin(/RIEMANN_COM/)
+  data pi/0.0/
+
+! CHECK-DAG: acc.global_ctor @{{.*}}_acc_ctor {
+! CHECK-DAG: %[[ADDR0:.*]] = fir.address_of(@{{.*}}) {acc.declare = #acc.declare<dataClause = acc_copyin>} : {{.*}}
+! CHECK-DAG: acc.declare_enter dataOperands(%{{.*}} : {{.*}})
+! CHECK-DAG: acc.terminator
+! CHECK-DAG: }
+
+! CHECK-DAG: acc.global_dtor @{{.*}}_acc_dtor {
+! CHECK-DAG: %[[ADDR1:.*]] = fir.address_of(@{{.*}}) {acc.declare = #acc.declare<dataClause = acc_copyin>} : !fir.ref<tuple<f32>>
+! CHECK-DAG: %[[GDP:.*]] = acc.getdeviceptr varPtr(%[[ADDR1]] : !fir.ref<tuple<f32>>) -> !fir.ref<tuple<f32>> {dataClause = #acc<data_clause acc_copyin>, {{.*}}}
+! CHECK-DAG: acc.declare_exit dataOperands(%[[GDP]] : !fir.ref<tuple<f32>>)
+! CHECK-DAG: acc.delete accPtr(%[[GDP]] : !fir.ref<tuple<f32>>) {dataClause = #acc<data_clause acc_copyin>{{.*}}}
+! CHECK-DAG: acc.terminator
+! CHECK-DAG: }
+
+contains
+
+  subroutine s()
+    implicit none
+    real :: pi
+    common /RIEMANN_COM/ pi
+!$acc declare copyin(/RIEMANN_COM/)
+  end subroutine s
+
+end program p
+
+
>From bd6d4f98943a0f8b1cd4d81a4971f39f2e060920 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Thu, 16 Oct 2025 07:54:42 -0700
Subject: [PATCH 5/6] change test name
---
 .../test/Lower/OpenACC/acc-declare-common-in-function.f90 | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90 b/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
index bffbe304c7078..5038f718517ac 100644
--- a/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
+++ b/flang/test/Lower/OpenACC/acc-declare-common-in-function.f90
@@ -8,8 +8,8 @@ program p
   implicit none
   real :: pi
   integer :: i
-  common /RIEMANN_COM/ pi
-!$acc declare copyin(/RIEMANN_COM/)
+  common /COM/ pi
+!$acc declare copyin(/COM/)
   data pi/0.0/
 
 ! CHECK-DAG: acc.global_ctor @{{.*}}_acc_ctor {
@@ -31,8 +31,8 @@ program p
   subroutine s()
     implicit none
     real :: pi
-    common /RIEMANN_COM/ pi
-!$acc declare copyin(/RIEMANN_COM/)
+    common /COM/ pi
+!$acc declare copyin(/COM/)
   end subroutine s
 
 end program p
>From b3f733ca077b05f50e9aeccbd2443dd56173080e Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Fri, 17 Oct 2025 10:34:03 -0700
Subject: [PATCH 6/6] refactor lamda to a standalone function
---
 flang/lib/Lower/OpenACC.cpp | 107 +++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 49 deletions(-)
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index f2afc75b7f6b3..410d4d3dad18c 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -4342,6 +4342,55 @@ genGlobalCtorsWithModifier(Fortran::lower::AbstractConverter &converter,
                                   dataClause);
 }
 
+// Emit module-level declare for COMMON symbols referenced by an ACC clause.
+// The emitter functor is responsible for creating ctor/dtor operations.
+template <typename EmitterFn>
+static void emitCommonGlobal(Fortran::lower::AbstractConverter &converter,
+    fir::FirOpBuilder &builder, const Fortran::parser::AccObject &obj,
+    mlir::acc::DataClause clause, EmitterFn &&emitCtorDtor) {
+  Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
+  if (!(sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
+        Fortran::semantics::FindCommonBlockContaining(sym))) {
+    return;
+  }
+
+  std::string globalName = converter.mangleName(sym);
+  fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
+  if (!globalOp) {
+    if (Fortran::semantics::FindEquivalenceSet(sym)) {
+      for (Fortran::semantics::EquivalenceObject eqObj :
+          *Fortran::semantics::FindEquivalenceSet(sym)) {
+        std::string eqName = converter.mangleName(eqObj.symbol);
+        globalOp = builder.getNamedGlobal(eqName);
+        if (globalOp)
+          break;
+      }
+    }
+  }
+  if (!globalOp) {
+    llvm::report_fatal_error("could not retrieve global symbol");
+  }
+
+  std::stringstream ctorName;
+  ctorName << globalName << "_acc_ctor";
+  if (builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
+          ctorName.str())) {
+    return;
+  }
+
+  mlir::Location operandLocation = genOperandLocation(converter, obj);
+  addDeclareAttr(builder, globalOp.getOperation(), clause);
+  mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
+  modBuilder.setInsertionPointAfter(globalOp);
+  std::stringstream asFortran;
+  asFortran << sym.name().ToString();
+
+  auto savedIP = builder.saveInsertionPoint();
+  emitCtorDtor(modBuilder, operandLocation, globalOp, clause, asFortran,
+      ctorName.str());
+  builder.restoreInsertionPoint(savedIP);
+}
+
 static void
 genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
                      Fortran::semantics::SemanticsContext &semanticsContext,
@@ -4354,50 +4403,6 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
   Fortran::lower::StatementContext stmtCtx;
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
 
-  // Inline helper to emit module-level declare for COMMON symbols in a clause.
-  auto emitCommonGlobal = [&](const Fortran::parser::AccObject &obj,
-                              mlir::acc::DataClause clause,
-                              auto emitCtorDtor) {
-    Fortran::semantics::Symbol &sym = getSymbolFromAccObject(obj);
-    if (!(sym.detailsIf<Fortran::semantics::CommonBlockDetails>() ||
-          Fortran::semantics::FindCommonBlockContaining(sym)))
-      return;
-
-    std::string globalName = converter.mangleName(sym);
-    fir::GlobalOp globalOp = builder.getNamedGlobal(globalName);
-    if (!globalOp) {
-      if (Fortran::semantics::FindEquivalenceSet(sym)) {
-        for (Fortran::semantics::EquivalenceObject eqObj :
-             *Fortran::semantics::FindEquivalenceSet(sym)) {
-          std::string eqName = converter.mangleName(eqObj.symbol);
-          globalOp = builder.getNamedGlobal(eqName);
-          if (globalOp)
-            break;
-        }
-      }
-    }
-    if (!globalOp)
-      llvm::report_fatal_error("could not retrieve global symbol");
-
-    std::stringstream ctorName;
-    ctorName << globalName << "_acc_ctor";
-    if (builder.getModule().lookupSymbol<mlir::acc::GlobalConstructorOp>(
-            ctorName.str()))
-      return;
-
-    mlir::Location operandLocation = genOperandLocation(converter, obj);
-    addDeclareAttr(builder, globalOp.getOperation(), clause);
-    mlir::OpBuilder modBuilder(builder.getModule().getBodyRegion());
-    modBuilder.setInsertionPointAfter(globalOp);
-    std::stringstream asFortran;
-    asFortran << sym.name().ToString();
-
-    auto savedIP = builder.saveInsertionPoint();
-    emitCtorDtor(modBuilder, operandLocation, globalOp, clause, asFortran,
-                 ctorName.str());
-    builder.restoreInsertionPoint(savedIP);
-  };
-
   for (const Fortran::parser::AccClause &clause : accClauseList.v) {
     if (const auto *copyClause =
             std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
@@ -4416,7 +4421,8 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
       for (const auto &obj : accObjectList.v) {
-        emitCommonGlobal(obj, mlir::acc::DataClause::acc_create,
+        emitCommonGlobal(converter, builder, obj,
+            mlir::acc::DataClause::acc_create,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
@@ -4449,7 +4455,8 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
       const auto ©inObjs =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
       for (const auto &obj : copyinObjs.v) {
-        emitCommonGlobal(obj, mlir::acc::DataClause::acc_copyin,
+        emitCommonGlobal(converter, builder, obj,
+            mlir::acc::DataClause::acc_copyin,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
@@ -4475,7 +4482,8 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
       const auto &accObjectList =
           std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
       for (const auto &obj : accObjectList.v) {
-        emitCommonGlobal(obj, mlir::acc::DataClause::acc_copyout,
+        emitCommonGlobal(converter, builder, obj,
+            mlir::acc::DataClause::acc_copyout,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
@@ -4504,7 +4512,8 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
                    std::get_if<Fortran::parser::AccClause::Link>(&clause.u)) {
       const auto &linkObjs = linkClause->v;
       for (const auto &obj : linkObjs.v) {
-        emitCommonGlobal(obj, mlir::acc::DataClause::acc_declare_link,
+        emitCommonGlobal(converter, builder, obj,
+            mlir::acc::DataClause::acc_declare_link,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
                 std::stringstream &asFortran, const std::string &ctorName) {
@@ -4526,7 +4535,7 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
                        &clause.u)) {
       const auto &devResObjs = deviceResidentClause->v;
       for (const auto &obj : devResObjs.v) {
-        emitCommonGlobal(obj,
+        emitCommonGlobal(converter, builder, obj,
             mlir::acc::DataClause::acc_declare_device_resident,
             [&](mlir::OpBuilder &modBuilder, mlir::Location operandLocation,
                 fir::GlobalOp globalOp, mlir::acc::DataClause clause,
    
    
More information about the flang-commits
mailing list