@@ -62,14 +62,15 @@ class DSAStackTy {
62
62
struct DSAVarData {
63
63
OpenMPDirectiveKind DKind = OMPD_unknown;
64
64
OpenMPClauseKind CKind = OMPC_unknown;
65
+ unsigned Modifier = 0;
65
66
const Expr *RefExpr = nullptr;
66
67
DeclRefExpr *PrivateCopy = nullptr;
67
68
SourceLocation ImplicitDSALoc;
68
69
DSAVarData() = default;
69
70
DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
70
71
const Expr *RefExpr, DeclRefExpr *PrivateCopy,
71
- SourceLocation ImplicitDSALoc)
72
- : DKind(DKind), CKind(CKind), RefExpr(RefExpr),
72
+ SourceLocation ImplicitDSALoc, unsigned Modifier )
73
+ : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr),
73
74
PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
74
75
};
75
76
using OperatorOffsetTy =
@@ -80,6 +81,7 @@ class DSAStackTy {
80
81
private:
81
82
struct DSAInfo {
82
83
OpenMPClauseKind Attributes = OMPC_unknown;
84
+ unsigned Modifier = 0;
83
85
/// Pointer to a reference expression and a flag which shows that the
84
86
/// variable is marked as lastprivate(true) or not (false).
85
87
llvm::PointerIntPair<const Expr *, 1, bool> RefExpr;
@@ -164,6 +166,8 @@ class DSAStackTy {
164
166
/// List of globals marked as declare target link in this target region
165
167
/// (isOpenMPTargetExecutionDirective(Directive) == true).
166
168
llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
169
+ /// List of decls used in inclusive/exclusive clauses of the scan directive.
170
+ llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
167
171
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
168
172
Scope *CurScope, SourceLocation Loc)
169
173
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -469,9 +473,22 @@ class DSAStackTy {
469
473
/// parent directive.
470
474
const ValueDecl *getParentLoopControlVariable(unsigned I) const;
471
475
476
+ /// Marks the specified decl \p D as used in scan directive.
477
+ void markDeclAsUsedInScanDirective(ValueDecl *D) {
478
+ if (SharingMapTy *Stack = getSecondOnStackOrNull())
479
+ Stack->UsedInScanDirective.insert(D);
480
+ }
481
+
482
+ /// Checks if the specified declaration was used in the inner scan directive.
483
+ bool isUsedInScanDirective(ValueDecl *D) const {
484
+ if (const SharingMapTy *Stack = getTopOfStackOrNull())
485
+ return Stack->UsedInScanDirective.count(D) > 0;
486
+ return false;
487
+ }
488
+
472
489
/// Adds explicit data sharing attribute to the specified declaration.
473
490
void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
474
- DeclRefExpr *PrivateCopy = nullptr);
491
+ DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0 );
475
492
476
493
/// Adds additional information for the reduction items with the reduction id
477
494
/// represented as an operator.
@@ -1079,6 +1096,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
1079
1096
DVar.PrivateCopy = Data.PrivateCopy;
1080
1097
DVar.CKind = Data.Attributes;
1081
1098
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1099
+ DVar.Modifier = Data.Modifier;
1082
1100
return DVar;
1083
1101
}
1084
1102
@@ -1226,19 +1244,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
1226
1244
}
1227
1245
1228
1246
void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
1229
- DeclRefExpr *PrivateCopy) {
1247
+ DeclRefExpr *PrivateCopy, unsigned Modifier ) {
1230
1248
D = getCanonicalDecl(D);
1231
1249
if (A == OMPC_threadprivate) {
1232
1250
DSAInfo &Data = Threadprivates[D];
1233
1251
Data.Attributes = A;
1234
1252
Data.RefExpr.setPointer(E);
1235
1253
Data.PrivateCopy = nullptr;
1254
+ Data.Modifier = Modifier;
1236
1255
} else {
1237
1256
DSAInfo &Data = getTopOfStack().SharingMap[D];
1238
1257
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
1239
1258
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
1240
1259
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
1241
1260
(isLoopControlVariable(D).first && A == OMPC_private));
1261
+ Data.Modifier = Modifier;
1242
1262
if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
1243
1263
Data.RefExpr.setInt(/*IntVal=*/true);
1244
1264
return;
@@ -1250,6 +1270,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
1250
1270
Data.PrivateCopy = PrivateCopy;
1251
1271
if (PrivateCopy) {
1252
1272
DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
1273
+ Data.Modifier = Modifier;
1253
1274
Data.Attributes = A;
1254
1275
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
1255
1276
Data.PrivateCopy = nullptr;
@@ -1355,7 +1376,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
1355
1376
"set.");
1356
1377
TaskgroupDescriptor = I->TaskgroupReductionRef;
1357
1378
return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
1358
- Data.PrivateCopy, I->DefaultAttrLoc);
1379
+ Data.PrivateCopy, I->DefaultAttrLoc, /*Modifier=*/0 );
1359
1380
}
1360
1381
return DSAVarData();
1361
1382
}
@@ -1380,7 +1401,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
1380
1401
"set.");
1381
1402
TaskgroupDescriptor = I->TaskgroupReductionRef;
1382
1403
return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
1383
- Data.PrivateCopy, I->DefaultAttrLoc);
1404
+ Data.PrivateCopy, I->DefaultAttrLoc, /*Modifier=*/0 );
1384
1405
}
1385
1406
return DSAVarData();
1386
1407
}
@@ -1455,6 +1476,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
1455
1476
if (TI != Threadprivates.end()) {
1456
1477
DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
1457
1478
DVar.CKind = OMPC_threadprivate;
1479
+ DVar.Modifier = TI->getSecond().Modifier;
1458
1480
return DVar;
1459
1481
}
1460
1482
if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
@@ -1538,15 +1560,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
1538
1560
const_iterator EndI = end();
1539
1561
if (FromParent && I != EndI)
1540
1562
++I;
1541
- auto It = I->SharingMap.find(D);
1542
- if (It != I->SharingMap.end()) {
1543
- const DSAInfo &Data = It->getSecond();
1544
- DVar.RefExpr = Data.RefExpr.getPointer();
1545
- DVar.PrivateCopy = Data.PrivateCopy;
1546
- DVar.CKind = Data.Attributes;
1547
- DVar.ImplicitDSALoc = I->DefaultAttrLoc;
1548
- DVar.DKind = I->Directive;
1549
- return DVar;
1563
+ if (I != EndI) {
1564
+ auto It = I->SharingMap.find(D);
1565
+ if (It != I->SharingMap.end()) {
1566
+ const DSAInfo &Data = It->getSecond();
1567
+ DVar.RefExpr = Data.RefExpr.getPointer();
1568
+ DVar.PrivateCopy = Data.PrivateCopy;
1569
+ DVar.CKind = Data.Attributes;
1570
+ DVar.ImplicitDSALoc = I->DefaultAttrLoc;
1571
+ DVar.DKind = I->Directive;
1572
+ DVar.Modifier = Data.Modifier;
1573
+ return DVar;
1574
+ }
1550
1575
}
1551
1576
1552
1577
DVar.CKind = OMPC_shared;
@@ -1584,6 +1609,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
1584
1609
const_iterator EndI = end();
1585
1610
if (FromParent && I != EndI)
1586
1611
++I;
1612
+ if (I == EndI)
1613
+ return DVar;
1587
1614
auto It = I->SharingMap.find(D);
1588
1615
if (It != I->SharingMap.end()) {
1589
1616
const DSAInfo &Data = It->getSecond();
@@ -1592,6 +1619,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
1592
1619
DVar.CKind = Data.Attributes;
1593
1620
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
1594
1621
DVar.DKind = I->Directive;
1622
+ DVar.Modifier = Data.Modifier;
1595
1623
}
1596
1624
1597
1625
return DVar;
@@ -2315,11 +2343,64 @@ void Sema::EndOpenMPClause() {
2315
2343
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
2316
2344
}
2317
2345
2318
- static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
2319
- ArrayRef<OMPClause *> Clauses);
2320
2346
static std::pair<ValueDecl *, bool>
2321
2347
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
2322
2348
SourceRange &ERange, bool AllowArraySection = false);
2349
+
2350
+ /// Check consistency of the reduction clauses.
2351
+ static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
2352
+ ArrayRef<OMPClause *> Clauses) {
2353
+ bool InscanFound = false;
2354
+ SourceLocation InscanLoc;
2355
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions.
2356
+ // A reduction clause without the inscan reduction-modifier may not appear on
2357
+ // a construct on which a reduction clause with the inscan reduction-modifier
2358
+ // appears.
2359
+ for (OMPClause *C : Clauses) {
2360
+ if (C->getClauseKind() != OMPC_reduction)
2361
+ continue;
2362
+ auto *RC = cast<OMPReductionClause>(C);
2363
+ if (RC->getModifier() == OMPC_REDUCTION_inscan) {
2364
+ InscanFound = true;
2365
+ InscanLoc = RC->getModifierLoc();
2366
+ break;
2367
+ }
2368
+ }
2369
+ if (InscanFound) {
2370
+ for (OMPClause *C : Clauses) {
2371
+ if (C->getClauseKind() != OMPC_reduction)
2372
+ continue;
2373
+ auto *RC = cast<OMPReductionClause>(C);
2374
+ if (RC->getModifier() != OMPC_REDUCTION_inscan) {
2375
+ S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown
2376
+ ? RC->getBeginLoc()
2377
+ : RC->getModifierLoc(),
2378
+ diag::err_omp_inscan_reduction_expected);
2379
+ S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction);
2380
+ continue;
2381
+ }
2382
+ for (Expr *Ref : RC->varlists()) {
2383
+ assert(Ref && "NULL expr in OpenMP nontemporal clause.");
2384
+ SourceLocation ELoc;
2385
+ SourceRange ERange;
2386
+ Expr *SimpleRefExpr = Ref;
2387
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
2388
+ /*AllowArraySection=*/true);
2389
+ ValueDecl *D = Res.first;
2390
+ if (!D)
2391
+ continue;
2392
+ if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) {
2393
+ S.Diag(Ref->getExprLoc(),
2394
+ diag::err_omp_reduction_not_inclusive_exclusive)
2395
+ << Ref->getSourceRange();
2396
+ }
2397
+ }
2398
+ }
2399
+ }
2400
+ }
2401
+
2402
+ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
2403
+ ArrayRef<OMPClause *> Clauses);
2323
2404
static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
2324
2405
bool WithInit);
2325
2406
@@ -2396,6 +2477,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
2396
2477
// Check allocate clauses.
2397
2478
if (!CurContext->isDependentContext())
2398
2479
checkAllocateClauses(*this, DSAStack, D->clauses());
2480
+ checkReductionClauses(*this, DSAStack, D->clauses());
2399
2481
}
2400
2482
2401
2483
DSAStack->pop();
@@ -14111,9 +14193,11 @@ struct ReductionData {
14111
14193
SmallVector<Decl *, 4> ExprCaptures;
14112
14194
/// List of postupdate expressions.
14113
14195
SmallVector<Expr *, 4> ExprPostUpdates;
14196
+ /// Reduction modifier.
14197
+ unsigned RedModifier = 0;
14114
14198
ReductionData() = delete;
14115
14199
/// Reserves required memory for the reduction data.
14116
- ReductionData(unsigned Size) {
14200
+ ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier ) {
14117
14201
Vars.reserve(Size);
14118
14202
Privates.reserve(Size);
14119
14203
LHSs.reserve(Size);
@@ -14831,7 +14915,8 @@ static bool actOnOMPReductionKindClause(
14831
14915
}
14832
14916
// All reduction items are still marked as reduction (to do not increase
14833
14917
// code base size).
14834
- Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
14918
+ Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref,
14919
+ RD.RedModifier);
14835
14920
if (CurrDir == OMPD_taskgroup) {
14836
14921
if (DeclareReductionRef.isUsable())
14837
14922
Stack->addTaskgroupReductionData(D, ReductionIdRange,
@@ -14858,8 +14943,22 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
14858
14943
<< getOpenMPClauseName(OMPC_reduction);
14859
14944
return nullptr;
14860
14945
}
14946
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions
14947
+ // A reduction clause with the inscan reduction-modifier may only appear on a
14948
+ // worksharing-loop construct, a worksharing-loop SIMD construct, a simd
14949
+ // construct, a parallel worksharing-loop construct or a parallel
14950
+ // worksharing-loop SIMD construct.
14951
+ if (Modifier == OMPC_REDUCTION_inscan &&
14952
+ (DSAStack->getCurrentDirective() != OMPD_for &&
14953
+ DSAStack->getCurrentDirective() != OMPD_for_simd &&
14954
+ DSAStack->getCurrentDirective() != OMPD_simd &&
14955
+ DSAStack->getCurrentDirective() != OMPD_parallel_for &&
14956
+ DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) {
14957
+ Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction);
14958
+ return nullptr;
14959
+ }
14861
14960
14862
- ReductionData RD(VarList.size());
14961
+ ReductionData RD(VarList.size(), Modifier );
14863
14962
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
14864
14963
StartLoc, LParenLoc, ColonLoc, EndLoc,
14865
14964
ReductionIdScopeSpec, ReductionId,
@@ -18161,6 +18260,19 @@ OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList,
18161
18260
if (!D)
18162
18261
continue;
18163
18262
18263
+ const DSAStackTy::DSAVarData DVar =
18264
+ DSAStack->getTopDSA(D, /*FromParent=*/true);
18265
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
18266
+ // A list item that appears in the inclusive or exclusive clause must appear
18267
+ // in a reduction clause with the inscan modifier on the enclosing
18268
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
18269
+ if (DVar.CKind != OMPC_reduction ||
18270
+ DVar.Modifier != OMPC_REDUCTION_inscan)
18271
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
18272
+ << RefExpr->getSourceRange();
18273
+
18274
+ if (DSAStack->getParentDirective() != OMPD_unknown)
18275
+ DSAStack->markDeclAsUsedInScanDirective(D);
18164
18276
Vars.push_back(RefExpr);
18165
18277
}
18166
18278
@@ -18189,6 +18301,21 @@ OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList,
18189
18301
if (!D)
18190
18302
continue;
18191
18303
18304
+ OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
18305
+ DSAStackTy::DSAVarData DVar;
18306
+ if (ParentDirective != OMPD_unknown)
18307
+ DVar = DSAStack->getTopDSA(D, /*FromParent=*/true);
18308
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
18309
+ // A list item that appears in the inclusive or exclusive clause must appear
18310
+ // in a reduction clause with the inscan modifier on the enclosing
18311
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
18312
+ if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction ||
18313
+ DVar.Modifier != OMPC_REDUCTION_inscan) {
18314
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
18315
+ << RefExpr->getSourceRange();
18316
+ } else {
18317
+ DSAStack->markDeclAsUsedInScanDirective(D);
18318
+ }
18192
18319
Vars.push_back(RefExpr);
18193
18320
}
18194
18321
0 commit comments