[OPENMP 4.5] Initial support for data members in 'linear' clause.
authorAlexey Bataev <a.bataev@hotmail.com>
Thu, 3 Mar 2016 03:52:24 +0000 (03:52 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Thu, 3 Mar 2016 03:52:24 +0000 (03:52 +0000)
OpenMP 4.5 allows to privatize data members of current class in member
functions. Patch adds initial support for privatization of data members
in 'linear' clause, no codegen support.

llvm-svn: 262578

clang/include/clang/Basic/Attr.td
clang/lib/CodeGen/CGStmtOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/test/OpenMP/for_ast_print.cpp
clang/test/OpenMP/for_linear_messages.cpp
clang/test/OpenMP/for_simd_linear_messages.cpp
clang/test/OpenMP/parallel_for_linear_messages.cpp
clang/test/OpenMP/parallel_for_simd_linear_messages.cpp
clang/test/OpenMP/target_parallel_for_linear_messages.cpp

index b77a533..983f534 100644 (file)
@@ -2185,6 +2185,13 @@ def OMPThreadPrivateDecl : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
+def OMPCaptureNoInit : InheritableAttr {
+  // This attribute has no spellings as it is only ever created implicitly.
+  let Spellings = [];
+  let SemaHandler = 0;
+  let Documentation = [Undocumented];
+}
+
 def InternalLinkage : InheritableAttr {
   let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
index 90d6a82..ddceb1b 100644 (file)
@@ -18,6 +18,7 @@
 #include "TargetInfo.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/DeclOpenMP.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -30,8 +31,15 @@ class OMPLexicalScope {
     for (const auto *C : S.clauses()) {
       if (auto *CPI = OMPClauseWithPreInit::get(C)) {
         if (auto *PreInit = cast_or_null<DeclStmt>(CPI->getPreInitStmt())) {
-          for (const auto *I : PreInit->decls())
-            CGF.EmitVarDecl(cast<VarDecl>(*I));
+          for (const auto *I : PreInit->decls()) {
+            if (!I->hasAttr<OMPCaptureNoInitAttr>())
+              CGF.EmitVarDecl(cast<VarDecl>(*I));
+            else {
+              CodeGenFunction::AutoVarEmission Emission =
+                  CGF.EmitAutoVarAlloca(cast<VarDecl>(*I));
+              CGF.EmitAutoVarCleanups(Emission);
+            }
+          }
         }
       }
     }
index 86ad66f..50148b5 100644 (file)
@@ -1706,6 +1706,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
 
 static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
                                              Expr *CaptureExpr, bool WithInit) {
+  assert(CaptureExpr);
   ASTContext &C = S.getASTContext();
   Expr *Init = CaptureExpr->IgnoreImpCasts();
   QualType Ty = Init->getType();
@@ -1723,12 +1724,11 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
     WithInit = true;
   }
   auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty);
+  if (!WithInit)
+    CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange()));
   S.CurContext->addHiddenDecl(CED);
-  if (WithInit)
-    S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false,
-                           /*TypeMayContainAuto=*/true);
-  else
-    S.ActOnUninitializedDecl(CED, /*TypeMayContainAuto=*/true);
+  S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false,
+                         /*TypeMayContainAuto=*/true);
   return CED;
 }
 
