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
}
@@ -560,6 +569,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
560
569
ResolveOmpObjectList (x.v , Symbol::Flag::OmpExclusiveScan);
561
570
return false ;
562
571
}
572
+ void Post (const parser::OmpClause::Defaultmap &);
563
573
void Post (const parser::OmpDefaultClause &);
564
574
bool Pre (const parser::OmpClause::Shared &x) {
565
575
ResolveOmpObjectList (x.v , Symbol::Flag::OmpShared);
@@ -813,6 +823,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
813
823
Symbol::Flag::OmpLastPrivate, Symbol::Flag::OmpReduction,
814
824
Symbol::Flag::OmpLinear};
815
825
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
+
816
831
Symbol::Flags privateDataSharingAttributeFlags{Symbol::Flag::OmpPrivate,
817
832
Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate};
818
833
@@ -2223,6 +2238,28 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
2223
2238
return true ;
2224
2239
}
2225
2240
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
+
2226
2263
void OmpAttributeVisitor::Post (const parser::OmpDefaultClause &x) {
2227
2264
// The DEFAULT clause may also be used on METADIRECTIVE. In that case
2228
2265
// there is nothing to do.
@@ -2374,6 +2411,70 @@ static bool IsSymbolStaticStorageDuration(const Symbol &symbol) {
2374
2411
(ultSym.flags ().test (Symbol::Flag::InCommonBlock));
2375
2412
}
2376
2413
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
+
2377
2478
void OmpAttributeVisitor::CreateImplicitSymbols (const Symbol *symbol) {
2378
2479
if (!IsPrivatizable (symbol)) {
2379
2480
return ;
@@ -2465,7 +2566,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
2465
2566
2466
2567
bool taskGenDir = llvm::omp::taskGeneratingSet.test (dirContext.directive );
2467
2568
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 );
2469
2570
bool teamsDir = llvm::omp::allTeamsSet.test (dirContext.directive );
2470
2571
bool isStaticStorageDuration = IsSymbolStaticStorageDuration (*symbol);
2471
2572
@@ -2521,8 +2622,19 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
2521
2622
useLastDeclSymbol ();
2522
2623
PRINT_IMPLICIT_RULE (" 3) enclosing context" );
2523
2624
} 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
+ }
2525
2636
dsa = prevDSA;
2637
+ PRINT_IMPLICIT_RULE (" 4) not mapped target variable -> firstprivate" );
2526
2638
} else if (taskGenDir) {
2527
2639
// TODO 5) dummy arg in orphaned taskgen construct -> firstprivate
2528
2640
if (prevDSA.test (Symbol::Flag::OmpShared) ||
0 commit comments