Index: clang/include/clang/AST/StmtOpenMP.h =================================================================== --- clang/include/clang/AST/StmtOpenMP.h +++ clang/include/clang/AST/StmtOpenMP.h @@ -1126,6 +1126,9 @@ return llvm::MutableArrayRef(Storage, getLoopsNumber()); } + // This is copied over from Sema::DSAStackTy + OpenMPDirectiveKind MappedDirective = llvm::omp::OMPD_unknown; + protected: /// Build instance of loop directive of class \a Kind. /// @@ -1556,6 +1559,12 @@ T->getStmtClass() == OMPTargetTeamsDistributeDirectiveClass || T->getStmtClass() == OMPTargetTeamsDistributeSimdDirectiveClass; } + + // The following two are copied over from Sema::DSAStackTy for -ast-print + void setMappedDirective(OpenMPDirectiveKind NewDK) { + MappedDirective = NewDK; + } + OpenMPDirectiveKind getMappedDirective() const { return MappedDirective; } }; /// This represents '#pragma omp simd' directive. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9813,6 +9813,11 @@ def warn_loop_ctrl_binds_to_inner : Warning< "'%0' is bound to current loop, GCC binds it to the enclosing loop">, InGroup; +def err_omp_bind_required_on_loop : Error< + "expected 'bind' clause for loop construct without an enclosing OpenMP " + "construct">; +def err_omp_loop_reduction_clause : Error< + "reduction clause not handled with '#pragma omp loop bind(teams)'">; def warn_break_binds_to_switch : Warning< "'break' is bound to loop, GCC binds it to switch">, InGroup; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11080,6 +11080,8 @@ /// All `omp assumes` we encountered so far. SmallVector OMPAssumeGlobal; + bool CheckLastPrivateForMappedDirectives(ArrayRef Clauses); + public: /// The declarator \p D defines a function in the scope \p S which is nested /// in an `omp begin/end declare variant` scope. In this method we create a Index: clang/lib/AST/StmtPrinter.cpp =================================================================== --- clang/lib/AST/StmtPrinter.cpp +++ clang/lib/AST/StmtPrinter.cpp @@ -741,7 +741,12 @@ } void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) { - Indent() << "#pragma omp simd"; + OpenMPDirectiveKind MappedDirective = Node->getMappedDirective(); + if (MappedDirective != llvm::omp::OMPD_unknown && + MappedDirective == llvm::omp::OMPD_loop) { + Indent() << "#pragma omp loop bind(thread)"; + } else + Indent() << "#pragma omp simd"; PrintOMPExecutableDirective(Node); } @@ -756,7 +761,12 @@ } void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { - Indent() << "#pragma omp for"; + OpenMPDirectiveKind MappedDirective = Node->getMappedDirective(); + if (MappedDirective != llvm::omp::OMPD_unknown && + MappedDirective == llvm::omp::OMPD_loop) { + Indent() << "#pragma omp loop bind(parallel)"; + } else + Indent() << "#pragma omp for"; PrintOMPExecutableDirective(Node); } @@ -991,7 +1001,12 @@ } void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { - Indent() << "#pragma omp distribute"; + OpenMPDirectiveKind MappedDirective = Node->getMappedDirective(); + if (MappedDirective != llvm::omp::OMPD_unknown && + MappedDirective == llvm::omp::OMPD_loop) { + Indent() << "#pragma omp loop bind(teams)"; + } else + Indent() << "#pragma omp distribute"; PrintOMPExecutableDirective(Node); } Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -337,6 +337,11 @@ /// Vector of declare variant construct traits. SmallVector ConstructTraits; + /// GenericLoopDirective with bind clause is mapped to other directives, + /// like for, distribute and simd. Presently, set MappedDirective to OMPLoop. + /// This may also be used in a similar way for other constructs. + OpenMPDirectiveKind MappedDirective = OMPD_unknown; + public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} @@ -636,6 +641,17 @@ const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->Directive : OMPD_unknown; } + OpenMPDirectiveKind getMappedDirective() const { return MappedDirective; } + void setCurrentDirective(OpenMPDirectiveKind NewDK) { + SharingMapTy *Top = (SharingMapTy *)getTopOfStackOrNull(); + assert(Top != NULL && + "Before calling setCurrentDirective Top of Stack not to be NULL."); + // Store the old into MappedDirective & assign argument NewDK to Directive. + Top->Directive = NewDK; + } + void setMappedDirective(OpenMPDirectiveKind NewDK) { + MappedDirective = NewDK; + } /// Returns directive kind at specified level. OpenMPDirectiveKind getDirective(unsigned Level) const { assert(!isStackEmpty() && "No directive at specified level."); @@ -6121,10 +6137,78 @@ isOpenMPTargetDataManagementDirective(Kind))) Diag(StartLoc, diag::warn_hip_omp_target_directives); + llvm::SmallVector ClausesWithoutBind; + bool UseClausesWithoutBind = false; + + // Restricting to "#pragma omp loop bind" + if (Kind == OMPD_loop) { + if (BindKind == OMPC_BIND_unknown) { + // Setting the enclosing teams or parallel construct for the loop + // directive without bind clause. + BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown + + const OpenMPDirectiveKind ParentDirective = + DSAStack->getParentDirective(); + if (ParentDirective == OMPD_unknown) { + Diag(DSAStack->getDefaultDSALocation(), + diag::err_omp_bind_required_on_loop); + } else if (ParentDirective == OMPD_parallel || + ParentDirective == OMPD_target_parallel) { + BindKind = OMPC_BIND_parallel; + } else if (ParentDirective == OMPD_teams || + ParentDirective == OMPD_target_teams) { + BindKind = OMPC_BIND_teams; + } + } else { + // bind clause is present, so we should set flag indicating to only + // use the clauses that aren't the bind clause for the new directive that + // loop is lowered to. + UseClausesWithoutBind = true; + } + + for (OMPClause *C : Clauses) { + // Spec restriction : bind(teams) and reduction not permitted. + if (BindKind == OMPC_BIND_teams && + C->getClauseKind() == llvm::omp::Clause::OMPC_reduction) + Diag(DSAStack->getDefaultDSALocation(), + diag::err_omp_loop_reduction_clause); + + // A new Vector ClausesWithoutBind, which does not contain the bind + // clause, for passing to new directive. + if (C->getClauseKind() != llvm::omp::Clause::OMPC_bind) + ClausesWithoutBind.push_back(C); + } + + switch (BindKind) { + case OMPC_BIND_parallel: + Kind = OMPD_for; + DSAStack->setCurrentDirective(OMPD_for); + DSAStack->setMappedDirective(OMPD_loop); + break; + case OMPC_BIND_teams: + Kind = OMPD_distribute; + DSAStack->setCurrentDirective(OMPD_distribute); + DSAStack->setMappedDirective(OMPD_loop); + break; + case OMPC_BIND_thread: + Kind = OMPD_simd; + DSAStack->setCurrentDirective(OMPD_simd); + DSAStack->setMappedDirective(OMPD_loop); + break; + case OMPC_BIND_unknown: + break; + } + } + llvm::SmallVector ClausesWithImplicit; VarsWithInheritedDSAType VarsWithInheritedDSA; bool ErrorFound = false; - ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); + if (UseClausesWithoutBind) { + ClausesWithImplicit.append(ClausesWithoutBind.begin(), + ClausesWithoutBind.end()); + } else { + ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); + } if (AStmt && !CurContext->isDependentContext() && Kind != OMPD_atomic && Kind != OMPD_critical && Kind != OMPD_section && Kind != OMPD_master && Kind != OMPD_masked && !isOpenMPLoopTransformationDirective(Kind)) { @@ -9201,9 +9285,12 @@ auto *CXXFor = dyn_cast_or_null(S); // Ranged for is supported only in OpenMP 5.0. if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) { + OpenMPDirectiveKind DK = (DSA.getMappedDirective() == OMPD_unknown) + ? DKind + : DSA.getMappedDirective(); SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for) << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) - << getOpenMPDirectiveName(DKind) << TotalNestedLoopCount + << getOpenMPDirectiveName(DK) << TotalNestedLoopCount << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount; if (TotalNestedLoopCount > 1) { if (CollapseLoopCountExpr && OrderedLoopCountExpr) @@ -10287,6 +10374,10 @@ return false; } +static bool checkGenericLoopLastprivate(Sema &S, ArrayRef Clauses, + OpenMPDirectiveKind K, + DSAStackTy *Stack); + StmtResult Sema::ActOnOpenMPSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, @@ -10294,6 +10385,9 @@ if (!AStmt) return StmtError(); + if (!CheckLastPrivateForMappedDirectives(Clauses)) + return StmtError(); + assert(isa(AStmt) && "Captured statement expected"); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -10322,8 +10416,10 @@ return StmtError(); setFunctionHasBranchProtectedScope(); - return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt, B); + OMPSimdDirective *tmp = OMPSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + tmp->setMappedDirective(DSAStack->getMappedDirective()); + return tmp; } StmtResult @@ -10334,6 +10430,10 @@ return StmtError(); assert(isa(AStmt) && "Captured statement expected"); + + if (!CheckLastPrivateForMappedDirectives(Clauses)) + return StmtError(); + OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. @@ -10358,9 +10458,11 @@ } setFunctionHasBranchProtectedScope(); - return OMPForDirective::Create( + OMPForDirective *tmp = OMPForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); + tmp->setMappedDirective(DSAStack->getMappedDirective()); + return tmp; } StmtResult Sema::ActOnOpenMPForSimdDirective( @@ -10369,6 +10471,12 @@ if (!AStmt) return StmtError(); + /* Check for syntax of lastprivate */ + if (DSAStack->getMappedDirective() == OMPD_loop) { + if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack)) + return StmtError(); + } + assert(isa(AStmt) && "Captured statement expected"); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -13880,12 +13988,31 @@ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } +bool Sema::CheckLastPrivateForMappedDirectives(ArrayRef Clauses) { + + /* Check for syntax of lastprivate */ + if (DSAStack->getMappedDirective() == OMPD_loop) { + if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack)) + return false; + } + return true; +} + StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); + if (!CheckLastPrivateForMappedDirectives(Clauses)) + return StmtError(); + + /* Check for syntax of lastprivate */ + if (DSAStack->getMappedDirective() == OMPD_loop) { + if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack)) + return StmtError(); + } + assert(isa(AStmt) && "Captured statement expected"); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -13901,8 +14028,10 @@ "omp for loop exprs were not built"); setFunctionHasBranchProtectedScope(); - return OMPDistributeDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + OMPDistributeDirective *tmp = OMPDistributeDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + tmp->setMappedDirective(DSAStack->getMappedDirective()); + return tmp; } StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( Index: clang/test/OpenMP/loop_bind_codegen.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/loop_bind_codegen.cpp @@ -0,0 +1,141 @@ +// expected-no-diagnostics +// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s + + +#define NNN 50 +int aaa[NNN]; + +void parallel_loop() { + #pragma omp parallel + { + #pragma omp loop bind(parallel) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } +} + +void parallel_loop_orphan() { + #pragma omp loop bind(parallel) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } +} + + +void teams_loop() { + #pragma omp teams + { + #pragma omp loop bind(teams) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } +} + +void thread_loop() { + #pragma omp parallel + { + #pragma omp loop bind(thread) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } +} + +void thread_loop_orphan() { + #pragma omp loop bind(thread) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } +} + +int main() { + parallel_loop(); + parallel_loop_orphan(); + teams_loop(); + thread_loop(); + thread_loop_orphan(); + + return 0; +} +// CHECK-LABEL: define {{[^@]+}}@_Z13parallel_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}}) +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[J:%.*]] = alloca i32, align 4 +// CHECK: call void @__kmpc_for_static_init_4(ptr @1, i32 %1, i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-LABEL: cond.true: +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK-LABEL: cond.false: +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: br label [[COND_END]] +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK: omp.inner.for.body: +// CHECK: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @1, i32 %1) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @2, i32 %1) +// CHECK-NEXT: ret void +// +// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_loop_orphanv +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK: call void @__kmpc_for_static_init_4(ptr @1, i32 %0, i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-LABEL: cond.true: +// CHECK: omp.inner.for.cond: +// CHECK: omp.loop.exit: +// +// CHECK-LABEL: define {{[^@]+}}@_Z10teams_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.1]*}}) +// CHECK-NEXT: ret void +// +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[J:%.*]] = alloca i32, align 4 +// CHECK: call void @__kmpc_for_static_init_4(ptr @4, i32 %1, i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) +// CHECK-LABEL: cond.true: +// CHECK-NEXT: br label [[COND_END:%.*]] +// CHECK-LABEL: cond.false: +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK-NEXT: br label [[COND_END]] +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK: omp.inner.for.body: +// CHECK: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @4, i32 %1) +// CHECK-NEXT: ret void +// +// CHECK-LABEL: define {{[^@]+}}@_Z11thread_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @3, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.2]*}}) +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK: omp.inner.for.cond: +// +// CHECK-LABEL: define {{[^@]+}}@_Z18thread_loop_orphanv +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK: omp.inner.for.cond: +// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// +// CHECK-LABEL: @main{{.*}} Index: clang/test/OpenMP/loop_bind_enclosed.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/loop_bind_enclosed.cpp @@ -0,0 +1,140 @@ +// expected-no-diagnostics +// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s + +#define NNN 50 +int aaa[NNN]; + +void parallel_taskgroup_loop() { + #pragma omp parallel + { + #pragma omp taskgroup + for (int i = 0 ; i < 2 ; i++) { + #pragma omp loop + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } + } +} +// CHECK-LABEL: define {{[^@]+}}@_Z23parallel_taskgroup_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}}) +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK-NEXT: entry: +// CHECK: call void @__kmpc_taskgroup(ptr @1, i32 %1) +// CHECK-LABEL: omp.inner.for.end: +// CHECK-LABEL: for.end: +// CHECK-NEXT: call void @__kmpc_end_taskgroup(ptr @1, i32 %1) +// CHECK-NEXT: ret void + +void parallel_taskwait_loop() { + #pragma omp parallel + { + #pragma omp taskwait + for (int i = 0 ; i < 2 ; i++) { + #pragma omp loop + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } + } +} +// CHECK-LABEL: define {{[^@]+}}@_Z22parallel_taskwait_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}}) +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK: call i32 @__kmpc_omp_taskwait(ptr @1, i32 %1) +// CHECK-LABEL: omp.loop.exit: +// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr @2, i32 %1) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @3, i32 %1) +// CHECK-LABEL: for.end: +// CHECK-NEXT: ret void + +void parallel_single_loop() { + #pragma omp parallel + { + for (int i = 0 ; i < 2 ; i++) { + #pragma omp single + #pragma omp loop + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } + } +} +// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_single_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}}) +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK-NEXT: entry: +// CHECK: [[TMP:%.*]] = call i32 @__kmpc_single(ptr @1, i32 %2) +// CHECK-LABEL: omp.inner.for.end: +// CHECK: call void @__kmpc_end_single(ptr @1, i32 %2) +// CHECK-LABEL: for.end: +// CHECK-NEXT: ret void + +void parallel_order_loop() { + #pragma omp parallel + { + #pragma omp for order(concurrent) + { + for (int i = 0 ; i < 2 ; i++) { + #pragma omp loop + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } + } + } +} +// CHECK-LABEL: define {{[^@]+}}@_Z19parallel_order_loopv +// CHECK-NEXT: entry: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 0, ptr @{{[_A-Za-z0-9]*}}.omp_outlined{{[.]*}}) +// CHECK-NEXT: ret void +// CHECK-LABEL: define {{[^@]+}}@{{[_A-Za-z0-9]*}}.omp_outlined +// CHECK-NEXT: entry: +// CHECK: call void @__kmpc_for_static_fini(ptr @2, i32 %1) +// CHECK-NEXT: call void @__kmpc_barrier(ptr @3, i32 %1) +// CHECK-NEXT: ret void + + +void parallel_cancel_loop(bool flag) { + #pragma omp ordered + for (int i = 0 ; i < 2 ; i++) { + #pragma omp parallel + { + #pragma omp cancel parallel if(flag) + aaa[0] = 0; + #pragma omp loop bind(parallel) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } + } +} +// CHECK-LABEL: define {{[^@]+}}@_Z20parallel_cancel_loopb +// CHECK-NEXT: entry: +// CHECK-NEXT: [[FLAG_DOTADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK: call void @__kmpc_ordered(ptr @1, i32 %0) +// CHECK-LABEL: for.body: +// CHECK-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 1, ptr @_Z20parallel_cancel_loopb.omp_outlined, ptr [[FLAG_DOTADDR]]) +// CHECK-LABEL: for.end: +// CHECK-NEXT: call void @__kmpc_end_ordered(ptr @1, i32 %0) +// CHECK-NEXT: ret void + +int +main(int argc, char *argv[]) { + parallel_taskgroup_loop(); + parallel_taskwait_loop(); + parallel_single_loop(); + parallel_order_loop(); + parallel_cancel_loop(true); + parallel_cancel_loop(false); + + return 0; +} Index: clang/test/OpenMP/loop_bind_messages.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/loop_bind_messages.cpp @@ -0,0 +1,76 @@ +#ifndef HEADER +#define HEADER +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -verify %s + +#define NNN 50 +int aaa[NNN]; + +void parallel_loop() { + #pragma omp parallel + { + #pragma omp loop + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + } +} + +void teams_loop() { + int var1, var2; + + #pragma omp teams + { + #pragma omp loop bind(teams) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + + #pragma omp loop bind(teams) collapse(2) private(var1) + for (int i = 0 ; i < 3 ; i++) { + for (int j = 0 ; j < NNN ; j++) { + var1 += aaa[j]; + } + } + } +} + +void orphan_loop_with_bind() { + #pragma omp loop bind(parallel) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } +} + +void orphan_loop_no_bind() { + #pragma omp loop // expected-error{{expected 'bind' clause for loop construct without an enclosing OpenMP construct}} + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } +} + +void teams_loop_reduction() { + int total = 0; + + #pragma omp teams + { + #pragma omp loop bind(teams) + for (int j = 0 ; j < NNN ; j++) { + aaa[j] = j*NNN; + } + + #pragma omp loop bind(teams) reduction(+:total) // expected-error{{reduction clause not handled with '#pragma omp loop bind(teams)'}} + for (int j = 0 ; j < NNN ; j++) { + total+=aaa[j]; + } + } +} + +int main(int argc, char *argv[]) { + parallel_loop(); + teams_loop(); + orphan_loop_with_bind(); + orphan_loop_no_bind(); + teams_loop_reduction(); +} + +#endif Index: clang/test/OpenMP/nested_loop_codegen.cpp =================================================================== --- clang/test/OpenMP/nested_loop_codegen.cpp +++ clang/test/OpenMP/nested_loop_codegen.cpp @@ -58,6 +58,11 @@ // CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[I_ADDR:%.*]] = alloca ptr, align 8 +// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4 +// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4 +// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4 +// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4 +// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[K:%.*]] = alloca i32, align 4 // CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 // CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 @@ -71,6 +76,9 @@ // CHECK1-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END7:%.*]] // CHECK1: for.body: // CHECK1-NEXT: store i32 0, ptr [[K]], align 4 +// CHECK: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBSL_TID__ADDR]], align 8 +// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4 +// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @1, i32 [[TMP3]], i32 34, ptr %.omp.is_last, ptr %.omp.lb, ptr %.omp.ub, ptr %.omp.stride, i32 1, i32 1) // CHECK1-NEXT: br label [[FOR_COND1:%.*]] // CHECK1: for.cond1: // CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[K]], align 4