diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h --- a/flang/include/flang/Lower/OpenMP.h +++ b/flang/include/flang/Lower/OpenMP.h @@ -53,6 +53,7 @@ const parser::OpenMPDeclarativeConstruct &); int64_t getCollapseValue(const Fortran::parser::OmpClauseList &clauseList); void genThreadprivateOp(AbstractConverter &, const pft::Variable &); +void genDeclareTargetIntGlobal(AbstractConverter &, const pft::Variable &); void genOpenMPReduction(AbstractConverter &, const Fortran::parser::OmpClauseList &clauseList); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -4013,10 +4013,15 @@ void instantiateVar(const Fortran::lower::pft::Variable &var, Fortran::lower::AggregateStoreMap &storeMap) { Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap); - if (var.hasSymbol() && - var.getSymbol().test( - Fortran::semantics::Symbol::Flag::OmpThreadprivate)) - Fortran::lower::genThreadprivateOp(*this, var); + if (var.hasSymbol()) { + if (var.getSymbol().test( + Fortran::semantics::Symbol::Flag::OmpThreadprivate)) + Fortran::lower::genThreadprivateOp(*this, var); + + if (var.getSymbol().test( + Fortran::semantics::Symbol::Flag::OmpDeclareTarget)) + Fortran::lower::genDeclareTargetIntGlobal(*this, var); + } } /// Start translation of a function. diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -2641,6 +2641,39 @@ ompConstruct.u); } +fir::GlobalOp globalInitialization(Fortran::lower::AbstractConverter &converter, + fir::FirOpBuilder &firOpBuilder, + const Fortran::semantics::Symbol &sym, + const Fortran::lower::pft::Variable &var, + mlir::Location currentLocation) { + mlir::Type ty = converter.genType(sym); + std::string globalName = converter.mangleName(sym); + mlir::StringAttr linkage = firOpBuilder.createInternalLinkage(); + fir::GlobalOp global = + firOpBuilder.createGlobal(currentLocation, ty, globalName, linkage); + + // Create default initialization for non-character scalar. + if (Fortran::semantics::IsAllocatableOrPointer(sym)) { + mlir::Type baseAddrType = ty.dyn_cast().getEleTy(); + Fortran::lower::createGlobalInitialization( + firOpBuilder, global, [&](fir::FirOpBuilder &b) { + mlir::Value nullAddr = + b.createNullConstant(currentLocation, baseAddrType); + mlir::Value box = + b.create(currentLocation, ty, nullAddr); + b.create(currentLocation, box); + }); + } else { + Fortran::lower::createGlobalInitialization( + firOpBuilder, global, [&](fir::FirOpBuilder &b) { + mlir::Value undef = b.create(currentLocation, ty); + b.create(currentLocation, undef); + }); + } + + return global; +} + void Fortran::lower::genThreadprivateOp( Fortran::lower::AbstractConverter &converter, const Fortran::lower::pft::Variable &var) { @@ -2670,30 +2703,9 @@ // variable in main program, and it has implicit SAVE attribute. Take it as // with SAVE attribute, so to create GlobalOp for it to simplify the // translation to LLVM IR. - mlir::Type ty = converter.genType(sym); - std::string globalName = converter.mangleName(sym); - mlir::StringAttr linkage = firOpBuilder.createInternalLinkage(); - fir::GlobalOp global = - firOpBuilder.createGlobal(currentLocation, ty, globalName, linkage); - - // Create default initialization for non-character scalar. - if (Fortran::semantics::IsAllocatableOrPointer(sym)) { - mlir::Type baseAddrType = ty.dyn_cast().getEleTy(); - Fortran::lower::createGlobalInitialization( - firOpBuilder, global, [&](fir::FirOpBuilder &b) { - mlir::Value nullAddr = - b.createNullConstant(currentLocation, baseAddrType); - mlir::Value box = - b.create(currentLocation, ty, nullAddr); - b.create(currentLocation, box); - }); - } else { - Fortran::lower::createGlobalInitialization( - firOpBuilder, global, [&](fir::FirOpBuilder &b) { - mlir::Value undef = b.create(currentLocation, ty); - b.create(currentLocation, undef); - }); - } + fir::GlobalOp global = globalInitialization(converter, firOpBuilder, sym, + var, currentLocation); + mlir::Value symValue = firOpBuilder.create( currentLocation, global.resultType(), global.getSymbol()); symThreadprivateValue = firOpBuilder.create( @@ -2716,6 +2728,23 @@ converter.bindSymbol(sym, symThreadprivateExv); } +// This function replicates threadprivate's behaviour of generating +// an internal fir.GlobalOp for non-global variables in the main program +// that have the implicit SAVE attribute, to simplifiy LLVM-IR and MLIR +// generation. +void Fortran::lower::genDeclareTargetIntGlobal( + Fortran::lower::AbstractConverter &converter, + const Fortran::lower::pft::Variable &var) { + if (!var.isGlobal()) { + // A non-global variable which can be in a declare target directive must + // be a variable in the main program, and it has the implicit SAVE + // attribute. We create a GlobalOp for it to simplify the translation to + // LLVM IR. + globalInitialization(converter, converter.getFirOpBuilder(), + var.getSymbol(), var, converter.getCurrentLocation()); + } +} + void handleDeclareTarget(Fortran::lower::AbstractConverter &converter, Fortran::lower::pft::Evaluation &eval, const Fortran::parser::OpenMPDeclareTargetConstruct diff --git a/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 b/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-declare-target-program-var.f90 @@ -0,0 +1,12 @@ +!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s + +PROGRAM main + ! CHECK-DAG: %0 = fir.alloca f32 {bindc_name = "i", uniq_name = "_QFEi"} + REAL :: I + ! CHECK-DAG: fir.global internal @_QFEi {omp.declare_target = #omp.declaretarget} : f32 { + ! CHECK-DAG: %0 = fir.undefined f32 + ! CHECK-DAG: fir.has_value %0 : f32 + ! CHECK-DAG: } + !$omp declare target(I) +END