24
24
#include " flang/Semantics/openmp-modifiers.h"
25
25
#include " flang/Semantics/symbol.h"
26
26
#include " flang/Semantics/tools.h"
27
+ #include " flang/Support/Flags.h"
27
28
#include " llvm/Frontend/OpenMP/OMP.h.inc"
28
29
#include " llvm/Support/Debug.h"
29
30
#include < list>
@@ -56,6 +57,10 @@ template <typename T> class DirectiveAttributeVisitor {
56
57
Scope &scope;
57
58
Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC
58
59
std::map<const Symbol *, Symbol::Flag> objectWithDSA;
60
+ std::map<parser::OmpVariableCategory::Value,
61
+ parser::OmpDefaultmapClause::ImplicitBehavior>
62
+ defaultMap;
63
+
59
64
bool withinConstruct{false };
60
65
std::int64_t associatedLoopLevel{0 };
61
66
};
@@ -80,6 +85,10 @@ template <typename T> class DirectiveAttributeVisitor {
80
85
GetContext ().directiveSource = dir;
81
86
}
82
87
Scope &currScope () { return GetContext ().scope ; }
88
+ void AddContextDefaultmapBehaviour (parser::OmpVariableCategory::Value VarCat,
89
+ parser::OmpDefaultmapClause::ImplicitBehavior ImpBehav) {
90
+ GetContext ().defaultMap [VarCat] = ImpBehav;
91
+ }
83
92
void SetContextDefaultDSA (Symbol::Flag flag) {
84
93
GetContext ().defaultDSA = flag;
85
94
}
@@ -557,6 +566,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
557
566
ResolveOmpObjectList (x.v , Symbol::Flag::OmpExclusiveScan);
558
567
return false ;
559
568
}
569
+ void Post (const parser::OmpClause::Defaultmap &);
560
570
void Post (const parser::OmpDefaultClause &);
561
571
bool Pre (const parser::OmpClause::Shared &x) {
562
572
ResolveOmpObjectList (x.v , Symbol::Flag::OmpShared);
@@ -810,6 +820,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
810
820
Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction,
811
821
Symbol::Flag::OmpLinear};
812
822
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
+
813
828
Symbol::Flags privateDataSharingAttributeFlags{Symbol::Flag::OmpPrivate,
814
829
Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate};
815
830
@@ -2214,6 +2229,28 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
2214
2229
return true ;
2215
2230
}
2216
2231
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
+
2217
2254
void OmpAttributeVisitor::Post (const parser::OmpDefaultClause &x) {
2218
2255
// The DEFAULT clause may also be used on METADIRECTIVE. In that case
2219
2256
// there is nothing to do.
@@ -2365,6 +2402,70 @@ static bool IsSymbolStaticStorageDuration(const Symbol &symbol) {
2365
2402
(ultSym.flags ().test (Symbol::Flag::InCommonBlock));
2366
2403
}
2367
2404
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
+
2368
2469
void OmpAttributeVisitor::CreateImplicitSymbols (const Symbol *symbol) {
2369
2470
if (!IsPrivatizable (symbol)) {
2370
2471
return ;
@@ -2456,7 +2557,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
2456
2557
2457
2558
bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2458
2559
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 );
2460
2561
bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2461
2562
bool isStaticStorageDuration = IsSymbolStaticStorageDuration (*symbol);
2462
2563
@@ -2512,8 +2613,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
2512
2613
useLastDeclSymbol ();
2513
2614
PRINT_IMPLICIT_RULE (" 3) enclosing context" );
2514
2615
} 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
+ }
2516
2627
dsa = prevDSA;
2628
+ PRINT_IMPLICIT_RULE (" 4) not mapped target variable -> firstprivate" );
2517
2629
} else if (taskGenDir) {
2518
2630
// TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
2519
2631
if (prevDSA.test (Symbol::Flag::OmpShared) ||
0 commit comments