[clang] 8bbf2e3 - [OPENMP50]Support for imperfectly nested loops.
Alexey Bataev via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 4 13:26:08 PST 2019
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 at +2 2 {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}}
// expected-error at +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)
+ ;
+ }
+ }
+}
More information about the cfe-commits
mailing list