[OPENMP 4.5] Initial support for data members in 'linear' clause.

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
This commit is contained in:
Alexey Bataev 2016-03-03 03:52:24 +00:00
parent 600ca6fd39
commit 2bbf7217ea
9 changed files with 92 additions and 76 deletions

View 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]>;

View 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);
}
}
}
}
}

View 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);
}

View 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) {

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}