[OPENMP50]Treat range-based for as canonical loop.

According to OpenMP 5.0, range-based for is also considered as a
canonical form of loops.

llvm-svn: 373939
This commit is contained in:
Alexey Bataev 2019-10-07 18:54:57 +00:00
parent b4cbf9862c
commit bef93a98cd
27 changed files with 291 additions and 42 deletions

View File

@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
@ -1087,10 +1088,22 @@ public:
// This relies on the loop form is already checked by Sema.
const Stmt *Body =
getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
Body = cast<ForStmt>(Body)->getBody();
if (auto *For = dyn_cast<ForStmt>(Body)) {
Body = For->getBody();
} else {
assert(isa<CXXForRangeStmt>(Body) &&
"Expected caonical for loop or range-based for loop.");
Body = cast<CXXForRangeStmt>(Body)->getBody();
}
for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
Body = Body->IgnoreContainers();
Body = cast<ForStmt>(Body)->getBody();
if (auto *For = dyn_cast<ForStmt>(Body)) {
Body = For->getBody();
} else {
assert(isa<CXXForRangeStmt>(Body) &&
"Expected caonical for loop or range-based for loop.");
Body = cast<CXXForRangeStmt>(Body)->getBody();
}
}
return Body;
}

View File

@ -9154,6 +9154,10 @@ public:
/// construct.
void startOpenMPLoop();
/// If the current region is a range loop-based region, mark the start of the
/// loop construct.
void startOpenMPCXXRangeFor();
/// Check if the specified variable is used in 'private' clause.
/// \param Level Relative level of nested OpenMP construct for that the check
/// is performed.

View File

@ -142,6 +142,24 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
}
}
(void)PreCondVars.apply(CGF);
// Emit init, __range and __end variables for C++ range loops.
const Stmt *Body =
S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) {
Body = Body->IgnoreContainers();
if (auto *For = dyn_cast<ForStmt>(Body)) {
Body = For->getBody();
} else {
assert(isa<CXXForRangeStmt>(Body) &&
"Expected caonical for loop or range-based for loop.");
auto *CXXFor = cast<CXXForRangeStmt>(Body);
if (const Stmt *Init = CXXFor->getInit())
CGF.EmitStmt(Init);
CGF.EmitStmt(CXXFor->getRangeStmt());
CGF.EmitStmt(CXXFor->getEndStmt());
Body = CXXFor->getBody();
}
}
if (const auto *PreInits = cast_or_null<DeclStmt>(S.getPreInits())) {
for (const auto *I : PreInits->decls())
CGF.EmitVarDecl(cast<VarDecl>(*I));
@ -1350,6 +1368,21 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
getProfileCount(D.getBody()));
EmitBlock(NextBB);
}
// 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 caonical for loop or range-based for loop.");
auto *CXXFor = cast<CXXForRangeStmt>(Body);
EmitStmt(CXXFor->getLoopVarStmt());
Body = CXXFor->getBody();
}
}
// Emit loop body.
EmitStmt(D.getBody());
// The end (updates/cleanups).

View File

@ -2100,6 +2100,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
bool IsForRangeLoop = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
if (getLangOpts().OpenMP)
Actions.startOpenMPCXXRangeFor();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else

View File

