[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:
parent
b4cbf9862c
commit
bef93a98cd
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue