Author: Alexey Bataev Date: 2019-11-04T16:09:25-05:00 New Revision: 8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6
URL: https://github.com/llvm/llvm-project/commit/8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6 DIFF: https://github.com/llvm/llvm-project/commit/8bbf2e37167d9ac08fa9d3c772d48ca7d9a6f8f6.diff LOG: [OPENMP50]Support for imperfectly nested loops. Added support for imperfectly nested loops introduced in OpenMP 5.0. Added: Modified: clang/include/clang/AST/StmtOpenMP.h clang/lib/AST/StmtOpenMP.cpp clang/lib/CodeGen/CGStmtOpenMP.cpp clang/lib/Sema/SemaOpenMP.cpp clang/test/OpenMP/for_ast_print.cpp clang/test/OpenMP/for_codegen.cpp clang/test/OpenMP/for_collapse_messages.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 722aa509b132..9807b3c8f680 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -1084,28 +1084,20 @@ class OMPLoopDirective : public OMPExecutableDirective { return const_cast<Expr *>(reinterpret_cast<const Expr *>( *std::next(child_begin(), CombinedParForInDistConditionOffset))); } + /// Try to find the next loop sub-statement in the specified statement \p + /// CurStmt. + /// \param TryImperfectlyNestedLoops true, if we need to try to look for the + /// imperfectly nested loop. + static Stmt *tryToFindNextInnerLoop(Stmt *CurStmt, + bool TryImperfectlyNestedLoops); + static const Stmt *tryToFindNextInnerLoop(const Stmt *CurStmt, + bool TryImperfectlyNestedLoops) { + return tryToFindNextInnerLoop(const_cast<Stmt *>(CurStmt), + TryImperfectlyNestedLoops); + } + Stmt *getBody(); const Stmt *getBody() const { - // This relies on the loop form is already checked by Sema. - const Stmt *Body = - getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); - if (auto *For = dyn_cast<ForStmt>(Body)) { - Body = For->getBody(); - } else { - assert(isa<CXXForRangeStmt>(Body) && - "Expected canonical for loop or range-based for loop."); - Body = cast<CXXForRangeStmt>(Body)->getBody(); - } - for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { - Body = Body->IgnoreContainers(); - if (auto *For = dyn_cast<ForStmt>(Body)) { - Body = For->getBody(); - } else { - assert(isa<CXXForRangeStmt>(Body) && - "Expected canonical for loop or range-based for loop."); - Body = cast<CXXForRangeStmt>(Body)->getBody(); - } - } - return Body; + return const_cast<OMPLoopDirective *>(this)->getBody(); } ArrayRef<Expr *> counters() { return getCounters(); } diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index a93192b4857f..12201ef9ec28 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -41,6 +41,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const { return getInnermostCapturedStmt()->getCapturedStmt(); } +Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt, + bool TryImperfectlyNestedLoops) { + Stmt *OrigStmt = CurStmt; + CurStmt = CurStmt->IgnoreContainers(); + // Additional work for imperfectly nested loops, introduced in OpenMP 5.0. + if (TryImperfectlyNestedLoops) { + if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) { + CurStmt = nullptr; + SmallVector<CompoundStmt *, 4> Statements(1, CS); + SmallVector<CompoundStmt *, 4> NextStatements; + while (!Statements.empty()) { + CS = Statements.pop_back_val(); + if (!CS) + continue; + for (Stmt *S : CS->body()) { + if (!S) + continue; + if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) { + // Only single loop construct is allowed. + if (CurStmt) { + CurStmt = OrigStmt; + break; + } + CurStmt = S; + continue; + } + S = S->IgnoreContainers(); + if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S)) + NextStatements.push_back(InnerCS); + } + if (Statements.empty()) { + // Found single inner loop or multiple loops - exit. + if (CurStmt) + break; + Statements.swap(NextStatements); + } + } + if (!CurStmt) + CurStmt = OrigStmt; + } + } + return CurStmt; +} + +Stmt *OMPLoopDirective::getBody() { + // This relies on the loop form is already checked by Sema. + Stmt *Body = + getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(Body)) { + Body = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(Body) && + "Expected canonical for loop or range-based for loop."); + Body = cast<CXXForRangeStmt>(Body)->getBody(); + } + for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { + Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true); + if (auto *For = dyn_cast<ForStmt>(Body)) { + Body = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(Body) && + "Expected canonical for loop or range-based for loop."); + Body = cast<CXXForRangeStmt>(Body)->getBody(); + } + } + return Body; +} + void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) { assert(A.size() == getCollapsedNumber() && "Number of loop counters is not the same as the collapsed number"); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index df4b69e49866..4406fbc4144b 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/DeclOpenMP.h" +#include "clang/Basic/PrettyStackTrace.h" using namespace clang; using namespace CodeGen; @@ -146,7 +147,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { const Stmt *Body = S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) { - Body = Body->IgnoreContainers(); + Body = OMPLoopDirective::tryToFindNextInnerLoop( + Body, /*TryImperfectlyNestedLoops=*/true); if (auto *For = dyn_cast<ForStmt>(Body)) { Body = For->getBody(); } else { @@ -1339,6 +1341,41 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { [](CodeGenFunction &) { return nullptr; }); } +static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop, + int MaxLevel, int Level = 0) { + assert(Level < MaxLevel && "Too deep lookup during loop body codegen."); + const Stmt *SimplifiedS = S->IgnoreContainers(); + if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) { + PrettyStackTraceLoc CrashInfo( + CGF.getContext().getSourceManager(), CS->getLBracLoc(), + "LLVM IR generation of compound statement ('{}')"); + + // Keep track of the current cleanup stack depth, including debug scopes. + CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange()); + for (const Stmt *CurStmt : CS->body()) + emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level); + return; + } + if (SimplifiedS == NextLoop) { + if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) { + S = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(SimplifiedS) && + "Expected canonical for loop or range-based for loop."); + const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS); + CGF.EmitStmt(CXXFor->getLoopVarStmt()); + S = CXXFor->getBody(); + } + if (Level + 1 < MaxLevel) { + NextLoop = OMPLoopDirective::tryToFindNextInnerLoop( + S, /*TryImperfectlyNestedLoops=*/true); + emitBody(CGF, S, NextLoop, MaxLevel, Level + 1); + return; + } + } + CGF.EmitStmt(S); +} + void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit) { RunCleanupsScope BodyScope(*this); @@ -1371,20 +1408,12 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, // Emit loop variables for C++ range loops. const Stmt *Body = D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); - for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) { - Body = Body->IgnoreContainers(); - if (auto *For = dyn_cast<ForStmt>(Body)) { - Body = For->getBody(); - } else { - assert(isa<CXXForRangeStmt>(Body) && - "Expected canonical for loop or range-based for loop."); - auto *CXXFor = cast<CXXForRangeStmt>(Body); - EmitStmt(CXXFor->getLoopVarStmt()); - Body = CXXFor->getBody(); - } - } // Emit loop body. - EmitStmt(D.getBody()); + emitBody(*this, Body, + OMPLoopDirective::tryToFindNextInnerLoop( + Body, /*TryImperfectlyNestedLoops=*/true), + D.getCollapsedNumber()); + // The end (updates/cleanups). EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 595281a7c372..9055eff872a3 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -6979,7 +6979,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, "Expected canonical for or range-based for loops."); CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); } - CurStmt = CurStmt->IgnoreContainers(); + CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( + CurStmt, SemaRef.LangOpts.OpenMP >= 50); } for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( @@ -7006,7 +7007,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, "Expected canonical for or range-based for loops."); CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); } - CurStmt = CurStmt->IgnoreContainers(); + CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( + CurStmt, SemaRef.LangOpts.OpenMP >= 50); } Built.clear(/* size */ NestedLoopCount); diff --git a/clang/test/OpenMP/for_ast_print.cpp b/clang/test/OpenMP/for_ast_print.cpp index edb4b9a7ac0e..f5b98c88a812 100644 --- a/clang/test/OpenMP/for_ast_print.cpp +++ b/clang/test/OpenMP/for_ast_print.cpp @@ -114,22 +114,30 @@ T tmain(T argc) { // CHECK-NEXT: a = 2; #pragma omp parallel #pragma omp for allocate(argc) private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) schedule(static, N) ordered(N) nowait - for (auto &x : arr) - for (int i = 0; i < 2; ++i) - for (int j = 0; j < 2; ++j) + for (auto &x : arr) { + int j, hhh = 0; + for (int i = 0; i < 2; ++i) { + int j, hhh = 0; for (int j = 0; j < 2; ++j) for (int j = 0; j < 2; ++j) for (int j = 0; j < 2; ++j) - for (int i = 0; i < 2; ++i) - for (int j = 0; j < 2; ++j) - for (int j = 0; j < 2; ++j) - for (int j = 0; j < 2; ++j) - for (int j = 0; j < 2; ++j) - foo(); + for (int j = 0; j < 2; ++j) + for (int i = 0; i < 2; ++i) + for (int j = 0; j < 2; ++j) + for (int j = 0; j < 2; ++j) + for (int j = 0; j < 2; ++j) + for (int j = 0; j < 2; ++j) + foo(); + ++hhh; + } + ++hhh; + } // CHECK-NEXT: #pragma omp parallel // CHECK-NEXT: #pragma omp for allocate(argc) private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) schedule(static, N) ordered(N) nowait - // CHECK-NEXT: for (auto &x : arr) - // CHECK-NEXT: for (int i = 0; i < 2; ++i) + // CHECK-NEXT: for (auto &x : arr) { + // CHECK-NEXT: int j, hhh = 0; + // CHECK-NEXT: for (int i = 0; i < 2; ++i) { + // CHECK-NEXT: int j, hhh = 0; // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: for (int j = 0; j < 2; ++j) @@ -140,6 +148,10 @@ T tmain(T argc) { // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: foo(); + // CHECK-NEXT: ++hhh; + // CHECK-NEXT: } + // CHECK-NEXT: ++hhh; + // CHECK-NEXT: } return T(); } diff --git a/clang/test/OpenMP/for_codegen.cpp b/clang/test/OpenMP/for_codegen.cpp index 925235ef960e..a837a4a04d7b 100644 --- a/clang/test/OpenMP/for_codegen.cpp +++ b/clang/test/OpenMP/for_codegen.cpp @@ -732,4 +732,50 @@ T ftemplate() { int fint(void) { return ftemplate<int>(); } +// Check for imperfectly loop nests codegen. +#if _OPENMP == 201811 +void first(); +void last(); +void inner_f(); +void inner_l(); +void body_f(); + +// OMP5-LABEL: imperfectly_nested_loop +void imperfectly_nested_loop() { + // OMP5: call void @__kmpc_for_static_init_4( +#pragma omp for collapse(3) + for (int i = 0; i < 10; ++i) { + { + int a, d; + // OMP5: invoke void @{{.+}}first{{.+}}() + first(); + // OMP5: load i32 + // OMP5: store i32 + a = d; + for (int j = 0; j < 10; ++j) { + int a, d; + // OMP5: invoke void @{{.+}}inner_f{{.+}}() + inner_f(); + // OMP5: load i32 + // OMP5: store i32 + a = d; + for (int k = 0; k < 10; ++k) { + int a, d; + // OMP5: invoke void @{{.+}}body_f{{.+}}() + body_f(); + // OMP5: load i32 + // OMP5: store i32 + a = d; + } + // OMP5: invoke void @{{.+}}inner_l{{.+}}() + inner_l(); + } + // OMP5: invoke void @{{.+}}last{{.+}}() + last(); + } + } + // OMP5: call void @__kmpc_for_static_fini( +} +#endif + #endif // HEADER diff --git a/clang/test/OpenMP/for_collapse_messages.cpp b/clang/test/OpenMP/for_collapse_messages.cpp index ce656515b1ef..2316ca6ba3f0 100644 --- a/clang/test/OpenMP/for_collapse_messages.cpp +++ b/clang/test/OpenMP/for_collapse_messages.cpp @@ -1,10 +1,16 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp -std=c++98 %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++98 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp -std=c++11 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++98 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp -fopenmp-version=50 -std=c++11 %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++98 %s -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd -std=c++11 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++98 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp45 -fopenmp-simd -std=c++11 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++98 %s -Wuninitialized +// RUN: %clang_cc1 -verify=expected,omp50 -fopenmp-simd -fopenmp-version=50 -std=c++11 %s -Wuninitialized void foo() { } @@ -87,7 +93,7 @@ int main(int argc, char **argv) { #endif // expected-error@+2 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}} // expected-error@+1 {{argument to 'collapse' clause must be a strictly positive integer value}} - #pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5) + #pragma omp for collapse (foobool(argc)), collapse (true), collapse (-5) for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; #pragma omp for collapse (S1) // expected-error {{'S1' does not refer to a value}} for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; @@ -108,3 +114,39 @@ int main(int argc, char **argv) { return tmain<int, char, 1, 0>(argc, argv); } +void imperfectlyNestedLoops() { +#pragma omp for collapse(2) // expected-note {{as specified in 'collapse' clause}} + for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}} + for (int j = 0; j < 10; ++j) + ; + for (int j = 0; j < 10; ++j) + ; + } +#pragma omp for collapse(2) // expected-note {{as specified in 'collapse' clause}} + for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}} + { + for (int j = 0; j < 10; ++j) + ; + for (int j = 0; j < 10; ++j) + ; + } + { + for (int j = 0; j < 10; ++j) + ; + for (int j = 0; j < 10; ++j) + ; + } + } +#pragma omp for collapse(2) // omp45-note {{as specified in 'collapse' clause}} + for (int i = 0; i < 10; ++i) { // omp45-error {{expected 2 for loops after '#pragma omp for', but found only 1}} + int a, b, c; + for (int j = 0; j < 10; ++j) + ; + { + for (int j = 0; j < 10; ++j) + ; + for (int j = 0; j < 10; ++j) + ; + } + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits