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 }
@@ -560,6 +569,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
560569 ResolveOmpObjectList (x.v , Symbol::Flag::OmpExclusiveScan);
561570 return false ;
562571 }
572+ void Post (const parser::OmpClause::Defaultmap &);
563573 void Post (const parser::OmpDefaultClause &);
564574 bool Pre (const parser::OmpClause::Shared &x) {
565575 ResolveOmpObjectList (x.v , Symbol::Flag::OmpShared);
@@ -813,6 +823,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
813823 Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction,
814824 Symbol::Flag::OmpLinear};
815825
826+ Symbol::Flags dataMappingAttributeFlags{Symbol::Flag::OmpMapTo,
827+ Symbol::Flag::OmpMapFrom, Symbol::Flag::OmpMapToFrom,
828+ Symbol::Flag::OmpMapStorage, Symbol::Flag::OmpMapDelete,
829+ Symbol::Flag::OmpIsDevicePtr, Symbol::Flag::OmpHasDeviceAddr};
830+
816831 Symbol::Flags privateDataSharingAttributeFlags{Symbol::Flag::OmpPrivate,
817832 Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate};
818833
@@ -2223,6 +2238,28 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
22232238 return true ;
22242239}
22252240
2241+ void OmpAttributeVisitor::Post (const parser::OmpClause::Defaultmap &x) {
2242+ using ImplicitBehavior = parser::OmpDefaultmapClause::ImplicitBehavior;
2243+ using VariableCategory = parser::OmpVariableCategory;
2244+
2245+ VariableCategory::Value varCategory;
2246+ ImplicitBehavior impBehavior;
2247+
2248+ if (!dirContext_.empty ()) {
2249+ impBehavior = std::get<ImplicitBehavior>(x.v .t );
2250+
2251+ auto &modifiers{OmpGetModifiers (x.v )};
2252+ auto *maybeCategory{
2253+ OmpGetUniqueModifier<parser::OmpVariableCategory>(modifiers)};
2254+ if (maybeCategory)
2255+ varCategory = maybeCategory->v ;
2256+ else
2257+ varCategory = VariableCategory::Value::All;
2258+
2259+ AddContextDefaultmapBehaviour (varCategory, impBehavior);
2260+ }
2261+ }
2262+
22262263void OmpAttributeVisitor::Post (const parser::OmpDefaultClause &x) {
22272264 // The DEFAULT clause may also be used on METADIRECTIVE. In that case
22282265 // there is nothing to do.
@@ -2374,6 +2411,70 @@ static bool IsSymbolStaticStorageDuration(const Symbol &symbol) {
23742411 (ultSym.flags ().test (Symbol::Flag::InCommonBlock));
23752412}
23762413
2414+ static bool IsTargetCaptureImplicitlyFirstprivatizeable (const Symbol &symbol,
2415+ const Symbol::Flags &dsa, const Symbol::Flags &dataSharingAttributeFlags,
2416+ const Symbol::Flags &dataMappingAttributeFlags,
2417+ std::map<parser::OmpVariableCategory::Value,
2418+ parser::OmpDefaultmapClause::ImplicitBehavior>
2419+ defaultMap) {
2420+ // If a Defaultmap clause is present for the current target scope, and it has
2421+ // specified behaviour other than Firstprivate for scalars then we exit early,
2422+ // as it overrides the implicit Firstprivatization of scalars OpenMP rule.
2423+ if (!defaultMap.empty ()) {
2424+ if (llvm::is_contained (
2425+ defaultMap, parser::OmpVariableCategory::Value::All) &&
2426+ defaultMap[parser::OmpVariableCategory::Value::All] !=
2427+ parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) {
2428+ return false ;
2429+ }
2430+
2431+ if (llvm::is_contained (
2432+ defaultMap, parser::OmpVariableCategory::Value::Scalar) &&
2433+ defaultMap[parser::OmpVariableCategory::Value::Scalar] !=
2434+ parser::OmpDefaultmapClause::ImplicitBehavior::Firstprivate) {
2435+ return false ;
2436+ }
2437+ }
2438+
2439+ auto checkSymbol = [&](const Symbol &checkSym) {
2440+ // if we're associated with any other flags we skip implicit privitization
2441+ // for now. If we're an allocatable, pointer or declare target, we're not
2442+ // implicitly firstprivitizeable under OpenMP restrictions.
2443+ // TODO: Relax restriction as we progress privitization and further
2444+ // investigate the flags we can intermix with.
2445+ if (!(dsa & (dataSharingAttributeFlags | dataMappingAttributeFlags))
2446+ .none () ||
2447+ !checkSym.flags ().none () || semantics::IsAssumedShape (checkSym) ||
2448+ semantics::IsAllocatableOrPointer (checkSym)) {
2449+ return false ;
2450+ }
2451+
2452+ // It is default firstprivatizeable as far as the OpenMP specification is
2453+ // concerned if it is a non-array scalar type that has been implicitly
2454+ // captured in a target region
2455+ const auto *type{checkSym.GetType ()};
2456+ if ((!checkSym.GetShape () || checkSym.GetShape ()->empty ()) &&
2457+ (type->category () ==
2458+ Fortran::semantics::DeclTypeSpec::Category::Numeric ||
2459+ type->category () ==
2460+ Fortran::semantics::DeclTypeSpec::Category::Logical ||
2461+ type->category () ==
2462+ Fortran::semantics::DeclTypeSpec::Category::Character)) {
2463+ return true ;
2464+ }
2465+ return false ;
2466+ };
2467+
2468+ if (checkSymbol (symbol)) {
2469+ const auto *hostAssoc{symbol.detailsIf <HostAssocDetails>()};
2470+ if (hostAssoc) {
2471+ return checkSymbol (hostAssoc->symbol ());
2472+ }
2473+ return true ;
2474+ }
2475+ return false ;
2476+ }
2477+
23772478void OmpAttributeVisitor::CreateImplicitSymbols (const Symbol *symbol) {
23782479 if (!IsPrivatizable (symbol)) {
23792480 return ;
@@ -2465,7 +2566,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
24652566
24662567 bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
24672568 bool targetDir = llvm::omp::allTargetSet.test (dirContext.directive );
2468- bool parallelDir = llvm::omp::allParallelSet .test (dirContext.directive );
2569+ bool parallelDir = llvm::omp::topParallelSet .test (dirContext.directive );
24692570 bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
24702571 bool isStaticStorageDuration = IsSymbolStaticStorageDuration (*symbol);
24712572
@@ -2521,8 +2622,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
25212622 useLastDeclSymbol ();
25222623 PRINT_IMPLICIT_RULE (" 3) enclosing context" );
25232624 } else if (targetDir) {
2524- // TODO 4) not mapped target variable -> firstprivate
2625+ // 4) not mapped target variable -> firstprivate
2626+ // - i.e. implicit, but meets OpenMP specification rules for
2627+ // firstprivate "promotion"
2628+ if (enableDelayedPrivatizationStaging &&
2629+ IsTargetCaptureImplicitlyFirstprivatizeable (*symbol, prevDSA,
2630+ dataSharingAttributeFlags, dataMappingAttributeFlags,
2631+ dirContext.defaultMap )) {
2632+ prevDSA.set (Symbol::Flag::OmpImplicit);
2633+ prevDSA.set (Symbol::Flag::OmpFirstPrivate);
2634+ makeSymbol (prevDSA);
2635+ }
25252636 dsa = prevDSA;
2637+ PRINT_IMPLICIT_RULE (" 4) not mapped target variable -> firstprivate" );
25262638 } else if (taskGenDir) {
25272639 // TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
25282640 if (prevDSA.test (Symbol::Flag::OmpShared) ||
0 commit comments