@@ -7676,7 +7676,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
       }
       if (TopDVar.CKind == OMPC_firstprivate ||
           (!IsOpenMPCapturedDecl(D) &&
-           !cast<OMPCapturedExprDecl>(Ref->getDecl())->getInit())) {
+           Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) {
         ExprResult RefRes = DefaultLvalueConversion(Ref);
         if (!RefRes.isUsable())
           continue;
@@ -8277,7 +8277,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
             buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
         if (!IsOpenMPCapturedDecl(D)) {
           ExprCaptures.push_back(Ref->getDecl());
-          if (!cast<OMPCapturedExprDecl>(Ref->getDecl())->getInit()) {
+          if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
             ExprResult RefRes = DefaultLvalueConversion(Ref);
             if (!RefRes.isUsable())
               continue;
@@ -8340,115 +8340,96 @@ OMPClause *Sema::ActOnOpenMPLinearClause(
   }
   for (auto &RefExpr : VarList) {
     assert(RefExpr && "NULL expr in OpenMP linear clause.");
-    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+    SourceLocation ELoc;
+    SourceRange ERange;
+    Expr *SimpleRefExpr = RefExpr;
+    auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+                              /*AllowArraySection=*/false);
+    if (Res.second) {
       // It will be analyzed later.
       Vars.push_back(RefExpr);
       Privates.push_back(nullptr);
       Inits.push_back(nullptr);
-      continue;
     }
-
-    // OpenMP [2.14.3.7, linear clause]
-    // A list item that appears in a linear clause is subject to the private
-    // clause semantics described in Section 2.14.3.3 on page 159 except as
-    // noted. In addition, the value of the new list item on each iteration
-    // of the associated loop(s) corresponds to the value of the original
-    // list item before entering the construct plus the logical number of
-    // the iteration times linear-step.
-
-    SourceLocation ELoc = RefExpr->getExprLoc();
-    // OpenMP [2.1, C/C++]
-    //  A list item is a variable name.
-    // OpenMP  [2.14.3.3, Restrictions, p.1]
-    //  A variable that is part of another variable (as an array or
-    //  structure element) cannot appear in a private clause.
-    DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
-    if (!DE || !isa<VarDecl>(DE->getDecl())) {
-      Diag(ELoc, diag::err_omp_expected_var_name_member_expr)
-          << 0 << RefExpr->getSourceRange();
+    ValueDecl *D = Res.first;
+    if (!D)
       continue;
-    }
 
-    VarDecl *VD = cast<VarDecl>(DE->getDecl());
+    QualType Type = D->getType();
+    auto *VD = dyn_cast<VarDecl>(D);
 
     // OpenMP [2.14.3.7, linear clause]
     //  A list-item cannot appear in more than one linear clause.
     //  A list-item that appears in a linear clause cannot appear in any
     //  other data-sharing attribute clause.
-    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
     if (DVar.RefExpr) {
       Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
                                           << getOpenMPClauseName(OMPC_linear);
-      ReportOriginalDSA(*this, DSAStack, VD, DVar);
-      continue;
-    }
-
-    QualType QType = VD->getType();
-    if (QType->isDependentType() || QType->isInstantiationDependentType()) {
-      // It will be analyzed later.
-      Vars.push_back(DE);
-      Privates.push_back(nullptr);
-      Inits.push_back(nullptr);
+      ReportOriginalDSA(*this, DSAStack, D, DVar);
       continue;
     }
 
     // A variable must not have an incomplete type or a reference type.
-    if (RequireCompleteType(ELoc, QType,
-                            diag::err_omp_linear_incomplete_type)) {
+    if (RequireCompleteType(ELoc, Type,
+                            diag::err_omp_linear_incomplete_type))
       continue;
-    }
     if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
-        !QType->isReferenceType()) {
+        !Type->isReferenceType()) {
       Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
-          << QType << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
+          << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
       continue;
     }
-    QType = QType.getNonReferenceType();
+    Type = Type.getNonReferenceType();
 
     // A list item must not be const-qualified.
-    if (QType.isConstant(Context)) {
+    if (Type.isConstant(Context)) {
       Diag(ELoc, diag::err_omp_const_variable)
           << getOpenMPClauseName(OMPC_linear);
       bool IsDecl =
+          !VD ||
           VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
-      Diag(VD->getLocation(),
+      Diag(D->getLocation(),
            IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-          << VD;
+          << D;
       continue;
     }
 
     // A list item must be of integral or pointer type.
-    QType = QType.getUnqualifiedType().getCanonicalType();
-    const Type *Ty = QType.getTypePtrOrNull();
+    Type = Type.getUnqualifiedType().getCanonicalType();
+    const auto *Ty = Type.getTypePtrOrNull();
     if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
                 !Ty->isPointerType())) {
-      Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType;
+      Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
       bool IsDecl =
+          !VD ||
           VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
-      Diag(VD->getLocation(),
+      Diag(D->getLocation(),
            IsDecl ? diag::note_previous_decl : diag::note_defined_here)
-          << VD;
+          << D;
       continue;
     }
 
     // Build private copy of original var.
-    auto *Private = buildVarDecl(*this, ELoc, QType, VD->getName(),
-                                 VD->hasAttrs() ? &VD->getAttrs() : nullptr);
-    auto *PrivateRef = buildDeclRefExpr(
-        *this, Private, DE->getType().getUnqualifiedType(), DE->getExprLoc());
+    auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(),
+                                 D->hasAttrs() ? &D->getAttrs() : nullptr);
+    auto *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc);
     // Build var to save initial value.
-    VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start");
+    VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start");
     Expr *InitExpr;
+    DeclRefExpr *Ref = nullptr;
+    if (!VD)
+      Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
     if (LinKind == OMPC_LINEAR_uval)
-      InitExpr = VD->getInit();
+      InitExpr = VD ? VD->getInit() : SimpleRefExpr;
     else
-      InitExpr = DE;
+      InitExpr = VD ? SimpleRefExpr : Ref;
     AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(),
-                         /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
-    auto InitRef = buildDeclRefExpr(
-        *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc());
-    DSAStack->addDSA(VD, DE, OMPC_linear);
-    Vars.push_back(DE);
+                         /*DirectInit=*/false, /*TypeMayContainAuto=*/false);
+    auto InitRef = buildDeclRefExpr(*this, Init, Type, ELoc);
+
+    DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref);
+    Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref);
     Privates.push_back(PrivateRef);
     Inits.push_back(InitRef);
   }
