[OpenMP] Added parsing and semantic analysis for firstprivate clause

llvm-svn: 191730
This commit is contained in:
Alexey Bataev 2013-10-01 05:32:34 +00:00
parent de111a425c
commit d5af8e472d
20 changed files with 554 additions and 20 deletions

View File

@ -2366,6 +2366,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
VisitOMPClauseList(C);

View File

@ -249,6 +249,67 @@ public:
}
};
/// \brief This represents clause 'firstprivate' in the '#pragma omp ...'
/// directives.
///
/// \code
/// #pragma omp parallel firstprivate(a,b)
/// \endcode
/// In this example directive '#pragma omp parallel' has clause 'firstprivate'
/// with the variables 'a' and 'b'.
///
class OMPFirstprivateClause : public OMPClause,
public OMPVarList<OMPFirstprivateClause> {
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param N Number of the variables in the clause.
///
OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned N)
: OMPClause(OMPC_firstprivate, StartLoc, EndLoc),
OMPVarList<OMPFirstprivateClause>(LParenLoc, N) { }
/// \brief Build an empty clause.
///
/// \param N Number of variables.
///
explicit OMPFirstprivateClause(unsigned N)
: OMPClause(OMPC_firstprivate, SourceLocation(), SourceLocation()),
OMPVarList<OMPFirstprivateClause>(SourceLocation(), N) { }
public:
/// \brief Creates clause with a list of variables \a VL.
///
/// \param C AST context.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
///
static OMPFirstprivateClause *Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
/// \param N The number of variables.
///
static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == OMPC_firstprivate;
}
};
/// \brief This represents clause 'shared' in the '#pragma omp ...' directives.
///
/// \code

View File

@ -6627,6 +6627,8 @@ def err_omp_var_thread_local : Error<
"variable %0 cannot be threadprivate because it is thread-local">;
def err_omp_private_incomplete_type : Error<
"a private variable with incomplete type %0">;
def err_omp_firstprivate_incomplete_type : Error<
"a firstprivate variable with incomplete type %0">;
def err_omp_unexpected_clause_value : Error <
"expected %0 in OpenMP clause '%1'">;
def err_omp_expected_var_name : Error <

View File

@ -33,11 +33,13 @@ OPENMP_DIRECTIVE(task)
// OpenMP clauses.
OPENMP_CLAUSE(default, OMPDefaultClause)
OPENMP_CLAUSE(private, OMPPrivateClause)
OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
OPENMP_CLAUSE(shared, OMPSharedClause)
// Clauses allowed for OpenMP directives.
OPENMP_PARALLEL_CLAUSE(default)
OPENMP_PARALLEL_CLAUSE(private)
OPENMP_PARALLEL_CLAUSE(firstprivate)
OPENMP_PARALLEL_CLAUSE(shared)
// Static attributes for 'default' clause.

View File

@ -7027,6 +7027,11 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed 'firstprivate' clause.
OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed 'shared' clause.
OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,

View File

@ -1145,6 +1145,29 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPPrivateClause(N);
}
OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) +
sizeof(Expr *) * VL.size(),
llvm::alignOf<OMPFirstprivateClause>());
OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
LParenLoc,
EndLoc,
VL.size());
Clause->setVarRefs(VL);
return Clause;
}
OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N,
llvm::alignOf<OMPFirstprivateClause>());
return new (Mem) OMPFirstprivateClause(N);
}
OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,

View File

@ -619,6 +619,14 @@ void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
}
}
void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
if (!Node->varlist_empty()) {
OS << "firstprivate";
VisitOMPClauseList(Node, '(');
OS << ")";
}
}
void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
if (!Node->varlist_empty()) {
OS << "shared";

View File

@ -278,6 +278,10 @@ void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseProfiler::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}

View File

@ -78,6 +78,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
case NUM_OPENMP_CLAUSES:
break;
@ -100,6 +101,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
case NUM_OPENMP_CLAUSES:
break;

View File

@ -252,7 +252,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// \brief Parsing of OpenMP clauses.
///
/// clause:
/// default-clause|private-clause|shared-clause
/// default-clause|private-clause|firstprivate-clause|shared-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@ -278,6 +278,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
Clause = ParseOpenMPSimpleClause(CKind);
break;
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
Clause = ParseOpenMPVarListClause(CKind);
break;
@ -330,6 +331,8 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
///
/// private-clause:
/// 'private' '(' list ')'
/// firstprivate-clause:
/// 'firstprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
///

View File

