Skip to content

Commit ea0e6e3

Browse files
committed
[OpenACC] Improve 'loop' content restrictions
The 'loop' construct has some limitations that are not particularly clear on what can be in the for-loop. This patch adds some restriction so that the increment can only be a addition or subtraction operation, BUT starts allowing Itr = Itr +/- N forms.
1 parent fa76965 commit ea0e6e3

File tree

2 files changed

+106
-24
lines changed

2 files changed

+106
-24
lines changed

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,11 +1275,8 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
12751275
CondVar->getCanonicalDecl() != InitVar->getCanonicalDecl() &&
12761276
CE->getNumArgs() > 1))
12771277
CondVar = getDeclFromExpr(CE->getArg(1));
1278-
} else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(CondStmt)) {
1279-
// Here there isn't much we can do besides hope it is the right variable.
1280-
// Codegen might have to just give up on figuring out trip count in this
1281-
// case?
1282-
CondVar = getDeclFromExpr(ME->getImplicitObjectArgument());
1278+
} else {
1279+
return DiagCondVar();
12831280
}
12841281

12851282
if (!CondVar)
@@ -1293,6 +1290,59 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForCond(const Stmt *CondStmt,
12931290
return false;
12941291
}
12951292

1293+
namespace {
1294+
// Helper to check the RHS of an assignment during for's step. We can allow
1295+
// InitVar = InitVar + N, InitVar = N + InitVar, and Initvar = Initvar - N,
1296+
// where N is an integer.
1297+
bool isValidForIncRHSAssign(const ValueDecl *InitVar, const Expr *RHS) {
1298+
1299+
auto isValid = [](const ValueDecl *InitVar, const Expr *InnerLHS,
1300+
const Expr *InnerRHS, bool IsAddition) {
1301+
// ONE of the sides has to be an integer type.
1302+
if (!InnerLHS->getType()->isIntegerType() &&
1303+
!InnerRHS->getType()->isIntegerType())
1304+
return false;
1305+
1306+
// If the init var is already an error, don't bother trying to check for
1307+
// it.
1308+
if (!InitVar)
1309+
return true;
1310+
1311+
const ValueDecl *LHSDecl = getDeclFromExpr(InnerLHS);
1312+
const ValueDecl *RHSDecl = getDeclFromExpr(InnerRHS);
1313+
// If we can't get a declaration, this is probably an error, so give up.
1314+
if (!LHSDecl || !RHSDecl)
1315+
return true;
1316+
1317+
// If the LHS is the InitVar, the other must be int, so this is valid.
1318+
if (LHSDecl->getCanonicalDecl() ==
1319+
InitVar->getCanonicalDecl())
1320+
return true;
1321+
1322+
// Subtraction doesn't allow the RHS to be init var, so this is invalid.
1323+
if (!IsAddition)
1324+
return false;
1325+
1326+
return RHSDecl->getCanonicalDecl() ==
1327+
InitVar->getCanonicalDecl();
1328+
};
1329+
1330+
if (const auto *BO = dyn_cast<BinaryOperator>(RHS)) {
1331+
BinaryOperatorKind OpC = BO->getOpcode();
1332+
if (OpC != BO_Add && OpC != BO_Sub)
1333+
return false;
1334+
return isValid(InitVar, BO->getLHS(), BO->getRHS(), OpC == BO_Add);
1335+
} else if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
1336+
OverloadedOperatorKind Op = CE->getOperator();
1337+
if (Op != OO_Plus && Op != OO_Minus)
1338+
return false;
1339+
return isValid(InitVar, CE->getArg(0), CE->getArg(1), Op == OO_Plus);
1340+
}
1341+
1342+
return false;
1343+
}
1344+
} // namespace
1345+
12961346
bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
12971347
const ValueDecl *InitVar,
12981348
bool Diag) {
@@ -1335,14 +1385,12 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
13351385
return DiagIncVar();
13361386
case BO_AddAssign:
13371387
case BO_SubAssign:
1338-
case BO_MulAssign:
1339-
case BO_DivAssign:
1388+
break;
13401389
case BO_Assign:
1341-
// += -= *= /= should all be fine here, this should be all of the
1342-
// 'monotonical' compound-assign ops.
1343-
// Assignment we just give up on, we could do better, and ensure that it
1344-
// is a binary/operator expr doing more work, but that seems like a lot
1345-
// of work for an error prone check.
1390+
// For assignment we also allow InitVar = InitVar + N, InitVar = N +
1391+
// InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1392+
if (!isValidForIncRHSAssign(InitVar, BO->getRHS()))
1393+
return DiagIncVar();
13461394
break;
13471395
}
13481396
IncVar = getDeclFromExpr(BO->getLHS());
@@ -1354,23 +1402,18 @@ bool SemaOpenACC::ForStmtBeginChecker::checkForInc(const Stmt *IncStmt,
13541402
case OO_MinusMinus:
13551403
case OO_PlusEqual:
13561404
case OO_MinusEqual:
1357-
case OO_StarEqual:
1358-
case OO_SlashEqual:
1405+
break;
13591406
case OO_Equal:
1360-
// += -= *= /= should all be fine here, this should be all of the
1361-
// 'monotonical' compound-assign ops.
1362-
// Assignment we just give up on, we could do better, and ensure that it
1363-
// is a binary/operator expr doing more work, but that seems like a
1364-
// lot of work for an error prone check.
1407+
// For assignment we also allow InitVar = InitVar + N, InitVar = N +
1408+
// InitVar, and InitVar = InitVar - N; BUT only if 'N' is integral.
1409+
if (!isValidForIncRHSAssign(InitVar, CE->getArg(1)))
1410+
return DiagIncVar();
13651411
break;
13661412
}
13671413

