2424#include " flang/Semantics/openmp-modifiers.h"
2525#include " flang/Semantics/symbol.h"
2626#include " flang/Semantics/tools.h"
27+ #include " flang/Support/Flags.h"
2728#include " llvm/Frontend/OpenMP/OMP.h.inc"
2829#include " llvm/Support/Debug.h"
2930#include < list>
@@ -56,6 +57,10 @@ template <typename T> class DirectiveAttributeVisitor {
5657 Scope &scope;
5758 Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC
5859 std::map<const Symbol *, Symbol::Flag> objectWithDSA;
60+ std::map<parser::OmpVariableCategory::Value,
61+ parser::OmpDefaultmapClause::ImplicitBehavior>
62+ defaultMap;
63+
5964 bool withinConstruct{false };
6065 std::int64_t associatedLoopLevel{0 };
6166 };
@@ -80,6 +85,10 @@ template <typename T> class DirectiveAttributeVisitor {
8085 GetContext ().directiveSource = dir;
8186 }
8287 Scope &currScope () { return GetContext ().scope ; }
88+ void AddContextDefaultmapBehaviour (parser::OmpVariableCategory::Value VarCat,
89+ parser::OmpDefaultmapClause::ImplicitBehavior ImpBehav) {
90+ GetContext ().defaultMap [VarCat] = ImpBehav;
91+ }
8392 void SetContextDefaultDSA (Symbol::Flag flag) {
8493 GetContext ().defaultDSA = flag;
8594 }
@@ -557,6 +566,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
557566 ResolveOmpObjectList (x.v , Symbol::Flag::OmpExclusiveScan);
558567 return false ;
559568 }
569+ void Post (const parser::OmpClause::Defaultmap &);
560570 void Post (const parser::OmpDefaultClause &);
561571 bool Pre (const parser::OmpClause::Shared &x) {
562572 ResolveOmpObjectList (x.v , Symbol::Flag::OmpShared);
@@ -810,6 +820,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
810820 Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction,
811821 Symbol::Flag::OmpLinear};
812822
823+ Symbol::Flags dataMappingAttributeFlags{Symbol::Flag::OmpMapTo,
824+ Symbol::Flag::OmpMapFrom, Symbol::Flag::OmpMapToFrom,
825+ Symbol::Flag::OmpMapStorage, Symbol::Flag::OmpMapDelete,
826+ Symbol::Flag::OmpIsDevicePtr, Symbol::Flag::OmpHasDeviceAddr};
827+
813828 Symbol::Flags privateDataSharingAttributeFlags{Symbol::Flag::OmpPrivate,
814829 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate};
815830
@@ -2214,6 +2229,28 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
22142229 return true ;
22152230}
22162231
2232+ void OmpAttributeVisitor::Post (const parser::OmpClause::Defaultmap &x) {
2233+ using ImplicitBehavior = parser::OmpDefaultmapClause::ImplicitBehavior;
2234+ using VariableCategory = parser::OmpVariableCategory;
2235+
2236+ VariableCategory::Value varCategory;
2237+ ImplicitBehavior impBehavior;
2238+
2239+ if (!dirContext_.empty ()) {
2240+ impBehavior = std::get<ImplicitBehavior>(x.v .t );
2241+
2242+ auto &modifiers{OmpGetModifiers (x.v )};
2243+ auto *maybeCategory{
2244+ OmpGetUniqueModifier<parser::OmpVariableCategory>(modifiers)};
2245+ if (maybeCategory)
2246+ varCategory = maybeCategory->v ;
2247+ else
2248+ varCategory = VariableCategory::Value::All;
2249+
2250+ AddContextDefaultmapBehaviour (varCategory, impBehavior);
2251+ }
2252+ }
2253+
22172254void OmpAttributeVisitor::Post (const parser::OmpDefaultClause &x) {
22182255 // The DEFAULT clause may also be used on METADIRECTIVE. In that case
22192256 // there is nothing to do.
@@ -2365,6 +2402,70 @@ static bool IsSymbolStaticStorageDuration(const Symbol &symbol) {
23652402 (ultSym.flags ().test (Symbol::Flag::InCommonBlock));
23662403}
23672404
2405+ static bool IsTargetCaptureImplicitlyFirstprivatizeable (const Symbol &symbol,
2406+ const Symbol::Flags &dsa, const Symbol::Flags &dataSharingAttributeFlags,
2407+ const Symbol::Flags &dataMappingAttributeFlags,
2408+ std::map<parser::OmpVariableCategory::Value,
2409+ parser::OmpDefaultmapClause::ImplicitBehavior>
2410+ defaultMap) {
2411+ // If a Defaultmap clause is present for the current target scope, and it has
2412+ // specified behaviour other than Firstprivate for scalars then we exit early,
2413+ // as it overrides the implicit Firstprivatization of scalars OpenMP rule.
2414+ if (!defaultMap.empty ()) {
2415+ if (llvm::is_contained (
2416+ defaultMap, parser::OmpVariableCategory::Value::All) &&
2417+ defaultMap[parser::OmpVariableCategory::Value::All] !=
2418+ parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) {
2419+ return false ;
2420+ }
2421+
2422+ if (llvm::is_contained (
2423+ defaultMap, parser::OmpVariableCategory::Value::Scalar) &&
2424+ defaultMap[parser::OmpVariableCategory::Value::Scalar] !=
2425+ parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) {
2426+ return false ;
2427+ }
2428+ }
2429+
2430+ auto checkSymbol = [&](const Symbol &checkSym) {
2431+ // if we're associated with any other flags we skip implicit privitization
2432+ // for now. If we're an allocatable, pointer or declare target, we're not
2433+ // implicitly firstprivitizeable under OpenMP restrictions.
2434+ // TODO: Relax restriction as we progress privitization and further
2435+ // investigate the flags we can intermix with.
2436+ if (!(dsa & (dataSharingAttributeFlags | dataMappingAttributeFlags))
2437+ .none () ||
2438+ !checkSym.flags ().none () || semantics::IsAssumedShape (checkSym) ||
2439+ semantics::IsAllocatableOrPointer (checkSym)) {
2440+ return false ;
2441+ }
2442+
2443+ // It is default firstprivatizeable as far as the OpenMP specification is
2444+ // concerned if it is a non-array scalar type that has been implicitly
2445+ // captured in a target region
2446+ const auto *type{checkSym.GetType ()};
2447+ if ((!checkSym.GetShape () || checkSym.GetShape ()->empty ()) &&
2448+ (type->category () ==
2449+ Fortran::semantics::DeclTypeSpec::Category::Numeric ||
2450+ type->category () ==
2451+ Fortran::semantics::DeclTypeSpec::Category::Logical ||
2452+ type->category () ==
2453+ Fortran::semantics::DeclTypeSpec::Category::Character)) {
2454+ return true ;
2455+ }
2456+ return false ;
2457+ };
2458+
2459+ if (checkSymbol (symbol)) {
2460+ const auto *hostAssoc{symbol.detailsIf <HostAssocDetails>()};
2461+ if (hostAssoc) {
2462+ return checkSymbol (hostAssoc->symbol ());
2463+ }
2464+ return true ;
2465+ }
2466+ return false ;
2467+ }
2468+
23682469void OmpAttributeVisitor::CreateImplicitSymbols (const Symbol *symbol) {
23692470 if (!IsPrivatizable (symbol)) {
23702471 return ;
@@ -2456,7 +2557,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
24562557
24572558 bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
24582559 bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2459- bool parallelDir = llvm::omp::allParallelSet .test (dirContext.directive );
2560+ bool parallelDir = llvm::omp::topParallelSet .test (dirContext.directive );
24602561 bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
24612562 bool isStaticStorageDuration = IsSymbolStaticStorageDuration (*symbol);
24622563
@@ -2512,8 +2613,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
25122613 useLastDeclSymbol ();
25132614 PRINT_IMPLICIT_RULE (" 3) enclosing context" );
25142615 } else if (targetDir) {
2515- // TODO 4) not mapped target variable -> firstprivate
2616+ // 4) not mapped target variable -> firstprivate
2617+ // - i.e. implicit, but meets OpenMP specification rules for
2618+ // firstprivate "promotion"
2619+ if (enableDelayedPrivatizationStaging &&
2620+ IsTargetCaptureImplicitlyFirstprivatizeable (*symbol, prevDSA,
2621+ dataSharingAttributeFlags, dataMappingAttributeFlags,
2622+ dirContext.defaultMap )) {
2623+ prevDSA.set (Symbol::Flag::OmpImplicit);
2624+ prevDSA.set (Symbol::Flag::OmpFirstPrivate);
2625+ makeSymbol (prevDSA);
2626+ }
25162627 dsa = prevDSA;
2628+ PRINT_IMPLICIT_RULE (" 4) not mapped target variable -> firstprivate" );
25172629 } else if (taskGenDir) {
25182630 // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
25192631 if (prevDSA.test (Symbol::Flag::OmpShared) ||
0 commit comments