@ -106,6 +106,11 @@ public:
DSAVarData getTopDSA(VarDecl *D);
/// \brief Returns data-sharing attributes for the specified declaration.
DSAVarData getImplicitDSA(VarDecl *D);
/// \brief Checks if the specified variables has \a CKind data-sharing
/// attribute in \a DKind directive.
DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
OpenMPDirectiveKind DKind = OMPD_unknown);
/// \brief Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
@ -138,6 +143,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
if (!D->isFunctionOrMethodVarDecl())
DVar.CKind = OMPC_shared;
// OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// Variables with static storage duration that are declared in called
// routines in the region are shared.
if (D->hasGlobalStorage())
DVar.CKind = OMPC_shared;
return DVar;
}
DVar.DKind = Iter->Directive;
@ -189,16 +201,14 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
if (DVarTemp.CKind != OMPC_shared) {
DVar.RefExpr = 0;
DVar.DKind = OMPD_task;
DVar.CKind = OMPC_unknown;
// TODO: should return OMPC_firstprivate
DVar.CKind = OMPC_firstprivate;
return DVar;
}
if (I->Directive == OMPD_parallel) break;
}
DVar.DKind = OMPD_task;
// TODO: Should return OMPC_firstprivate instead of OMPC_unknown.
DVar.CKind =
(DVarTemp.CKind == OMPC_unknown) ? OMPC_unknown : OMPC_shared;
(DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
}
}
@ -272,9 +282,12 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
// in a Construct, C/C++, predetermined, p.4]
// Static data memebers are shared.
if (D->isStaticDataMember()) {
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
// TODO:
// Variables with const-qualified type having no mutable member may be listed
// in a firstprivate clause, even if they are static data members.
DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
return DVar;
DVar.CKind = OMPC_shared;
return DVar;
}
@ -295,7 +308,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
!(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
// TODO
DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
return DVar;
DVar.CKind = OMPC_shared;
return DVar;
}
@ -323,6 +339,19 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) {
return getDSA(Stack.rbegin() + 1, D);
}
DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind,
OpenMPDirectiveKind DKind) {
for (StackTy::reverse_iterator I = Stack.rbegin() + 1,
E = Stack.rend() - 1;
I != E; ++I) {
if (DKind != OMPD_unknown && DKind != I->Directive) continue;
DSAVarData DVar = getDSA(I, D);
if (DVar.CKind == CKind)
return DVar;
}
return DSAVarData();
}
void Sema::InitDataSharingAttributesStack() {
VarDataSharingAttributesStack = new DSAStackTy(*this);
}
@ -551,10 +580,10 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
Sema &Actions;
bool ErrorFound;
CapturedStmt *CS;
llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
if(VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
if (VD->isImplicit() && VD->hasAttr<UnusedAttr>()) return;
// Skip internally declared variables.
if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return;
@ -564,9 +593,8 @@ public:
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
if (DVar.CKind != OMPC_unknown) {
if (DKind == OMPD_task && DVar.CKind != OMPC_shared &&
DVar.CKind != OMPC_threadprivate && !DVar.RefExpr) {
// TODO: should be marked as firstprivate.
}
DVar.CKind != OMPC_threadprivate && !DVar.RefExpr)
ImplicitFirstprivate.push_back(DVar.RefExpr);
return;
}
// The default(none) clause requires that each variable that is referenced
@ -588,9 +616,8 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD);
if (DKind == OMPD_task && DVar.CKind != OMPC_shared) {
// TODO: should be marked as firstprivate.
}
if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
ImplicitFirstprivate.push_back(DVar.RefExpr);
}
}
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
@ -611,6 +638,7 @@ public:
}
bool isErrorFound() { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS)
: Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { }
@ -631,10 +659,27 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
if (DSAChecker.isErrorFound())
return StmtError();
// Generate list of implicitly defined firstprivate variables.
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
bool ErrorFound = false;
if (!DSAChecker.getImplicitFirstprivate().empty()) {
if (OMPClause *Implicit =
ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(),
SourceLocation(), SourceLocation(),
SourceLocation())) {
ClausesWithImplicit.push_back(Implicit);
ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
DSAChecker.getImplicitFirstprivate().size();
} else
ErrorFound = true;
}
switch (Kind) {
case OMPD_parallel:
Res = ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc);
Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
break;
case OMPD_threadprivate:
case OMPD_task:
@ -643,6 +688,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
case NUM_OPENMP_DIRECTIVES:
llvm_unreachable("Unknown OpenMP directive");
}
if (ErrorFound) return StmtError();
return Res;
}
@ -670,6 +717,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
case OMPC_threadprivate:
case OMPC_unknown:
@ -731,6 +779,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_private:
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_firstprivate:
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
@ -876,6 +927,177 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
I != E; ++I) {
assert(*I && "NULL expr in OpenMP firstprivate clause.");
if (isa<DependentScopeDeclRefExpr>(*I)) {
// It will be analyzed later.
Vars.push_back(*I);
continue;
}
SourceLocation ELoc = (*I)->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.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_or_null<DeclRefExpr>(*I);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
Diag(ELoc, diag::err_omp_expected_var_name)
<< (*I)->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
VarDecl *VD = cast<VarDecl>(D);
QualType Type = VD->getType();
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
continue;
}
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
if (RequireCompleteType(ELoc, Type,
diag::err_omp_firstprivate_incomplete_type)) {
continue;
}
if (Type->isReferenceType()) {
Diag(ELoc, diag::err_omp_clause_ref_type_arg)
<< getOpenMPClauseName(OMPC_firstprivate) << Type;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
continue;
}
// OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
// clause requires an accesible, unambiguous copy constructor for the
// class type.
Type = Context.getBaseElementType(Type);
CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
if (RD) {
CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
PartialDiagnostic PD =
PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
if (!CD ||
CheckConstructorAccess(ELoc, CD,
InitializedEntity::InitializeTemporary(Type),
CD->getAccess(), PD) == AR_inaccessible ||
CD->isDeleted()) {
Diag(ELoc, diag::err_omp_required_method)
<< getOpenMPClauseName(OMPC_firstprivate) << 1;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
MarkFunctionReferenced(ELoc, CD);
DiagnoseUseOfDecl(CD, ELoc);
CXXDestructorDecl *DD = RD->getDestructor();
if (DD) {
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
DD->isDeleted()) {
Diag(ELoc, diag::err_omp_required_method)
<< getOpenMPClauseName(OMPC_firstprivate) << 4;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
MarkFunctionReferenced(ELoc, DD);
DiagnoseUseOfDecl(DD, ELoc);
}
}
// If StartLoc and EndLoc are invalid - this is an implicit firstprivate
// variable and it was checked already.
if (StartLoc.isValid() && EndLoc.isValid()) {
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
Type = Type.getNonReferenceType().getCanonicalType();
bool IsConstant = Type.isConstant(Context);
Type = Context.getBaseElementType(Type);
// OpenMP [2.4.13, Data-sharing Attribute Clauses]
// A list item that specifies a given variable may not appear in more
// than one clause on the same directive, except that a variable may be
// specified in both firstprivate and lastprivate clauses.
// TODO: add processing for lastprivate.
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
continue;
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, p.2]
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&
DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
<< getOpenMPClauseName(DVar.CKind);
continue;
}
// OpenMP [2.9.3.4, Restrictions, p.2]
// A list item that is private within a parallel region must not appear
// in a firstprivate clause on a worksharing construct if any of the
// worksharing regions arising from the worksharing construct ever bind
// to any of the parallel regions arising from the parallel construct.
// OpenMP [2.9.3.4, Restrictions, p.3]
// A list item that appears in a reduction clause of a parallel construct
// must not appear in a firstprivate clause on a worksharing or task
// construct if any of the worksharing or task regions arising from the
// worksharing or task construct ever bind to any of the parallel regions
// arising from the parallel construct.
// OpenMP [2.9.3.4, Restrictions, p.4]
// A list item that appears in a reduction clause in worksharing
// construct must not appear in a firstprivate clause in a task construct
// encountered during execution of any of the worksharing regions arising
// from the worksharing construct.
// TODO:
}
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
Vars.push_back(DE);
}
if (Vars.empty()) return 0;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars);
}
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,

