@@ -718,6 +718,84 @@ static void genDataOperandOperations(
718718 }
719719}
720720
721+ template <typename GlobalCtorOrDtorOp, typename EntryOp, typename DeclareOp,
722+ typename ExitOp>
723+ static void createDeclareGlobalOp (mlir::OpBuilder &modBuilder,
724+ fir::FirOpBuilder &builder,
725+ mlir::Location loc, fir::GlobalOp globalOp,
726+ mlir::acc::DataClause clause,
727+ const std::string &declareGlobalName,
728+ bool implicit, std::stringstream &asFortran) {
729+ GlobalCtorOrDtorOp declareGlobalOp =
730+ GlobalCtorOrDtorOp::create (modBuilder, loc, declareGlobalName);
731+ builder.createBlock (&declareGlobalOp.getRegion (),
732+ declareGlobalOp.getRegion ().end (), {}, {});
733+ builder.setInsertionPointToEnd (&declareGlobalOp.getRegion ().back ());
734+
735+ fir::AddrOfOp addrOp = fir::AddrOfOp::create (
736+ builder, loc, fir::ReferenceType::get (globalOp.getType ()),
737+ globalOp.getSymbol ());
738+ addDeclareAttr (builder, addrOp, clause);
739+
740+ llvm::SmallVector<mlir::Value> bounds;
741+ EntryOp entryOp = createDataEntryOp<EntryOp>(
742+ builder, loc, addrOp.getResTy (), asFortran, bounds,
743+ /* structured=*/ false , implicit, clause, addrOp.getResTy ().getType (),
744+ /* async=*/ {}, /* asyncDeviceTypes=*/ {}, /* asyncOnlyDeviceTypes=*/ {});
745+ if constexpr (std::is_same_v<DeclareOp, mlir::acc::DeclareEnterOp>)
746+ DeclareOp::create (builder, loc,
747+ mlir::acc::DeclareTokenType::get (entryOp.getContext ()),
748+ mlir::ValueRange (entryOp.getAccVar ()));
749+ else
750+ DeclareOp::create (builder, loc, mlir::Value{},
751+ mlir::ValueRange (entryOp.getAccVar ()));
752+ if constexpr (std::is_same_v<GlobalCtorOrDtorOp,
753+ mlir::acc::GlobalDestructorOp>) {
754+ if constexpr (std::is_same_v<ExitOp, mlir::acc::DeclareLinkOp>) {
755+ // No destructor emission for declare link in this path to avoid
756+ // complex var/varType/varPtrPtr signatures. The ctor registers the link.
757+ } else if constexpr (std::is_same_v<ExitOp, mlir::acc::CopyoutOp> ||
758+ std::is_same_v<ExitOp, mlir::acc::UpdateHostOp>) {
759+ ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
760+ entryOp.getVar (), entryOp.getVarType (),
761+ entryOp.getBounds (), entryOp.getAsyncOperands (),
762+ entryOp.getAsyncOperandsDeviceTypeAttr (),
763+ entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
764+ /* structured=*/ false , /* implicit=*/ false ,
765+ builder.getStringAttr (*entryOp.getName ()));
766+ } else {
767+ ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
768+ entryOp.getBounds (), entryOp.getAsyncOperands (),
769+ entryOp.getAsyncOperandsDeviceTypeAttr (),
770+ entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
771+ /* structured=*/ false , /* implicit=*/ false ,
772+ builder.getStringAttr (*entryOp.getName ()));
773+ }
774+ }
775+ mlir::acc::TerminatorOp::create (builder, loc);
776+ modBuilder.setInsertionPointAfter (declareGlobalOp);
777+ }
778+
779+ template <typename EntryOp, typename ExitOp>
780+ static void
781+ emitCtorDtorPair (mlir::OpBuilder &modBuilder, fir::FirOpBuilder &builder,
782+ mlir::Location operandLocation, fir::GlobalOp globalOp,
783+ mlir::acc::DataClause clause, std::stringstream &asFortran,
784+ const std::string &ctorName) {
785+ createDeclareGlobalOp<mlir::acc::GlobalConstructorOp, EntryOp,
786+ mlir::acc::DeclareEnterOp, ExitOp>(
787+ modBuilder, builder, operandLocation, globalOp, clause, ctorName,
788+ /* implicit=*/ false , asFortran);
789+
790+ std::stringstream dtorName;
791+ dtorName << globalOp.getSymName ().str () << " _acc_dtor" ;
792+ createDeclareGlobalOp<mlir::acc::GlobalDestructorOp,
793+ mlir::acc::GetDevicePtrOp, mlir::acc::DeclareExitOp,
794+ ExitOp>(modBuilder, builder, operandLocation, globalOp,
795+ clause, dtorName.str (),
796+ /* implicit=*/ false , asFortran);
797+ }
798+
721799template <typename EntryOp, typename ExitOp>
722800static void genDeclareDataOperandOperations (
723801 const Fortran::parser::AccObjectList &objectList,
@@ -733,6 +811,37 @@ static void genDeclareDataOperandOperations(
733811 std::stringstream asFortran;
734812 mlir::Location operandLocation = genOperandLocation (converter, accObject);
735813 Fortran::semantics::Symbol &symbol = getSymbolFromAccObject (accObject);
814+ // Handle COMMON/global symbols via module-level ctor/dtor path.
815+ if (symbol.detailsIf <Fortran::semantics::CommonBlockDetails>() ||
816+ Fortran::semantics::FindCommonBlockContaining (symbol)) {
817+ emitCommonGlobal (
818+ converter, builder, accObject, dataClause,
819+ [&](mlir::OpBuilder &modBuilder, mlir::Location loc,
820+ fir::GlobalOp globalOp, mlir::acc::DataClause clause,
821+ std::stringstream &asFortranStr, const std::string &ctorName) {
822+ if constexpr (std::is_same_v<EntryOp, mlir::acc::DeclareLinkOp>) {
823+ createDeclareGlobalOp<
824+ mlir::acc::GlobalConstructorOp, mlir::acc::DeclareLinkOp,
825+ mlir::acc::DeclareEnterOp, mlir::acc::DeclareLinkOp>(
826+ modBuilder, builder, loc, globalOp, clause, ctorName,
827+ /* implicit=*/ false , asFortranStr);
828+ } else if constexpr (std::is_same_v<EntryOp, mlir::acc::CreateOp> ||
829+ std::is_same_v<EntryOp, mlir::acc::CopyinOp> ||
830+ std::is_same_v<
831+ EntryOp,
832+ mlir::acc::DeclareDeviceResidentOp> ||
833+ std::is_same_v<ExitOp, mlir::acc::CopyoutOp>) {
834+ emitCtorDtorPair<EntryOp, ExitOp>(modBuilder, builder, loc,
835+ globalOp, clause, asFortranStr,
836+ ctorName);
837+ } else {
838+ // No module-level ctor/dtor for this clause (e.g., deviceptr,
839+ // present). Handled via structured declare region only.
840+ return ;
841+ }
842+ });
843+ continue ;
844+ }
736845 Fortran::semantics::MaybeExpr designator = Fortran::common::visit (
737846 [&](auto &&s) { return ea.Analyze (s); }, accObject.u );
738847 fir::factory::AddrAndBoundsInfo info =
@@ -4098,49 +4207,6 @@ static void genACC(Fortran::lower::AbstractConverter &converter,
40984207 waitOp.setAsyncAttr (firOpBuilder.getUnitAttr ());
40994208}
41004209
4101- template <typename GlobalOp, typename EntryOp, typename DeclareOp,
4102- typename ExitOp>
4103- static void createDeclareGlobalOp (mlir::OpBuilder &modBuilder,
4104- fir::FirOpBuilder &builder,
4105- mlir::Location loc, fir::GlobalOp globalOp,
4106- mlir::acc::DataClause clause,
4107- const std::string &declareGlobalName,
4108- bool implicit, std::stringstream &asFortran) {
4109- GlobalOp declareGlobalOp =
4110- GlobalOp::create (modBuilder, loc, declareGlobalName);
4111- builder.createBlock (&declareGlobalOp.getRegion (),
4112- declareGlobalOp.getRegion ().end (), {}, {});
4113- builder.setInsertionPointToEnd (&declareGlobalOp.getRegion ().back ());
4114-
4115- fir::AddrOfOp addrOp = fir::AddrOfOp::create (
4116- builder, loc, fir::ReferenceType::get (globalOp.getType ()),
4117- globalOp.getSymbol ());
4118- addDeclareAttr (builder, addrOp, clause);
4119-
4120- llvm::SmallVector<mlir::Value> bounds;
4121- EntryOp entryOp = createDataEntryOp<EntryOp>(
4122- builder, loc, addrOp.getResTy (), asFortran, bounds,
4123- /* structured=*/ false , implicit, clause, addrOp.getResTy ().getType (),
4124- /* async=*/ {}, /* asyncDeviceTypes=*/ {}, /* asyncOnlyDeviceTypes=*/ {});
4125- if constexpr (std::is_same_v<DeclareOp, mlir::acc::DeclareEnterOp>)
4126- DeclareOp::create (builder, loc,
4127- mlir::acc::DeclareTokenType::get (entryOp.getContext ()),
4128- mlir::ValueRange (entryOp.getAccVar ()));
4129- else
4130- DeclareOp::create (builder, loc, mlir::Value{},
4131- mlir::ValueRange (entryOp.getAccVar ()));
4132- if constexpr (std::is_same_v<GlobalOp, mlir::acc::GlobalDestructorOp>) {
4133- ExitOp::create (builder, entryOp.getLoc (), entryOp.getAccVar (),
4134- entryOp.getBounds (), entryOp.getAsyncOperands (),
4135- entryOp.getAsyncOperandsDeviceTypeAttr (),
4136- entryOp.getAsyncOnlyAttr (), entryOp.getDataClause (),
4137- /* structured=*/ false , /* implicit=*/ false ,
4138- builder.getStringAttr (*entryOp.getName ()));
4139- }
4140- mlir::acc::TerminatorOp::create (builder, loc);
4141- modBuilder.setInsertionPointAfter (declareGlobalOp);
4142- }
4143-
41444210template <typename EntryOp>
41454211static void createDeclareAllocFunc (mlir::OpBuilder &modBuilder,
41464212 fir::FirOpBuilder &builder,
@@ -4317,6 +4383,66 @@ genGlobalCtorsWithModifier(Fortran::lower::AbstractConverter &converter,
43174383 dataClause);
43184384}
43194385
4386+ static fir::GlobalOp
4387+ lookupGlobalBySymbolOrEquivalence (Fortran::lower::AbstractConverter &converter,
4388+ fir::FirOpBuilder &builder,
4389+ const Fortran::semantics::Symbol &sym) {
4390+ const Fortran::semantics::Symbol *commonBlock =
4391+ Fortran::semantics::FindCommonBlockContaining (sym);
4392+ std::string globalName = commonBlock ? converter.mangleName (*commonBlock)
4393+ : converter.mangleName (sym);
4394+ if (fir::GlobalOp g = builder.getNamedGlobal (globalName)) {
4395+ return g;
4396+ }
4397+ // Not found: if not a COMMON member, try equivalence members
4398+ if (!commonBlock) {
4399+ if (const Fortran::semantics::EquivalenceSet *eqSet =
4400+ Fortran::semantics::FindEquivalenceSet (sym)) {
4401+ for (const Fortran::semantics::EquivalenceObject &eqObj : *eqSet) {
4402+ std::string eqName = converter.mangleName (eqObj.symbol );
4403+ if (fir::GlobalOp g = builder.getNamedGlobal (eqName))
4404+ return g;
4405+ }
4406+ }
4407+ }
4408+ return {};
4409+ }
4410+
4411+ template <typename EmitterFn>
4412+ static void emitCommonGlobal (Fortran::lower::AbstractConverter &converter,
4413+ fir::FirOpBuilder &builder,
4414+ const Fortran::parser::AccObject &obj,
4415+ mlir::acc::DataClause clause,
4416+ EmitterFn &&emitCtorDtor) {
4417+ Fortran::semantics::Symbol &sym = getSymbolFromAccObject (obj);
4418+ if (!(sym.detailsIf <Fortran::semantics::CommonBlockDetails>() ||
4419+ Fortran::semantics::FindCommonBlockContaining (sym)))
4420+ return ;
4421+
4422+ fir::GlobalOp globalOp =
4423+ lookupGlobalBySymbolOrEquivalence (converter, builder, sym);
4424+ if (!globalOp)
4425+ llvm::report_fatal_error (" could not retrieve global symbol" );
4426+
4427+ std::stringstream ctorName;
4428+ ctorName << globalOp.getSymName ().str () << " _acc_ctor" ;
4429+ if (builder.getModule ().lookupSymbol <mlir::acc::GlobalConstructorOp>(
4430+ ctorName.str ()))
4431+ return ;
4432+
4433+ mlir::Location operandLocation = genOperandLocation (converter, obj);
4434+ addDeclareAttr (builder, globalOp.getOperation (), clause);
4435+ mlir::OpBuilder modBuilder (builder.getModule ().getBodyRegion ());
4436+ modBuilder.setInsertionPointAfter (globalOp);
4437+ std::stringstream asFortran;
4438+ asFortran << sym.name ().ToString ();
4439+
4440+ auto savedIP = builder.saveInsertionPoint ();
4441+ emitCtorDtor (modBuilder, operandLocation, globalOp, clause, asFortran,
4442+ ctorName.str ());
4443+ builder.restoreInsertionPoint (savedIP);
4444+ }
4445+
43204446static void
43214447genDeclareInFunction (Fortran::lower::AbstractConverter &converter,
43224448 Fortran::semantics::SemanticsContext &semanticsContext,
@@ -4342,11 +4468,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
43424468 dataClauseOperands.end ());
43434469 } else if (const auto *createClause =
43444470 std::get_if<Fortran::parser::AccClause::Create>(&clause.u )) {
4345- const Fortran::parser::AccObjectListWithModifier &listWithModifier =
4346- createClause->v ;
4347- const auto &accObjectList =
4348- std::get<Fortran::parser::AccObjectList>(listWithModifier.t );
43494471 auto crtDataStart = dataClauseOperands.size ();
4472+ const auto &accObjectList =
4473+ std::get<Fortran::parser::AccObjectList>(createClause->v .t );
43504474 genDeclareDataOperandOperations<mlir::acc::CreateOp, mlir::acc::DeleteOp>(
43514475 accObjectList, converter, semanticsContext, stmtCtx,
43524476 dataClauseOperands, mlir::acc::DataClause::acc_create,
@@ -4378,11 +4502,9 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
43784502 } else if (const auto *copyoutClause =
43794503 std::get_if<Fortran::parser::AccClause::Copyout>(
43804504 &clause.u )) {
4381- const Fortran::parser::AccObjectListWithModifier &listWithModifier =
4382- copyoutClause->v ;
4383- const auto &accObjectList =
4384- std::get<Fortran::parser::AccObjectList>(listWithModifier.t );
43854505 auto crtDataStart = dataClauseOperands.size ();
4506+ const auto &accObjectList =
4507+ std::get<Fortran::parser::AccObjectList>(copyoutClause->v .t );
43864508 genDeclareDataOperandOperations<mlir::acc::CreateOp,
43874509 mlir::acc::CopyoutOp>(
43884510 accObjectList, converter, semanticsContext, stmtCtx,
@@ -4423,6 +4545,11 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
44234545 }
44244546 }
44254547
4548+ // If no structured operands were generated (all objects were COMMON),
4549+ // do not create a declare region.
4550+ if (dataClauseOperands.empty ())
4551+ return ;
4552+
44264553 mlir::func::FuncOp funcOp = builder.getFunction ();
44274554 auto ops = funcOp.getOps <mlir::acc::DeclareEnterOp>();
44284555 mlir::Value declareToken;
0 commit comments