From 622af1d282a1715bd9fb4c3c473b0f3865d8a9c7 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 24 Apr 2019 19:58:30 +0000 Subject: [PATCH] [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 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 + clang/lib/Sema/SemaOpenMP.cpp | 100 ++++++++++++++++++++--- clang/test/OpenMP/for_loop_messages.cpp | 17 +++- 3 files changed, 105 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 93663fb..5237456 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9170,6 +9170,8 @@ def warn_omp_allocate_thread_on_task_target_directive : Warning< InGroup; 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 { diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bdf4263..a5afce4 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -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 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 { + Sema &SemaRef; + DSAStackTy &Stack; + const ValueDecl *CurLCDecl = nullptr; + bool IsInitializer = true; + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + if (isa(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(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(LHS)) { if (auto *CED = dyn_cast(DRE->getDecl())) if (auto *ME = dyn_cast(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(LHS)) { if (ME->isArrow() && isa(ME->getBase()->IgnoreParenImpCasts())) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); } } } else if (auto *DS = dyn_cast(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(LHS)) { if (auto *CED = dyn_cast(DRE->getDecl())) if (auto *ME = dyn_cast(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(LHS)) { if (ME->isArrow() && isa(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(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(); diff --git a/clang/test/OpenMP/for_loop_messages.cpp b/clang/test/OpenMP/for_loop_messages.cpp index 8817c77..01c96ad 100644 --- a/clang/test/OpenMP/for_loop_messages.cpp +++ b/clang/test/OpenMP/for_loop_messages.cpp @@ -287,6 +287,13 @@ int test_iteration_spaces() { 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}} #pragma omp for firstprivate(ii) @@ -596,9 +603,17 @@ int test_with_random_access_iterator() { template 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 t1; TC t2; - t1.dotest_lt(begin, end); + t1.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC::dotest_lt' requested here}} t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC::dotest_lt' requested here}} dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt' requested here}} dotest_gt(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt' requested here}} -- 2.7.4