13681414
IncVar = getDeclFromExpr(CE->getArg(0));
1369-
1370-
} else if (const auto *ME = dyn_cast<CXXMemberCallExpr>(IncStmt)) {
1371-
IncVar = getDeclFromExpr(ME->getImplicitObjectArgument());
1372-
// We can't really do much for member expressions, other than hope they are
1373-
// doing the right thing, so give up here.
1415+
} else {
1416+
return DiagIncVar();
13741417
}
13751418

13761419
if (!IncVar)

clang/test/SemaOpenACC/loop-construct.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ struct SomeRAIterator {
3030
bool operator!=(SomeRAIterator&);
3131
};
3232

33+
SomeRAIterator &operator+(const SomeRAIterator&, int);
34+
SomeRAIterator &operator+(int,const SomeRAIterator&);
35+
SomeRAIterator &operator-(const SomeRAIterator&, int);
36+
SomeRAIterator &operator-(int,const SomeRAIterator&);
37+
3338
struct HasIteratorCollection {
3439
SomeIterator &begin();
3540
SomeIterator &end();
@@ -400,3 +405,37 @@ void inst() {
400405
LoopRules<int, int*, float, SomeStruct, SomeIterator, SomeRAIterator>();
401406
}
402407

408+
void allowTrivialAssignStep(int N) {
409+
#pragma acc loop
410+
for(int i = 0; i !=5; i = i + N);
411+
#pragma acc loop
412+
for(int i = 0; i !=5; i = i - N);
413+
#pragma acc loop
414+
for(int i = 0; i !=5; i = N + i);
415+
416+
// expected-error@+3{{OpenACC 'loop' variable must monotonically increase or decrease}}
417+
// expected-note@+1{{'loop' construct is here}}
418+
#pragma acc loop
419+
for(int i = 0; i !=5; i = N - i);
420+
// expected-error@+3{{OpenACC 'loop' variable must monotonically increase or decrease}}
421+
// expected-note@+1{{'loop' construct is here}}
422+
#pragma acc loop
423+
for(int i = 0; i !=5; i = N + N);
424+
425+
HasRAIteratorCollection Col;
426+
427+
#pragma acc loop
428+
for (auto Itr = Col.begin(); Itr != Col.end(); Itr = Itr + N);
429+
430+
#pragma acc loop
431+
for (auto Itr = Col.begin(); Itr != Col.end(); Itr = Itr - N);
432+
433+
#pragma acc loop
434+
for (auto Itr = Col.begin(); Itr != Col.end(); Itr = N + Itr);
435+
436+
// expected-error@+3{{OpenACC 'loop' variable must monotonically increase or decrease}}
437+
// expected-note@+1{{'loop' construct is here}}
438+
#pragma acc loop
439+
for (auto Itr = Col.begin(); Itr != Col.end(); Itr = N - Itr);
440+
}
441+

0 commit comments

Comments
 (0)