View File

@ -1313,6 +1313,18 @@ public:
EndLoc);
}
/// \brief Build a new OpenMP 'firstprivate' clause.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc,
EndLoc);
}
OMPClause *RebuildOMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@ -6341,6 +6353,26 @@ TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
C->getLocEnd());
}
template<typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPFirstprivateClause(
OMPFirstprivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
E = C->varlist_end();
I != E; ++I) {
ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
if (EVar.isInvalid())
return 0;
Vars.push_back(EVar.take());
}
return getDerived().RebuildOMPFirstprivateClause(Vars,
C->getLocStart(),
C->getLParenLoc(),
C->getLocEnd());
}
template<typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {

View File

@ -1697,6 +1697,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_firstprivate:
C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_shared:
C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
break;
@ -1725,6 +1728,16 @@ void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setVarRefs(Vars);
}
void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
}
void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();

View File

@ -1712,6 +1712,15 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Writer->Writer.AddStmt(*I);
}
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
E = C->varlist_end();
I != E; ++I)
Writer->Writer.AddStmt(*I);
}
void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);

View File

@ -8,7 +8,41 @@
void foo() {}
template <typename T>
T tmain(T argc, T *argv) {
T b = argc, c, d, e, f, g;
static T a;
#pragma omp parallel
a=2;
#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d)
foo();
return 0;
}
// CHECK: template <typename T = int> int tmain(int argc, int *argv) {
// CHECK-NEXT: int b = argc, c, d, e, f, g;
// CHECK-NEXT: static int a;
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
// CHECK-NEXT: foo()
// CHECK: template <typename T = float> float tmain(float argc, float *argv) {
// CHECK-NEXT: float b = argc, c, d, e, f, g;
// CHECK-NEXT: static float a;
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
// CHECK-NEXT: foo()
// CHECK: template <typename T> T tmain(T argc, T *argv) {
// CHECK-NEXT: T b = argc, c, d, e, f, g;
// CHECK-NEXT: static T a;
// CHECK-NEXT: #pragma omp parallel
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d)
// CHECK-NEXT: foo()
int main (int argc, char **argv) {
float x;
int b = argc, c, d, e, f, g;
static int a;
// CHECK: static int a;
@ -16,11 +50,11 @@ int main (int argc, char **argv) {
// CHECK-NEXT: #pragma omp parallel
a=2;
// CHECK-NEXT: a = 2;
#pragma omp parallel default(none), private(argc,b)
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b)
#pragma omp parallel default(none), private(argc,b) firstprivate(argv)
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv)
foo();
// CHECK-NEXT: foo();
return (0);
return tmain(b, &b) + tmain(x, &x);
}
#endif