index 38dafc0..182b395 100644 (file)
@@ -19,16 +19,22 @@ template <typename T>
 class S7 : public T {
 protected:
   T a;
-  S7() : a(0) {}
+  T &b;
+  typename T::type c:12;
+  typename T::type &d;
+  S7() : a(0), b(a), c(0), d(a.a) {}
 
 public:
-  S7(typename T::type v) : a(v) {
+  S7(typename T::type v) : a(v), b(a), c(v), d(a.a) {
 #pragma omp for private(a) private(this->a) private(T::a)
     for (int k = 0; k < a.a; ++k)
       ++this->a.a;
 #pragma omp for lastprivate(a) lastprivate(this->a) lastprivate(T::a)
     for (int k = 0; k < a.a; ++k)
       ++this->a.a;
+#pragma omp for linear(val(c))
+    for (int k = 0; k < a.a; ++k)
+      ++this->a.a;
   }
   S7 &operator=(S7 &s) {
 #pragma omp for private(a) private(this->a)
@@ -37,16 +43,22 @@ public:
 #pragma omp for lastprivate(a) lastprivate(this->a)
     for (int k = 0; k < s.a.a; ++k)
       ++s.a.a;
+#pragma omp for linear(uval(this->b))
+    for (int k = 0; k < s.a.a; ++k)
+      ++s.a.a;
     return *this;
   }
 };
 
 // CHECK: #pragma omp for private(this->a) private(this->a) private(this->S::a)
 // CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(this->S::a)
+// CHECK: #pragma omp for linear(val(this->c))
 // CHECK: #pragma omp for private(this->a) private(this->a) private(T::a)
 // CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(T::a)
+// CHECK: #pragma omp for linear(val(this->c))
 // CHECK: #pragma omp for private(this->a) private(this->a)
 // CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a)
+// CHECK: #pragma omp for linear(uval(this->b))
 
 class S8 : public S7<S> {
   S8() {}
@@ -59,6 +71,9 @@ public:
 #pragma omp for lastprivate(a) lastprivate(this->a) lastprivate(S7<S>::a)
     for (int k = 0; k < a.a; ++k)
       ++this->a.a;
+#pragma omp for linear(ref(S7<S>::d))
+    for (int k = 0; k < a.a; ++k)
+      ++this->a.a;
   }
   S8 &operator=(S8 &s) {
 #pragma omp for private(a) private(this->a)
@@ -67,14 +82,19 @@ public:
 #pragma omp for lastprivate(a) lastprivate(this->a)
     for (int k = 0; k < s.a.a; ++k)
       ++s.a.a;
+#pragma omp for linear(this->c)
+    for (int k = 0; k < s.a.a; ++k)
+      ++s.a.a;
     return *this;
   }
 };
 
 // CHECK: #pragma omp for private(this->a) private(this->a) private(this->S7<S>::a)
 // CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(this->S7<S>::a)
+// CHECK: #pragma omp for linear(ref(this->S7<S>::d))
 // CHECK: #pragma omp for private(this->a) private(this->a)
 // CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a)
+// CHECK: #pragma omp for linear(this->c)
 
 template <class T, int N>
 T tmain(T argc) {
index 39fb21e..ab89349 100644 (file)
@@ -212,7 +212,7 @@ int main(int argc, char **argv) {
   #pragma omp for linear(i) ordered(1) // expected-error {{'linear' clause cannot be specified along with 'ordered' clause with a parameter}}
   for (int k = 0; k < argc; ++k) ++k;
 
-  foomain<int,char>(argc,argv);
+  foomain<int,char>(argc,argv); // expected-note {{n instantiation of function template specialization 'foomain<int, char>' requested here}}
   return 0;
 }
 
index 44370a1..3f93125 100644 (file)
@@ -208,7 +208,7 @@ int main(int argc, char **argv) {
   #pragma omp for simd linear(i)
   for (int k = 0; k < argc; ++k) ++k;
 
-  foomain<int,char>(argc,argv);
+  foomain<int,char>(argc,argv); // expected-note {{in instantiation of function template specialization 'foomain<int, char>' requested here}}
   return 0;
 }
 
index 7272aad..e5f5b61 100644 (file)
@@ -263,7 +263,7 @@ int main(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 
-  foomain<int, char>(argc, argv);
+  foomain<int, char>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<int, char>' requested here}}
   return 0;
 }
 
index 858f53f..fc1895a 100644 (file)
@@ -208,7 +208,7 @@ int main(int argc, char **argv) {
   #pragma omp parallel for simd linear(i)
   for (int k = 0; k < argc; ++k) ++k;
 
-  foomain<int,char>(argc,argv);
+  foomain<int,char>(argc,argv); // expected-note {{in instantiation of function template specialization 'foomain<int, char>' requested here}}
   return 0;
 }
 
index c1694c0..36e897d 100644 (file)
@@ -263,7 +263,7 @@ int main(int argc, char **argv) {
   for (int k = 0; k < argc; ++k)
     ++k;
 
-  foomain<int, char>(argc, argv);
+  foomain<int, char>(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain<int, char>' requested here}}
   return 0;
 }