From 5ddc6d180cd660fa1b70e0c251a95b70ad743ac9 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 26 Apr 2019 19:28:37 +0000 Subject: [PATCH] [OPENMP]Added check for non-random access types for the dependent loop counters. According to the OpenMP 5.0, For any associated loop where the b or lb expression is not loop invariant with respect to the outermost loop, the var-outer that appears in the expression may not have a random access iterator type. llvm-svn: 359340 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaOpenMP.cpp | 129 ++++++++++++++--------- clang/test/OpenMP/for_loop_messages.cpp | 28 ++++- 3 files changed, 108 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2461921..0ef70f7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9177,8 +9177,10 @@ 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">; -def err_omp_invariant_or_linear_dependancy : Error< +def err_omp_invariant_or_linear_dependency : Error< "expected loop invariant expression or ' * %0 + ' kind of expression">; +def err_omp_wrong_dependency_iterator_type : Error< + "expected an integer or a pointer type of the outer loop counter '%0' for non-rectangular nests">; } // 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 8aaa184..2011c0b 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4520,8 +4520,16 @@ class OpenMPIterationSpaceChecker { bool TestIsStrictOp = false; /// This flag is true when step is subtracted on each iteration. bool SubtractStep = false; + /// The outer loop counter this loop depends on (if any). + const ValueDecl *DepDecl = nullptr; + /// Contains number of loop (starts from 1) on which loop counter init + /// expression of this loop depends on. + Optional InitDependOnLC; + /// Contains number of loop (starts from 1) on which loop counter condition + /// expression of this loop depends on. + Optional CondDependOnLC; /// Checks if the provide statement depends on the loop counter. - bool doesDependOnLoopCounter(const Stmt *S, bool IsInitializer) const; + Optional doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); public: OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -4622,7 +4630,7 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, NewLB = CE->getArg(0)->IgnoreParenImpCasts(); LB = NewLB; if (EmitDiags) - (void)doesDependOnLoopCounter(LB, /*IsInitializer=*/true); + InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true); return false; } @@ -4641,7 +4649,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, TestIsStrictOp = StrictOp; ConditionSrcRange = SR; ConditionLoc = SL; - (void)doesDependOnLoopCounter(UB, /*IsInitializer=*/false); + CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false); return false; } @@ -4716,58 +4724,62 @@ class LoopCounterRefChecker final DSAStackTy &Stack; const ValueDecl *CurLCDecl = nullptr; const ValueDecl *DepDecl = nullptr; + const ValueDecl *PrevDepDecl = nullptr; bool IsInitializer = true; + unsigned BaseLoopId = 0; + bool checkDecl(const Expr *E, const ValueDecl *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); + // OpenMP, 2.9.1 Canonical Loop Form, Restrictions. + // The type of the loop iterator on which we depend may not have a random + // access iterator type. + if (Data.first && VD->getType()->isRecordType()) { + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_wrong_dependency_iterator_type) + << OS.str(); + SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD; + return false; + } + if (Data.first && + (DepDecl || (PrevDepDecl && + getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) { + if (!DepDecl && PrevDepDecl) + DepDecl = PrevDepDecl; + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_invariant_or_linear_dependency) + << OS.str(); + return false; + } + if (Data.first) { + DepDecl = VD; + BaseLoopId = Data.first; + } + return Data.first; + } 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); - if (DepDecl && Data.first) { - SmallString<128> Name; - llvm::raw_svector_ostream OS(Name); - DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), - /*Qualified=*/true); - SemaRef.Diag(E->getExprLoc(), - diag::err_omp_invariant_or_linear_dependancy) - << OS.str(); - return false; - } - if (Data.first) - DepDecl = VD; - return Data.first; - } + if (isa(VD)) + return checkDecl(E, VD); 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); - if (DepDecl && Data.first) { - SmallString<128> Name; - llvm::raw_svector_ostream OS(Name); - DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), - /*Qualified=*/true); - SemaRef.Diag(E->getExprLoc(), - diag::err_omp_invariant_or_linear_dependancy) - << OS.str(); - return false; - } - if (Data.first) - DepDecl = VD; - return Data.first; + return checkDecl(E, VD); } return false; } @@ -4778,17 +4790,32 @@ public: return Res; } explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, - const ValueDecl *CurLCDecl, bool IsInitializer) + const ValueDecl *CurLCDecl, bool IsInitializer, + const ValueDecl *PrevDepDecl = nullptr) : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl), - IsInitializer(IsInitializer) {} + PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {} + unsigned getBaseLoopId() const { + assert(CurLCDecl && "Expected loop dependency."); + return BaseLoopId; + } + const ValueDecl *getDepDecl() const { + assert(CurLCDecl && "Expected loop dependency."); + return DepDecl; + } }; } // namespace -bool OpenMPIterationSpaceChecker::doesDependOnLoopCounter( - const Stmt *S, bool IsInitializer) const { +Optional +OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, + bool IsInitializer) { // Check for the non-rectangular loops. - LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer); - return LoopStmtChecker.Visit(S); + LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer, + DepDecl); + if (LoopStmtChecker.Visit(S)) { + DepDecl = LoopStmtChecker.getDepDecl(); + return LoopStmtChecker.getBaseLoopId(); + } + return llvm::None; } bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { diff --git a/clang/test/OpenMP/for_loop_messages.cpp b/clang/test/OpenMP/for_loop_messages.cpp index f3fba67..f5ee0d4 100644 --- a/clang/test/OpenMP/for_loop_messages.cpp +++ b/clang/test/OpenMP/for_loop_messages.cpp @@ -299,6 +299,13 @@ int test_iteration_spaces() { for (kk = ii * 10 + 25; kk < ii / ii - 23; kk += 1) ; +// expected-error@+4 {{expected loop invariant expression or ' * ii + ' kind of expression}} +#pragma omp for collapse(3) + for (ii = 10 + 25; ii < 1000; ii += 1) + for (jj = 10 + 25; jj < 1000; jj += 1) + for (kk = ii * 10 + 25; kk < jj - 23; kk += 1) + ; + #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}} @@ -601,6 +608,14 @@ int test_with_random_access_iterator() { for (Iter1 I; I < end1; ++I) { } GoodIter1 I1, E1; +// expected-error@+4 {{expected an integer or a pointer type of the outer loop counter 'I' for non-rectangular nests}} +// expected-error@+4 {{expected an integer or a pointer type of the outer loop counter 'I' for non-rectangular nests}} +#pragma omp for collapse(3) + for (GoodIter1 I = I1; I < E1; I++) // expected-note 2 {{'I' declared here}} + for (int i = (I - I1) * 10 + 25; i < 23; i += 1) + for (int j = 10 + 25; j < 23 + (I - E1); j += 1) + ; + #pragma omp for for (GoodIter1 I = I1; I < E1; I++) ; @@ -609,7 +624,7 @@ int test_with_random_access_iterator() { template class TC { - int ii, iii; + int ii, iii, kk; public: int dotest_lt(IT begin, IT end) { #pragma omp parallel @@ -628,6 +643,17 @@ public: ; #pragma omp parallel +// expected-error@+6 2 {{expected loop invariant expression or ' * ii + ' kind of expression}} +// expected-error@+5 {{expected loop invariant expression or ' * TC::ii + ' kind of expression}} +// expected-error@+5 2 {{expected loop invariant expression or ' * ii + ' kind of expression}} +// expected-error@+4 {{expected loop invariant expression or ' * TC::ii + ' kind of expression}} +#pragma omp for collapse(3) + for (ii = 10 + 25; ii < 1000; ii += 1) + for (iii = ii * 10 + 25; iii < ii / ii - 23; iii += 1) + for (kk = ii * 10 + 25; kk < iii - 23; kk += 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 -- 2.7.4