View File

@ -0,0 +1,82 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
void foo() {
}
bool foobool(int argc) {
return argc;
}
struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}}
extern S1 a;
class S2 {
mutable int a;
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
static float S2s;
static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
int a;
public:
S3():a(0) { }
S3(S3 &s3):a(s3.a) { }
};
const S3 c;
const S3 ca[5];
extern const int f;
class S4 { // expected-note {{'S4' declared here}}
int a;
S4();
S4(const S4 &s4);
public:
S4(int v):a(v) { }
};
class S5 { // expected-note {{'S5' declared here}}
int a;
S5():a(0) {}
S5(const S5 &s5):a(s5.a) { }
public:
S5(int v):a(v) { }
};
S3 h;
#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}}
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
S4 e(4); // expected-note {{'e' defined here}}
S5 g(5); // expected-note {{'g' defined here}}
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}}
#pragma omp parallel firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel firstprivate () // expected-error {{expected expression}}
#pragma omp parallel firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp parallel firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel firstprivate (argc)
#pragma omp parallel firstprivate (S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}}
#pragma omp parallel firstprivate (argv[1]) // expected-error {{expected variable name}}
#pragma omp parallel firstprivate(ba)
#pragma omp parallel firstprivate(ca)
#pragma omp parallel firstprivate(da)
#pragma omp parallel firstprivate(S2::S2s)
#pragma omp parallel firstprivate(S2::S2sc)
#pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}}
#pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
#pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}}
foo();
#pragma omp parallel shared(i)
#pragma omp parallel firstprivate(i)
#pragma omp parallel firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}}
foo();
return 0;
}

View File

@ -64,10 +64,18 @@ int main(int argc, char **argv) {
#pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
#pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
#pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
#pragma omp parallel firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}}
foo();
#pragma omp parallel private(i)
#pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}}
foo();
#pragma omp parallel firstprivate(i)
for (int k = 0; k < 10; ++k) {
#pragma omp parallel private(i)
foo();
}
return 0;
}

View File

@ -68,10 +68,16 @@ int main(int argc, char **argv) {
#pragma omp parallel shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}}
#pragma omp parallel private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}}
foo();
#pragma omp parallel firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}}
foo();
#pragma omp parallel private(i)
#pragma omp parallel shared(i)
#pragma omp parallel shared(j)
foo();
#pragma omp parallel firstprivate(i)
#pragma omp parallel shared(i)
#pragma omp parallel shared(j)
foo();
return 0;
}

View File

@ -1934,6 +1934,10 @@ void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseEnqueue::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}

View File

@ -2344,6 +2344,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause(
OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
return true;
}
template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
VisitOMPClauseList(C);