@ -2008,6 +2008,14 @@ void Sema::startOpenMPLoop() {
DSAStack->loopInit();
}
void Sema::startOpenMPCXXRangeFor() {
assert(LangOpts.OpenMP && "OpenMP must be enabled.");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
DSAStack->resetPossibleLoopCounter();
DSAStack->loopStart();
}
}
bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
@ -6490,10 +6498,13 @@ static bool checkOpenMPIterationSpace(
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// OpenMP [2.6, Canonical Loop Form]
// OpenMP [2.9.1, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
// for (range-decl: range-expr) structured-block
auto *For = dyn_cast_or_null<ForStmt>(S);
if (!For) {
auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
// Ranged for is supported only in OpenMP 5.0.
if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
@ -6515,12 +6526,14 @@ static bool checkOpenMPIterationSpace(
}
return true;
}
assert(For->getBody());
assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) &&
"No loop body.");
OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
OpenMPIterationSpaceChecker ISC(SemaRef, DSA,
For ? For->getForLoc() : CXXFor->getForLoc());
// Check init.
Stmt *Init = For->getInit();
Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
if (ISC.checkAndSetInit(Init))
return true;
@ -6556,18 +6569,18 @@ static bool checkOpenMPIterationSpace(
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
// Check test-expr.
HasErrors |= ISC.checkAndSetCond(For->getCond());
HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond());
// Check incr-expr.
HasErrors |= ISC.checkAndSetInc(For->getInc());
HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc());
}
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
ResultIterSpaces[CurrentNestedLoopCount].PreCond =
ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures);
ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond(
DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures);
ResultIterSpaces[CurrentNestedLoopCount].NumIterations =
ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces,
(isOpenMPWorksharingDirective(DKind) ||
@ -6881,7 +6894,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
CurStmt = For->getBody();
} else {
assert(isa<CXXForRangeStmt>(CurStmt) &&
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
CurStmt = CurStmt->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
@ -6901,7 +6921,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
CurStmt = For->getBody();
} else {
assert(isa<CXXForRangeStmt>(CurStmt) &&
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
CurStmt = CurStmt->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);

View File

@ -2674,6 +2674,11 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
if (Kind == BFRK_Check)
return StmtResult();
// In OpenMP loop region loop control variable must be private. Perform
// analysis of first part (if any).
if (getLangOpts().OpenMP >= 50 && BeginDeclStmt.isUsable())
ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get());
return new (Context) CXXForRangeStmt(
InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),

View File

@ -379,7 +379,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams
// expected-error@+2 {{statement after '#pragma omp distribute parallel for simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp distribute parallel for simd' must be a for loop}}
#pragma omp distribute parallel for simd
for (auto &item : a) {
item = item + 1;

View File

@ -376,7 +376,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams
// expected-error@+2 {{statement after '#pragma omp distribute simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp distribute simd' must be a for loop}}
#pragma omp distribute simd
for (auto &item : a) {
item = item + 1;

View File

@ -1,10 +1,10 @@
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
@ -103,6 +103,7 @@ public:
template <class T, int N>
T tmain(T argc) {
T b = argc, c, d, e, f, g;
T arr[N];
static T a;
// CHECK: static T a;
#pragma omp for schedule(dynamic) linear(a) allocate(a)
@ -113,6 +114,7 @@ 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 (int j = 0; j < 2; ++j)
@ -126,6 +128,7 @@ T tmain(T argc) {
foo();
// 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 (int j = 0; j < 2; ++j)
// CHECK-NEXT: for (int j = 0; j < 2; ++j)
@ -143,6 +146,7 @@ T tmain(T argc) {
int main(int argc, char **argv) {
// CHECK: int main(int argc, char **argv) {
int b = argc, c, d, e, f, g;
float arr[20];
static int a;
// CHECK: static int a;
#pragma omp for schedule(guided, argc) reduction(+:argv[0][:1])
@ -152,15 +156,17 @@ int main(int argc, char **argv) {
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
#pragma omp for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) ordered nowait linear(g:-1)
#pragma omp for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(3) schedule(auto) ordered nowait linear(g:-1)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
foo();
for (auto x : arr)
foo(), (void)x;
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) ordered nowait linear(g: -1)
// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(3) schedule(auto) ordered nowait linear(g: -1)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: foo();
// CHECK-NEXT: for (auto x : arr)
// CHECK-NEXT: foo() , (void)x;
char buf[9] = "01234567";
char *p, *q;
#pragma omp parallel

View File

@ -370,7 +370,7 @@ int test_iteration_spaces() {
}
#pragma omp parallel
// expected-error@+2 {{statement after '#pragma omp for' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp for' must be a for loop}}
#pragma omp for
for (auto &item : a) {
item = item + 1;

View File

@ -333,7 +333,7 @@ int test_iteration_spaces() {
}
#pragma omp parallel
// expected-error@+2 {{statement after '#pragma omp for simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp for simd' must be a for loop}}
#pragma omp for simd
for (auto &item : a) {
item = item + 1;

View File

@ -469,6 +469,165 @@ int decrement_nowait () {
return 0;
// OMP5: ret i32 0
}
// OMP5-LABEL: range_for_single
void range_for_single() {
int arr[10] = {0};
// OMP5: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* {{.+}}, i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [10 x i32]*)* [[OUTLINED:@.+]] to void (i32*, i32*, ...)*), [10 x i32]* %{{.+}})
#pragma omp parallel for
for (auto &a : arr)
(void)a;
}
// OMP5: define internal void @.omp_outlined.(i32* {{.+}}, i32* {{.+}}, [10 x i32]* dereferenceable(40) %arr)
// OMP5: [[ARR_ADDR:%.+]] = alloca [10 x i32]*,
// OMP5: [[IV:%.+]] = alloca i64,
// OMP5: [[RANGE_ADDR:%.+]] = alloca [10 x i32]*,
// OMP5: [[END_ADDR:%.+]] = alloca i32*,
// OMP5: alloca i32*,
// OMP5: alloca i32*,
// OMP5: alloca i64,
// OMP5: [[BEGIN_INIT:%.+]] = alloca i32*,
// OMP5: [[LB:%.+]] = alloca i64,
// OMP5: [[UB:%.+]] = alloca i64,
// OMP5: [[STRIDE:%.+]] = alloca i64,
// OMP5: [[IS_LAST:%.+]] = alloca i32,
// OMP5: [[BEGIN:%.+]] = alloca i32*,
// OMP5: [[A_PTR:%.+]] = alloca i32*,
// OMP5: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
// __range = arr;
// OMP5: [[ARR:%.+]] = load [10 x i32]*, [10 x i32]** [[ARR_ADDR]],
// OMP5: store [10 x i32]* [[ARR]], [10 x i32]** [[RANGE_ADDR]],
// __end = end(_range);
// OMP5: [[RANGE:%.+]] = load [10 x i32]*, [10 x i32]** [[RANGE_ADDR]],
// OMP5: [[RANGE_0:%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[RANGE]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// OMP5: [[RANGE_10:%.+]] = getelementptr inbounds i32, i32* [[RANGE_0]], i{{[0-9]+}} 10
// OMP5: store i32* [[RANGE_10]], i32** [[END_ADDR]],
// OMP5: [[RANGE:%.+]] = load [10 x i32]*, [10 x i32]** [[RANGE_ADDR]],
// OMP5: [[RANGE_0:%.+]] = getelementptr inbounds [10 x i32], [10 x i32]* [[RANGE]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// OMP5: store i32* [[RANGE_0]], i32** [[CAP1:%.+]],
// OMP5: [[END:%.+]] = load i32*, i32** [[END_ADDR]],
// OMP5: store i32* [[END]], i32** [[CAP2:%.+]],
// calculate number of elements.
// OMP5: [[CAP2_VAL:%.+]] = load i32*, i32** [[CAP2]],
// OMP5: [[CAP1_VAL:%.+]] = load i32*, i32** [[CAP1]],
// OMP5: [[CAP2_I64:%.+]] = ptrtoint i32* [[CAP2_VAL]] to i64
// OMP5: [[CAP1_I64:%.+]] = ptrtoint i32* [[CAP1_VAL]] to i64
// OMP5: [[DIFF:%.+]] = sub i64 [[CAP2_I64]], [[CAP1_I64]]
// OMP5: [[NUM:%.+]] = sdiv exact i64 [[DIFF]], 4
// OMP5: [[NUM1:%.+]] = sub nsw i64 [[NUM]], 1
// OMP5: [[NUM2:%.+]] = add nsw i64 [[NUM1]], 1
// OMP5: [[NUM3:%.+]] = sdiv i64 [[NUM2]], 1
// OMP5: [[NUM4:%.+]] = sub nsw i64 [[NUM3]], 1
// OMP5: store i64 [[NUM4]], i64* [[CAP3:%.+]],
// OMP5: [[RANGE_0:%.+]] = load i32*, i32** [[CAP1]],
// __begin = begin(range);
// OMP5: store i32* [[RANGE_0]], i32** [[BEGIN_INIT]],
// OMP5: [[CAP1_VAL:%.+]] = load i32*, i32** [[CAP1]],
// OMP5: [[CAP2_VAL:%.+]] = load i32*, i32** [[CAP2]],
// OMP5: [[CMP:%.+]] = icmp ult i32* [[CAP1_VAL]], [[CAP2_VAL]]
// __begin >= __end ? goto then : goto exit;
// OMP5: br i1 [[CMP]], label %[[THEN:.+]], label %[[EXIT:.+]]
// OMP5: [[THEN]]:
// lb = 0;
// OMP5: store i64 0, i64* [[LB]],
// ub = number of elements
// OMP5: [[NUM:%.+]] = load i64, i64* [[CAP3]],
// OMP5: store i64 [[NUM]], i64* [[UB]],
// stride = 1;
// OMP5: store i64 1, i64* [[STRIDE]],
// is_last = 0;
// OMP5: store i32 0, i32* [[IS_LAST]],
// loop.
// OMP5: call void @__kmpc_for_static_init_8(%struct.ident_t* {{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST]], i64* [[LB]], i64* [[UB]], i64* [[STRIDE]], i64 1, i64 1)
// ub = (ub > number_of_elems ? number_of_elems : ub);
// OMP5: [[UB_VAL:%.+]] = load i64, i64* [[UB]],
// OMP5: [[NUM_VAL:%.+]] = load i64, i64* [[CAP3]],
// OMP5: [[CMP:%.+]] = icmp sgt i64 [[UB_VAL]], [[NUM_VAL]]
// OMP5: br i1 [[CMP]], label %[[TRUE:.+]], label %[[FALSE:.+]]
// OMP5: [[TRUE]]:
// OMP5: [[NUM_VAL:%.+]] = load i64, i64* [[CAP3]],
// OMP5: br label %[[END:.+]]
// OMP5: [[FALSE]]:
// OMP5: [[UB_VAL:%.+]] = load i64, i64* [[UB]],
// OMP5: br label %[[END:.+]]
// OMP5: [[END]]:
// OMP5: [[MIN:%.+]] = phi i64 [ [[NUM_VAL]], %[[TRUE]] ], [ [[UB_VAL]], %[[FALSE]] ]
// OMP%: store i64 [[MIN]], i64* [[UB]],
// iv = lb;
// OMP5: [[LB_VAL:%.+]] = load i64, i64* [[LB]],
// OMP5: store i64 [[LB_VAL]], i64* [[IV]],
// goto loop;
// loop:
// OMP5: br label %[[LOOP:.+]]
// OMP5: [[LOOP]]:
// iv <= ub ? goto body : goto end;
// OMP5: [[IV_VAL:%.+]] = load i64, i64* [[IV]],
// OMP5: [[UB_VAL:%.+]] = load i64, i64* [[UB]],
// OMP5: [[CMP:%.+]] = icmp sle i64 [[IV_VAL]], [[UB_VAL]]
// OMP5: br i1 [[CMP]], label %[[BODY:.+]], label %[[END:.+]]
// body:
// __begin = begin(arr) + iv * 1;
// OMP5: [[BODY]]:
// OMP5: [[CAP1_VAL:%.+]] = load i32*, i32** [[CAP1]],
// OMP5: [[IV_VAL:%.+]] = load i64, i64* [[IV]],
// OMP5: [[MUL:%.+]] = mul nsw i64 [[IV_VAL]], 1
// OMP5: [[ADDR:%.+]] = getelementptr inbounds i32, i32* [[CAP1_VAL]], i64 [[MUL]]
// OMP5: store i32* [[ADDR]], i32** [[BEGIN]],
// a = *__begin;
// OMP5: [[BEGIN_VAL:%.+]] = load i32*, i32** [[BEGIN]],
// OMP5: store i32* [[BEGIN_VAL]], i32** [[A_PTR]],
// (void)a;
// OMP5: load i32*, i32** [[A_PTR]],
// iv += 1;
// OMP5: [[IV_VAL:%.+]] = load i64, i64* [[IV]],
// OMP5: [[IV_VAL_ADD_1:%.+]] = add nsw i64 [[IV_VAL]], 1
// OMP5: store i64 [[IV_VAL_ADD_1]], i64* [[IV]],
// goto loop;
// OMP5: br label %[[LOOP]]
// end:
// OMP5: [[END]]:
// OMP5: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 [[GTID]])
// exit:
// OMP5: [[EXIT]]:
// OMP5: ret void
// OMP5-LABEL: range_for_collapsed
void range_for_collapsed() {
int arr[10] = {0};
// OMP5: call void @__kmpc_for_static_init_8(%struct.ident_t* {{.+}}, i32 [[GTID%.+]], i32 34, i32* %{{.+}}, i64* %{{.+}}, i64* %{{.+}}, i64* %{{.+}}, i64 1, i64 1)
#pragma omp parallel for collapse(2)
for (auto &a : arr)
for (auto b : arr)
a = b;
// OMP5: call void @__kmpc_for_static_fini(%struct.ident_t* {{.+}}, i32 [[GTID]])
}
#endif // OMP5
#endif // HEADER

View File

@ -281,7 +281,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp parallel for' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp parallel for' must be a for loop}}
#pragma omp parallel for
for (auto &item : a) {
item = item + 1;

View File

@ -283,7 +283,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp parallel for simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp parallel for simd' must be a for loop}}
#pragma omp parallel for simd
for (auto &item : a) {
item = item + 1;

View File

@ -300,7 +300,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp simd' must be a for loop}}
#pragma omp simd
for (auto &item : a) {
item = item + 1;

View File

@ -281,7 +281,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp target parallel for' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp target parallel for' must be a for loop}}
#pragma omp target parallel for
for (auto &item : a) {
item = item + 1;

View File

@ -283,7 +283,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp target parallel for simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp target parallel for simd' must be a for loop}}
#pragma omp target parallel for simd
for (auto &item : a) {
item = item + 1;

View File

@ -283,7 +283,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp target simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp target simd' must be a for loop}}
#pragma omp target simd
for (auto &item : a) {
item = item + 1;

View File

@ -269,7 +269,7 @@ int test_iteration_spaces() {
}
#pragma omp target teams distribute
// expected-error@+1 {{statement after '#pragma omp target teams distribute' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp target teams distribute' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}

View File

@ -267,7 +267,7 @@ int test_iteration_spaces() {
}
#pragma omp target teams distribute parallel for
// expected-error@+1 {{statement after '#pragma omp target teams distribute parallel for' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp target teams distribute parallel for' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}

View File

@ -269,7 +269,7 @@ int test_iteration_spaces() {
c[globalii] += a[globalii] + ii;
}
// expected-error@+2 {{statement after '#pragma omp target teams distribute parallel for simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp target teams distribute parallel for simd' must be a for loop}}
#pragma omp target teams distribute parallel for simd
for (auto &item : a) {
item = item + 1;

View File

@ -350,7 +350,7 @@ int test_iteration_spaces() {
}
#pragma omp parallel
// expected-error@+2 {{statement after '#pragma omp taskloop' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp taskloop' must be a for loop}}
#pragma omp taskloop
for (auto &item : a) {
item = item + 1;

View File

@ -352,7 +352,7 @@ int test_iteration_spaces() {
}
#pragma omp parallel
// expected-error@+2 {{statement after '#pragma omp taskloop simd' must be a for loop}}
// omp4-error@+2 {{statement after '#pragma omp taskloop simd' must be a for loop}}
#pragma omp taskloop simd
for (auto &item : a) {
item = item + 1;

View File

@ -317,7 +317,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams distribute
// expected-error@+1 {{statement after '#pragma omp teams distribute' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp teams distribute' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}

View File

@ -315,7 +315,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams distribute parallel for
// expected-error@+1 {{statement after '#pragma omp teams distribute parallel for' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp teams distribute parallel for' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}

View File

@ -317,7 +317,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams distribute parallel for simd
// expected-error@+1 {{statement after '#pragma omp teams distribute parallel for simd' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp teams distribute parallel for simd' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}

View File

@ -317,7 +317,7 @@ int test_iteration_spaces() {
#pragma omp target
#pragma omp teams distribute simd
// expected-error@+1 {{statement after '#pragma omp teams distribute simd' must be a for loop}}
// omp4-error@+1 {{statement after '#pragma omp teams distribute simd' must be a for loop}}
for (auto &item : a) {
item = item + 1;
}