diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -424,6 +424,11 @@ /// for-loops (from outer to inner). const LCDeclInfo isLoopControlVariable(const ValueDecl *D) const; /// Check if the specified variable is a loop control variable for + /// given region. + /// \return The index of the loop control variable in the list of associated + /// for-loops (from outer to inner). + const LCDeclInfo isLoopControlVariable(const ValueDecl *D, const SharingMapTy &Region) const; + /// Check if the specified variable is a loop control variable for /// parent region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). @@ -946,11 +951,24 @@ case DSA_none: return DVar; case DSA_unspecified: + DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, implicitly determined] + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct is (are) private. + // OpenMP 5.0 includes taskloop and distribute directives + if (!isOpenMPSimdDirective(DVar.DKind) && + isOpenMPLoopDirective(DVar.DKind) && + isLoopControlVariable(D, *Iter).first) { + DVar.CKind = OMPC_private; + // TODO: OpenMP 5.0: if (Dvar.DKind == OMPD_loop) DVar.CKind = OMPC_lastprivate; + return DVar; + } + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.2] // In a parallel construct, if no default clause is present, these // variables are shared. - DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; if (isOpenMPParallelDirective(DVar.DKind) || isOpenMPTeamsDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; @@ -1018,8 +1036,13 @@ const DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + return isLoopControlVariable(D, getTopOfStack()); +} + +const DSAStackTy::LCDeclInfo +DSAStackTy::isLoopControlVariable(const ValueDecl *D, const SharingMapTy &Region) const { D = getCanonicalDecl(D); - const SharingMapTy &StackElem = getTopOfStack(); + const SharingMapTy &StackElem = Region; auto It = StackElem.LCVMap.find(D); if (It != StackElem.LCVMap.end()) return It->second; diff --git a/clang/test/OpenMP/loop_control_var_nested_task.cpp b/clang/test/OpenMP/loop_control_var_nested_task.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/loop_control_var_nested_task.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -fopenmp -emit-llvm -o - | FileCheck %s +// CHECK: {{%struct}}.kmp_task_t_with_privates = type { {{.*%struct\.\.kmp_privates.t.*}} } +// CHECK: define internal void @.omp_task_privates_map.({{.*%struct\.\.kmp_privates.t.*}}) +#define N 100 +int main(void) { + // declare this variable outside, so that it will be shared on the outer parallel construct + int i; + int arr[N]; + + #pragma omp parallel // shared(i) shared(arr) + #pragma omp for // private(i) - i should be privatized because it is an iteration variable + for (i = 0; i < N; i++) { + #pragma omp task + // CHECK: %.firstpriv.ptr.addr.i = alloca i32*, align 8 + // CHECK: {{%[0-9]+}} = load i32*, i32** %.firstpriv.ptr.addr.i, align 8 + arr[i] = i; + } +}