[OPENMP]Initial support for non-rectangular loop nest.

Added basic semantic analysis for the non-rectangular loop nests for
OpenMP 5.0 support.

llvm-svn: 359132
This commit is contained in:
Alexey Bataev 2019-04-24 19:58:30 +00:00
parent 499c80b890
commit 622af1d282
3 changed files with 105 additions and 14 deletions

View File

@ -9170,6 +9170,8 @@ def warn_omp_allocate_thread_on_task_target_directive : Warning<
InGroup<OpenMPClauses>;
def err_omp_expected_private_copy_for_allocate : Error<
"the referenced item is not found in any private clause on the same directive">;
def err_omp_stmt_depends_on_loop_counter : Error<
"the loop %select{initializer|condition}0 expression depends on the current loop control variable">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {

View File

@ -4487,6 +4487,8 @@ namespace {
class OpenMPIterationSpaceChecker {
/// Reference to Sema.
Sema &SemaRef;
/// Data-sharing stack.
DSAStackTy &Stack;
/// A location for diagnostics (when there is no some better location).
SourceLocation DefaultLoc;
/// A location for diagnostics (when increment is not compatible).
@ -4518,10 +4520,14 @@ class OpenMPIterationSpaceChecker {
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
bool SubtractStep = false;
/// Checks if the provide statement depends on the loop counter.
bool doesDependOnLoopCounter(const Stmt *S, bool IsInitializer) const;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
: SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {}
OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
SourceLocation DefaultLoc)
: SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc),
ConditionLoc(DefaultLoc) {}
/// Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
@ -4579,7 +4585,8 @@ private:
/// expression.
bool checkAndSetIncRHS(Expr *RHS);
/// Helper to set loop counter variable and its initializer.
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB);
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
bool EmitDiags);
/// Helper to set upper bound.
bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
@ -4599,7 +4606,7 @@ bool OpenMPIterationSpaceChecker::dependent() const {
bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
Expr *NewLB) {
Expr *NewLB, bool EmitDiags) {
// State consistency checking to ensure correct usage.
assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
@ -4614,6 +4621,8 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
NewLB = CE->getArg(0)->IgnoreParenImpCasts();
LB = NewLB;
if (EmitDiags)
(void)doesDependOnLoopCounter(LB, /*IsInitializer=*/true);
return false;
}
@ -4632,6 +4641,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB,
TestIsStrictOp = StrictOp;
ConditionSrcRange = SR;
ConditionLoc = SL;
(void)doesDependOnLoopCounter(UB, /*IsInitializer=*/false);
return false;
}
@ -4697,6 +4707,66 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
return false;
}
namespace {
/// Checker for the non-rectangular loops. Checks if the initializer or
/// condition expression references loop counter variable.
class LoopCounterRefChecker final
: public ConstStmtVisitor<LoopCounterRefChecker, bool> {
Sema &SemaRef;
DSAStackTy &Stack;
const ValueDecl *CurLCDecl = nullptr;
bool IsInitializer = true;
public:
bool VisitDeclRefExpr(const DeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
if (isa<VarDecl>(VD)) {
if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) {
SemaRef.Diag(E->getExprLoc(),
diag::err_omp_stmt_depends_on_loop_counter)
<< (IsInitializer ? 0 : 1);
return false;
}
const auto &&Data = Stack.isLoopControlVariable(VD);
return Data.first;
}
return false;
}
bool VisitMemberExpr(const MemberExpr *E) {
if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
const ValueDecl *VD = E->getMemberDecl();
if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) {
SemaRef.Diag(E->getExprLoc(),
diag::err_omp_stmt_depends_on_loop_counter)
<< (IsInitializer ? 0 : 1);
return false;
}
const auto &&Data = Stack.isLoopControlVariable(VD);
return Data.first;
}
return false;
}
bool VisitStmt(const Stmt *S) {
for (const Stmt *Child : S->children()) {
if (Child && Visit(Child))
return true;
}
return false;
}
explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
const ValueDecl *CurLCDecl, bool IsInitializer)
: SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl),
IsInitializer(IsInitializer) {}
};
} // namespace
bool OpenMPIterationSpaceChecker::doesDependOnLoopCounter(
const Stmt *S, bool IsInitializer) const {
// Check for the non-rectangular loops.
LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer);
return LoopStmtChecker.Visit(S);
}
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
// Check init-expr for canonical loop form and save loop counter
// variable - #Var and its initialization value - #LB.
@ -4725,13 +4795,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS());
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
EmitDiags);
return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
EmitDiags);
}
}
} else if (auto *DS = dyn_cast<DeclStmt>(S)) {
@ -4748,7 +4820,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
buildDeclRefExpr(SemaRef, Var,
Var->getType().getNonReferenceType(),
DS->getBeginLoc()),
Var->getInit());
Var->getInit(), EmitDiags);
}
}
}
@ -4758,13 +4830,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1));
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
EmitDiags);
return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
EmitDiags);
}
}
}
@ -5261,7 +5335,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
DSAStack->loopStart();
OpenMPIterationSpaceChecker ISC(*this, ForLoc);
OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc);
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
@ -5327,7 +5401,7 @@ static bool checkOpenMPIterationSpace(
}
assert(For->getBody());
OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
// Check init.
Stmt *Init = For->getInit();

View File

@ -286,6 +286,13 @@ int test_iteration_spaces() {
for (ii = 0; (ii < 10); (ii -= 0))
c[ii] = a[ii];
#pragma omp parallel
// expected-error@+3 {{the loop initializer expression depends on the current loop control variable}}
// expected-error@+2 2 {{the loop condition expression depends on the current loop control variable}}
#pragma omp for
for (ii = ii * 10 + 25; ii < ii / ii - 23; ii += 1)
c[ii] = a[ii];
#pragma omp parallel
// expected-note@+2 {{defined as firstprivate}}
// expected-error@+2 {{loop iteration variable in the associated loop of 'omp for' directive may not be firstprivate, predetermined as private}}
@ -596,9 +603,17 @@ int test_with_random_access_iterator() {
template <typename IT, int ST>
class TC {
int ii;
public:
int dotest_lt(IT begin, IT end) {
#pragma omp parallel
// expected-error@+3 3 {{the loop initializer expression depends on the current loop control variable}}
// expected-error@+2 6 {{the loop condition expression depends on the current loop control variable}}
#pragma omp for
for (ii = ii * 10 + 25; ii < ii / ii - 23; ii += 1)
;
#pragma omp parallel
// expected-note@+3 {{loop step is expected to be positive due to this condition}}
// expected-error@+2 {{increment expression must cause 'I' to increase on each iteration of OpenMP for loop}}
#pragma omp for
@ -659,7 +674,7 @@ void test_with_template() {
GoodIter begin, end;
TC<GoodIter, 100> t1;
TC<GoodIter, -100> t2;
t1.dotest_lt(begin, end);
t1.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, 100>::dotest_lt' requested here}}
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}