diff -uNr clang-3.4/CMakeLists.txt clang/CMakeLists.txt --- clang-3.4/CMakeLists.txt 2013-11-06 03:37:50.000000000 -0500 +++ clang/CMakeLists.txt 2014-05-19 19:58:57.000000000 -0400 @@ -394,7 +394,7 @@ endif() endif() -set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING +set(BUG_REPORT_URL "https://github.com/clang-omp/clang/issues" CACHE STRING "Default URL where bug reports are to be submitted.") set(CLANG_ORDER_FILE "" CACHE FILEPATH diff -uNr clang-3.4/include/clang/AST/DeclBase.h clang/include/clang/AST/DeclBase.h --- clang-3.4/include/clang/AST/DeclBase.h 2013-11-13 21:13:03.000000000 -0500 +++ clang/include/clang/AST/DeclBase.h 2014-05-19 19:58:57.000000000 -0400 @@ -164,7 +164,9 @@ /// This declaration is a function-local extern declaration of a /// variable or function. This may also be IDNS_Ordinary if it /// has been declared outside any function. - IDNS_LocalExtern = 0x0800 + IDNS_LocalExtern = 0x0800, + /// For OpenMP declare reduction constructs. + IDNS_OMPDeclareReduction = 0x1000 }; /// ObjCDeclQualifier - 'Qualifiers' written next to the return and @@ -289,7 +291,7 @@ unsigned Hidden : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. - unsigned IdentifierNamespace : 12; + unsigned IdentifierNamespace : 13; /// \brief If 0, we have not computed the linkage of this declaration. /// Otherwise, it is the linkage + 1. diff -uNr clang-3.4/include/clang/AST/DeclCXX.h clang/include/clang/AST/DeclCXX.h --- clang-3.4/include/clang/AST/DeclCXX.h 2013-11-06 17:39:46.000000000 -0500 +++ clang/include/clang/AST/DeclCXX.h 2014-05-19 19:58:57.000000000 -0400 @@ -1519,6 +1519,15 @@ CXXBasePath &Path, void *UserData); + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name. + /// + /// This callback can be used with \c lookupInBases() to find members + /// of the given name within a C++ class hierarchy. The user data pointer + /// is an opaque \c DeclarationName pointer. + static bool FindOMPDeclareReductionMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *Name); + /// \brief Retrieve the final overriders for each virtual member /// function in the class hierarchy where this class is the /// most-derived class in the class hierarchy. diff -uNr clang-3.4/include/clang/AST/DeclOpenMP.h clang/include/clang/AST/DeclOpenMP.h --- clang-3.4/include/clang/AST/DeclOpenMP.h 2013-05-13 00:18:18.000000000 -0400 +++ clang/include/clang/AST/DeclOpenMP.h 2014-05-19 19:58:57.000000000 -0400 @@ -1,4 +1,4 @@ -//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===// +//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++-*-===// // // The LLVM Compiler Infrastructure // @@ -15,7 +15,8 @@ #ifndef LLVM_CLANG_AST_OPENMP_H #define LLVM_CLANG_AST_OPENMP_H -#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" +#include "clang/AST/OpenMPClause.h" #include "llvm/ADT/ArrayRef.h" namespace clang { @@ -38,29 +39,26 @@ virtual void anchor(); - OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) : - Decl(DK, DC, L), NumVars(0) { } + OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) + : Decl(DK, DC, L), NumVars(0) {} ArrayRef getVars() const { return ArrayRef( - reinterpret_cast(this + 1), - NumVars); + reinterpret_cast(this + 1), NumVars); } llvm::MutableArrayRef getVars() { - return llvm::MutableArrayRef( - reinterpret_cast(this + 1), - NumVars); + return llvm::MutableArrayRef(reinterpret_cast(this + 1), + NumVars); } void setVars(ArrayRef VL); public: static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - ArrayRef VL); - static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, - unsigned ID, unsigned N); + SourceLocation L, ArrayRef VL); + static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned N); typedef llvm::MutableArrayRef::iterator varlist_iterator; typedef ArrayRef::iterator varlist_const_iterator; @@ -76,6 +74,230 @@ static bool classofKind(Kind K) { return K == OMPThreadPrivate; } }; -} // end namespace clang +/// \brief This represents '#pragma omp declare reduction ...' directive. +/// For example, in the following, declared reduction 'foo': +/// +/// \code +/// #pragma omp declare reduction (foo : int,float : omp_out += omp_in) +/// initializer (omp_priv = 0) +/// \endcode +/// +class OMPDeclareReductionDecl : public NamedDecl, public DeclContext { +public: + struct ReductionData { + ReductionData(QualType QTy, SourceRange TyRange, Expr *Combiner, Expr *Init) + : QTy(QTy), TyRange(TyRange), CombinerFunction(Combiner), + InitFunction(Init) {} + ReductionData() : QTy(), TyRange(), CombinerFunction(0), InitFunction(0) {} + QualType QTy; + SourceRange TyRange; + Expr *CombinerFunction; + Expr *InitFunction; + }; + +private: + friend class ASTDeclReader; + unsigned NumTypes; + + virtual void anchor(); + + OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name) + : NamedDecl(DK, DC, L, Name), DeclContext(DK), NumTypes(0) { + setModulePrivate(); + } + + static unsigned getFirstElementOffset(); + + ArrayRef getData() const { + return ArrayRef( + reinterpret_cast( + reinterpret_cast(this) + getFirstElementOffset()), + NumTypes); + } + + llvm::MutableArrayRef getData() { + return llvm::MutableArrayRef( + reinterpret_cast(reinterpret_cast(this) + + getFirstElementOffset()), + NumTypes); + } + +public: + static OMPDeclareReductionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + unsigned N); + static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned N); + + void setData(ArrayRef RD); + + typedef llvm::MutableArrayRef::iterator datalist_iterator; + typedef ArrayRef::iterator datalist_const_iterator; + + unsigned datalist_size() const { return NumTypes; } + bool datalist_empty() const { return NumTypes == 0; } + datalist_iterator datalist_begin() { return getData().begin(); } + datalist_iterator datalist_end() { return getData().end(); } + datalist_const_iterator datalist_begin() const { return getData().begin(); } + datalist_const_iterator datalist_end() const { return getData().end(); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPDeclareReduction; } + static DeclContext *castToDeclContext(const OMPDeclareReductionDecl *D) { + return static_cast(const_cast(D)); + } + static OMPDeclareReductionDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast( + const_cast(DC)); + } +}; + +/// \brief This represents '#pragma omp declare simd ...' directive. +/// Here is an example, where two simd-variants are declared for a function: +/// +/// #pragma omp declare simd inbranch uniform(a) linear(b:4) simdlen(8) +/// #pragma omp declare simd inbranch uniform(a) linear(b:4) simdlen(16) +/// void func(float *a, float *b); +/// +class OMPDeclareSimdDecl : public Decl { +public: + /// \brief SimdVariant refers to a list of clauses which describe some + /// variant of the function that will need to be instantiated. + struct SimdVariant { + SimdVariant(SourceRange SR, unsigned BI, unsigned EI) + : SrcRange(SR), BeginIdx(BI), EndIdx(EI) {} + SourceRange SrcRange; + unsigned BeginIdx; + unsigned EndIdx; + }; + +private: + friend class ASTDeclReader; + unsigned NumVariants; + unsigned NumClauses; + Decl *FuncDecl; + + virtual void anchor(); + + OMPDeclareSimdDecl(Kind DK, DeclContext *DC, SourceLocation L, unsigned NV, + unsigned NC) + : Decl(DK, DC, L), NumVariants(NV), NumClauses(NC), FuncDecl(0) {} + + static unsigned getFirstVariantOffset(); + static unsigned getFirstClauseOffset(unsigned NV); + static unsigned getTotalSize(unsigned NV, unsigned NC); + +public: + // Getters for the array of simd variants. + ArrayRef getVariants() const { + return ArrayRef( + reinterpret_cast( + reinterpret_cast(this) + getFirstVariantOffset()), + NumVariants); + } + + llvm::MutableArrayRef getVariants() { + return llvm::MutableArrayRef( + reinterpret_cast(reinterpret_cast(this) + + getFirstVariantOffset()), + NumVariants); + } + + // Getters for the array of clauses. + ArrayRef getClauses() const { + return ArrayRef(reinterpret_cast( + reinterpret_cast(this) + + getFirstClauseOffset(NumVariants)), + NumClauses); + } + + llvm::MutableArrayRef getClauses() { + return llvm::MutableArrayRef( + reinterpret_cast(reinterpret_cast(this) + + getFirstClauseOffset(NumVariants)), + NumClauses); + } + +public: + static OMPDeclareSimdDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, Decl *FuncDecl, + unsigned NV, ArrayRef CL); + static OMPDeclareSimdDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NV, unsigned NC); + + Decl *getFunction() const { return FuncDecl; } + void setFunction(Decl *FD) { FuncDecl = FD; } + unsigned getNumVariants() const { return NumVariants; } + unsigned getNumClauses() const { return NumClauses; } + + // Stuff to work with variants + void setVariants(ArrayRef SV); + + typedef llvm::MutableArrayRef::iterator simd_variants_iterator; + typedef ArrayRef::iterator simd_variants_const_iterator; + + unsigned simd_variants_size() const { return NumVariants; } + bool simds_variant_empty() const { return NumVariants == 0; } + simd_variants_iterator simd_variants_begin() { return getVariants().begin(); } + simd_variants_iterator simd_variants_end() { return getVariants().end(); } + simd_variants_const_iterator simd_variants_begin() const { + return getVariants().begin(); + } + simd_variants_const_iterator simd_variants_end() const { + return getVariants().end(); + } + + // Stuff to work with clauses + void setClauses(ArrayRef CL); + + typedef llvm::MutableArrayRef::iterator clauses_iterator; + typedef ArrayRef::iterator clauses_const_iterator; + + unsigned clauses_size() const { return NumClauses; } + bool clauses_empty() const { return NumClauses == 0; } + clauses_iterator clauses_begin() { return getClauses().begin(); } + clauses_iterator clauses_end() { return getClauses().end(); } + clauses_const_iterator clauses_begin() const { return getClauses().begin(); } + clauses_const_iterator clauses_end() const { return getClauses().end(); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPDeclareSimd; } +}; + +/// For example, in the following, declared target variable 'foo': +/// +/// \code +/// #pragma omp declare target +/// int foo; +/// #pragma omp end declare target +/// \endcode +/// +class OMPDeclareTargetDecl : public Decl, public DeclContext { + friend class ASTDeclReader; + + virtual void anchor(); + + OMPDeclareTargetDecl(Kind DK, DeclContext *DC, SourceLocation L) + : Decl(DK, DC, L), DeclContext(DK) { + setModulePrivate(); + } + +public: + static OMPDeclareTargetDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L); + static OMPDeclareTargetDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPDeclareTarget; } + static DeclContext *castToDeclContext(const OMPDeclareTargetDecl *D) { + return static_cast(const_cast(D)); + } + static OMPDeclareTargetDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast(const_cast(DC)); + } +}; + +} // end namespace clang #endif diff -uNr clang-3.4/include/clang/AST/Expr.h clang/include/clang/AST/Expr.h --- clang-3.4/include/clang/AST/Expr.h 2013-11-06 18:31:56.000000000 -0500 +++ clang/include/clang/AST/Expr.h 2014-05-19 19:58:57.000000000 -0400 @@ -4791,6 +4791,89 @@ return child_range(SubExprs, SubExprs+NumSubExprs); } }; + +/// CEANIndexExpr - CEAN index triplet. +class CEANIndexExpr : public Expr { + enum { BASE, LOWER_BOUND, LENGTH, INDEX_EXPR, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation ColonLoc; +public: + CEANIndexExpr(Expr *Base, Expr *LowerBound, SourceLocation ColonLoc, + Expr *Length, QualType QTy) + : Expr(CEANIndexExprClass, QTy, VK_RValue, OK_Ordinary, + (Base && Base->isTypeDependent()) || + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent()), + (Base && Base->isValueDependent()) || + (LowerBound && LowerBound->isValueDependent()) || + (Length && Length->isValueDependent()), + ((Base && Base->isInstantiationDependent()) || + (LowerBound && LowerBound->isInstantiationDependent()) || + (Length && Length->isInstantiationDependent())), + ((Base && Base->containsUnexpandedParameterPack()) || + (LowerBound && LowerBound->containsUnexpandedParameterPack()) || + (Length && Length->containsUnexpandedParameterPack()))), + ColonLoc(ColonLoc) { + SubExprs[BASE] = Base; + SubExprs[LOWER_BOUND] = LowerBound; + SubExprs[LENGTH] = Length; + SubExprs[INDEX_EXPR] = 0; + } + + /// \brief Create an empty CEAN index expression. + explicit CEANIndexExpr(EmptyShell Shell) + : Expr(CEANIndexExprClass, Shell), ColonLoc() { } + + Expr *getBase() { return dyn_cast_or_null(SubExprs[BASE]); } + const Expr *getBase() const { return dyn_cast_or_null(SubExprs[BASE]); } + void setBase(Expr *E) { SubExprs[BASE] = E; } + + Expr *getLowerBound() { + return dyn_cast_or_null(SubExprs[LOWER_BOUND]); + } + const Expr *getLowerBound() const { + return dyn_cast_or_null(SubExprs[LOWER_BOUND]); + } + void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } + + Expr *getLength() { return dyn_cast_or_null(SubExprs[LENGTH]); } + const Expr *getLength() const { + return dyn_cast_or_null(SubExprs[LENGTH]); + } + void setLength(Expr *E) { SubExprs[LENGTH] = E; } + + Expr *getIndexExpr() { + return SubExprs[INDEX_EXPR] ? cast(SubExprs[INDEX_EXPR]) : 0; + } + Expr *getIndexExpr() const { + return SubExprs[INDEX_EXPR] ? cast(SubExprs[INDEX_EXPR]) : 0; + } + void setIndexExpr(Expr *E) { SubExprs[INDEX_EXPR] = E; } + + SourceLocation getLocStart() const LLVM_READONLY { + return getLowerBound()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getLength()->getLocEnd(); + } + + SourceLocation getColonLoc() const LLVM_READONLY { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getLocStart(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CEANIndexExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[LOWER_BOUND], &SubExprs[END_EXPR]); + } +}; + } // end namespace clang #endif diff -uNr clang-3.4/include/clang/AST/OpenMPClause.h clang/include/clang/AST/OpenMPClause.h --- clang-3.4/include/clang/AST/OpenMPClause.h 1969-12-31 19:00:00.000000000 -0500 +++ clang/include/clang/AST/OpenMPClause.h 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,2671 @@ +//===- OpenMPClause.h - Classes for OpenMP clauses --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file defines OpenMP AST classes for clauses. +/// There are clauses for executable directives, clauses for declarative +/// directives and clauses which can be used in both kinds of directives. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_OPENMPCLAUSE_H +#define LLVM_CLANG_AST_OPENMPCLAUSE_H + +#include "clang/AST/Expr.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Stmt.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { +class TemplateDeclInstantiator; + +//===----------------------------------------------------------------------===// +// AST classes for clauses. +//===----------------------------------------------------------------------===// + +/// \brief This is a basic class for representing single OpenMP clause. +/// +class OMPClause { + /// \brief Starting location of the clause. + SourceLocation StartLoc; + /// \brief Ending location of the clause. + SourceLocation EndLoc; + /// \brief Kind of the clause. + OpenMPClauseKind Kind; + +protected: + OMPClause(OpenMPClauseKind K, SourceLocation StartLoc, SourceLocation EndLoc) + : StartLoc(StartLoc), EndLoc(EndLoc), Kind(K) {} + +public: + /// \brief Fetches the starting location of the clause. + SourceLocation getLocStart() const { return StartLoc; } + /// \brief Fetches the ending location of the clause. + SourceLocation getLocEnd() const { return EndLoc; } + + /// \brief Sets the starting location of the clause. + void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Sets the ending location of the clause. + void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + + /// \brief Fetches kind of OpenMP clause (private, shared, reduction, etc.). + OpenMPClauseKind getClauseKind() const { return Kind; } + + static bool classof(const OMPClause *) { return true; } + + bool isImplicit() { return StartLoc.isInvalid(); } + + StmtRange children(); + ConstStmtRange children() const { + return const_cast(this)->children(); + } + + /// \brief Prints the clause using OMPClausePrinter + void printPretty(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, unsigned Indentation) const; +}; + +/// \brief This represents clauses with the list of variables like 'private', +/// 'firstprivate', 'copyin', 'shared', 'reduction' or 'flush' clauses in the +/// '#pragma omp ...' directives. +template class OMPVarListClause : public OMPClause { + friend class OMPClauseReader; + friend class TemplateDeclInstantiator; + /// \brief Number of variables in the list. + unsigned NumVars; + +protected: + /// \brief Fetches the list of variables associated with this clause. + llvm::MutableArrayRef getVars() { + return llvm::MutableArrayRef( + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(T), sizeof(Expr *))), + NumVars); + } + + /// \brief Sets the list of variables for this clause. + void setVars(ArrayRef VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(T), sizeof(Expr *)))); + } + + /// \brief Build clause with number of variables \a N. + /// + /// \param N Number of the variables in the clause. + /// + OMPVarListClause(OpenMPClauseKind K, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned N) + : OMPClause(K, StartLoc, EndLoc), NumVars(N) {} + +public: + typedef llvm::MutableArrayRef::iterator varlist_iterator; + typedef ArrayRef::iterator varlist_const_iterator; + + unsigned varlist_size() const { return NumVars; } + bool varlist_empty() const { return NumVars == 0; } + varlist_iterator varlist_begin() { return getVars().begin(); } + varlist_iterator varlist_end() { return getVars().end(); } + varlist_const_iterator varlist_begin() const { return getVars().begin(); } + varlist_const_iterator varlist_end() const { return getVars().end(); } + unsigned numberOfVariables() const { return NumVars; } + + /// \brief Return the list of all variables in the clause. + ArrayRef getVars() const { + return ArrayRef( + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(T), sizeof(Expr *))), + NumVars); + } +}; + +/// \brief This represents 'if' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel if(a) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'if' with +/// single expression 'a'. +/// +class OMPIfClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Clause condition. + Stmt *Condition; + /// \brief Set the condition. + /// + /// \param E New condition. + /// + void setCondition(Expr *E) { Condition = E; } + +public: + /// \brief Build 'if' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPIfClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_if, StartLoc, EndLoc), Condition(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPIfClause() + : OMPClause(OMPC_if, SourceLocation(), SourceLocation()), Condition(0) {} + + /// \brief Return condition. + Expr *getCondition() { return dyn_cast_or_null(Condition); } + + /// \brief Return condition. + Expr *getCondition() const { return dyn_cast_or_null(Condition); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_if; + } + + StmtRange children() { return StmtRange(&Condition, &Condition + 1); } +}; + +/// \brief This represents 'final' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp task final(a) +/// \endcode +/// In this example directive '#pragma omp task' has clause 'final' with +/// single expression 'a'. +/// +class OMPFinalClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Clause condition. + Stmt *Condition; + /// \brief Set the condition. + /// + /// \param E New condition. + /// + void setCondition(Expr *E) { Condition = E; } + +public: + /// \brief Build 'if' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPFinalClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_final, StartLoc, EndLoc), Condition(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPFinalClause() + : OMPClause(OMPC_final, SourceLocation(), SourceLocation()), + Condition(0) {} + + /// \brief Return condition. + Expr *getCondition() { return dyn_cast_or_null(Condition); } + /// \brief Return condition. + Expr *getCondition() const { return dyn_cast_or_null(Condition); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_final; + } + + StmtRange children() { return StmtRange(&Condition, &Condition + 1); } +}; + +/// \brief This represents 'num_threads' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp parallel num_threads(a) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'num_threads' +/// with single expression 'a'. +/// +class OMPNumThreadsClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Number of threads. + Stmt *NumThreads; + /// \brief Set the number of threads. + /// + /// \param E Number of threads. + /// + void setNumThreads(Expr *E) { NumThreads = E; } + +public: + /// \brief Build 'num_threads' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNumThreadsClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_num_threads, StartLoc, EndLoc), NumThreads(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPNumThreadsClause() + : OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()), + NumThreads(0) {} + + /// \brief Return number of threads. + Expr *getNumThreads() { return dyn_cast_or_null(NumThreads); } + + /// \brief Return number of threads. + Expr *getNumThreads() const { return dyn_cast_or_null(NumThreads); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_threads; + } + + StmtRange children() { return StmtRange(&NumThreads, &NumThreads + 1); } +}; + +/// \brief This represents 'collapse' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp for collapse(3) +/// \endcode +/// In this example directive '#pragma omp for' has clause 'collapse' +/// with single expression '3'. +/// +class OMPCollapseClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Number of for-loops. + Stmt *NumForLoops; + /// \brief Set the number of associated for-loops. + /// + /// \param E Number of for-loops. + /// + void setNumForLoops(Expr *E) { NumForLoops = E; } + +public: + /// \brief Build 'collapse' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPCollapseClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_collapse, StartLoc, EndLoc), NumForLoops(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPCollapseClause() + : OMPClause(OMPC_collapse, SourceLocation(), SourceLocation()), + NumForLoops(0) {} + + /// \brief Return number of associated for-loops. + /// + Expr *getNumForLoops() { return dyn_cast_or_null(NumForLoops); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_collapse; + } + + StmtRange children() { return StmtRange(&NumForLoops, &NumForLoops + 1); } +}; + +/// \brief This represents 'device' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp target device(a) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'device' +/// with single expression 'a'. +/// +class OMPDeviceClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Device number. + Stmt *Device; + /// \brief Set the device number. + /// + /// \param E Device number. + /// + void setDevice(Expr *E) { Device = E; } + +public: + /// \brief Build 'device' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPDeviceClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_device, StartLoc, EndLoc), Device(E) {} + + /// \brief Build an empty clause. + /// + OMPDeviceClause() + : OMPClause(OMPC_device, SourceLocation(), SourceLocation()), Device(0) {} + + /// \brief Return device number. + Expr *getDevice() { return dyn_cast_or_null(Device); } + + /// \brief Return device number. + Expr *getDevice() const { return dyn_cast_or_null(Device); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_device; + } + + StmtRange children() { return StmtRange(&Device, &Device + 1); } +}; + +/// \brief This represents 'default' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel default(shared) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'default' +/// clause with kind 'shared'. +/// +class OMPDefaultClause : public OMPClause { + friend class OMPClauseReader; + /// \brief A kind of the 'default' clause. + OpenMPDefaultClauseKind Kind; + /// \brief Start location of the kind in cource code. + SourceLocation KindLoc; + + /// \brief Set kind of the clauses. + /// + /// \param K Argument of clause. + /// + void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; } + + /// \brief Set argument location. + /// + /// \param KLoc Argument location. + /// + void setDefaultKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + +public: + /// \brief Build 'default' clause with argument \a A ('none' or 'shared'). + /// + /// \brief A Argument of the clause ('none' or 'shared'). + /// \brief ALoc Starting location of the argument. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// + OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_default, StartLoc, EndLoc), Kind(A), KindLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPDefaultClause() + : OMPClause(OMPC_default, SourceLocation(), SourceLocation()), + Kind(OMPC_DEFAULT_unknown), KindLoc(SourceLocation()) {} + + /// \brief Fetches kind of the clause. + /// + OpenMPDefaultClauseKind getDefaultKind() const { return Kind; } + + /// \brief Fetches location of clause kind. + /// + SourceLocation getDefaultKindLoc() const { return KindLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_default; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'proc_bind' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp parallel proc_bind(master) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'proc_bind' +/// clause with thread affinity 'master'. +/// +class OMPProcBindClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Thread affinity defined in 'proc_bind' clause. + OpenMPProcBindClauseKind ThreadAffinity; + /// \brief Start location of the thread affinity in source code. + SourceLocation ThreadAffinityLoc; + + /// \brief Set thread affinity of the clauses. + /// + /// \param K Argument of clause. + /// + void setThreadAffinity(OpenMPProcBindClauseKind K) { ThreadAffinity = K; } + + /// \brief Set argument location. + /// + /// \param KLoc Argument location. + /// + void setThreadAffinityLoc(SourceLocation KLoc) { ThreadAffinityLoc = KLoc; } + +public: + /// \brief Build 'proc_bind' clause with argument \a A ('master', 'close' or + /// 'spread'). + /// + /// \brief A Argument of the clause ('master', 'close' or 'spread'). + /// \brief ALoc Starting location of the argument. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// + OMPProcBindClause(OpenMPProcBindClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_proc_bind, StartLoc, EndLoc), ThreadAffinity(A), + ThreadAffinityLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPProcBindClause() + : OMPClause(OMPC_proc_bind, SourceLocation(), SourceLocation()), + ThreadAffinity(OMPC_PROC_BIND_unknown), + ThreadAffinityLoc(SourceLocation()) {} + + /// \brief Fetches thread affinity. + /// + OpenMPProcBindClauseKind getThreadAffinity() const { return ThreadAffinity; } + + /// \brief Fetches location of clause kind. + /// + SourceLocation getThreadAffinityLoc() const { return ThreadAffinityLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_proc_bind; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents clause 'private' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel private(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'private' +/// with the variables 'a' and 'b'. +/// +class OMPPrivateClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPPrivateClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_private, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPPrivateClause(unsigned N) + : OMPVarListClause(OMPC_private, SourceLocation(), + SourceLocation(), N) {} + + /// \brief Sets the list of generated default inits. + void setDefaultInits(ArrayRef DefaultInits); + + /// \brief Return the list of all generated expressions. + llvm::MutableArrayRef getDefaultInits() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef DefaultInits); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_private; + } + + /// \brief Return the list of all default initializations. + ArrayRef getDefaultInits() const { + return llvm::makeArrayRef(varlist_end(), numberOfVariables()); + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getDefaultInits().end())); + } +}; + +/// \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 OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPFirstPrivateClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPVarListClause(OMPC_firstprivate, StartLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFirstPrivateClause(unsigned N) + : OMPVarListClause( + OMPC_firstprivate, SourceLocation(), SourceLocation(), N) {} + + /// \brief Sets the list of pseudo vars. + void setPseudoVars(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets the list of generated inits. + void setInits(ArrayRef Inits); + + /// \brief Return the list of all inits. + llvm::MutableArrayRef getInits() { + return llvm::MutableArrayRef(getPseudoVars().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPFirstPrivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars, + ArrayRef Inits); + /// \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); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_firstprivate; + } + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars() const { + return llvm::makeArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return the list of all initializations. + ArrayRef getInits() const { + return llvm::makeArrayRef(getPseudoVars().end(), numberOfVariables()); + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getInits().end())); + } +}; + +/// \brief This represents clause 'lastprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp for lastprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp for' has clause 'lastprivate' +/// with the variables 'a' and 'b'. +/// +class OMPLastPrivateClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + friend class Sema; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + explicit OMPLastPrivateClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPVarListClause(OMPC_lastprivate, StartLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPLastPrivateClause(unsigned N) + : OMPVarListClause( + OMPC_lastprivate, SourceLocation(), SourceLocation(), N) {} + + /// \brief Sets the list of pseudo vars. + void setPseudoVars1(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars1() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets the list of pseudo vars. + void setPseudoVars2(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars2() { + return llvm::MutableArrayRef(getPseudoVars1().end(), + numberOfVariables()); + } + + /// \brief Sets the list of generated default inits. + void setDefaultInits(ArrayRef DefaultInits); + + /// \brief Return the list of all generated expressions. + llvm::MutableArrayRef getDefaultInits() { + return llvm::MutableArrayRef(getPseudoVars2().end(), + numberOfVariables()); + } + /// \brief Sets the list of generated inits. + void setAssignments(ArrayRef Assignments); + + /// \brief Return the list of all inits. + llvm::MutableArrayRef getAssignments() { + return llvm::MutableArrayRef(getDefaultInits().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPLastPrivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars1, + ArrayRef PseudoVars2, ArrayRef Assignments); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPLastPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars1() const { + return llvm::makeArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars2() const { + return llvm::makeArrayRef(getPseudoVars1().end(), numberOfVariables()); + } + + /// \brief Return the list of all default initializations. + ArrayRef getDefaultInits() const { + return llvm::makeArrayRef(getPseudoVars2().end(), numberOfVariables()); + } + + /// \brief Return the list of all initializations. + ArrayRef getAssignments() const { + return llvm::makeArrayRef(getDefaultInits().end(), numberOfVariables()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_lastprivate; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getAssignments().end())); + } +}; + +/// \brief This represents clause 'shared' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel shared(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'shared' +/// with the variables 'a' and 'b'. +/// +class OMPSharedClause : public OMPVarListClause { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPSharedClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_shared, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPSharedClause(unsigned N) + : OMPVarListClause(OMPC_shared, SourceLocation(), + SourceLocation(), N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPSharedClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPSharedClause *CreateEmpty(const ASTContext &C, unsigned N); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_shared; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } +}; + +/// \brief This represents clause 'copyin' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel copyin(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'copyin' +/// with the variables 'a' and 'b'. +/// +class OMPCopyinClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPCopyinClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_copyin, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyinClause(unsigned N) + : OMPVarListClause(OMPC_copyin, SourceLocation(), + SourceLocation(), N) {} + + /// \brief Sets the list of pseudo vars. + void setPseudoVars1(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars1() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets the list of pseudo vars. + void setPseudoVars2(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars2() { + return llvm::MutableArrayRef(getPseudoVars1().end(), + numberOfVariables()); + } + + /// \brief Sets the list of generated inits. + void setAssignments(ArrayRef Assignments); + + /// \brief Return the list of all inits. + llvm::MutableArrayRef getAssignments() { + return llvm::MutableArrayRef(getPseudoVars2().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPCopyinClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef PseudoVars1, + ArrayRef PseudoVars2, + ArrayRef Assignments); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPCopyinClause *CreateEmpty(const ASTContext &C, unsigned N); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_copyin; + } + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars1() const { + return llvm::makeArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars2() const { + return llvm::makeArrayRef(getPseudoVars1().end(), numberOfVariables()); + } + + /// \brief Return the list of all initializations. + ArrayRef getAssignments() const { + return llvm::makeArrayRef(getPseudoVars2().end(), numberOfVariables()); + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getAssignments().end())); + } +}; + +/// \brief This represents clause 'copyprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp single copyprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp single' has clause 'copyprivate' +/// with the variables 'a' and 'b'. +/// +class OMPCopyPrivateClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPCopyPrivateClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPVarListClause(OMPC_copyprivate, StartLoc, + EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPCopyPrivateClause(unsigned N) + : OMPVarListClause( + OMPC_copyprivate, SourceLocation(), SourceLocation(), N) {} + + /// \brief Sets the list of pseudo vars. + void setPseudoVars1(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars1() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets the list of pseudo vars. + void setPseudoVars2(ArrayRef PseudoVars); + + /// \brief Return the list of pseudo vars. + llvm::MutableArrayRef getPseudoVars2() { + return llvm::MutableArrayRef(getPseudoVars1().end(), + numberOfVariables()); + } + + /// \brief Sets the list of generated inits. + void setAssignments(ArrayRef Assignments); + + /// \brief Return the list of all inits. + llvm::MutableArrayRef getAssignments() { + return llvm::MutableArrayRef(getPseudoVars2().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPCopyPrivateClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars1, + ArrayRef PseudoVars2, ArrayRef Assignments); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPCopyPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars1() const { + return llvm::makeArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return the list of pseudo vars. + ArrayRef getPseudoVars2() const { + return llvm::makeArrayRef(getPseudoVars1().end(), numberOfVariables()); + } + + /// \brief Return the list of all initializations. + ArrayRef getAssignments() const { + return llvm::makeArrayRef(getPseudoVars2().end(), numberOfVariables()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_copyprivate; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getAssignments().end())); + } +}; + +/// \brief This represents clause 'reduction' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp parallel reduction(+ : a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'reduction' +/// with operator '+' and variables 'a' and 'b'. +/// +class OMPReductionClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief An operator for the 'reduction' clause. + OpenMPReductionClauseOperator Operator; + /// \brief Nested name specifier for C++. + NestedNameSpecifierLoc Spec; + /// \brief Name of custom operator. + DeclarationNameInfo OperatorName; + + /// \brief Set operator for the clause. + /// + /// \param Op Operator for the clause. + /// + void setOperator(OpenMPReductionClauseOperator Op) { Operator = Op; } + + /// \brief Set operator name for the clause. + /// + /// \param S Nested name specifier. + /// \param Op Operator name for the clause. + /// + void setOpName(NestedNameSpecifierLoc S, DeclarationNameInfo OpName) { + Spec = S; + OperatorName = OpName; + } + + /// \brief Build clause with number of variables \a N and an operator \a Op. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// \param Op reduction operator. + /// \param OpLoc Location of the operator. + /// + OMPReductionClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N, + OpenMPReductionClauseOperator Op, + NestedNameSpecifierLoc Spec, DeclarationNameInfo OpName) + : OMPVarListClause(OMPC_reduction, StartLoc, EndLoc, + N), + Operator(Op), Spec(Spec), OperatorName(OpName) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPReductionClause(unsigned N) + : OMPVarListClause(OMPC_reduction, SourceLocation(), + SourceLocation(), N), + Operator(OMPC_REDUCTION_unknown), Spec(), OperatorName() {} + + /// \brief Sets the list of generated expresssions. + void setOpExprs(ArrayRef OpExprs); + /// \brief Sets the list of 1st helper parameters. + void setHelperParameters1st(ArrayRef HelperParams); + /// \brief Sets the list of 1st helper parameters. + void setHelperParameters2nd(ArrayRef HelperParams); + + /// \brief Return the list of all generated expressions. + llvm::MutableArrayRef getOpExprs() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return the list of 1st helper parameters. + llvm::MutableArrayRef getHelperParameters1st() { + return llvm::MutableArrayRef(getOpExprs().end(), + numberOfVariables()); + } + + /// \brief Return the list of 2nd helper parameters. + llvm::MutableArrayRef getHelperParameters2nd() { + return llvm::MutableArrayRef(getHelperParameters1st().end(), + numberOfVariables()); + } + + /// \brief Sets the list of generated default inits. + void setDefaultInits(ArrayRef DefaultInits); + + /// \brief Return the list of all generated expressions. + llvm::MutableArrayRef getDefaultInits() { + return llvm::MutableArrayRef(getHelperParameters2nd().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL and an operator + /// \a Op. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param Op reduction operator. + /// \param S nested name specifier. + /// \param OpName Reduction identifier. + /// + static OMPReductionClause * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef OpExprs, + ArrayRef HelperParams1, ArrayRef HelperParams2, + ArrayRef DefaultInits, OpenMPReductionClauseOperator Op, + NestedNameSpecifierLoc S, DeclarationNameInfo OpName); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches operator for the clause. + OpenMPReductionClauseOperator getOperator() const { return Operator; } + + /// \brief Fetches nested name specifier for the clause. + NestedNameSpecifierLoc getSpec() const { return Spec; } + + /// \brief Fetches operator name for the clause. + DeclarationNameInfo getOpName() const { return OperatorName; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_reduction; + } + + /// \brief Return the list of all generated expressions. + ArrayRef getOpExprs() const { + return llvm::makeArrayRef(getVars().end(), numberOfVariables()); + } + /// \brief Return the list of 1st helper parameters. + ArrayRef getHelperParameters1st() const { + return llvm::makeArrayRef(getOpExprs().end(), numberOfVariables()); + } + /// \brief Return the list of 2nd helper parameters. + ArrayRef getHelperParameters2nd() const { + return llvm::makeArrayRef(getHelperParameters1st().end(), + numberOfVariables()); + } + + /// \brief Return the list of all default initializations. + ArrayRef getDefaultInits() const { + return llvm::makeArrayRef(getHelperParameters2nd().end(), + numberOfVariables()); + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(getDefaultInits().end())); + } +}; + +/// \brief This represents clause 'map' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp target map(a,b) +/// \endcode +/// In this example directive '#pragma omp target' has clause 'map' +/// with the variables 'a' and 'b'. +/// +class OMPMapClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + friend class Sema; + + /// \brief Mapping kind for the 'map' clause. + OpenMPMapClauseKind Kind; + /// \brief Location of the mapping kind. + SourceLocation KindLoc; + + /// \brief Set Kind for the clause. + /// + /// \param K Kind for the clause. + /// + void setKind(OpenMPMapClauseKind K) { Kind = K; } + + /// \brief Set kind location. + /// + /// \param KLoc Kind location. + /// + void setKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + explicit OMPMapClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N, OpenMPMapClauseKind K, SourceLocation KLoc) + : OMPVarListClause(OMPC_map, StartLoc, EndLoc, N), Kind(K), + KindLoc(KLoc) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPMapClause(unsigned N) + : OMPVarListClause(OMPC_map, SourceLocation(), + SourceLocation(), N), + Kind(OMPC_MAP_unknown), KindLoc() {} + + /// \brief Sets whole starting addresses for the items. + void setWholeStartAddresses(ArrayRef WholeStartAddresses); + + /// \brief Return the list of whole starting addresses. + llvm::MutableArrayRef getWholeStartAddresses() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets whole sizes/ending addresses for the items. + void setWholeSizesEndAddresses(ArrayRef WholeSizesEndAddresses); + + /// \brief Return whole sizes/ending addresses for the items. + llvm::MutableArrayRef getWholeSizesEndAddresses() { + return llvm::MutableArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets starting addresses for the items to be copied. + void setCopyingStartAddresses(ArrayRef CopyingStartAddresses); + + /// \brief Return the list of copied starting addresses. + llvm::MutableArrayRef getCopyingStartAddresses() { + return llvm::MutableArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets sizes/ending addresses for the copied items. + void setCopyingSizesEndAddresses(ArrayRef CopyingSizesEndAddresses); + + /// \brief Return sizes/ending addresses for the copied items. + llvm::MutableArrayRef getCopyingSizesEndAddresses() { + return llvm::MutableArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPMapClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses, + OpenMPMapClauseKind Kind, SourceLocation KindLoc); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPMapClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches mapping kind for the clause. + OpenMPMapClauseKind getKind() const LLVM_READONLY { return Kind; } + + /// \brief Fetches location of clause mapping kind. + SourceLocation getKindLoc() const LLVM_READONLY { return KindLoc; } + + /// \brief Return the list of whole starting addresses. + ArrayRef getWholeStartAddresses() const { + return ArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return whole sizes/ending addresses for the items. + ArrayRef getWholeSizesEndAddresses() const { + return ArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Return the list of copied starting addresses. + ArrayRef getCopyingStartAddresses() const { + return ArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Return sizes/ending addresses for the copied items. + ArrayRef getCopyingSizesEndAddresses() const { + return ArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_map; + } + + StmtRange children() { + return StmtRange( + reinterpret_cast(varlist_begin()), + reinterpret_cast(getCopyingSizesEndAddresses().end())); + } +}; + +/// \brief This represents clause 'to' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp target update to(a,b) +/// \endcode +/// In this example directive '#pragma omp target update' has clause 'to' +/// with the variables 'a' and 'b'. +/// +class OMPToClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + friend class Sema; + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + explicit OMPToClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPVarListClause(OMPC_to, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPToClause(unsigned N) + : OMPVarListClause(OMPC_to, SourceLocation(), + SourceLocation(), N) {} + + /// \brief Sets whole starting addresses for the items. + void setWholeStartAddresses(ArrayRef WholeStartAddresses); + + /// \brief Return the list of whole starting addresses. + llvm::MutableArrayRef getWholeStartAddresses() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets whole sizes/ending addresses for the items. + void setWholeSizesEndAddresses(ArrayRef WholeSizesEndAddresses); + + /// \brief Return whole sizes/ending addresses for the items. + llvm::MutableArrayRef getWholeSizesEndAddresses() { + return llvm::MutableArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets starting addresses for the items to be copied. + void setCopyingStartAddresses(ArrayRef CopyingStartAddresses); + + /// \brief Return the list of copied starting addresses. + llvm::MutableArrayRef getCopyingStartAddresses() { + return llvm::MutableArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets sizes/ending addresses for the copied items. + void setCopyingSizesEndAddresses(ArrayRef CopyingSizesEndAddresses); + + /// \brief Return sizes/ending addresses for the copied items. + llvm::MutableArrayRef getCopyingSizesEndAddresses() { + return llvm::MutableArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPToClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPToClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Return the list of whole starting addresses. + ArrayRef getWholeStartAddresses() const { + return ArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return whole sizes/ending addresses for the items. + ArrayRef getWholeSizesEndAddresses() const { + return ArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Return the list of copied starting addresses. + ArrayRef getCopyingStartAddresses() const { + return ArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Return sizes/ending addresses for the copied items. + ArrayRef getCopyingSizesEndAddresses() const { + return ArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_to; + } + + StmtRange children() { + return StmtRange( + reinterpret_cast(varlist_begin()), + reinterpret_cast(getCopyingSizesEndAddresses().end())); + } +}; + +/// \brief This represents clause 'from' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp target update from(a,b) +/// \endcode +/// In this example directive '#pragma omp target update' has clause 'from' +/// with the variables 'a' and 'b'. +/// +class OMPFromClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + friend class Sema; + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + explicit OMPFromClause(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPVarListClause(OMPC_from, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFromClause(unsigned N) + : OMPVarListClause(OMPC_from, SourceLocation(), + SourceLocation(), N) {} + + /// \brief Sets whole starting addresses for the items. + void setWholeStartAddresses(ArrayRef WholeStartAddresses); + + /// \brief Return the list of whole starting addresses. + llvm::MutableArrayRef getWholeStartAddresses() { + return llvm::MutableArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Sets whole sizes/ending addresses for the items. + void setWholeSizesEndAddresses(ArrayRef WholeSizesEndAddresses); + + /// \brief Return whole sizes/ending addresses for the items. + llvm::MutableArrayRef getWholeSizesEndAddresses() { + return llvm::MutableArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets starting addresses for the items to be copied. + void setCopyingStartAddresses(ArrayRef CopyingStartAddresses); + + /// \brief Return the list of copied starting addresses. + llvm::MutableArrayRef getCopyingStartAddresses() { + return llvm::MutableArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Sets sizes/ending addresses for the copied items. + void setCopyingSizesEndAddresses(ArrayRef CopyingSizesEndAddresses); + + /// \brief Return sizes/ending addresses for the copied items. + llvm::MutableArrayRef getCopyingSizesEndAddresses() { + return llvm::MutableArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPFromClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPFromClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Return the list of whole starting addresses. + ArrayRef getWholeStartAddresses() const { + return ArrayRef(varlist_end(), numberOfVariables()); + } + + /// \brief Return whole sizes/ending addresses for the items. + ArrayRef getWholeSizesEndAddresses() const { + return ArrayRef(getWholeStartAddresses().end(), + numberOfVariables()); + } + + /// \brief Return the list of copied starting addresses. + ArrayRef getCopyingStartAddresses() const { + return ArrayRef(getWholeSizesEndAddresses().end(), + numberOfVariables()); + } + + /// \brief Return sizes/ending addresses for the copied items. + ArrayRef getCopyingSizesEndAddresses() const { + return ArrayRef(getCopyingStartAddresses().end(), + numberOfVariables()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_from; + } + + StmtRange children() { + return StmtRange( + reinterpret_cast(varlist_begin()), + reinterpret_cast(getCopyingSizesEndAddresses().end())); + } +}; + +/// \brief This represents 'schedule' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp for schedule(static, 3) +/// \endcode +/// In this example directive '#pragma omp for' has 'schedule' +/// clause with arguments 'static' and '3'. +/// +class OMPScheduleClause : public OMPClause { + friend class OMPClauseReader; + /// \brief A kind of the 'schedule' clause. + OpenMPScheduleClauseKind Kind; + /// \brief Start location of the kind in cource code. + SourceLocation KindLoc; + /// \brief Chunk size. + Stmt *ChunkSize; + + /// \brief Set kind of the clauses. + /// + /// \param K Argument of clause. + /// + void setScheduleKind(OpenMPScheduleClauseKind K) { Kind = K; } + /// \brief Set kind location. + /// + /// \param KLoc Kind location. + /// + void setScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + /// \brief Set chunk size. + /// + /// \param E Chunk size. + /// + void setChunkSize(Expr *E) { ChunkSize = E; } + +public: + /// \brief Build 'schedule' clause with argument \a Kind and + /// an expression \a E. + /// + /// \brief K Argument of the clause. + /// \brief KLoc Starting location of the argument. + /// \brief E Chunk size. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// + OMPScheduleClause(OpenMPScheduleClauseKind K, SourceLocation KLoc, Expr *E, + SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_schedule, StartLoc, EndLoc), Kind(K), KindLoc(KLoc), + ChunkSize(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPScheduleClause() + : OMPClause(OMPC_schedule, SourceLocation(), SourceLocation()), + Kind(OMPC_SCHEDULE_unknown), KindLoc(SourceLocation()), ChunkSize(0) {} + + /// \brief Get kind of the clause. + /// + OpenMPScheduleClauseKind getScheduleKind() const { return Kind; } + /// \brief Get kind location. + /// + SourceLocation getScheduleKindLoc() { return KindLoc; } + /// \brief Get chunk size. + /// + Expr *getChunkSize() { return dyn_cast_or_null(ChunkSize); } + /// \brief Get chunk size. + /// + Expr *getChunkSize() const { return dyn_cast_or_null(ChunkSize); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_schedule; + } + + StmtRange children() { return StmtRange(&ChunkSize, &ChunkSize + 1); } +}; + +/// \brief This represents 'dist_schedule' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp distribute dist_schedule(static, 3) +/// \endcode +/// In this example directive '#pragma omp distribute' has 'dist_schedule' +/// clause with arguments 'static' and '3'. +/// +class OMPDistScheduleClause : public OMPClause { + friend class OMPClauseReader; + /// \brief A kind of the 'dist_schedule' clause. + OpenMPDistScheduleClauseKind Kind; + /// \brief Start location of the kind in cource code. + SourceLocation KindLoc; + /// \brief Chunk size. + Stmt *ChunkSize; + + /// \brief Set kind of the clauses. + /// + /// \param K Argument of clause. + /// + void setDistScheduleKind(OpenMPDistScheduleClauseKind K) { Kind = K; } + /// \brief Set kind location. + /// + /// \param KLoc Kind location. + /// + void setDistScheduleKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + /// \brief Set chunk size. + /// + /// \param E Chunk size. + /// + void setDistChunkSize(Expr *E) { ChunkSize = E; } + +public: + /// \brief Build 'dist_schedule' clause with argument \a Kind and + /// an expression \a E. + /// + /// \brief K Argument of the clause. + /// \brief KLoc Starting location of the argument. + /// \brief E Chunk size. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// + OMPDistScheduleClause(OpenMPDistScheduleClauseKind K, SourceLocation KLoc, + Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_dist_schedule, StartLoc, EndLoc), Kind(K), KindLoc(KLoc), + ChunkSize(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPDistScheduleClause() + : OMPClause(OMPC_dist_schedule, SourceLocation(), SourceLocation()), + Kind(OMPC_DIST_SCHEDULE_unknown), KindLoc(SourceLocation()), + ChunkSize(0) {} + + /// \brief Get kind of the clause. + /// + OpenMPDistScheduleClauseKind getDistScheduleKind() const { return Kind; } + /// \brief Get kind location. + /// + SourceLocation getDistScheduleKindLoc() { return KindLoc; } + /// \brief Get chunk size. + /// + Expr *getDistChunkSize() { return dyn_cast_or_null(ChunkSize); } + /// \brief Get chunk size. + /// + Expr *getDistChunkSize() const { return dyn_cast_or_null(ChunkSize); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_dist_schedule; + } + + StmtRange children() { return StmtRange(&ChunkSize, &ChunkSize + 1); } +}; + +/// \brief This represents 'ordered' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp for ordered +/// \endcode +/// In this example directive '#pragma omp for' has clause 'ordered'. +/// +class OMPOrderedClause : public OMPClause { +public: + /// \brief Build 'ordered' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_ordered, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPOrderedClause() + : OMPClause(OMPC_ordered, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_ordered; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'nowait' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp for nowait +/// \endcode +/// In this example directive '#pragma omp for' has clause 'nowait'. +/// +class OMPNowaitClause : public OMPClause { +public: + /// \brief Build 'nowait' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_nowait, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPNowaitClause() + : OMPClause(OMPC_nowait, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_nowait; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'untied' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp task untied +/// \endcode +/// In this example directive '#pragma omp task' has clause 'untied'. +/// +class OMPUntiedClause : public OMPClause { +public: + /// \brief Build 'untied' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_untied, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPUntiedClause() + : OMPClause(OMPC_untied, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_untied; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'mergeable' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp task mergeable +/// \endcode +/// In this example directive '#pragma omp task' has clause 'mergeable'. +/// +class OMPMergeableClause : public OMPClause { +public: + /// \brief Build 'mergeable' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_mergeable, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPMergeableClause() + : OMPClause(OMPC_mergeable, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_mergeable; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'read' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp atomic read +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'read'. +/// +class OMPReadClause : public OMPClause { +public: + /// \brief Build 'read' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_read, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPReadClause() + : OMPClause(OMPC_read, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_read; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'write' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp atomic write +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'write'. +/// +class OMPWriteClause : public OMPClause { +public: + /// \brief Build 'write' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_write, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPWriteClause() + : OMPClause(OMPC_write, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_write; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'update' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp atomic update +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'update'. +/// +class OMPUpdateClause : public OMPClause { +public: + /// \brief Build 'update' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_update, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPUpdateClause() + : OMPClause(OMPC_update, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_update; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'capture' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp atomic capture +/// \endcode +/// In this example directive '#pragma omp atomic' has clause 'capture'. +/// +class OMPCaptureClause : public OMPClause { +public: + /// \brief Build 'write' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_capture, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPCaptureClause() + : OMPClause(OMPC_capture, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_capture; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'seq_cst' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp atomic capture seq_cst +/// \endcode +/// In this example directive '#pragma omp atomic' has clauses 'capture' and +/// 'seq_cst'. +/// +class OMPSeqCstClause : public OMPClause { +public: + /// \brief Build 'seq_cst' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_seq_cst, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPSeqCstClause() + : OMPClause(OMPC_seq_cst, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_seq_cst; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'inbranch' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp declare simd inbranch +/// \endcode +/// In this example directive '#pragma omp declare simd' has clause 'inbranch'. +/// +class OMPInBranchClause : public OMPClause { +public: + /// \brief Build 'inbranch' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPInBranchClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_inbranch, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPInBranchClause() + : OMPClause(OMPC_inbranch, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_inbranch; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents 'notinbranch' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp declare simd notinbranch +/// \endcode +/// In this example directive '#pragma omp declare simd' has +/// clause 'notinbranch'. +/// +class OMPNotInBranchClause : public OMPClause { +public: + /// \brief Build 'notinbranch' clause. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNotInBranchClause(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_notinbranch, StartLoc, EndLoc) {} + + /// \brief Build an empty clause. + /// + explicit OMPNotInBranchClause() + : OMPClause(OMPC_notinbranch, SourceLocation(), SourceLocation()) {} + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_notinbranch; + } + + StmtRange children() { return StmtRange(); } +}; + +/// \brief This represents clause 'flush' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp flush(a,b) +/// \endcode +/// In this example directive '#pragma omp flush' has pseudo clause 'flush' +/// with the variables 'a' and 'b'. +/// +class OMPFlushClause : public OMPVarListClause { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPFlushClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_flush, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFlushClause(unsigned N) + : OMPVarListClause(OMPC_flush, SourceLocation(), + SourceLocation(), N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPFlushClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPFlushClause *CreateEmpty(const ASTContext &C, unsigned N); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_flush; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } +}; + +/// \brief This represents clause 'depend' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp task depend(in : a,b[:]) +/// \endcode +/// In this example directive '#pragma omp task' has clause 'depend' +/// with dependence type 'in' and variables 'a' and 'b[:]'. +/// +class OMPDependClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + /// \brief Dependence type for the 'depend' clause. + OpenMPDependClauseType Type; + /// \brief Location of the dependence type. + SourceLocation TypeLoc; + + /// \brief Set Type for the clause. + /// + /// \param Ty Type for the clause. + /// + void setType(OpenMPDependClauseType Ty) { Type = Ty; } + + /// \brief Set type location. + /// + /// \param TyLoc Type location. + /// + void setTypeLoc(SourceLocation TyLoc) { TypeLoc = TyLoc; } + + /// \brief Build clause with number of variables \a N and type \a Ty. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// \param Ty Dependence type. + /// \param TyLoc Location of the type. + /// + OMPDependClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N, + OpenMPDependClauseType Ty, SourceLocation TyLoc) + : OMPVarListClause(OMPC_depend, StartLoc, EndLoc, N), + Type(Ty), TypeLoc(TyLoc) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPDependClause(unsigned N) + : OMPVarListClause(OMPC_depend, SourceLocation(), + SourceLocation(), N), + Type(OMPC_DEPEND_unknown), TypeLoc(SourceLocation()) {} + + /// \brief Sets begins for the clause. + void setBegins(ArrayRef Begins); + /// \brief Sets size in bytes for the clause. + void setSizeInBytes(ArrayRef SizeInBytes); + +public: + /// \brief Creates clause with a list of variables \a VL and type \a Ty. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param Ty reduction operator. + /// \param TyLoc Location of the operator. + /// + static OMPDependClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef Begins, + ArrayRef SizeInBytes, + OpenMPDependClauseType Ty, + SourceLocation TyLoc); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPDependClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches dependence type for the clause. + OpenMPDependClauseType getType() const LLVM_READONLY { return Type; } + + /// \brief Fetches location of clause dependence type. + SourceLocation getTypeLoc() const LLVM_READONLY { return TypeLoc; } + + /// \brief Fetches begins for the specified index. + Expr *getBegins(unsigned Index) LLVM_READONLY; + Expr *getBegins(unsigned Index) const LLVM_READONLY { + return const_cast(this)->getBegins(Index); + } + /// \brief Fetches the size in bytes for the specified index. + Expr *getSizeInBytes(unsigned Index) LLVM_READONLY; + Expr *getSizeInBytes(unsigned Index) const LLVM_READONLY { + return const_cast(this)->getSizeInBytes(Index); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_depend; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end()) + + 2 * varlist_size()); + } +}; + +/// \brief This represents clause 'uniform' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp declare simd uniform(a,b) +/// \endcode +/// In this example directive '#pragma omp declare simd' has clause 'uniform' +/// with the variables 'a' and 'b'. +/// +class OMPUniformClause : public OMPVarListClause { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPUniformClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_uniform, StartLoc, EndLoc, N) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPUniformClause(unsigned N) + : OMPVarListClause(OMPC_uniform, SourceLocation(), + SourceLocation(), N) {} + +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPUniformClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPUniformClause *CreateEmpty(const ASTContext &C, unsigned N); + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_uniform; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } +}; + +/// \brief This represents 'safelen' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp simd safelen(4) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'safelen' +/// with single expression '4'. +/// If the safelen clause is used then no two iterations executed +/// concurrently with SIMD instructions can have a greater distance +/// in the logical iteration space than its value. The parameter of +/// the safelen clause must be a constant positive integer expression. +/// +class OMPSafelenClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Safe iteration space distance. + Stmt *Safelen; + /// \brief Set the safe iteration space distance. + /// + /// \param E safe iteration space distance. + /// + void setSafelen(Expr *E) { Safelen = E; } + +public: + /// \brief Build 'safelen' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSafelenClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_safelen, StartLoc, EndLoc), Safelen(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPSafelenClause() + : OMPClause(OMPC_safelen, SourceLocation(), SourceLocation()), + Safelen(0) {} + + /// \brief Return safe iteration space distance. + /// + Expr *getSafelen() { return dyn_cast_or_null(Safelen); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_safelen; + } + + StmtRange children() { return StmtRange(&Safelen, &Safelen + 1); } +}; + +/// \brief This represents 'simdlen' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp declare simd simdlen(4) +/// \endcode +/// In this example directive '#pragma omp declare simd' has clause 'simdlen' +/// with single expression '4'. +/// +class OMPSimdlenClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Safe iteration space distance. + Stmt *Simdlen; + /// \brief Set the safe iteration space distance. + /// + /// \param E safe iteration space distance. + /// + void setSimdlen(Expr *E) { Simdlen = E; } + +public: + /// \brief Build 'simdlen' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPSimdlenClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_simdlen, StartLoc, EndLoc), Simdlen(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPSimdlenClause() + : OMPClause(OMPC_simdlen, SourceLocation(), SourceLocation()), + Simdlen(0) {} + + /// \brief Return safe iteration space distance. + /// + Expr *getSimdlen() const { return dyn_cast_or_null(Simdlen); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_simdlen; + } + + StmtRange children() { return StmtRange(&Simdlen, &Simdlen + 1); } +}; + +/// \brief This represents 'num_teams' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp teams num_teams(4) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'num_teams' +/// with single expression '4'. +/// +class OMPNumTeamsClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Number of teams. + Stmt *NumTeams; + /// \brief Set the number of teams. + /// + /// \param E number of teams. + /// + void setNumTeams(Expr *E) { NumTeams = E; } + +public: + /// \brief Build 'num_teams' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_num_teams, StartLoc, EndLoc), NumTeams(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPNumTeamsClause() + : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()), + NumTeams(0) {} + + /// \brief Return the number of teams. + /// + Expr *getNumTeams() const { return dyn_cast_or_null(NumTeams); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_num_teams; + } + + StmtRange children() { return StmtRange(&NumTeams, &NumTeams + 1); } +}; + +/// \brief This represents 'thread_limit' clause in the '#pragma omp ...' +/// directive. +/// +/// \code +/// #pragma omp teams thread_limit(4) +/// \endcode +/// In this example directive '#pragma omp teams' has clause 'thread_limit' +/// with single expression '4'. +/// +class OMPThreadLimitClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Thread limit. + Stmt *ThreadLimit; + /// \brief Set the thread limit. + /// + /// \param E thread limit. + /// + void setThreadLimit(Expr *E) { ThreadLimit = E; } + +public: + /// \brief Build 'thread_limit' clause. + /// + /// \param E Expression associated with this clause. + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// + OMPThreadLimitClause(Expr *E, SourceLocation StartLoc, SourceLocation EndLoc) + : OMPClause(OMPC_thread_limit, StartLoc, EndLoc), ThreadLimit(E) {} + + /// \brief Build an empty clause. + /// + explicit OMPThreadLimitClause() + : OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()), + ThreadLimit(0) {} + + /// \brief Return the number of teams. + /// + Expr *getThreadLimit() const { return dyn_cast_or_null(ThreadLimit); } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_thread_limit; + } + + StmtRange children() { return StmtRange(&ThreadLimit, &ThreadLimit + 1); } +}; + +/// \brief This represents clause 'linear' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp simd linear(a,b : 2) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'linear' +/// with variables 'a', 'b' and linear step '2'. +/// +class OMPLinearClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + + /// \brief Start location of the linear step in cource code. + SourceLocation StepLoc; + + /// \brief Set step for the clause. + /// + /// \param E step for the clause. + /// + void setStep(Expr *E) { + *(reinterpret_cast(varlist_end())) = cast_or_null(E); + } + + /// \brief Set step location. + /// + /// \param StLoc step location. + /// + void setStepLoc(SourceLocation StLoc) { StepLoc = StLoc; } + + /// \brief Build clause with number of variables \a N and a step \a St. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// \param StLoc Location of the linear step. + /// + OMPLinearClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N, + SourceLocation StLoc) + : OMPVarListClause(OMPC_linear, StartLoc, EndLoc, N), + StepLoc(StLoc) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPLinearClause(unsigned N) + : OMPVarListClause(OMPC_linear, SourceLocation(), + SourceLocation(), N), + StepLoc(SourceLocation()) {} + +public: + /// \brief Creates clause with a list of variables \a VL and a step + /// \a St. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param St Linear step. + /// \param StLoc Location of the linear step. + /// + static OMPLinearClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + Expr *St, SourceLocation StLoc); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPLinearClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches the linear step. + Expr *getStep() { + return dyn_cast_or_null(*(reinterpret_cast(varlist_end()))); + } + + /// \brief Fetches location of linear step. + SourceLocation getStepLoc() const { return StepLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_linear; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end() + 1)); + } +}; + +/// \brief This represents clause 'aligned' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp simd aligned(a,b : 8) +/// \endcode +/// In this example directive '#pragma omp simd' has clause 'aligned' +/// with variables 'a', 'b' and alignment '8'. +/// +class OMPAlignedClause : public OMPVarListClause { + friend class OMPClauseReader; + friend class OMPClauseWriter; + + /// \brief Start location of the alignment in cource code. + SourceLocation AlignmentLoc; + + /// \brief Set alignment for the clause. + /// + /// \param E alignment for the clause. + /// + void setAlignment(Expr *E) { + *(reinterpret_cast(varlist_end())) = cast_or_null(E); + } + + /// \brief Set alignment location. + /// + /// \param ALoc alignment location. + /// + void setAlignmentLoc(SourceLocation ALoc) { AlignmentLoc = ALoc; } + + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// \param ALoc Location of the alignment. + /// + OMPAlignedClause(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N, + SourceLocation ALoc) + : OMPVarListClause(OMPC_aligned, StartLoc, EndLoc, N), + AlignmentLoc(ALoc) {} + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPAlignedClause(unsigned N) + : OMPVarListClause(OMPC_aligned, SourceLocation(), + SourceLocation(), N), + AlignmentLoc(SourceLocation()) {} + +public: + /// \brief Creates clause with a list of variables \a VL and an alignment + /// \a A. + /// + /// \param C AST context. + /// \brief StartLoc Starting location of the clause. + /// \brief EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// \param A Alignment. + /// \param ALoc Location of the alignment. + /// + static OMPAlignedClause *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + Expr *A, SourceLocation ALoc); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPAlignedClause *CreateEmpty(const ASTContext &C, unsigned N); + + /// \brief Fetches the alignment. + Expr *getAlignment() { + return dyn_cast_or_null(*(reinterpret_cast(varlist_end()))); + } + + /// \brief Fetches location of the alignment. + SourceLocation getAlignmentLoc() const { return AlignmentLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_aligned; + } + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end() + 1)); + } +}; + +template struct make_ptr_clause { + typedef T *type; +}; +template struct make_const_ptr_clause { + typedef const T *type; +}; +/// \brief This class implements a simple visitor for OMPClause +/// subclasses. +template class Ptr, typename RetTy> +class OMPClauseVisitorBase { +public: +#define PTR(CLASS) typename Ptr::type +#define DISPATCH(CLASS) \ + return static_cast(this) \ + ->Visit##CLASS(static_cast(S)) + +#define OPENMP_CLAUSE(Name, Class) \ + RetTy Visit##Class(PTR(Class) S) { DISPATCH(Class); } +#include "clang/Basic/OpenMPKinds.def" + + RetTy Visit(PTR(OMPClause) S) { + // Top switch clause: visit each OMPClause. + switch (S->getClauseKind()) { + default: + llvm_unreachable("Unknown stmt kind!"); +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return Visit##Class(static_cast(S)); +#include "clang/Basic/OpenMPKinds.def" + } + } + // Base case, ignore it. :) + RetTy VisitOMPClause(PTR(OMPClause)) { return RetTy(); } +#undef PTR +#undef DISPATCH +}; + +template +class OMPClauseVisitor + : public OMPClauseVisitorBase {}; +template +class ConstOMPClauseVisitor + : public OMPClauseVisitorBase {}; + +} // end namespace clang + +#endif diff -uNr clang-3.4/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/RecursiveASTVisitor.h --- clang-3.4/include/clang/AST/RecursiveASTVisitor.h 2013-10-01 01:32:34.000000000 -0400 +++ clang/include/clang/AST/RecursiveASTVisitor.h 2014-06-09 10:05:34.000000000 -0400 @@ -263,6 +263,9 @@ #include "clang/AST/StmtNodes.inc" // The above header #undefs ABSTRACT_STMT and STMT upon exit. + /// \brief Traverses OMPExecutableDirective class. + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); } bool VisitStmt(Stmt *S) { return true; } @@ -1377,7 +1380,6 @@ // There is no code in a LabelDecl. }) - DEF_TRAVERSE_DECL(NamespaceDecl, { // Code in an unnamed namespace shows up automatically in // decls_begin()/decls_end(). Thus we don't need to recurse on @@ -1445,6 +1447,22 @@ } }) +DEF_TRAVERSE_DECL(OMPDeclareSimdDecl, { + if (D->getFunction()) { TRY_TO(TraverseDecl(D->getFunction())); } + }) + +DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, { + for (OMPDeclareReductionDecl::datalist_iterator I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + TRY_TO(TraverseType(I->QTy)); + TRY_TO(TraverseStmt(I->CombinerFunction)); + TRY_TO(TraverseStmt(I->InitFunction)); + } + }) + +DEF_TRAVERSE_DECL(OMPDeclareTargetDecl, { }) + // A helper method for TemplateDecl's children. template bool RecursiveASTVisitor::TraverseTemplateParameterListHelper( @@ -2212,6 +2230,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, { }) DEF_TRAVERSE_STMT(ArraySubscriptExpr, { }) +DEF_TRAVERSE_STMT(CEANIndexExpr, { }) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. @@ -2324,60 +2343,158 @@ // Traverse OpenCL: AsType, Convert. DEF_TRAVERSE_STMT(AsTypeExpr, { }) -// OpenMP directives. -DEF_TRAVERSE_STMT(OMPParallelDirective, { +// OpenMP directives +namespace { +template +class RecursiveOMPClauseVisitor : + public OMPClauseVisitor, bool> { + RecursiveASTVisitor *Visitor; + RecursiveASTVisitor &getDerived() { return *Visitor; } +public: + RecursiveOMPClauseVisitor(RecursiveASTVisitor *V) : Visitor(V) { } +#define OPENMP_CLAUSE(Name, Class) \ + bool Visit##Class(Class *S) { \ + for (Stmt::child_range Range = S->children(); Range; ++Range) { \ + if (!Visitor->TraverseStmt(*Range)) return false; \ + } \ + return true; \ + } +#include "clang/Basic/OpenMPKinds.def" +}; +} + +DEF_TRAVERSE_STMT(OMPExecutableDirective, { + RecursiveOMPClauseVisitor V(this); ArrayRef Clauses = S->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) - if (!TraverseOMPClause(*I)) return false; + if (!V.Visit(*I)) return false; }) -// OpenMP clauses. -template -bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { - if (!C) return true; - switch (C->getClauseKind()) { -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_##Name: \ - return getDerived().Visit##Class(static_cast(C)); -#include "clang/Basic/OpenMPKinds.def" - default: break; - } - return true; -} +DEF_TRAVERSE_STMT(OMPParallelDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { - return true; -} +DEF_TRAVERSE_STMT(OMPTeamsDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -template -void RecursiveASTVisitor::VisitOMPClauseList(T *Node) { - for (typename T::varlist_iterator I = Node->varlist_begin(), - E = Node->varlist_end(); - I != E; ++I) - TraverseStmt(*I); -} +DEF_TRAVERSE_STMT(OMPDistributeDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPForDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPFirstprivateClause( - OMPFirstprivateClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPParallelForDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPSharedClause(OMPSharedClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPParallelForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeParallelForDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeParallelForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSectionsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPParallelSectionsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSectionDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSingleDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskyieldDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPMasterDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCriticalDirective, { + TRY_TO(TraverseDeclarationNameInfo(S->getDirectiveName())); + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPBarrierDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskwaitDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskgroupDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPAtomicDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPFlushDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPOrderedDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCancelDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCancellationPointDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetDataDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetUpdateDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetTeamsDirective, { + return TraverseOMPExecutableDirective(S); +}) // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods diff -uNr clang-3.4/include/clang/AST/Stmt.h clang/include/clang/AST/Stmt.h --- clang-3.4/include/clang/AST/Stmt.h 2013-10-20 07:47:15.000000000 -0400 +++ clang/include/clang/AST/Stmt.h 2014-05-19 19:58:57.000000000 -0400 @@ -1967,9 +1967,11 @@ /// \brief The number of variable captured, including 'this'. unsigned NumCaptures; - /// \brief The pointer part is the implicit the outlined function and the - /// int part is the captured region kind, 'CR_Default' etc. - llvm::PointerIntPair CapDeclAndKind; + /// \brief The implicit outlined function. + CapturedDecl *TheCapturedDecl; + + /// \brief The kind of this statement, including 'CR_Default', etc. + CapturedRegionKind RegionKind; /// \brief The record for captured variables, a RecordDecl or CXXRecordDecl. RecordDecl *TheRecordDecl; @@ -2006,7 +2008,7 @@ } /// \brief Retrieve the outlined function declaration. - CapturedDecl *getCapturedDecl() { return CapDeclAndKind.getPointer(); } + CapturedDecl *getCapturedDecl() { return TheCapturedDecl; } const CapturedDecl *getCapturedDecl() const { return const_cast(this)->getCapturedDecl(); } @@ -2014,17 +2016,17 @@ /// \brief Set the outlined function declaration. void setCapturedDecl(CapturedDecl *D) { assert(D && "null CapturedDecl"); - CapDeclAndKind.setPointer(D); + TheCapturedDecl = D; } /// \brief Retrieve the captured region kind. CapturedRegionKind getCapturedRegionKind() const { - return CapDeclAndKind.getInt(); + return RegionKind; } /// \brief Set the captured region kind. void setCapturedRegionKind(CapturedRegionKind Kind) { - CapDeclAndKind.setInt(Kind); + RegionKind = Kind; } /// \brief Retrieve the record declaration for captured variables. diff -uNr clang-3.4/include/clang/AST/StmtOpenMP.h clang/include/clang/AST/StmtOpenMP.h --- clang-3.4/include/clang/AST/StmtOpenMP.h 2013-10-01 01:32:34.000000000 -0400 +++ clang/include/clang/AST/StmtOpenMP.h 2014-06-09 10:05:34.000000000 -0400 @@ -1,4 +1,4 @@ -//===- StmtOpenMP.h - Classes for OpenMP directives and clauses --*- C++ -*-===// +//===- StmtOpenMP.h - Classes for OpenMP directives and clauses -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,486 +15,2797 @@ #ifndef LLVM_CLANG_AST_STMTOPENMP_H #define LLVM_CLANG_AST_STMTOPENMP_H -#include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceLocation.h" -#include "clang/AST/Expr.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +#include "clang/AST/OpenMPClause.h" namespace clang { //===----------------------------------------------------------------------===// -// AST classes for clauses. +// AST classes for directives. //===----------------------------------------------------------------------===// -/// \brief This is a basic class for representing single OpenMP clause. +/// \brief This is a basic class for representing single OpenMP executable +/// directive. /// -class OMPClause { - /// \brief Starting location of the clause (the clause keyword). +class OMPExecutableDirective : public Stmt { + friend class ASTStmtReader; + /// \brief Kind of the directive. + OpenMPDirectiveKind Kind; + /// \brief Starting location of the directive kind. SourceLocation StartLoc; - /// \brief Ending location of the clause. + /// \brief Ending location of the directive. SourceLocation EndLoc; - /// \brief Kind of the clause. - OpenMPClauseKind Kind; + /// \brief Number of clauses. + unsigned NumClauses; + /// \brief Pointer to the list of clauses. + OMPClause **const Clauses; + /// \brief Number of associated expressions and statements. + unsigned NumStmts; + /// \brief Has associated statement. + bool AStmt; + protected: - OMPClause(OpenMPClauseKind K, SourceLocation StartLoc, SourceLocation EndLoc) - : StartLoc(StartLoc), EndLoc(EndLoc), Kind(K) {} + /// \brief Build instance of directive of class \a K. + /// + /// \param SC Statement class. + /// \param K Kind of OpenMP directive. + /// \param SL Starting location of the directive kind. + /// \param EL Ending location of the directive. + /// \param N Number of clauses. + /// \param ClausesAndStmt A pointer to the buffer for clauses. + /// + OMPExecutableDirective(StmtClass SC, OpenMPDirectiveKind K, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N, OMPClause **CL, bool AStmt, + unsigned NumStmts) + : Stmt(SC), Kind(K), StartLoc(StartLoc), EndLoc(EndLoc), NumClauses(N), + Clauses(CL), NumStmts(NumStmts), AStmt(AStmt) {} + + /// \brief Fetches the list of clauses associated with this directive. + llvm::MutableArrayRef getClauses() { + return llvm::MutableArrayRef(Clauses, NumClauses); + } -public: + /// \brief Fetches the list of clauses associated with this directive. + ArrayRef getClauses() const { + return ArrayRef(Clauses, NumClauses); + } + + /// \brief Sets the list of variables for this clause. + /// + /// \brief Clauses The list of clauses for the directive. + /// + void setClauses(ArrayRef CL); + + /// \brief Set the associated statement for the directive. + /// + /// /param S Associated statement. + /// + void setAssociatedStmt(Stmt *S) { + assert(AStmt && "No associated stmt allowed."); + *reinterpret_cast(&Clauses[NumClauses]) = S; + } + + OMPClause **getClausesStorage() const { return Clauses; } - /// \brief Returns the starting location of the clause. +public: + /// \brief Return starting location of directive kind. SourceLocation getLocStart() const { return StartLoc; } - /// \brief Returns the ending location of the clause. + /// \brief Return ending location of directive. SourceLocation getLocEnd() const { return EndLoc; } - /// \brief Sets the starting location of the clause. + /// \brief Set starting location of directive kind. + /// + /// \brief Loc New starting location of directive. + /// void setLocStart(SourceLocation Loc) { StartLoc = Loc; } - /// \brief Sets the ending location of the clause. + /// \brief Set ending location of directive. + /// + /// \brief Loc New ending location of directive. + /// void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } - /// \brief Returns kind of OpenMP clause (private, shared, reduction, etc.). - OpenMPClauseKind getClauseKind() const { return Kind; } + /// \brief Get number of clauses. + unsigned getNumClauses() const { return NumClauses; } + + /// \brief Fetches specified clause. + /// + /// \param i Number of clause. + /// + OMPClause *getClause(unsigned i) { + assert(i < NumClauses && "Wrong number of clause!"); + return getClauses()[i]; + } + + /// \brief Fetches specified clause. + /// + /// \param i Number of clause. + /// + OMPClause *getClause(unsigned i) const { + assert(i < NumClauses && "Wrong number of clause!"); + return getClauses()[i]; + } + + /// \brief Return statement associated with the directive. + Stmt *getAssociatedStmt() { + return AStmt ? *reinterpret_cast(&Clauses[NumClauses]) : 0; + } + + /// \brief Return statement associated with the directive. + Stmt *getAssociatedStmt() const { + return AStmt ? *reinterpret_cast(&Clauses[NumClauses]) : 0; + } + + bool hasAssociatedStmt() const { return AStmt; } + + OpenMPDirectiveKind getDirectiveKind() const { return Kind; } + + static bool classof(const Stmt *S) { + return S->getStmtClass() >= firstOMPExecutableDirectiveConstant && + S->getStmtClass() <= lastOMPExecutableDirectiveConstant; + } + + child_range children() { + return child_range(reinterpret_cast(&Clauses[NumClauses]), + reinterpret_cast(&Clauses[NumClauses]) + + NumStmts); + } + + ArrayRef clauses() { return getClauses(); } + ArrayRef clauses() const { return getClauses(); } +}; + +/// \brief This represents '#pragma omp parallel' directive. +/// +/// \code +/// #pragma omp parallel private(a,b) reduction(+: c,d) +/// \endcode +/// In this example directive '#pragma omp parallel' has clauses 'private' +/// with the variables 'a' and 'b' and 'reduction' with operator '+' and +/// variables 'c' and 'd'. +/// +class OMPParallelDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPParallelDirectiveClass, OMPD_parallel, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPParallelDirective(unsigned N) + : OMPExecutableDirective( + OMPParallelDirectiveClass, OMPD_parallel, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelDirective), + llvm::alignOf())), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPParallelDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPParallelDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp for' directive. +/// +/// \code +/// #pragma omp for private(a,b) reduction(+: c,d) ordered +/// \endcode +/// In this example directive '#pragma omp for' has clauses 'private' +/// with the variables 'a' and 'b', 'reduction' with operator '+' and +/// variables 'c' and 'd' and 'ordered'. +/// +class OMPForDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPForDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPForDirectiveClass, OMPD_for, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPForDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPForDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPForDirectiveClass, OMPD_for, SourceLocation(), SourceLocation(), + N, reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPForDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + // 5 is for AssociatedStmt, NewIterVar, NewIterEnd, Init, Final + // and CollapsedNum is for Counters. + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPForDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPForDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPForDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel for' directive. +/// +/// \code +/// #pragma omp parallel for private(a,b) reduction(+: c,d) ordered +/// \endcode +/// In this example directive '#pragma omp parallel for' has clauses 'private' +/// with the variables 'a' and 'b', 'reduction' with operator '+' and +/// variables 'c' and 'd' and 'ordered'. +/// +class OMPParallelForDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPParallelForDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPParallelForDirectiveClass, OMPD_parallel_for, StartLoc, EndLoc, + N, reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPParallelForDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPParallelForDirectiveClass, OMPD_parallel_for, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + // 5 is for AssociatedStmt, NewIterVar, NewIterEnd, Init, Final + // and CollapsedNum is for Counters. + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPParallelForDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPParallelForDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelForDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp simd' directive. +/// +/// \code +/// #pragma omp simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp simd' has clauses 'private' +/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and +/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPSimdDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPSimdDirectiveClass, OMPD_simd, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPSimdDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPSimdDirectiveClass, OMPD_simd, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPSimdDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp for simd' directive. +/// +/// \code +/// #pragma omp for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp for simd' has clauses 'private' +/// with the variables 'a' and 'b', 'linear' with variables 'i', 'j' and +/// linear step 's', 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPForSimdDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPForSimdDirectiveClass, OMPD_for_simd, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPForSimdDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPForSimdDirectiveClass, OMPD_for_simd, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPForSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel for simd' directive. +/// +/// \code +/// #pragma omp parallel for simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp parallel for simd' has clauses +/// 'private' with the variables 'a' and 'b', 'linear' with variables 'i', 'j' +/// and linear step 's', 'reduction' with operator '+' and variables 'c' and +/// 'd'. +/// +class OMPParallelForSimdDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPParallelForSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPParallelForSimdDirectiveClass, OMPD_parallel_for_simd, StartLoc, + EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPParallelForSimdDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPParallelForSimdDirectiveClass, OMPD_parallel_for_simd, + SourceLocation(), SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPParallelForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPParallelForSimdDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, + unsigned N, EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelForSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp distribute simd' directive. +/// +/// \code +/// #pragma omp distribute simd private(a,b) linear(i,j:s) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp distribute simd' has clauses +/// 'private' with the variables 'a' and 'b', 'linear' with variables 'i', 'j' +/// and linear step 's', 'reduction' with operator '+' and variables 'c' and +/// 'd'. +/// +class OMPDistributeSimdDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPDistributeSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeSimdDirectiveClass, OMPD_distribute_simd, StartLoc, + EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPDistributeSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPDistributeSimdDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeSimdDirectiveClass, OMPD_distribute_simd, + SourceLocation(), SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPDistributeSimdDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPDistributeSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPDistributeSimdDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, + unsigned N, EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDistributeSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp distribute parallel for' directive. +/// +/// \code +/// #pragma omp distribute parallel for private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp distribute parallel for' has clauses +/// 'private' +/// with the variables 'a' and 'b' and +/// 'reduction' with operator '+' and variables 'c' and 'd'. +/// +class OMPDistributeParallelForDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPDistributeParallelForDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeParallelForDirectiveClass, + OMPD_distribute_parallel_for, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment( + sizeof(OMPDistributeParallelForDirective), + llvm::alignOf())), + true, 7 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPDistributeParallelForDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeParallelForDirectiveClass, + OMPD_distribute_parallel_for, SourceLocation(), SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment( + sizeof(OMPDistributeParallelForDirective), + llvm::alignOf())), + true, 7 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setLowerBound(Expr *LB) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[5] = LB; + } + void setUpperBound(Expr *UB) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[6] = UB; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[7])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPDistributeParallelForDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, Expr *LowerBound, + Expr *UpperBound, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPDistributeParallelForDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, + unsigned N, EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + Expr *getLowerBound() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[5]); + } + Expr *getUpperBound() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[6]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[7])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + Expr *getLowerBound() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[5]); + } + Expr *getUpperBound() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[6]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDistributeParallelForDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp distribute parallel for simd' directive. +/// +/// \code +/// #pragma omp distribute parallel for simd private(a,b) reduction(+:c,d) +/// \endcode +/// In this example directive '#pragma omp distribute parallel for simd' has +/// clauses 'private' with the variables 'a' and 'b' and 'reduction' with +/// operator '+' and variables 'c' and 'd'. +/// +class OMPDistributeParallelForSimdDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param N The number of clauses. + /// + OMPDistributeParallelForSimdDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeParallelForSimdDirectiveClass, + OMPD_distribute_parallel_for_simd, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment( + sizeof(OMPDistributeParallelForSimdDirective), + llvm::alignOf())), + true, 7 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPDistributeParallelForSimdDirective(unsigned CollapsedNum, + unsigned N) + : OMPExecutableDirective( + OMPDistributeParallelForSimdDirectiveClass, + OMPD_distribute_parallel_for_simd, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment( + sizeof(OMPDistributeParallelForSimdDirective), + llvm::alignOf())), + true, 7 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setLowerBound(Expr *LB) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[5] = LB; + } + void setUpperBound(Expr *UB) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[6] = UB; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[7])); + } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPDistributeParallelForSimdDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, Expr *LowerBound, + Expr *UpperBound, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPDistributeParallelForSimdDirective * + CreateEmpty(const ASTContext &C, unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[4]); + } + Expr *getLowerBound() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[5]); + } + Expr *getUpperBound() const { + return cast_or_null(reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[6]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &reinterpret_cast(this + + 1)[getNumClauses()])[7])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); + } + Expr *getLowerBound() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[5]); + } + Expr *getUpperBound() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[6]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDistributeParallelForSimdDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp sections' directive. +/// +/// \code +/// #pragma omp sections private(a,b) reduction(+: c,d) nowait +/// \endcode +/// In this example directive '#pragma omp sections' has clauses 'private' +/// with the variables 'a' and 'b', 'reduction' with operator '+' and +/// variables 'c' and 'd' and 'nowait'. +/// +class OMPSectionsDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPSectionsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPSectionsDirectiveClass, OMPD_sections, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPSectionsDirective(unsigned N) + : OMPExecutableDirective( + OMPSectionsDirectiveClass, OMPD_sections, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective), + llvm::alignOf())), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPSectionsDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPSectionsDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSectionsDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp parallel sections' directive. +/// +/// \code +/// #pragma omp parallel sections private(a,b) reduction(+: c,d) +/// \endcode +/// In this example directive '#pragma omp parallel sections' has clauses +/// 'private' +/// with the variables 'a' and 'b', 'reduction' with operator '+' and +/// variables 'c' and 'd'. +/// +class OMPParallelSectionsDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPParallelSectionsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPParallelSectionsDirectiveClass, OMPD_parallel_sections, StartLoc, + EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPParallelSectionsDirective(unsigned N) + : OMPExecutableDirective( + OMPParallelSectionsDirectiveClass, OMPD_parallel_sections, + SourceLocation(), SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective), + llvm::alignOf())), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPParallelSectionsDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPParallelSectionsDirective *CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelSectionsDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp section' directive. +/// +/// \code +/// #pragma omp section +/// \endcode +/// In this example directive '#pragma omp section' is used. +/// +class OMPSectionDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPSectionDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective( + OMPSectionDirectiveClass, OMPD_section, StartLoc, EndLoc, 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSectionDirective), + sizeof(Stmt *))), + true, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPSectionDirective() + : OMPExecutableDirective( + OMPSectionDirectiveClass, OMPD_section, SourceLocation(), + SourceLocation(), 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSectionDirective), + sizeof(Stmt *))), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPSectionDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// + static OMPSectionDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSectionDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp single' directive. +/// +/// \code +/// #pragma omp single private(a,b) copyprivate(c,d) +/// \endcode +/// In this example directive '#pragma omp single' has clauses 'private' +/// with the variables 'a' and 'b', 'copyprivate' with variables 'c' and 'd'. +/// +class OMPSingleDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPSingleDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPSingleDirectiveClass, OMPD_single, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSingleDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPSingleDirective(unsigned N) + : OMPExecutableDirective( + OMPSingleDirectiveClass, OMPD_single, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPSingleDirective), + llvm::alignOf())), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPSingleDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPSingleDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSingleDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp task' directive. +/// +/// \code +/// #pragma omp task private(a,b) firstprivate(c,d) +/// \endcode +/// In this example directive '#pragma omp task' has clauses 'private' +/// with the variables 'a' and 'b', 'firstprivate' with variables 'c' and 'd'. +/// +class OMPTaskDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPTaskDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPTaskDirectiveClass, OMPD_task, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTaskDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPTaskDirective(unsigned N) + : OMPExecutableDirective( + OMPTaskDirectiveClass, OMPD_task, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTaskDirective), + llvm::alignOf())), + true, 1) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTaskDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPTaskDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskyield' directive. +/// +/// \code +/// #pragma omp taskyield +/// \endcode +/// In this example directive '#pragma omp taskyield' is used. +/// +class OMPTaskyieldDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPTaskyieldDirectiveClass, OMPD_taskyield, + StartLoc, EndLoc, 0, 0, false, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskyieldDirective() + : OMPExecutableDirective(OMPTaskyieldDirectiveClass, OMPD_taskyield, + SourceLocation(), SourceLocation(), 0, 0, false, + 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPTaskyieldDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskyieldDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskyieldDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp master' directive. +/// +/// \code +/// #pragma omp master +/// \endcode +/// In this example directive '#pragma omp master' is used. +/// +class OMPMasterDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPMasterDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective( + OMPMasterDirectiveClass, OMPD_master, StartLoc, EndLoc, 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPMasterDirective), + sizeof(Stmt *))), + true, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPMasterDirective() + : OMPExecutableDirective( + OMPMasterDirectiveClass, OMPD_master, SourceLocation(), + SourceLocation(), 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPMasterDirective), + sizeof(Stmt *))), + true, 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPMasterDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPMasterDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPMasterDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp critical' directive. +/// +/// \code +/// #pragma omp critical +/// \endcode +/// In this example directive '#pragma omp critical' is used. +/// +class OMPCriticalDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Name of thee directive. + DeclarationNameInfo DirName; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPCriticalDirective(DeclarationNameInfo Name, SourceLocation StartLoc, + SourceLocation EndLoc) + : OMPExecutableDirective( + OMPCriticalDirectiveClass, OMPD_critical, StartLoc, EndLoc, 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective), + sizeof(Stmt *))), + true, 1), + DirName(Name) {} + + /// \brief Build an empty directive. + /// + explicit OMPCriticalDirective() + : OMPExecutableDirective( + OMPCriticalDirectiveClass, OMPD_critical, SourceLocation(), + SourceLocation(), 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective), + sizeof(Stmt *))), + true, 1), + DirName() {} + /// \brief Set name of the directive. + /// + /// \param Name Name of the directive. + /// + void setDirectiveName(const DeclarationNameInfo &Name) { DirName = Name; } + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPCriticalDirective * + Create(const ASTContext &C, DeclarationNameInfo DirName, + SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPCriticalDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + /// \brief Return name of the directive. + /// + DeclarationNameInfo getDirectiveName() const { return DirName; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCriticalDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp barrier' directive. +/// +/// \code +/// #pragma omp barrier +/// \endcode +/// In this example directive '#pragma omp barrier' is used. +/// +class OMPBarrierDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPBarrierDirectiveClass, OMPD_barrier, StartLoc, + EndLoc, 0, 0, false, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPBarrierDirective() + : OMPExecutableDirective(OMPBarrierDirectiveClass, OMPD_barrier, + SourceLocation(), SourceLocation(), 0, 0, false, + 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPBarrierDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPBarrierDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPBarrierDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskwait' directive. +/// +/// \code +/// #pragma omp taskwait +/// \endcode +/// In this example directive '#pragma omp taskwait' is used. +/// +class OMPTaskwaitDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPTaskwaitDirectiveClass, OMPD_taskwait, + StartLoc, EndLoc, 0, 0, false, 0) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskwaitDirective() + : OMPExecutableDirective(OMPTaskwaitDirectiveClass, OMPD_taskwait, + SourceLocation(), SourceLocation(), 0, 0, false, + 0) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + static OMPTaskwaitDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskwaitDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskwaitDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp taskgroup' directive. +/// +/// \code +/// #pragma omp taskgroup +/// \endcode +/// In this example directive '#pragma omp taskgroup' is used. +/// +class OMPTaskgroupDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective( + OMPTaskgroupDirectiveClass, OMPD_taskgroup, StartLoc, EndLoc, 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective), + sizeof(Stmt *))), + true, 1) {} + + /// \brief Build an empty directive. + /// + explicit OMPTaskgroupDirective() + : OMPExecutableDirective( + OMPTaskgroupDirectiveClass, OMPD_taskgroup, SourceLocation(), + SourceLocation(), 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective), + sizeof(Stmt *))), + true, 1) {} + +public: + /// \brief Creates directive. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTaskgroupDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTaskgroupDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp atomic' directive. +/// +/// \code +/// #pragma omp atomic capture seq_cst +/// \endcode +/// In this example directive '#pragma omp atomic' has clauses 'capture' and +/// 'seq_cst'. +/// +class OMPAtomicDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + /// \brief Binary operator for atomic. + BinaryOperatorKind BinOp; + /// \brief Capture kind - true, if after expr, false, if before. + bool CaptureAfter; + /// \brief true, if operator for 'x' is reversed, false - otherwise. + bool Reversed; + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPAtomicDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPAtomicDirectiveClass, OMPD_atomic, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf())), + true, 4), + BinOp(BO_Assign), CaptureAfter(false), Reversed(false) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPAtomicDirective(unsigned N) + : OMPExecutableDirective( + OMPAtomicDirectiveClass, OMPD_atomic, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf())), + true, 4), + BinOp(BO_Assign), CaptureAfter(false), Reversed(false) {} + + /// \brief Sets binary operator for atomic. + void setOperator(BinaryOperatorKind Op) { BinOp = Op; } + + /// \brief Sets 'v' parameter for atomic. + void setV(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + + /// \brief Sets 'x' parameter for atomic. + void setX(Expr *X) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = X; + } + + /// \brief Sets 'expr' parameter for atomic. + void setExpr(Expr *OpExpr) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = + OpExpr; + } + + /// \brief Sets capture kind parameter for atomic. + void setCaptureAfter(bool CaptureKind) { CaptureAfter = CaptureKind; } + + /// \brief Sets update rules for 'x' parameter for atomic. + void setReversed(bool IsReversed) { Reversed = IsReversed; } + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPAtomicDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *V, Expr *X, + Expr *OpExpr, BinaryOperatorKind Op, bool CaptureAfter, bool Reversed); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPAtomicDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); + + /// \brief Returns binary operator for atomic. + BinaryOperatorKind getOperator() const { return BinOp; } + + /// \brief Returns 'v' parameter for atomic. + Expr *getV() const { + return reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[1]; + } + + /// \brief Returns 'x' parameter for atomic. + Expr *getX() const { + return reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[2]; + } + + /// \brief Returns 'expr' parameter for atomic. + Expr *getExpr() const { + return reinterpret_cast( + &reinterpret_cast(this + 1)[getNumClauses()])[3]; + } + + /// \brief Returns capture kind parameter for atomic. + bool isCaptureAfter() const { return CaptureAfter; } + + /// \brief Returns update kind of 'x' parameter for atomic. + bool isReversed() const { return Reversed; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPAtomicDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp flush' directive. +/// +/// \code +/// #pragma omp flush(a,b) +/// \endcode +/// In this example directive '#pragma omp flush' has list of variables 'a' and +/// 'b'. +/// +class OMPFlushDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPFlushDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPFlushDirectiveClass, OMPD_flush, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPFlushDirective), + llvm::alignOf())), + false, 0) {} + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPFlushDirective(unsigned N) + : OMPExecutableDirective( + OMPFlushDirectiveClass, OMPD_flush, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPFlushDirective), + llvm::alignOf())), + false, 0) {} + +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// + static OMPFlushDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses); - bool isImplicit() const { return StartLoc.isInvalid();} + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPFlushDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); - StmtRange children(); - ConstStmtRange children() const { - return const_cast(this)->children(); - } - static bool classof(const OMPClause *T) { - return true; + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPFlushDirectiveClass; } }; -/// \brief This represents clauses with the list of variables like 'private', -/// 'firstprivate', 'copyin', 'shared', or 'reduction' clauses in the -/// '#pragma omp ...' directives. -template -class OMPVarList { - friend class OMPClauseReader; - /// \brief Location of '('. - SourceLocation LParenLoc; - /// \brief Number of variables in the list. - unsigned NumVars; -protected: - /// \brief Fetches list of variables associated with this clause. - llvm::MutableArrayRef getVarRefs() { - return llvm::MutableArrayRef( - reinterpret_cast(static_cast(this) + 1), - NumVars); - } +/// \brief This represents '#pragma omp ordered' directive. +/// +/// \code +/// #pragma omp ordered +/// \endcode +/// In this example directive '#pragma omp ordered' is used. +/// +class OMPOrderedDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// + OMPOrderedDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective( + OMPOrderedDirectiveClass, OMPD_ordered, StartLoc, EndLoc, 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + sizeof(Stmt *))), + true, 1) {} - /// \brief Sets the list of variables for this clause. - void setVarRefs(ArrayRef VL) { - assert(VL.size() == NumVars && - "Number of variables is not the same as the preallocated buffer"); - std::copy(VL.begin(), VL.end(), - reinterpret_cast(static_cast(this) + 1)); - } + /// \brief Build an empty directive. + /// + explicit OMPOrderedDirective() + : OMPExecutableDirective( + OMPOrderedDirectiveClass, OMPD_ordered, SourceLocation(), + SourceLocation(), 0, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + sizeof(Stmt *))), + true, 1) {} - /// \brief Build clause with number of variables \a N. +public: + /// \brief Creates directive. /// - /// \param N Number of the variables in the clause. + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param AssociatedStmt Statement, associated with the directive. /// - OMPVarList(SourceLocation LParenLoc, unsigned N) - : LParenLoc(LParenLoc), NumVars(N) { } -public: - typedef llvm::MutableArrayRef::iterator varlist_iterator; - typedef ArrayRef::iterator varlist_const_iterator; + static OMPOrderedDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt); - unsigned varlist_size() const { return NumVars; } - bool varlist_empty() const { return NumVars == 0; } - varlist_iterator varlist_begin() { return getVarRefs().begin(); } - varlist_iterator varlist_end() { return getVarRefs().end(); } - varlist_const_iterator varlist_begin() const { return getVarRefs().begin(); } - varlist_const_iterator varlist_end() const { return getVarRefs().end(); } - - /// \brief Sets the location of '('. - void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } - /// \brief Returns the location of '('. - SourceLocation getLParenLoc() const { return LParenLoc; } + /// \brief Creates an empty directive. + /// + /// \param C AST context. + /// + static OMPOrderedDirective *CreateEmpty(const ASTContext &C, EmptyShell); - /// \brief Fetches list of all variables in the clause. - ArrayRef getVarRefs() const { - return ArrayRef( - reinterpret_cast(static_cast(this) + 1), - NumVars); + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPOrderedDirectiveClass; } }; -/// \brief This represents 'default' clause in the '#pragma omp ...' directive. +/// \brief This represents '#pragma omp teams' directive. /// /// \code -/// #pragma omp parallel default(shared) +/// #pragma omp teams private(a,b) reduction(+: c,d) /// \endcode -/// In this example directive '#pragma omp parallel' has simple 'default' -/// clause with kind 'shared'. +/// In this example directive '#pragma omp teams' has clauses 'private' +/// with the variables 'a' and 'b' and 'reduction' with operator '+' and +/// variables 'c' and 'd'. /// -class OMPDefaultClause : public OMPClause { - friend class OMPClauseReader; - /// \brief Location of '('. - SourceLocation LParenLoc; - /// \brief A kind of the 'default' clause. - OpenMPDefaultClauseKind Kind; - /// \brief Start location of the kind in source code. - SourceLocation KindKwLoc; - - /// \brief Set kind of the clauses. +class OMPTeamsDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. /// - /// \param K Argument of clause. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. /// - void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; } + OMPTeamsDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPTeamsDirectiveClass, OMPD_teams, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf())), + true, 1) {} - /// \brief Set argument location. + /// \brief Build an empty directive. /// - /// \param KLoc Argument location. + /// \param N Number of clauses. /// - void setDefaultKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } + explicit OMPTeamsDirective(unsigned N) + : OMPExecutableDirective( + OMPTeamsDirectiveClass, OMPD_teams, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf())), + true, 1) {} + public: - /// \brief Build 'default' clause with argument \a A ('none' or 'shared'). + /// \brief Creates directive with a list of \a Clauses. /// - /// \param A Argument of the clause ('none' or 'shared'). - /// \param ALoc Starting location of the argument. - /// \param StartLoc Starting location of the clause. - /// \param LParenLoc Location of '('. - /// \param EndLoc Ending location of the clause. + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) - : OMPClause(OMPC_default, StartLoc, EndLoc), LParenLoc(LParenLoc), - Kind(A), KindKwLoc(ALoc) { } + static OMPTeamsDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt); - /// \brief Build an empty clause. + /// \brief Creates an empty directive with the place for \a N clauses. /// - OMPDefaultClause() - : OMPClause(OMPC_default, SourceLocation(), SourceLocation()), - LParenLoc(SourceLocation()), Kind(OMPC_DEFAULT_unknown), - KindKwLoc(SourceLocation()) { } - - /// \brief Sets the location of '('. - void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } - /// \brief Returns the location of '('. - SourceLocation getLParenLoc() const { return LParenLoc; } - - /// \brief Returns kind of the clause. - OpenMPDefaultClauseKind getDefaultKind() const { return Kind; } - - /// \brief Returns location of clause kind. - SourceLocation getDefaultKindKwLoc() const { return KindKwLoc; } - - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_default; - } + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPTeamsDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); - StmtRange children() { - return StmtRange(); + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTeamsDirectiveClass; } }; -/// \brief This represents clause 'private' in the '#pragma omp ...' directives. +/// \brief This represents '#pragma omp distribute' directive. /// /// \code -/// #pragma omp parallel private(a,b) +/// #pragma omp distribute private(a,b) collapse(2) /// \endcode -/// In this example directive '#pragma omp parallel' has clause 'private' -/// with the variables 'a' and 'b'. +/// In this example directive '#pragma omp distribute' has clauses 'private' +/// with the variables 'a' and 'b', and 'collapse' with number '2' of loops to +/// be collapsed. /// -class OMPPrivateClause : public OMPClause, public OMPVarList { - /// \brief Build clause with number of variables \a N. +class OMPDistributeDirective : public OMPExecutableDirective { + friend class ASTStmtReader; + unsigned CollapsedNum; + /// \brief Build directive with the given start and end location. /// - /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. /// - OMPPrivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, unsigned N) - : OMPClause(OMPC_private, StartLoc, EndLoc), - OMPVarList(LParenLoc, N) { } + OMPDistributeDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeDirectiveClass, OMPD_distribute, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPDistributeDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} - /// \brief Build an empty clause. + /// \brief Build an empty directive. /// - /// \param N Number of variables. + /// \param N Number of clauses. /// - explicit OMPPrivateClause(unsigned N) - : OMPClause(OMPC_private, SourceLocation(), SourceLocation()), - OMPVarList(SourceLocation(), N) { } + explicit OMPDistributeDirective(unsigned CollapsedNum, unsigned N) + : OMPExecutableDirective( + OMPDistributeDirectiveClass, OMPD_distribute, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPDistributeDirective), + llvm::alignOf())), + true, 5 + CollapsedNum), + CollapsedNum(CollapsedNum) {} + // 5 is for AssociatedStmt, NewIterVar, NewIterEnd, Init, Final + // and CollapsedNum is for Counters. + void setNewIterVar(Expr *V) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1] = V; + } + void setNewIterEnd(Expr *E) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2] = E; + } + void setInit(Expr *I) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3] = I; + } + void setFinal(Expr *F) { + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4] = F; + } + void setCounters(ArrayRef VL) { + assert(VL.size() == CollapsedNum && "Number of variables is not the same " + "as the number of collapsed loops."); + std::copy( + VL.begin(), VL.end(), + &(reinterpret_cast(&getClausesStorage()[getNumClauses()])[5])); + } + public: - /// \brief Creates clause with a list of variables \a VL. + /// \brief Creates directive with a list of \a Clauses. /// /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL); - /// \brief Creates an empty clause with the place for \a N variables. + static OMPDistributeDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts); + + /// \brief Creates an empty directive with the place for \a N clauses. /// /// \param C AST context. - /// \param N The number of variables. + /// \param N The number of clauses. /// - static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); - - StmtRange children() { - return StmtRange(reinterpret_cast(varlist_begin()), - reinterpret_cast(varlist_end())); + static OMPDistributeDirective *CreateEmpty(const ASTContext &C, + unsigned CollapsedNum, unsigned N, + EmptyShell); + + Expr *getNewIterVar() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() const { + return cast_or_null(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[4]); + } + ArrayRef getCounters() const { + return llvm::makeArrayRef( + reinterpret_cast(&(reinterpret_cast( + &getClausesStorage()[getNumClauses()])[5])), + CollapsedNum); + } + unsigned getCollapsedNumber() const { return CollapsedNum; } + Expr *getNewIterVar() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[1]); + } + Expr *getNewIterEnd() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[2]); + } + Expr *getInit() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[3]); + } + Expr *getFinal() { + return cast_or_null( + reinterpret_cast(&getClausesStorage()[getNumClauses()])[4]); } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_private; + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPDistributeDirectiveClass; } }; -/// \brief This represents clause 'firstprivate' in the '#pragma omp ...' -/// directives. +/// \brief This represents '#pragma omp cancel' directive. /// /// \code -/// #pragma omp parallel firstprivate(a,b) +/// #pragma omp cancel parallel /// \endcode -/// In this example directive '#pragma omp parallel' has clause 'firstprivate' -/// with the variables 'a' and 'b'. +/// In this example directive '#pragma omp cancel' has construct type +/// 'parallel'. /// -class OMPFirstprivateClause : public OMPClause, - public OMPVarList { - /// \brief Build clause with number of variables \a N. +class OMPCancelDirective : public OMPExecutableDirective { + OpenMPDirectiveKind ConstructType; + /// \brief Build directive with the given start and end location. /// - /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// \param ConstructType Construct type. /// - OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, unsigned N) - : OMPClause(OMPC_firstprivate, StartLoc, EndLoc), - OMPVarList(LParenLoc, N) { } + OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N, + OpenMPDirectiveKind ConstructType) + : OMPExecutableDirective( + OMPCancelDirectiveClass, OMPD_cancel, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), + llvm::alignOf())), + false, 0), + ConstructType(ConstructType) {} - /// \brief Build an empty clause. + /// \brief Build an empty directive. /// - /// \param N Number of variables. + /// \param N Number of clauses. + /// \param ConstructType Construct type. /// - explicit OMPFirstprivateClause(unsigned N) - : OMPClause(OMPC_firstprivate, SourceLocation(), SourceLocation()), - OMPVarList(SourceLocation(), N) { } + explicit OMPCancelDirective(unsigned N, OpenMPDirectiveKind ConstructType) + : OMPExecutableDirective( + OMPCancelDirectiveClass, OMPD_cancel, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), + llvm::alignOf())), + false, 0), + ConstructType(ConstructType) {} + public: - /// \brief Creates clause with a list of variables \a VL. + /// \brief Creates directive with a list of \a Clauses. /// /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param ConstructType Construct type. /// - static OMPFirstprivateClause *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL); - /// \brief Creates an empty clause with the place for \a N variables. + static OMPCancelDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, OpenMPDirectiveKind ConstructType); + + /// \brief Creates an empty directive with the place for \a N clauses. /// /// \param C AST context. - /// \param N The number of variables. + /// \param N The number of clauses. + /// \param ConstructType Construct type. /// - static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + static OMPCancelDirective *CreateEmpty(const ASTContext &C, unsigned N, + OpenMPDirectiveKind ConstructType, + EmptyShell); - StmtRange children() { - return StmtRange(reinterpret_cast(varlist_begin()), - reinterpret_cast(varlist_end())); - } + /// \brief Fetches construct type. + OpenMPDirectiveKind getConstructType() const { return ConstructType; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_firstprivate; + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCancelDirectiveClass; } }; -/// \brief This represents clause 'shared' in the '#pragma omp ...' directives. +/// \brief This represents '#pragma omp cancellation point' directive. /// /// \code -/// #pragma omp parallel shared(a,b) +/// #pragma omp cancellation point parallel /// \endcode -/// In this example directive '#pragma omp parallel' has clause 'shared' -/// with the variables 'a' and 'b'. +/// In this example directive '#pragma omp cancellation point' has construct +/// type 'parallel'. /// -class OMPSharedClause : public OMPClause, public OMPVarList { - /// \brief Build clause with number of variables \a N. +class OMPCancellationPointDirective : public OMPExecutableDirective { + OpenMPDirectiveKind ConstructType; + /// \brief Build directive with the given start and end location. /// - /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param ConstructType Construct type. /// - OMPSharedClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, unsigned N) - : OMPClause(OMPC_shared, StartLoc, EndLoc), - OMPVarList(LParenLoc, N) { } + OMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType) + : OMPExecutableDirective(OMPCancellationPointDirectiveClass, + OMPD_cancellation_point, StartLoc, EndLoc, 0, 0, + false, 0), + ConstructType(ConstructType) {} - /// \brief Build an empty clause. + /// \brief Build an empty directive. /// - /// \param N Number of variables. + /// \param ConstructType Construct type. /// - explicit OMPSharedClause(unsigned N) - : OMPClause(OMPC_shared, SourceLocation(), SourceLocation()), - OMPVarList(SourceLocation(), N) { } + explicit OMPCancellationPointDirective(OpenMPDirectiveKind ConstructType) + : OMPExecutableDirective(OMPCancellationPointDirectiveClass, + OMPD_cancellation_point, SourceLocation(), + SourceLocation(), 0, 0, false, 0), + ConstructType(ConstructType) {} + public: - /// \brief Creates clause with a list of variables \a VL. + /// \brief Creates directive with a list of \a Clauses. /// /// \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. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param ConstructType Construct type. /// - static OMPSharedClause *Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef VL); - /// \brief Creates an empty clause with \a N variables. + static OMPCancellationPointDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType); + + /// \brief Creates an empty directive with the place for \a N clauses. /// /// \param C AST context. - /// \param N The number of variables. + /// \param ConstructType Construct type. /// - static OMPSharedClause *CreateEmpty(const ASTContext &C, unsigned N); + static OMPCancellationPointDirective * + CreateEmpty(const ASTContext &C, OpenMPDirectiveKind ConstructType, + EmptyShell); - StmtRange children() { - return StmtRange(reinterpret_cast(varlist_begin()), - reinterpret_cast(varlist_end())); - } + /// \brief Fetches construct type. + OpenMPDirectiveKind getConstructType() const { return ConstructType; } - static bool classof(const OMPClause *T) { - return T->getClauseKind() == OMPC_shared; + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPCancellationPointDirectiveClass; } }; -//===----------------------------------------------------------------------===// -// AST classes for directives. -//===----------------------------------------------------------------------===// - -/// \brief This is a basic class for representing single OpenMP executable -/// directive. +/// \brief This represents '#pragma omp target' directive. /// -class OMPExecutableDirective : public Stmt { - friend class ASTStmtReader; - /// \brief Kind of the directive. - OpenMPDirectiveKind Kind; - /// \brief Starting location of the directive (directive keyword). - SourceLocation StartLoc; - /// \brief Ending location of the directive. - SourceLocation EndLoc; - /// \brief Pointer to the list of clauses. - llvm::MutableArrayRef Clauses; - /// \brief Associated statement (if any) and expressions. - llvm::MutableArrayRef StmtAndExpressions; -protected: - /// \brief Build instance of directive of class \a K. +/// \code +/// #pragma omp target device(0) if(a) map(b[:]) +/// \endcode +/// In this example directive '#pragma omp target' has clauses 'device' +/// with the value '0', 'if' with condition 'a' and 'map' with array +/// section 'b[:]'. +/// +class OMPTargetDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. /// - /// \param SC Statement class. - /// \param K Kind of OpenMP directive. - /// \param StartLoc Starting location of the directive (directive keyword). - /// \param EndLoc Ending location of the directive. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. /// - template - OMPExecutableDirective(const T *, StmtClass SC, OpenMPDirectiveKind K, - SourceLocation StartLoc, SourceLocation EndLoc, - unsigned NumClauses, unsigned NumberOfExpressions) - : Stmt(SC), Kind(K), StartLoc(StartLoc), EndLoc(EndLoc), - Clauses(reinterpret_cast(static_cast(this) + 1), - NumClauses), - StmtAndExpressions(reinterpret_cast(Clauses.end()), - NumberOfExpressions) { } + OMPTargetDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned N) + : OMPExecutableDirective( + OMPTargetDirectiveClass, OMPD_target, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf())), + true, 1) {} - /// \brief Sets the list of variables for this clause. + /// \brief Build an empty directive. /// - /// \param Clauses The list of clauses for the directive. + /// \param N Number of clauses. /// - void setClauses(ArrayRef Clauses); + explicit OMPTargetDirective(unsigned N) + : OMPExecutableDirective( + OMPTargetDirectiveClass, OMPD_target, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf())), + true, 1) {} - /// \brief Set the associated statement for the directive. +public: + /// \brief Creates directive with a list of \a Clauses. /// - /// /param S Associated statement. + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. /// - void setAssociatedStmt(Stmt *S) { - StmtAndExpressions[0] = S; - } + static OMPTargetDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); -public: - /// \brief Returns starting location of directive kind. - SourceLocation getLocStart() const { return StartLoc; } - /// \brief Returns ending location of directive. - SourceLocation getLocEnd() const { return EndLoc; } + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPTargetDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); - /// \brief Set starting location of directive kind. + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetDirectiveClass; + } +}; + +/// \brief This represents '#pragma omp target teams' directive. +/// +/// \code +/// #pragma omp target teams device(0) if(a) map(b[:]) num_teams(10) +/// \endcode +/// In this example directive '#pragma omp target teams' has clauses 'device' +/// with the value '0', 'if' with condition 'a', 'map' with array +/// section 'b[:]' and 'num_teams' with number of teams '10'. +/// +class OMPTargetTeamsDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. /// - /// \param Loc New starting location of directive. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. /// - void setLocStart(SourceLocation Loc) { StartLoc = Loc; } - /// \brief Set ending location of directive. + OMPTargetTeamsDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPTargetTeamsDirectiveClass, OMPD_target_teams, StartLoc, EndLoc, + N, reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetTeamsDirective), + llvm::alignOf())), + true, 1) {} + + /// \brief Build an empty directive. /// - /// \param Loc New ending location of directive. + /// \param N Number of clauses. /// - void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + explicit OMPTargetTeamsDirective(unsigned N) + : OMPExecutableDirective( + OMPTargetTeamsDirectiveClass, OMPD_target_teams, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetTeamsDirective), + llvm::alignOf())), + true, 1) {} - /// \brief Get number of clauses. - unsigned getNumClauses() const { return Clauses.size(); } +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTargetTeamsDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); - /// \brief Returns specified clause. + /// \brief Creates an empty directive with the place for \a N clauses. /// - /// \param i Number of clause. + /// \param C AST context. + /// \param N The number of clauses. /// - OMPClause *getClause(unsigned i) const { - assert(i < Clauses.size() && "index out of bound!"); - return Clauses[i]; - } + static OMPTargetTeamsDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); - /// \brief Returns statement associated with the directive. - Stmt *getAssociatedStmt() const { - return StmtAndExpressions[0]; + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetTeamsDirectiveClass; } +}; - OpenMPDirectiveKind getDirectiveKind() const { return Kind; } +/// \brief This represents '#pragma omp target data' directive. +/// +/// \code +/// #pragma omp target data device(0) if(a) map(b[:]) +/// \endcode +/// In this example directive '#pragma omp target data' has clauses 'device' +/// with the value '0', 'if' with condition 'a' and 'map' with array +/// section 'b[:]'. +/// +class OMPTargetDataDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. + /// + OMPTargetDataDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPTargetDataDirectiveClass, OMPD_target_data, StartLoc, EndLoc, N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective), + llvm::alignOf())), + true, 1) {} - static bool classof(const Stmt *S) { - return S->getStmtClass() >= firstOMPExecutableDirectiveConstant && - S->getStmtClass() <= lastOMPExecutableDirectiveConstant; - } + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPTargetDataDirective(unsigned N) + : OMPExecutableDirective( + OMPTargetDataDirectiveClass, OMPD_target_data, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective), + llvm::alignOf())), + true, 1) {} - child_range children() { - return child_range(StmtAndExpressions.begin(), StmtAndExpressions.end()); - } +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// + static OMPTargetDataDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt); - ArrayRef clauses() { return Clauses; } + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPTargetDataDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); - ArrayRef clauses() const { return Clauses; } + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTargetDataDirectiveClass; + } }; -/// \brief This represents '#pragma omp parallel' directive. +/// \brief This represents '#pragma omp target update' directive. /// /// \code -/// #pragma omp parallel private(a,b) reduction(+: c,d) +/// #pragma omp target update to(a) from(b) device(1) /// \endcode -/// In this example directive '#pragma omp parallel' has clauses 'private' -/// with the variables 'a' and 'b' and 'reduction' with operator '+' and -/// variables 'c' and 'd'. +/// In this example directive '#pragma omp target update' has clause 'to' with +/// argument 'a', clause 'from' with argument 'b' and clause 'device' with +/// argument '1'. /// -class OMPParallelDirective : public OMPExecutableDirective { +class OMPTargetUpdateDirective : public OMPExecutableDirective { /// \brief Build directive with the given start and end location. /// - /// \param StartLoc Starting location of the directive (directive keyword). + /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. + /// \param N The number of clauses. /// - OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc, - unsigned N) - : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, - StartLoc, EndLoc, N, 1) { } + OMPTargetUpdateDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective( + OMPTargetUpdateDirectiveClass, OMPD_target_update, StartLoc, EndLoc, + N, reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetUpdateDirective), + llvm::alignOf())), + false, 0) {} /// \brief Build an empty directive. /// /// \param N Number of clauses. /// - explicit OMPParallelDirective(unsigned N) - : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, - SourceLocation(), SourceLocation(), N, 1) { } + explicit OMPTargetUpdateDirective(unsigned N) + : OMPExecutableDirective( + OMPTargetUpdateDirectiveClass, OMPD_target_update, SourceLocation(), + SourceLocation(), N, + reinterpret_cast( + reinterpret_cast(this) + + llvm::RoundUpToAlignment(sizeof(OMPTargetUpdateDirective), + llvm::alignOf())), + false, 0) {} + public: /// \brief Creates directive with a list of \a Clauses. /// @@ -502,27 +2813,24 @@ /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. /// \param Clauses List of clauses. - /// \param AssociatedStmt Statement associated with the directive. /// - static OMPParallelDirective *Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef Clauses, - Stmt *AssociatedStmt); + static OMPTargetUpdateDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses); /// \brief Creates an empty directive with the place for \a N clauses. /// /// \param C AST context. /// \param N The number of clauses. /// - static OMPParallelDirective *CreateEmpty(const ASTContext &C, unsigned N, - EmptyShell); + static OMPTargetUpdateDirective *CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell); static bool classof(const Stmt *T) { - return T->getStmtClass() == OMPParallelDirectiveClass; + return T->getStmtClass() == OMPTargetUpdateDirectiveClass; } }; - -} // end namespace clang +} // end namespace clang #endif diff -uNr clang-3.4/include/clang/AST/StmtVisitor.h clang/include/clang/AST/StmtVisitor.h --- clang-3.4/include/clang/AST/StmtVisitor.h 2013-07-18 23:13:43.000000000 -0400 +++ clang/include/clang/AST/StmtVisitor.h 2014-05-19 19:58:57.000000000 -0400 @@ -185,41 +185,6 @@ class ConstStmtVisitor : public StmtVisitorBase {}; -/// \brief This class implements a simple visitor for OMPClause -/// subclasses. -template class Ptr, typename RetTy> -class OMPClauseVisitorBase { -public: -#define PTR(CLASS) typename Ptr::type -#define DISPATCH(CLASS) \ - return static_cast(this)->Visit##CLASS(static_cast(S)) - -#define OPENMP_CLAUSE(Name, Class) \ - RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); } -#include "clang/Basic/OpenMPKinds.def" - - RetTy Visit(PTR(OMPClause) S) { - // Top switch clause: visit each OMPClause. - switch (S->getClauseKind()) { - default: llvm_unreachable("Unknown clause kind!"); -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_ ## Name : return Visit ## Class(static_cast(S)); -#include "clang/Basic/OpenMPKinds.def" - } - } - // Base case, ignore it. :) - RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); } -#undef PTR -#undef DISPATCH -}; - -template -class OMPClauseVisitor : - public OMPClauseVisitorBase {}; -template -class ConstOMPClauseVisitor : - public OMPClauseVisitorBase {}; - } // end namespace clang #endif diff -uNr clang-3.4/include/clang/Basic/Attr.td clang/include/clang/Basic/Attr.td --- clang-3.4/include/clang/Basic/Attr.td 2013-11-30 22:46:47.000000000 -0500 +++ clang/include/clang/Basic/Attr.td 2014-05-19 19:58:57.000000000 -0400 @@ -1101,3 +1101,9 @@ def Unaligned : IgnoredAttr { let Spellings = [Keyword<"__unaligned">]; } + +def OMPLocal : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; + let HasCustomParsing = 1; +} diff -uNr clang-3.4/include/clang/Basic/CapturedStmt.h clang/include/clang/Basic/CapturedStmt.h --- clang-3.4/include/clang/Basic/CapturedStmt.h 2013-09-06 14:03:48.000000000 -0400 +++ clang/include/clang/Basic/CapturedStmt.h 2014-05-19 19:58:57.000000000 -0400 @@ -16,6 +16,7 @@ /// \brief The different kinds of captured statement. enum CapturedRegionKind { CR_Default, + CR_SIMDFor, CR_OpenMP }; diff -uNr clang-3.4/include/clang/Basic/DeclNodes.td clang/include/clang/Basic/DeclNodes.td --- clang-3.4/include/clang/Basic/DeclNodes.td 2013-08-05 21:03:05.000000000 -0400 +++ clang/include/clang/Basic/DeclNodes.td 2014-05-19 19:58:57.000000000 -0400 @@ -69,6 +69,7 @@ def ObjCImplementation : DDecl; def ObjCProperty : DDecl; def ObjCCompatibleAlias : DDecl; + def OMPDeclareReduction : DDecl, DeclContext; def LinkageSpec : Decl, DeclContext; def ObjCPropertyImpl : Decl; def FileScopeAsm : Decl; @@ -81,5 +82,7 @@ def ClassScopeFunctionSpecialization : Decl; def Import : Decl; def OMPThreadPrivate : Decl; +def OMPDeclareSimd : Decl; +def OMPDeclareTarget : Decl, DeclContext; def Empty : Decl; diff -uNr clang-3.4/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Basic/DiagnosticParseKinds.td --- clang-3.4/include/clang/Basic/DiagnosticParseKinds.td 2013-12-15 21:32:55.000000000 -0500 +++ clang/include/clang/Basic/DiagnosticParseKinds.td 2014-05-19 19:58:57.000000000 -0400 @@ -411,9 +411,9 @@ "properties are an Objective-C 2 feature">; def err_objc_unexpected_attr : Error< "prefix attribute must be followed by an interface or protocol">; -def err_objc_postfix_attribute : Error < +def err_objc_postfix_attribute : Error< "postfix attributes are not allowed on Objective-C directives">; -def err_objc_postfix_attribute_hint : Error < +def err_objc_postfix_attribute_hint : Error< "postfix attributes are not allowed on Objective-C directives, place" " them in front of '%select{@interface|@protocol}0'">; def err_objc_directive_only_in_protocol : Error< @@ -834,23 +834,44 @@ def err_seh___finally_block : Error< "%0 only allowed in __finally block">; +} // end of Parse Issue category. // OpenMP support. -def warn_pragma_omp_ignored : Warning < +let CategoryName = "OpenMP Parse Issue" in { + +def warn_pragma_omp_ignored : Warning< "unexpected '#pragma omp ...' in program">, InGroup, DefaultIgnore; -def warn_omp_extra_tokens_at_eol : Warning < +def warn_omp_extra_tokens_at_eol : Warning< "extra tokens at the end of '#pragma omp %0' are ignored">, InGroup; -def err_omp_unknown_directive : Error < +def err_omp_unknown_directive : Error< "expected an OpenMP directive">; -def err_omp_unexpected_directive : Error < +def err_omp_unexpected_directive : Error< "unexpected OpenMP directive '#pragma omp %0'">; -def err_omp_expected_punc : Error < +def err_omp_expected_var : Error< + "expected '#pragma omp %0' argument to be a variable name">; +def err_omp_expected_punc : Error< "expected ',' or ')' in %select{'#pragma omp %1'|'%1' clause}0">; -def err_omp_unexpected_clause : Error < +def err_omp_unknown_clause : Error< + "expected OpenMP clause for directive '#pragma omp %0' or end of directive">; +def err_omp_unexpected_clause : Error< "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; -def err_omp_more_one_clause : Error < +def err_omp_more_one_clause : Error< "directive '#pragma omp %0' cannot contain more than one '%1' clause">; +def err_omp_expected_colon : Error< + "expected ':' in '%0' clause">; +def err_omp_unknown_reduction_op : Error< + "expected reduction identifier">; +def err_omp_immediate_directive : Error< + "'#pragma omp %0' cannot be immediate substatement">; +def err_omp_expected_reduction_identifier : Error< + "expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'">; +def err_omp_unknown_dependence_type : Error< + "expected dependence type 'in', 'out' or 'inout'">; +def err_omp_expected_cancel_construct_type : Error< + "expected 'parallel', 'sections', 'for' or 'taskgroup' construct type">; +def err_expected_end_declare_target : Error< + "expected '#pragma omp end declare target'">; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { diff -uNr clang-3.4/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/DiagnosticSemaKinds.td --- clang-3.4/include/clang/Basic/DiagnosticSemaKinds.td 2013-11-25 02:42:52.000000000 -0500 +++ clang/include/clang/Basic/DiagnosticSemaKinds.td 2014-06-09 10:05:34.000000000 -0400 @@ -674,7 +674,7 @@ InGroup; def warn_property_attr_mismatch : Warning< "property attribute in class extension does not match the primary class">; -def warn_property_implicitly_mismatched : Warning < +def warn_property_implicitly_mismatched : Warning< "primary property declaration is implicitly strong while redeclaration " "in class extension is weak">, InGroup>; @@ -704,7 +704,7 @@ "auto property synthesis will not synthesize property" " declared in a protocol">, InGroup>; -def warn_no_autosynthesis_shared_ivar_property : Warning < +def warn_no_autosynthesis_shared_ivar_property : Warning< "auto property synthesis will not synthesize property " "'%0' because it cannot share an ivar with another synthesized property">, InGroup; @@ -717,7 +717,7 @@ "autosynthesized property %0 will use %select{|synthesized}1 instance variable " "%2, not existing instance variable %3">, InGroup>; -def warn_missing_explicit_synthesis : Warning < +def warn_missing_explicit_synthesis : Warning< "auto property synthesis is synthesizing property not explicitly synthesized">, InGroup>, DefaultIgnore; def warn_property_getter_owning_mismatch : Warning< @@ -780,23 +780,23 @@ InGroup>; def err_gc_weak_property_strong_type : Error< "weak attribute declared on a __strong type property in GC mode">; -def warn_receiver_is_weak : Warning < +def warn_receiver_is_weak : Warning< "weak %select{receiver|property|implicit property}0 may be " "unpredictably set to nil">, InGroup>, DefaultIgnore; def note_arc_assign_to_strong : Note< "assign the value to a strong variable to keep the object alive during use">; -def warn_arc_repeated_use_of_weak : Warning < +def warn_arc_repeated_use_of_weak : Warning< "weak %select{variable|property|implicit property|instance variable}0 %1 is " "accessed multiple times in this %select{function|method|block|lambda}2 " "but may be unpredictably set to nil; assign to a strong variable to keep " "the object alive">, InGroup, DefaultIgnore; -def warn_implicitly_retains_self : Warning < +def warn_implicitly_retains_self : Warning< "block implicitly retains 'self'; explicitly mention 'self' to indicate " "this is intended behavior">, InGroup>, DefaultIgnore; -def warn_arc_possible_repeated_use_of_weak : Warning < +def warn_arc_possible_repeated_use_of_weak : Warning< "weak %select{variable|property|implicit property|instance variable}0 %1 may " "be accessed multiple times in this %select{function|method|block|lambda}2 " "and may be unpredictably set to nil; assign to a strong variable to keep " @@ -1642,7 +1642,7 @@ def err_for_range_dereference : Error< "invalid range expression of type %0; did you mean to dereference it " "with '*'?">; -def note_for_range_invalid_iterator : Note < +def note_for_range_invalid_iterator : Note< "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">; def note_for_range_begin_end : Note< "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">; @@ -2026,7 +2026,7 @@ "weakref declaration of '%0' must be in a global context">; def err_attribute_weakref_without_alias : Error< "weakref declaration of '%0' must also have an alias attribute">; -def err_alias_not_supported_on_darwin : Error < +def err_alias_not_supported_on_darwin : Error< "only weak aliases are supported on darwin">; def err_alias_to_undefined : Error< "alias must point to a defined variable or function">; @@ -3515,7 +3515,7 @@ def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; -def warn_missing_sentinel : Warning < +def warn_missing_sentinel : Warning< "missing sentinel in %select{function call|method dispatch|block call}0">, InGroup; def note_sentinel_here : Note< @@ -3618,7 +3618,7 @@ "conflicts with declaration %select{in global scope|with C language linkage}0">; def note_extern_c_global_conflict : Note< "declared %select{in global scope|with C language linkage}0 here">; -def warn_weak_import : Warning < +def warn_weak_import : Warning< "an already-declared variable is made a weak_import declaration %0">; def warn_static_non_static : ExtWarn< "static declaration of %0 follows non-static declaration">; @@ -4582,7 +4582,7 @@ InGroup; def ext_typecheck_cond_incompatible_operands : ExtWarn< "incompatible operand types (%0 and %1)">; -def err_cond_voidptr_arc : Error < +def err_cond_voidptr_arc : Error< "operands to conditional of types%diff{ $ and $|}0,1 are incompatible " "in ARC mode">; def err_typecheck_comparison_of_distinct_pointers : Error< @@ -5789,11 +5789,11 @@ def err_only_constructors_take_base_inits : Error< "only constructors take base initializers">; -def err_multiple_mem_initialization : Error < +def err_multiple_mem_initialization : Error< "multiple initializations given for non-static member %0">; -def err_multiple_mem_union_initialization : Error < +def err_multiple_mem_union_initialization : Error< "initializing multiple members of union">; -def err_multiple_base_initialization : Error < +def err_multiple_base_initialization : Error< "multiple initializations given for base %0">; def err_mem_init_not_member_or_class : Error< @@ -6127,7 +6127,7 @@ "values of type '%0' should not be used as format arguments; add an explicit " "cast to %1 instead">, InGroup; -def warn_printf_positional_arg_exceeds_data_args : Warning < +def warn_printf_positional_arg_exceeds_data_args : Warning< "data argument position '%0' exceeds the number of data arguments (%1)">, InGroup; def warn_format_zero_positional_specifier : Warning< @@ -6715,28 +6715,186 @@ "'#pragma omp %0' must precede all references to variable %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is thread-local">; +def err_omp_threadprivate_incomplete_type : Error< + "a threadprivate variable with incomplete type %0">; 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 < +def err_omp_reduction_incomplete_type : Error< + "a reduction variable with incomplete type %0">; +def err_omp_lastprivate_incomplete_type : Error< + "a lastprivate variable with incomplete type %0">; +def err_omp_linear_incomplete_type : Error< + "a linear variable with incomplete type %0">; +def err_omp_directive_nonblock : Error< + "directive '#pragma omp %0' bound to nonblock statement">; +def err_incomplete_class_type : Error< + "expression has incomplete type %0">; +def err_multiple_conversions : Error< + "multiple conversions from expression type %0 to an integral " + "or enumeration type">; +def err_explicit_conversion : Error< + "expression type %0 requires explicit conversion to %1">; +def note_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1">; +def err_negative_expression_in_clause : Error< + "expression is not a positive integer value">; +def err_zero_step_in_linear_clause : Error< + "zero is not linear enough to be a linear step">; +def err_omp_unexpected_clause_value : Error< "expected %0 in OpenMP clause '%1'">; -def err_omp_expected_var_name : Error < +def err_omp_expected_var_name : Error< "expected variable name">; -def err_omp_required_method : Error < +def err_omp_required_method : Error< "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">; +def note_omp_marked_here : Note< + "marked as %0 here">; def err_omp_clause_ref_type_arg : Error< - "arguments of OpenMP clause '%0' cannot be of reference type %1">; -def err_omp_threadprivate_incomplete_type : Error< - "threadprivate variable with incomplete type %0">; -def err_omp_no_dsa_for_variable : Error < - "variable %0 must have explicitly specified data sharing attributes">; + "arguments of OpenMP clause '%0' cannot be of reference type">; +def err_omp_expected_int_or_ptr : Error< + "argument of a linear clause should be of integral or pointer type">; +def err_omp_expected_array_or_ptr : Error< + "argument of an aligned clause should be array, pointer, reference to array or reference to pointer">; +def err_omp_required_access : Error< + "%0 variable must be %1">; +def err_omp_clause_not_arithmetic_type_arg : Error< + "arguments of OpenMP clause '%0'%select{| for 'min' and 'max'}1 must be of %select{scalar|arithmetic}1 type">; +def err_omp_clause_floating_type_arg : Error< + "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">; +def err_omp_clause_array_type_arg : Error< + "arguments of OpenMP clause '%0' cannot be of array type">; +def err_omp_reduction_ref_type_arg : Error< + "argument of OpenMP clause 'reduction' must reference the same object in all threads">; def err_omp_wrong_dsa : Error< "%0 variable cannot be %1">; -def note_omp_explicit_dsa : Note < +def err_omp_at_most_one_uniform_or_linear : Error< + "each argument may be in at most one uniform or linear clause">; +def err_omp_at_most_one_aligned : Error< + "each argument may be in at most one aligned clause">; +def err_omp_inbranch : Error< + "declare simd variant cannot be inbranch and notinbranch at the same time">; +def err_omp_arg_not_found : Error< + "cannot find the function argument with the name requested in the openmp clause">; +def err_omp_reduction_in_task : Error< + "reduction variables may not be accessed in an explicit task">; +def err_omp_once_referenced : Error< + "variable can appear only once in OpenMP '%0' clause">; +def err_omp_once_referenced_in_target_update : Error< + "variable can appear only once in OpenMP 'target update' construct">; +def err_omp_const_variable : Error< + "const-qualified variable cannot be %0">; +def note_omp_explicit_dsa : Note< "defined as %0">; -def note_omp_predetermined_dsa : Note < +def note_omp_predetermined_dsa : Note< "predetermined as %0">; +def note_omp_referenced : Note< + "previously referenced here">; +def note_omp_specified : Note< + "previously specified here">; +def err_omp_dsa_with_directives : Error< + "%0 variable in '#pragma omp %1' cannot be %2 in '#pragma omp %3'">; +def err_omp_not_for : Error< + "only for-loops are allowed for '#pragma omp %0'">; +def err_omp_for_variable : Error< + "variable must be of integer or %select{pointer|random access iterator}0 type">; +def err_omp_not_canonical_for : Error< + "%select{initialization|condition|increment}0 of for-loop does not have canonical form">; +def err_omp_for_incr_not_integer : Error< + "increment expression of for-loop must be of an integer type">; +def err_omp_for_incr_not_compatible : Error< + "increment expression must cause %q0 to %select{decrease|increase}1 on each iteration of the loop">; +def err_omp_for_type_not_compatible : Error< + "expression of type %0 is not compatible with variable %1 of type %2">; +def err_omp_for_wrong_count : Error< + "unable to calculate number of iterations of the for-loop">; +def err_omp_type_not_rai : Error< + "iteration variable is not of a random access iterator type">; +def err_omp_for_loop_var_dsa : Error< + "loop iteration variable may not be %0">; +def err_omp_sections_not_section : Error< + "the statement for '#pragma omp %0' must be '#pragma omp section'">; +def err_omp_section_orphaned : Error< + "orphaned '#pragma omp section' is prohibited">; +def err_omp_sections_not_compound_stmt : Error< + "the statement for '#pragma omp %0' must be compound statement">; +def err_omp_prohibited_region : Error< + "region cannot be%select{| closely}0 nested inside %1 region%select{| with name %3}2">; +def err_omp_prohibited_ordered_region : Error< + "region must be closely nested inside loop or parallel loop region with 'ordered' clause">; +def err_omp_prohibited_cancel_region : Error< + "region must be nested inside a taskgroup region">; +def err_omp_prohibited_cancel_region_nowait : Error< + "region cannot be nested inside region with 'nowait' clause">; +def err_omp_prohibited_cancel_region_ordered : Error< + "region cannot be nested inside region with 'ordered' clause">; +def err_omp_prohibited_distribute_region : Error< + "region must be closely nested inside a teams region">; +def err_omp_prohibited_teams_region : Error< + "region must be closely nested inside a target region">; +def err_omp_atomic_more_one_clause : Error< + "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">; +def err_omp_atomic_not_expression : Error< + "expected expression statement for '#pragma omp atomic %0'">; +def err_omp_atomic_wrong_statement : Error< + "statement form is not allowed for '#pragma omp atomic %0'">; +def err_omp_no_dsa_for_variable : Error< + "variable %q0 must have explicitly specified data sharing attributes">; +def err_omp_for_cannot_break: Error< + "cannot break from a '#pragma omp %0' loop">; +def err_omp_for_cannot_have_eh: Error< + "exception handling is not allowed in a '#pragma omp %0' loop">; +def err_capture_vm_type : Error< + "variable %q0 with variably modified type cannot be captured">; +def err_omp_wrong_var_in_combiner : Error< + "variable %q0 is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed">; +def err_omp_wrong_var_in_initializer : Error< + "variable %q0 is not allowed in initializer expression for '#pragma omp declare reduction', only 'omp_priv' or 'omp_orig' are allowed">; +def err_omp_reduction_qualified_type : Error< + "a type name cannot be qualified with 'const', 'volatile' or 'restrict'">; +def err_omp_reduction_function_type : Error< + "a type name cannot be a function type">; +def err_omp_reduction_reference_type : Error< + "a type name cannot be a reference type">; +def err_omp_reduction_array_type : Error< + "a type name cannot be an array type">; +def err_omp_reduction_redeclared : Error< + "previous declaration with type %0 is found">; +def err_omp_reduction_non_function_init : Error< + "expected function call">; +def err_setjmp_longjmp_in_omp_simd : Error< + "The simd region cannot contain calls to the longjmp/setjmp functions">; +def err_cean_not_in_statement : Error< + "extended array notation is not allowed">; +def err_cean_lower_bound_not_integer : Error< + "lower bound expression has non-integer type %0">; +def err_cean_length_not_integer : Error< + "length expression has non-integer type %0">; +def err_cean_no_length_for_non_array : Error< + "cannot define default length for non-array type %0">; +def err_omp_array_section_length_not_greater_zero : Error< + "length of the array section must be greater than 0">; +def err_omp_expected_var_name_or_array_item : Error< + "expected variable name or an array item">; +def err_omp_depend_arg_not_lvalue : Error< + "argument expression must be an l-value">; +def err_omp_teams_not_single_in_target : Error< + "the teams construct must be the only construct inside of target region">; +def err_omp_region_not_file_context : Error< + "directive must be at file or namespace scope">; +def warn_omp_not_in_target_context : Warning< + "declaration is not declared in any declare target region">, + InGroup, DefaultWarn; +def err_omp_threadprivate_in_target : Error< + "threadprivate variables cannot be used in target constructs">; +def err_omp_map_shared_storage : Error< + "variable already marked as mapped in current construct">; +def err_omp_not_mappable_type : Error< + "type %0 is not mappable to target">; +def note_omp_polymorphic_in_target : Note< + "mappable type cannot be polymorphic">; +def note_omp_static_member_in_target : Note< + "mappable type cannot contain static members">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { @@ -6786,3 +6944,4 @@ } // end of documentation issue category } // end of sema component. + diff -uNr clang-3.4/include/clang/Basic/OpenMPKinds.def clang/include/clang/Basic/OpenMPKinds.def --- clang-3.4/include/clang/Basic/OpenMPKinds.def 2013-10-01 01:32:34.000000000 -0400 +++ clang/include/clang/Basic/OpenMPKinds.def 2014-06-09 10:05:34.000000000 -0400 @@ -13,40 +13,480 @@ //===----------------------------------------------------------------------===// #ifndef OPENMP_DIRECTIVE -# define OPENMP_DIRECTIVE(Name) +#define OPENMP_DIRECTIVE(Name) +#endif +#ifndef OPENMP_DIRECTIVE_EXT +#define OPENMP_DIRECTIVE_EXT(Name, Str) #endif #ifndef OPENMP_CLAUSE -# define OPENMP_CLAUSE(Name, Class) +#define OPENMP_CLAUSE(Name, Class) #endif #ifndef OPENMP_PARALLEL_CLAUSE -# define OPENMP_PARALLEL_CLAUSE(Name) +#define OPENMP_PARALLEL_CLAUSE(Name) +#endif +#ifndef OPENMP_TEAMS_CLAUSE +#define OPENMP_TEAMS_CLAUSE(Name) +#endif +#ifndef OPENMP_DISTRIBUTE_CLAUSE +#define OPENMP_DISTRIBUTE_CLAUSE(Name) +#endif +#ifndef OPENMP_FOR_CLAUSE +#define OPENMP_FOR_CLAUSE(Name) +#endif +#ifndef OPENMP_SIMD_CLAUSE +#define OPENMP_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_FOR_SIMD_CLAUSE +#define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_FOR_SIMD_CLAUSE +#define OPENMP_FOR_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_DISTRIBUTE_SIMD_CLAUSE +#define OPENMP_DISTRIBUTE_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(Name) +#endif +#ifndef OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_DECLARE_SIMD_CLAUSE +#define OPENMP_DECLARE_SIMD_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_FOR_CLAUSE +#define OPENMP_PARALLEL_FOR_CLAUSE(Name) +#endif +#ifndef OPENMP_SECTIONS_CLAUSE +#define OPENMP_SECTIONS_CLAUSE(Name) +#endif +#ifndef OPENMP_PARALLEL_SECTIONS_CLAUSE +#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) +#endif +#ifndef OPENMP_SINGLE_CLAUSE +#define OPENMP_SINGLE_CLAUSE(Name) +#endif +#ifndef OPENMP_TASK_CLAUSE +#define OPENMP_TASK_CLAUSE(Name) +#endif +#ifndef OPENMP_ATOMIC_CLAUSE +#define OPENMP_ATOMIC_CLAUSE(Name) +#endif +#ifndef OPENMP_FLUSH_CLAUSE +#define OPENMP_FLUSH_CLAUSE(Name) +#endif +#ifndef OPENMP_CANCEL_CLAUSE +#define OPENMP_CANCEL_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_CLAUSE +#define OPENMP_TARGET_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_DATA_CLAUSE +#define OPENMP_TARGET_DATA_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_UPDATE_CLAUSE +#define OPENMP_TARGET_UPDATE_CLAUSE(Name) +#endif +#ifndef OPENMP_TARGET_TEAMS_CLAUSE +#define OPENMP_TARGET_TEAMS_CLAUSE(Name) #endif #ifndef OPENMP_DEFAULT_KIND -# define OPENMP_DEFAULT_KIND(Name) +#define OPENMP_DEFAULT_KIND(Name) +#endif +#ifndef OPENMP_PROC_BIND_KIND +#define OPENMP_PROC_BIND_KIND(Name) +#endif +#ifndef OPENMP_REDUCTION_OPERATOR +#define OPENMP_REDUCTION_OPERATOR(Name, Symbol) +#endif +#ifndef OPENMP_MAP_KIND +#define OPENMP_MAP_KIND(Name, Kind) +#endif +#ifndef OPENMP_DEPENDENCE_TYPE +#define OPENMP_DEPENDENCE_TYPE(Name, Type) +#endif +#ifndef OPENMP_SCHEDULE_KIND +#define OPENMP_SCHEDULE_KIND(Name) +#endif +#ifndef OPENMP_DIST_SCHEDULE_KIND +#define OPENMP_DIST_SCHEDULE_KIND(Name) #endif // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) OPENMP_DIRECTIVE(parallel) OPENMP_DIRECTIVE(task) +OPENMP_DIRECTIVE(for) +OPENMP_DIRECTIVE(simd) +OPENMP_DIRECTIVE(sections) +OPENMP_DIRECTIVE(section) +OPENMP_DIRECTIVE(single) +OPENMP_DIRECTIVE(taskyield) +OPENMP_DIRECTIVE(master) +OPENMP_DIRECTIVE(critical) +OPENMP_DIRECTIVE(barrier) +OPENMP_DIRECTIVE(taskwait) +OPENMP_DIRECTIVE(taskgroup) +OPENMP_DIRECTIVE(atomic) +OPENMP_DIRECTIVE(flush) +OPENMP_DIRECTIVE(ordered) +OPENMP_DIRECTIVE(declare) +OPENMP_DIRECTIVE(teams) +OPENMP_DIRECTIVE(distribute) +OPENMP_DIRECTIVE(cancel) +OPENMP_DIRECTIVE(target) +OPENMP_DIRECTIVE_EXT(target_data, "target data") +OPENMP_DIRECTIVE_EXT(target_update, "target update") +OPENMP_DIRECTIVE_EXT(parallel_for, "parallel for") +OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections") +OPENMP_DIRECTIVE_EXT(declare_reduction, "declare reduction") +OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd") +OPENMP_DIRECTIVE_EXT(declare_target, "declare target") +OPENMP_DIRECTIVE_EXT(end_declare_target, "end declare target") +OPENMP_DIRECTIVE_EXT(for_simd, "for simd") +OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point") +OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd") +OPENMP_DIRECTIVE_EXT(distribute_simd, "distribute simd") +OPENMP_DIRECTIVE_EXT(distribute_parallel_for, "distribute parallel for") +OPENMP_DIRECTIVE_EXT(distribute_parallel_for_simd, + "distribute parallel for simd") +OPENMP_DIRECTIVE_EXT(target_teams, "target teams") // OpenMP clauses. +OPENMP_CLAUSE(if, OMPIfClause) +OPENMP_CLAUSE(num_threads, OMPNumThreadsClause) +OPENMP_CLAUSE(device, OMPDeviceClause) +OPENMP_CLAUSE(final, OMPFinalClause) OPENMP_CLAUSE(default, OMPDefaultClause) +OPENMP_CLAUSE(proc_bind, OMPProcBindClause) OPENMP_CLAUSE(private, OMPPrivateClause) -OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause) -OPENMP_CLAUSE(shared, OMPSharedClause) +OPENMP_CLAUSE(firstprivate, OMPFirstPrivateClause) +OPENMP_CLAUSE(shared, OMPSharedClause) +OPENMP_CLAUSE(copyin, OMPCopyinClause) +OPENMP_CLAUSE(reduction, OMPReductionClause) +OPENMP_CLAUSE(lastprivate, OMPLastPrivateClause) +OPENMP_CLAUSE(copyprivate, OMPCopyPrivateClause) +OPENMP_CLAUSE(map, OMPMapClause) +OPENMP_CLAUSE(to, OMPToClause) +OPENMP_CLAUSE(from, OMPFromClause) +OPENMP_CLAUSE(schedule, OMPScheduleClause) +OPENMP_CLAUSE(dist_schedule, OMPDistScheduleClause) +OPENMP_CLAUSE(collapse, OMPCollapseClause) +OPENMP_CLAUSE(ordered, OMPOrderedClause) +OPENMP_CLAUSE(nowait, OMPNowaitClause) +OPENMP_CLAUSE(untied, OMPUntiedClause) +OPENMP_CLAUSE(mergeable, OMPMergeableClause) +OPENMP_CLAUSE(read, OMPReadClause) +OPENMP_CLAUSE(write, OMPWriteClause) +OPENMP_CLAUSE(update, OMPUpdateClause) +OPENMP_CLAUSE(capture, OMPCaptureClause) +OPENMP_CLAUSE(seq_cst, OMPSeqCstClause) +OPENMP_CLAUSE(flush, OMPFlushClause) +OPENMP_CLAUSE(depend, OMPDependClause) +OPENMP_CLAUSE(safelen, OMPSafelenClause) +OPENMP_CLAUSE(linear, OMPLinearClause) +OPENMP_CLAUSE(aligned, OMPAlignedClause) +OPENMP_CLAUSE(simdlen, OMPSimdlenClause) +OPENMP_CLAUSE(uniform, OMPUniformClause) +OPENMP_CLAUSE(inbranch, OMPInBranchClause) +OPENMP_CLAUSE(notinbranch, OMPNotInBranchClause) +OPENMP_CLAUSE(num_teams, OMPNumTeamsClause) +OPENMP_CLAUSE(thread_limit, OMPThreadLimitClause) -// Clauses allowed for OpenMP directives. +// Clauses allowed for OpenMP directive 'parallel'. +OPENMP_PARALLEL_CLAUSE(if) +OPENMP_PARALLEL_CLAUSE(num_threads) OPENMP_PARALLEL_CLAUSE(default) +OPENMP_PARALLEL_CLAUSE(proc_bind) OPENMP_PARALLEL_CLAUSE(private) OPENMP_PARALLEL_CLAUSE(firstprivate) OPENMP_PARALLEL_CLAUSE(shared) +OPENMP_PARALLEL_CLAUSE(copyin) +OPENMP_PARALLEL_CLAUSE(reduction) + +// Clauses allowed for OpenMP directive 'for'. +OPENMP_FOR_CLAUSE(private) +OPENMP_FOR_CLAUSE(firstprivate) +OPENMP_FOR_CLAUSE(lastprivate) +OPENMP_FOR_CLAUSE(reduction) +OPENMP_FOR_CLAUSE(schedule) +OPENMP_FOR_CLAUSE(collapse) +OPENMP_FOR_CLAUSE(ordered) +OPENMP_FOR_CLAUSE(nowait) + +// Clauses allowed for OpenMP directive 'simd'. +OPENMP_SIMD_CLAUSE(safelen) +OPENMP_SIMD_CLAUSE(linear) +OPENMP_SIMD_CLAUSE(aligned) +OPENMP_SIMD_CLAUSE(private) +OPENMP_SIMD_CLAUSE(lastprivate) +OPENMP_SIMD_CLAUSE(reduction) +OPENMP_SIMD_CLAUSE(collapse) + +// Clauses allowed for OpenMP directive 'for simd'. +OPENMP_FOR_SIMD_CLAUSE(private) +OPENMP_FOR_SIMD_CLAUSE(firstprivate) +OPENMP_FOR_SIMD_CLAUSE(lastprivate) +OPENMP_FOR_SIMD_CLAUSE(reduction) +OPENMP_FOR_SIMD_CLAUSE(schedule) +OPENMP_FOR_SIMD_CLAUSE(collapse) +OPENMP_FOR_SIMD_CLAUSE(nowait) +OPENMP_FOR_SIMD_CLAUSE(safelen) +OPENMP_FOR_SIMD_CLAUSE(linear) +OPENMP_FOR_SIMD_CLAUSE(aligned) + +// Clauses allowed for OpenMP directive 'distribute simd'. +OPENMP_DISTRIBUTE_SIMD_CLAUSE(private) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(lastprivate) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(reduction) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(collapse) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(safelen) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(linear) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(aligned) +OPENMP_DISTRIBUTE_SIMD_CLAUSE(dist_schedule) + +// Clauses allowed for OpenMP directive 'distribute parallel for'. +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(if) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(num_threads) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(default) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(proc_bind) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(private) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(shared) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(copyin) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(reduction) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(lastprivate) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(schedule) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(collapse) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(ordered) +OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(dist_schedule) + +// Clauses allowed for OpenMP directive 'distribute parallel for simd'. +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(if) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(num_threads) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(default) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(proc_bind) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(private) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(shared) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(copyin) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(reduction) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(lastprivate) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(schedule) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(collapse) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(ordered) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(dist_schedule) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(safelen) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(linear) +OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(aligned) + +// Clauses allowed for OpenMP directive 'parallel for simd'. +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(if) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(num_threads) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(default) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(proc_bind) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(shared) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(copyin) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(private) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(firstprivate) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(lastprivate) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(reduction) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(schedule) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(collapse) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(nowait) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(safelen) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(linear) +OPENMP_PARALLEL_FOR_SIMD_CLAUSE(aligned) + +// Clauses allowed for OpenMP directive 'declare simd'. +OPENMP_DECLARE_SIMD_CLAUSE(simdlen) +OPENMP_DECLARE_SIMD_CLAUSE(linear) +OPENMP_DECLARE_SIMD_CLAUSE(aligned) +OPENMP_DECLARE_SIMD_CLAUSE(uniform) +OPENMP_DECLARE_SIMD_CLAUSE(inbranch) +OPENMP_DECLARE_SIMD_CLAUSE(notinbranch) + +// Clauses allowed for OpenMP directive 'parallel for'. +OPENMP_PARALLEL_FOR_CLAUSE(if) +OPENMP_PARALLEL_FOR_CLAUSE(num_threads) +OPENMP_PARALLEL_FOR_CLAUSE(default) +OPENMP_PARALLEL_FOR_CLAUSE(proc_bind) +OPENMP_PARALLEL_FOR_CLAUSE(private) +OPENMP_PARALLEL_FOR_CLAUSE(firstprivate) +OPENMP_PARALLEL_FOR_CLAUSE(shared) +OPENMP_PARALLEL_FOR_CLAUSE(copyin) +OPENMP_PARALLEL_FOR_CLAUSE(reduction) +OPENMP_PARALLEL_FOR_CLAUSE(lastprivate) +OPENMP_PARALLEL_FOR_CLAUSE(schedule) +OPENMP_PARALLEL_FOR_CLAUSE(collapse) +OPENMP_PARALLEL_FOR_CLAUSE(ordered) + +// Clauses allowed for OpenMP directive 'sections'. +OPENMP_SECTIONS_CLAUSE(private) +OPENMP_SECTIONS_CLAUSE(firstprivate) +OPENMP_SECTIONS_CLAUSE(lastprivate) +OPENMP_SECTIONS_CLAUSE(reduction) +OPENMP_SECTIONS_CLAUSE(nowait) + +// Clauses allowed for OpenMP directive 'parallel sections'. +OPENMP_PARALLEL_SECTIONS_CLAUSE(if) +OPENMP_PARALLEL_SECTIONS_CLAUSE(num_threads) +OPENMP_PARALLEL_SECTIONS_CLAUSE(default) +OPENMP_PARALLEL_SECTIONS_CLAUSE(proc_bind) +OPENMP_PARALLEL_SECTIONS_CLAUSE(private) +OPENMP_PARALLEL_SECTIONS_CLAUSE(firstprivate) +OPENMP_PARALLEL_SECTIONS_CLAUSE(lastprivate) +OPENMP_PARALLEL_SECTIONS_CLAUSE(shared) +OPENMP_PARALLEL_SECTIONS_CLAUSE(copyin) +OPENMP_PARALLEL_SECTIONS_CLAUSE(reduction) + +// Clauses allowed for OpenMP directive 'single'. +OPENMP_SINGLE_CLAUSE(private) +OPENMP_SINGLE_CLAUSE(firstprivate) +OPENMP_SINGLE_CLAUSE(copyprivate) +OPENMP_SINGLE_CLAUSE(nowait) + +// Clauses allowed for OpenMP directive 'task'. +OPENMP_TASK_CLAUSE(if) +OPENMP_TASK_CLAUSE(final) +OPENMP_TASK_CLAUSE(untied) +OPENMP_TASK_CLAUSE(default) +OPENMP_TASK_CLAUSE(mergeable) +OPENMP_TASK_CLAUSE(private) +OPENMP_TASK_CLAUSE(firstprivate) +OPENMP_TASK_CLAUSE(shared) +OPENMP_TASK_CLAUSE(depend) // Static attributes for 'default' clause. OPENMP_DEFAULT_KIND(none) OPENMP_DEFAULT_KIND(shared) +// Static attributes for 'proc_bind' clause. +OPENMP_PROC_BIND_KIND(master) +OPENMP_PROC_BIND_KIND(close) +OPENMP_PROC_BIND_KIND(spread) + +// Possible operators for 'reduction' clause. +OPENMP_REDUCTION_OPERATOR(add, "+") +OPENMP_REDUCTION_OPERATOR(mult, "*") +OPENMP_REDUCTION_OPERATOR(sub, "-") +OPENMP_REDUCTION_OPERATOR(bitand, "&") +OPENMP_REDUCTION_OPERATOR(bitor, "|") +OPENMP_REDUCTION_OPERATOR(bitxor, "^") +OPENMP_REDUCTION_OPERATOR(and, "&&") +OPENMP_REDUCTION_OPERATOR(or, "||") +OPENMP_REDUCTION_OPERATOR(min, "min") +OPENMP_REDUCTION_OPERATOR(max, "max") +OPENMP_REDUCTION_OPERATOR(custom, "/*custom*/") + +// Possible dependence types for 'depend' clause. +OPENMP_DEPENDENCE_TYPE(in, "in") +OPENMP_DEPENDENCE_TYPE(out, "out") +OPENMP_DEPENDENCE_TYPE(inout, "inout") + +// Static attributes for 'schedule' clause. +OPENMP_SCHEDULE_KIND(static) +OPENMP_SCHEDULE_KIND(dynamic) +OPENMP_SCHEDULE_KIND(guided) +OPENMP_SCHEDULE_KIND(auto) +OPENMP_SCHEDULE_KIND(runtime) + +// Static attributes for 'dist_schedule' clause. +OPENMP_DIST_SCHEDULE_KIND(static) + +// Clauses allowed for OpenMP directive 'atomic'. +OPENMP_ATOMIC_CLAUSE(read) +OPENMP_ATOMIC_CLAUSE(write) +OPENMP_ATOMIC_CLAUSE(update) +OPENMP_ATOMIC_CLAUSE(capture) +OPENMP_ATOMIC_CLAUSE(seq_cst) + +// Clauses allowed for OpenMP directive 'flush'. +OPENMP_FLUSH_CLAUSE(flush) + +// Clauses allowed for OpenMP directive 'teams'. +OPENMP_TEAMS_CLAUSE(num_teams) +OPENMP_TEAMS_CLAUSE(thread_limit) +OPENMP_TEAMS_CLAUSE(default) +OPENMP_TEAMS_CLAUSE(private) +OPENMP_TEAMS_CLAUSE(firstprivate) +OPENMP_TEAMS_CLAUSE(shared) +OPENMP_TEAMS_CLAUSE(reduction) + +// Clauses allowed for OpenMP directive 'distribute'. +OPENMP_DISTRIBUTE_CLAUSE(private) +OPENMP_DISTRIBUTE_CLAUSE(firstprivate) +OPENMP_DISTRIBUTE_CLAUSE(collapse) +OPENMP_DISTRIBUTE_CLAUSE(dist_schedule) + +// Clauses allowed for OpenMP directive 'cancel'. +OPENMP_CANCEL_CLAUSE(if) + +// Clauses allowed for OpenMP directive 'target'. +OPENMP_TARGET_CLAUSE(if) +OPENMP_TARGET_CLAUSE(device) +OPENMP_TARGET_CLAUSE(map) + +// Clauses allowed for OpenMP directive 'target data'. +OPENMP_TARGET_DATA_CLAUSE(if) +OPENMP_TARGET_DATA_CLAUSE(device) +OPENMP_TARGET_DATA_CLAUSE(map) + +// Clauses allowed for OpenMP directive 'target update'. +OPENMP_TARGET_UPDATE_CLAUSE(if) +OPENMP_TARGET_UPDATE_CLAUSE(device) +OPENMP_TARGET_UPDATE_CLAUSE(to) +OPENMP_TARGET_UPDATE_CLAUSE(from) + +// Possible mapping types for 'map' clause. +OPENMP_MAP_KIND(alloc, "alloc") +OPENMP_MAP_KIND(to, "to") +OPENMP_MAP_KIND(from, "from") +OPENMP_MAP_KIND(tofrom, "tofrom") + +// Clauses allowed for OpenMP directive 'target teams'. +OPENMP_TARGET_TEAMS_CLAUSE(if) +OPENMP_TARGET_TEAMS_CLAUSE(device) +OPENMP_TARGET_TEAMS_CLAUSE(map) +OPENMP_TARGET_TEAMS_CLAUSE(num_teams) +OPENMP_TARGET_TEAMS_CLAUSE(thread_limit) +OPENMP_TARGET_TEAMS_CLAUSE(default) +OPENMP_TARGET_TEAMS_CLAUSE(private) +OPENMP_TARGET_TEAMS_CLAUSE(firstprivate) +OPENMP_TARGET_TEAMS_CLAUSE(shared) +OPENMP_TARGET_TEAMS_CLAUSE(reduction) + +#undef OPENMP_TARGET_CLAUSE +#undef OPENMP_TARGET_UPDATE_CLAUSE +#undef OPENMP_TARGET_TEAMS_CLAUSE +#undef OPENMP_TARGET_DATA_CLAUSE +#undef OPENMP_REDUCTION_OPERATOR +#undef OPENMP_MAP_KIND +#undef OPENMP_DEPENDENCE_TYPE #undef OPENMP_DEFAULT_KIND +#undef OPENMP_PROC_BIND_KIND #undef OPENMP_DIRECTIVE +#undef OPENMP_DIRECTIVE_EXT #undef OPENMP_CLAUSE +#undef OPENMP_CANCEL_CLAUSE +#undef OPENMP_ATOMIC_CLAUSE +#undef OPENMP_FLUSH_CLAUSE +#undef OPENMP_SECTIONS_CLAUSE +#undef OPENMP_PARALLEL_SECTIONS_CLAUSE +#undef OPENMP_SINGLE_CLAUSE +#undef OPENMP_TASK_CLAUSE #undef OPENMP_PARALLEL_CLAUSE +#undef OPENMP_TEAMS_CLAUSE +#undef OPENMP_DISTRIBUTE_CLAUSE +#undef OPENMP_PARALLEL_FOR_CLAUSE +#undef OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE +#undef OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE +#undef OPENMP_FOR_CLAUSE +#undef OPENMP_SIMD_CLAUSE +#undef OPENMP_FOR_SIMD_CLAUSE +#undef OPENMP_DISTRIBUTE_SIMD_CLAUSE +#undef OPENMP_PARALLEL_FOR_SIMD_CLAUSE +#undef OPENMP_DECLARE_SIMD_CLAUSE +#undef OPENMP_SCHEDULE_KIND +#undef OPENMP_DIST_SCHEDULE_KIND diff -uNr clang-3.4/include/clang/Basic/OpenMPKinds.h clang/include/clang/Basic/OpenMPKinds.h --- clang-3.4/include/clang/Basic/OpenMPKinds.h 2013-07-18 23:13:43.000000000 -0400 +++ clang/include/clang/Basic/OpenMPKinds.h 2014-05-19 19:58:57.000000000 -0400 @@ -24,6 +24,8 @@ OMPD_unknown = 0, #define OPENMP_DIRECTIVE(Name) \ OMPD_##Name, +#define OPENMP_DIRECTIVE_EXT(Name, Str) \ + OMPD_##Name, #include "clang/Basic/OpenMPKinds.def" NUM_OPENMP_DIRECTIVES }; @@ -47,6 +49,60 @@ NUM_OPENMP_DEFAULT_KINDS }; +/// \brief OpenMP attributes for 'proc_bind' clause. +enum OpenMPProcBindClauseKind { + OMPC_PROC_BIND_unknown = 0, +#define OPENMP_PROC_BIND_KIND(Name) \ + OMPC_PROC_BIND_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_PROC_BIND_KINDS +}; + +/// \brief OpenMP operators for 'reduction' clause. +enum OpenMPReductionClauseOperator { + OMPC_REDUCTION_unknown = 0, +#define OPENMP_REDUCTION_OPERATOR(Name, Symbol) \ + OMPC_REDUCTION_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_REDUCTION_OPERATORS +}; + +/// \brief OpenMP dependence types for 'depend' clause. +enum OpenMPDependClauseType { + OMPC_DEPEND_unknown = 0, +#define OPENMP_DEPENDENCE_TYPE(Name, Type) \ + OMPC_DEPEND_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_DEPENDENCE_TYPE +}; + +/// \brief OpenMP mapping kind for 'map' clause. +enum OpenMPMapClauseKind { + OMPC_MAP_unknown = 0, +#define OPENMP_MAP_KIND(Name, Kind) \ + OMPC_MAP_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_MAP_KIND +}; + +/// \brief OpenMP attributes for 'schedule' clause. +enum OpenMPScheduleClauseKind { + OMPC_SCHEDULE_unknown = 0, +#define OPENMP_SCHEDULE_KIND(Name) \ + OMPC_SCHEDULE_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_SCHEDULE_KINDS +}; + +/// \brief OpenMP attributes for 'dist_schedule' clause. +enum OpenMPDistScheduleClauseKind { + OMPC_DIST_SCHEDULE_unknown = 0, +#define OPENMP_DIST_SCHEDULE_KIND(Name) \ + OMPC_DIST_SCHEDULE_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_DIST_SCHEDULE_KINDS +}; + OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); @@ -62,4 +118,3 @@ } #endif - diff -uNr clang-3.4/include/clang/Basic/StmtNodes.td clang/include/clang/Basic/StmtNodes.td --- clang-3.4/include/clang/Basic/StmtNodes.td 2013-09-17 23:29:45.000000000 -0400 +++ clang/include/clang/Basic/StmtNodes.td 2014-06-09 10:05:34.000000000 -0400 @@ -177,6 +177,40 @@ // OpenCL Extensions. def AsTypeExpr : DStmt; +// Extended array notation index for OpenMP. +def CEANIndexExpr : DStmt; + // OpenMP Directives. def OMPExecutableDirective : Stmt<1>; def OMPParallelDirective : DStmt; +def OMPParallelForDirective : DStmt; +def OMPParallelForSimdDirective : DStmt; +def OMPForDirective : DStmt; +def OMPSimdDirective : DStmt; +def OMPForSimdDirective : DStmt; +def OMPDistributeSimdDirective : DStmt; +def OMPDistributeParallelForDirective : DStmt; +def OMPDistributeParallelForSimdDirective : DStmt; +def OMPSectionsDirective : DStmt; +def OMPParallelSectionsDirective : DStmt; +def OMPSectionDirective : DStmt; +def OMPSingleDirective : DStmt; +def OMPTaskDirective : DStmt; +def OMPTaskyieldDirective : DStmt; +def OMPMasterDirective : DStmt; +def OMPCriticalDirective : DStmt; +def OMPBarrierDirective : DStmt; +def OMPTaskwaitDirective : DStmt; +def OMPTaskgroupDirective : DStmt; +def OMPAtomicDirective : DStmt; +def OMPFlushDirective : DStmt; +def OMPOrderedDirective : DStmt; +def OMPTeamsDirective : DStmt; +def OMPDistributeDirective : DStmt; +def OMPCancelDirective : DStmt; +def OMPCancellationPointDirective : DStmt; +def OMPTargetDirective : DStmt; +def OMPTargetDataDirective : DStmt; +def OMPTargetUpdateDirective : DStmt; +def OMPTargetTeamsDirective : DStmt; + diff -uNr clang-3.4/include/clang/Parse/Parser.h clang/include/clang/Parse/Parser.h --- clang-3.4/include/clang/Parse/Parser.h 2013-12-15 21:32:55.000000000 -0500 +++ clang/include/clang/Parse/Parser.h 2014-05-19 19:58:57.000000000 -0400 @@ -59,6 +59,7 @@ friend class ObjCDeclContextSwitch; friend class ParenBraceBracketBalancer; friend class BalancedDelimiterTracker; + friend class AllowCEANExpressions; Preprocessor &PP; @@ -217,6 +218,8 @@ bool SkipFunctionBodies; + bool IsCEANAllowed; + public: Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); ~Parser(); @@ -931,6 +934,21 @@ CachedTokens *ExceptionSpecTokens; }; + /// LateParsedOpenMPDeclaration - An OpenMP declaration inside a class. + struct LateParsedOpenMPDeclaration : public LateParsedDeclaration { + explicit LateParsedOpenMPDeclaration(Parser *P, AccessSpecifier AS) + : Self(P), AS(AS) { } + + virtual void ParseLexedMethodDeclarations(); + + Parser* Self; + AccessSpecifier AS; + + /// \brief The set of tokens that make up an exception-specification that + /// has not yet been parsed. + CachedTokens Tokens; + }; + /// LateParsedMemberInitializer - An initializer for a non-static class data /// member whose parsing must to be delayed until the class is completely /// defined (C++11 [class.mem]p2). @@ -2184,8 +2202,13 @@ //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. + /// \brief Parses OpenMP directive. + OpenMPDirectiveKind ParseOpenMPDirective(); /// \brief Parses declarative OpenMP directives. - DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + DeclGroupPtrTy ParseOpenMPDeclarativeDirective(AccessSpecifier AS); + /// \brief Late parsing of declarative OpenMP directives. + void LateParseOpenMPDeclarativeDirective(AccessSpecifier AS); + /// \brief Parses simple list of variables. /// /// \param Kind Kind of the directive. @@ -2196,8 +2219,22 @@ bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, SmallVectorImpl &VarList, bool AllowScopeSpecifier); + /// \param [out] Inits List of inits. + /// + Decl *ParseOpenMPDeclareReduction(SmallVectorImpl &Types, + SmallVectorImpl &TyRanges, + SmallVectorImpl &Combiners, + SmallVectorImpl &Inits, + AccessSpecifier AS); + /// \brief Parses declarative or executable directive. - StmtResult ParseOpenMPDeclarativeOrExecutableDirective(); + /// + /// \param StandAloneAllowed true if allowed stand-alone directives, + /// false - otherwise + /// + StmtResult ParseOpenMPDeclarativeOrExecutableDirective( + bool StandAloneAllowed); + /// \brief Parses clause of kind \a CKind for directive of a kind \a Kind. /// /// \param DKind Kind of current directive. @@ -2206,7 +2243,8 @@ /// in current directive. /// OMPClause *ParseOpenMPClause(OpenMPDirectiveKind DKind, - OpenMPClauseKind CKind, bool FirstClause); + OpenMPClauseKind CKind, + bool FirstClause); /// \brief Parses clause with a single expression of a kind \a Kind. /// /// \param Kind Kind of current clause. @@ -2222,6 +2260,45 @@ /// \param Kind Kind of current clause. /// OMPClause *ParseOpenMPVarListClause(OpenMPClauseKind Kind); + typedef SmallVector DeclarationNameInfoList; + /// \brief The following is temporary info about a clause used later to + /// build it (after we have access to the function's arguments scope). + struct OmpDeclareSimdVariantInfo { + unsigned Idx; // index in the CL (array of clauses) + OpenMPClauseKind CKind; // clause kind + DeclarationNameInfoList NameInfos; + SourceLocation StartLoc; + SourceLocation EndLoc; + Expr *TailExpr; + SourceLocation TailLoc; + OmpDeclareSimdVariantInfo(OpenMPClauseKind CK, unsigned I) + :Idx(I), CKind(CK), TailExpr(0) { } + }; + /// \brief Parses clause with the list of variables of a kind \a Kind in + /// a declarative Varlist-parsing mode for the case when the vars + /// are not declared yet (e.g. arguments in 'declare simd'). + /// \param CKind Kind of current clause (for now, only OMPD_declare_simd). + /// \param pam pam. + /// + bool ParseOpenMPDeclarativeVarListClause( + OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind, + DeclarationNameInfoList &NameInfos, + SourceLocation &StartLoc, + SourceLocation &EndLoc, + Expr *&TailExpr, + SourceLocation &TailLoc); + /// \brief Parses clause with a single expression and a type of a kind + /// \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSingleExprWithTypeClause(OpenMPClauseKind Kind); + /// \brief Parses clause with type of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPClause(OpenMPClauseKind Kind); public: bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, diff -uNr clang-3.4/include/clang/Sema/Scope.h clang/include/clang/Sema/Scope.h --- clang-3.4/include/clang/Sema/Scope.h 2013-10-22 14:07:04.000000000 -0400 +++ clang/include/clang/Sema/Scope.h 2014-05-19 19:58:57.000000000 -0400 @@ -304,14 +304,18 @@ return false; } + /// \brief Determine whether this scope is a C++ 'try' block. + bool isTryScope() const { return getFlags() & Scope::TryScope; } + /// \brief Determines whether this scope is the OpenMP directive scope bool isOpenMPDirectiveScope() const { - return (getFlags() & Scope::OpenMPDirectiveScope); + for (const Scope *S = this; S; S = S->getParent()) { + if (S->getFlags() & Scope::OpenMPDirectiveScope) + return true; + } + return false; } - /// \brief Determine whether this scope is a C++ 'try' block. - bool isTryScope() const { return getFlags() & Scope::TryScope; } - /// containedInPrototypeScope - Return true if this or a parent scope /// is a FunctionPrototypeScope. bool containedInPrototypeScope() const; diff -uNr clang-3.4/include/clang/Sema/ScopeInfo.h clang/include/clang/Sema/ScopeInfo.h --- clang-3.4/include/clang/Sema/ScopeInfo.h 2013-11-07 00:17:06.000000000 -0500 +++ clang/include/clang/Sema/ScopeInfo.h 2014-05-19 19:58:57.000000000 -0400 @@ -552,6 +552,8 @@ /// \brief A descriptive name for the kind of captured region this is. StringRef getRegionName() const { switch (CapRegionKind) { + case CR_SIMDFor: + return "simd for - like captured statement"; case CR_Default: return "default captured statement"; case CR_OpenMP: diff -uNr clang-3.4/include/clang/Sema/Sema.h clang/include/clang/Sema/Sema.h --- clang-3.4/include/clang/Sema/Sema.h 2013-12-05 00:25:04.000000000 -0500 +++ clang/include/clang/Sema/Sema.h 2014-06-09 10:05:34.000000000 -0400 @@ -140,6 +140,9 @@ class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPClause; + class OMPDeclareReductionDecl; + class OMPDeclareSimdDecl; + class OMPDeclareTargetDecl; class OverloadCandidateSet; class OverloadExpr; class ParenListExpr; @@ -974,8 +977,7 @@ void RecordParsingTemplateParameterDepth(unsigned Depth); void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, - RecordDecl *RD, - CapturedRegionKind K); + RecordDecl *RD, CapturedRegionKind K); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, const Decl *D = 0, const BlockExpr *blkExpr = 0); @@ -2387,6 +2389,8 @@ LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, + // Look up OpenMP declare reduction constructs only. + LookupOMPDeclareReduction, /// \brief Look up any declaration with any name. LookupAnyName }; @@ -2908,6 +2912,8 @@ SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); + void CheckForLoopConditionalStatement(Expr *Second, Expr *Third, Stmt *Body); + StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, FullExprArg Second, @@ -3297,7 +3303,7 @@ TemplateArgumentListInfo *ExplicitTemplateArgs = 0); ExprResult BuildPredefinedExpr(SourceLocation Loc, - PredefinedExpr::IdentType IT); + PredefinedExpr::IdentType Kind); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0); @@ -3366,6 +3372,8 @@ Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); + ExprResult ActOnCEANIndexExpr(Scope *S, Expr *Base, Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, @@ -6423,6 +6431,11 @@ /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; + /// \brief We store OpenMP declarative pragmas that will need to be + /// instantiated together with the templated functions. + typedef llvm::DenseMap PendingOMPInstMap; + PendingOMPInstMap PendingOMP; + class SavePendingLocalImplicitInstantiationsRAII { public: SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) { @@ -7052,74 +7065,572 @@ /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); + /// \brief Check if \a S ia for-loop in canonical form for OpenMP. + /// + /// \param S A statement to check. + /// \param Kind A directive for which the verification is performed. + /// + /// \return true if not canonical form, false otherwise. + /// + bool isNotOpenMPCanonicalLoopForm(Stmt *S, OpenMPDirectiveKind Kind, + Expr *&NewEnd, Expr *&NewIncr, + Expr *&InitVal, Expr *&VarCnt, + BinaryOperatorKind &OpKind); + + /// \brief A helper routine for OpenMP loops collapsing. + bool CollapseOpenMPLoop(OpenMPDirectiveKind Kind, + ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + Expr *&NewEnd, Expr *&NewVar, Expr *&NewVarCntExpr, + Expr *&NewFinal, SmallVector &VarCnts); + + /// \brief A helper to rebuild a constant positive integer expression. + Expr *ActOnConstantPositiveSubExpressionInClause(Expr *E); + + /// \brief A helper to rebuild a linear step for linear clause. + Expr *ActOnConstantLinearStep(Expr *E); + + /// \brief A helper to add two simd-specific arguments into captured stmt. + CapturedStmt *AddSimdArgsIntoCapturedStmt(CapturedStmt *Cap, Expr *NewVar); + + /// \brief A helper to add two distributeparallel-specific arguments into + /// captured stmt. + Stmt *AddDistributedParallelArgsIntoCapturedStmt(CapturedStmt *Cap, + Expr *NewVar, + Expr *&LowerBound, + Expr *&UpperBound); + + bool HasOpenMPRegion(OpenMPDirectiveKind Kind); + + bool HasOpenMPSimdRegion(); + public: + DeclContext *GetOpenMPFunctionRegion(); + + bool IsDeclContextInOpenMPTarget(DeclContext *DC); + /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, - const DeclarationNameInfo &DirName, - Scope *CurScope); + const DeclarationNameInfo &DirName, Scope *CurScope); /// \brief Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); - // OpenMP directives and clauses. + typedef llvm::DenseMap + OMPDeclareSimdMap; + OMPDeclareSimdMap OMPDSimdMap; + /// \brief Called on correct id-expression from the '#pragma omp /// threadprivate'. - ExprResult ActOnOpenMPIdExpression(Scope *CurScope, - CXXScopeSpec &ScopeSpec, + ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id); /// \brief Called on well-formed '#pragma omp threadprivate'. - DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - ArrayRef VarList); - // \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. - OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( - SourceLocation Loc, - ArrayRef VarList); + DeclGroupPtrTy ActOnOpenMPThreadprivateDirective(SourceLocation Loc, + ArrayRef VarList); + /// \brief Builds a new OMPThreadPrivateDecl and checks its correctness. + OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(SourceLocation Loc, + ArrayRef VarList); + /// \brief Called on well-formed '#pragma omp declare simd'. + DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( + SourceLocation Loc, Decl *FuncDecl, ArrayRef SrcRanges, + ArrayRef BeginIdx, ArrayRef EndIdx, + ArrayRef CL); + /// \brief Builds a new OMPDeclareSimdDecl and checks its correctness. + OMPDeclareSimdDecl *CheckOMPDeclareSimdDecl( + SourceLocation Loc, Decl *FuncDecl, ArrayRef SrcRanges, + ArrayRef BeginIdx, ArrayRef EndIdx, + ArrayRef CL, DeclContext *CurDC); + /// \brief Transforms arrays into array of SimdVariant structures and + /// stores it into D. + void CompleteOMPDeclareSimdDecl(OMPDeclareSimdDecl *D, + ArrayRef SrcRanges, + ArrayRef BeginIdx, + ArrayRef EndIdx); + /// \brief A RAII object to enter scope of a declare reduction. + class OMPDeclareReductionRAII { + public: + OMPDeclareReductionRAII(Sema &S, Scope *CS, DeclContext *DC, + SourceLocation Loc, DeclarationName DN, + unsigned NumTypes, AccessSpecifier AS); - StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, - ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, - SourceLocation EndLoc); + Decl *getDecl(); + + private: + /// \brief Called on well-formed '#pragma omp declare reduction'. + OMPDeclareReductionDecl *InitDeclareReduction(Scope *CS, DeclContext *DC, + SourceLocation Loc, + DeclarationName Name, + unsigned NumTypes, + AccessSpecifier AS); + Sema &S; + OMPDeclareReductionDecl *D; + ContextRAII SavedContext; + }; + + class OMPDeclareReductionFunctionScope { + public: + OMPDeclareReductionFunctionScope(Sema &S, SourceLocation Loc, + DeclarationName Name, QualType QTy) + : S(S), FD(ActOnOMPDeclareReductionFunction(S, Loc, Name, QTy)) {} + + ~OMPDeclareReductionFunctionScope() { + if (S.CurContext) { + S.DiscardCleanupsInEvaluationContext(); + S.PopExpressionEvaluationContext(); + S.PopFunctionScopeInfo(); + S.PopDeclContext(); + } + } + + void setBody(Expr *E); + Expr *getCombiner(); + + private: + FunctionDecl *ActOnOMPDeclareReductionFunction(Sema &S, SourceLocation Loc, + DeclarationName Name, + QualType QTy); + + Sema &S; + FunctionDecl *FD; + ParmVarDecl *ParLHS, *ParRHS; + VarDecl *OmpOut, *OmpIn; + }; + + void CreateDefaultDeclareReductionInitFunctionBody(FunctionDecl *FD, + VarDecl *OmpPriv, + ParmVarDecl *ParLHS); + class OMPDeclareReductionInitFunctionScope { + public: + OMPDeclareReductionInitFunctionScope(Sema &S, SourceLocation Loc, + DeclarationName Name, QualType QTy, + SourceLocation OmpPrivLoc, bool IsInit) + : S(S), OmpPrivLoc(OmpPrivLoc), IsInit(IsInit), + FD(ActOnOMPDeclareReductionInitFunction(S, Loc, Name, QTy)) {} + + ~OMPDeclareReductionInitFunctionScope() { + if (S.CurContext) { + S.DiscardCleanupsInEvaluationContext(); + S.PopExpressionEvaluationContext(); + S.PopFunctionScopeInfo(); + S.PopDeclContext(); + } + } + + void setInit(Expr *E = 0); + Expr *getInitializer(); + + private: + FunctionDecl *ActOnOMPDeclareReductionInitFunction(Sema &S, + SourceLocation Loc, + DeclarationName Name, + QualType QTy); + + Sema &S; + SourceLocation OmpPrivLoc; + bool IsInit; + FunctionDecl *FD; + ParmVarDecl *ParLHS, *ParRHS; + VarDecl *OmpPriv, *OmpOrig; + }; + + llvm::SmallDenseMap OMPInstantiatedDecls; + + bool IsOMPDeclareReductionTypeAllowed(SourceRange Range, QualType QTy, + ArrayRef Types, + ArrayRef TyRanges); + + DeclGroupPtrTy ActOnOpenMPDeclareReductionDirective( + Decl *D, ArrayRef Types, ArrayRef TyRanges, + ArrayRef Combiners, ArrayRef Inits); + bool ActOnStartOpenMPDeclareTargetDirective(Scope *S, SourceLocation Loc); + void ActOnOpenMPDeclareTargetDecls(DeclGroupPtrTy Decls); + DeclGroupPtrTy ActOnFinishOpenMPDeclareTargetDirective(); + void ActOnOpenMPDeclareTargetDirectiveError(); + void CheckDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); + + /// \brief Builds a new OMPDeclareReductionDecl and checks its correctness. + void CompleteOMPDeclareReductionDecl(OMPDeclareReductionDecl *D, + ArrayRef Types, + ArrayRef TyRanges, + ArrayRef Combiners, + ArrayRef Inits); + + StmtResult ActOnOpenMPExecutableDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, OpenMPDirectiveKind ConstructType); /// \brief Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, + Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp for' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPForDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel for' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelForDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel for simd' after + /// parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelForSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp for simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPForSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp distribute simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPDistributeSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp distribute parallel for' after + /// parsing + /// of the associated statement. + StmtResult ActOnOpenMPDistributeParallelForDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp distribute parallel for simd' + /// after parsing + /// of the associated statement. + StmtResult ActOnOpenMPDistributeParallelForSimdDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc); - OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, - unsigned Argument, + /// \brief Called on well-formed '\#pragma omp sections' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSectionsDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel sections' after + /// parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelSectionsDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp section' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp single' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSingleDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp task' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTaskDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskyield' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp master' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp critical' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp barrier' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskwait' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp taskgroup' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp atomic' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPAtomicDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp flush' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPFlushDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp ordered' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPOrderedDirective(Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp teams' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTeamsDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp distribute' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPDistributeDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp cancel' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType); + + /// \brief Called on well-formed '\#pragma omp cancellation point' after + /// parsing of the associated statement. + StmtResult + ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType); + /// \brief Called on well-formed '\#pragma omp target' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTargetDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp target data' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTargetDataDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp target update' after parsing. + StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp target teams' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'if' clause. + OMPClause *ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'final' clause. + OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'num_threads' clause. + OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'device' clause. + OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'collapse' clause. + OMPClause *ActOnOpenMPCollapseClause(Expr *NumLoops, SourceLocation StartLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'proc_bind' clause. + OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Helper for all clauses with varlists. + OMPClause * + ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef Vars, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned Op, Expr *TailExpr, CXXScopeSpec &SS, + const UnqualifiedId &OpName, SourceLocation OpLoc); + /// \brief Helper to build DeclRefExpr for declarative clause. + Expr *ActOnOpenMPParameterInDeclarativeVarListClause(SourceLocation Loc, + ParmVarDecl *Param); + /// \brief Helper to find paremeter with given name in function. + Expr *FindOpenMPDeclarativeClauseParameter(StringRef Name, SourceLocation Loc, + Decl *FuncDecl); + /// \brief Helper for all declarative clauses with varlists + /// (i.e. for declarative form of linear, aligned and uniform). + OMPClause *ActOnOpenMPDeclarativeVarListClause( + OpenMPClauseKind CKind, ArrayRef NameInfos, + SourceLocation StartLoc, SourceLocation EndLoc, Expr *TailExpr, + SourceLocation TailLoc, Decl *FuncDecl); - OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind, - ArrayRef Vars, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc); /// \brief Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'firstprivate' clause. - OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef VarList, + OMPClause *ActOnOpenMPFirstPrivateClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'lastprivate' clause. + OMPClause *ActOnOpenMPLastPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); /// \brief Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'copyin' clause. + OMPClause *ActOnOpenMPCopyinClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'copyprivate' clause. + OMPClause *ActOnOpenMPCopyPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'reduction' clause. + OMPClause *ActOnOpenMPReductionClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPReductionClauseOperator Op, + CXXScopeSpec &SS, + DeclarationNameInfo OpName); + /// \brief Called on well-formed 'map' clause. + OMPClause *ActOnOpenMPMapClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPMapClauseKind Kind, + SourceLocation KindLoc); + /// \brief Called on well-formed 'to' clause. + OMPClause *ActOnOpenMPToClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'from' clause. + OMPClause *ActOnOpenMPFromClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'flush' clause. + OMPClause *ActOnOpenMPFlushClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'uniform' clause. + OMPClause *ActOnOpenMPUniformClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'ordered' clause. + OMPClause *ActOnOpenMPOrderedClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'nowait' clause. + OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'untied' clause. + OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'mergeable' clause. + OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'read' clause. + OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'write' clause. + OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'update' clause. + OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'capture' clause. + OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'seq_cst' clause. + OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'depend' clause. + OMPClause *ActOnOpenMPDependClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDependClauseType Ty, + SourceLocation TyLoc); + /// \brief Called on well-formed 'inbranch' clause. + OMPClause *ActOnOpenMPInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'notinbranch' clause. + OMPClause *ActOnOpenMPNotInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'safelen' clause. + OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'simdlen' clause. + OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'num_teams' clause. + OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'thread_limit' clause. + OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'linear' clause. + OMPClause *ActOnOpenMPLinearClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, Expr *Step, + SourceLocation StepLoc); + /// \brief Called on well-formed 'aligned' clause. + OMPClause *ActOnOpenMPAlignedClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, Expr *Alignment, + SourceLocation AlignmentLoc); + /// \brief Called on well-formed 'linear' clause (declarative form). + OMPClause *ActOnOpenMPDeclarativeLinearClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Step, + SourceLocation StepLoc); + /// \brief Called on well-formed 'aligned' clause (declarative form). + OMPClause *ActOnOpenMPDeclarativeAlignedClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Alignment, + SourceLocation AlignmentLoc); + /// \brief Called on well-formed 'uniform' clause (declarative form). + OMPClause *ActOnOpenMPDeclarativeUniformClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc); + OMPClause *ActOnOpenMPSingleExprWithTypeClause( + OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, + Expr *Expr, SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'schedule' clause. + OMPClause *ActOnOpenMPScheduleClause(OpenMPScheduleClauseKind Argument, + SourceLocation ArgumentLoc, + Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'dist_schedule' clause. + OMPClause * + ActOnOpenMPDistScheduleClause(OpenMPDistScheduleClauseKind Argument, + SourceLocation ArgumentLoc, Expr *ChunkSize, + SourceLocation StartLoc, SourceLocation EndLoc); + + /// \brief Marks all decls as used in associated captured statement. + void MarkOpenMPClauses(ArrayRef Clauses); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff -uNr clang-3.4/include/clang/Sema/Template.h clang/include/clang/Sema/Template.h --- clang-3.4/include/clang/Sema/Template.h 2013-09-27 16:14:12.000000000 -0400 +++ clang/include/clang/Sema/Template.h 2014-05-19 19:58:57.000000000 -0400 @@ -426,6 +426,11 @@ TemplateParameterList *TemplateParams); Decl *VisitDecl(Decl *D); Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate); + void TouchOMPVarlist(llvm::MutableArrayRef VL, + SmallVector &NewVL, + Decl *FuncDecl); + Decl *TouchOMPDeclareSimdDecl(OMPDeclareSimdDecl *D, + Decl *NewFunc, DeclContext *DC); // Enable late instantiation of attributes. Late instantiated attributes // will be stored in LA. diff -uNr clang-3.4/include/clang/Serialization/ASTBitCodes.h clang/include/clang/Serialization/ASTBitCodes.h --- clang-3.4/include/clang/Serialization/ASTBitCodes.h 2013-09-17 23:29:45.000000000 -0400 +++ clang/include/clang/Serialization/ASTBitCodes.h 2014-06-09 10:05:34.000000000 -0400 @@ -1065,6 +1065,12 @@ DECL_IMPORT, /// \brief An OMPThreadPrivateDecl record. DECL_OMP_THREADPRIVATE, + /// \brief An OMPDeclareReductionDecl record. + DECL_OMP_DECLAREREDUCTION, + /// \brief An OMPDeclareSimdDecl record. + DECL_OMP_DECLARESIMD, + /// \brief An OMPDeclareTargetDecl record. + DECL_OMP_DECLARETARGET, /// \brief An EmptyDecl record. DECL_EMPTY }; @@ -1150,6 +1156,8 @@ EXPR_SIZEOF_ALIGN_OF, /// \brief An ArraySubscriptExpr record. EXPR_ARRAY_SUBSCRIPT, + /// \brief A CEAN index expr. + EXPR_CEAN_INDEX, /// \brief A CallExpr record. EXPR_CALL, /// \brief A MemberExpr record. @@ -1331,8 +1339,38 @@ STMT_SEH_FINALLY, // SEHFinallyStmt STMT_SEH_TRY, // SEHTryStmt - // OpenMP drectives + // OpenMP directives STMT_OMP_PARALLEL_DIRECTIVE, + STMT_OMP_FOR_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_SIMD_DIRECTIVE, + STMT_OMP_FOR_SIMD_DIRECTIVE, + STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE, + STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE, + STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, + STMT_OMP_SECTIONS_DIRECTIVE, + STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE, + STMT_OMP_SECTION_DIRECTIVE, + STMT_OMP_SINGLE_DIRECTIVE, + STMT_OMP_TASK_DIRECTIVE, + STMT_OMP_TASKYIELD_DIRECTIVE, + STMT_OMP_MASTER_DIRECTIVE, + STMT_OMP_CRITICAL_DIRECTIVE, + STMT_OMP_BARRIER_DIRECTIVE, + STMT_OMP_TASKWAIT_DIRECTIVE, + STMT_OMP_TASKGROUP_DIRECTIVE, + STMT_OMP_ATOMIC_DIRECTIVE, + STMT_OMP_FLUSH_DIRECTIVE, + STMT_OMP_ORDERED_DIRECTIVE, + STMT_OMP_TEAMS_DIRECTIVE, + STMT_OMP_DISTRIBUTE_DIRECTIVE, + STMT_OMP_CANCEL_DIRECTIVE, + STMT_OMP_CANCELLATION_POINT_DIRECTIVE, + STMT_OMP_TARGET_DIRECTIVE, + STMT_OMP_TARGET_DATA_DIRECTIVE, + STMT_OMP_TARGET_UPDATE_DIRECTIVE, + STMT_OMP_TARGET_TEAMS_DIRECTIVE, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff -uNr clang-3.4/include/clang/Serialization/ASTReader.h clang/include/clang/Serialization/ASTReader.h --- clang-3.4/include/clang/Serialization/ASTReader.h 2013-10-18 02:54:39.000000000 -0400 +++ clang/include/clang/Serialization/ASTReader.h 2014-05-19 19:58:57.000000000 -0400 @@ -16,6 +16,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" @@ -1915,6 +1916,33 @@ void ReadComments(); }; +/// \brief AST Reader for OpenMP clauses, used for both clauses-stmts +/// (e.g. omp parallel) and clauses-decls (e.g. omp declare simd). +class OMPClauseReader : public OMPClauseVisitor { + ASTReader &Reader; + ASTContext &Context; + const ASTReader::RecordData &Record; + unsigned &Idx; + serialization::ModuleFile &MFile; +public: + OMPClauseReader(ASTReader &R, ASTContext &C, + const ASTReader::RecordData &Record, unsigned &Idx, + serialization::ModuleFile &MF) + : Reader(R), Context(C), Record(Record), Idx(Idx), MFile(MF) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + OMPClause *readClause(); + SourceLocation ReadSourceLocation(const ASTReader::RecordData &R, + unsigned &I) { + return Reader.ReadSourceLocation(MFile, R, I); + } + + SourceRange ReadSourceRange(const ASTReader::RecordData &R, unsigned &I) { + return Reader.ReadSourceRange(MFile, R, I); + } +}; + /// \brief Helper class that saves the current stream position and /// then restores it when destroyed. struct SavedStreamPosition { diff -uNr clang-3.4/include/clang/Serialization/ASTWriter.h clang/include/clang/Serialization/ASTWriter.h --- clang-3.4/include/clang/Serialization/ASTWriter.h 2013-09-04 20:02:25.000000000 -0400 +++ clang/include/clang/Serialization/ASTWriter.h 2014-05-19 19:58:57.000000000 -0400 @@ -17,6 +17,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/TemplateBase.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTBitCodes.h" @@ -746,6 +747,20 @@ void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE; }; +/// \brief AST Writer for OpenMP clauses, used for both clauses-stmts +/// (e.g. omp parallel) and clauses-decls (e.g. omp declare simd). +class OMPClauseWriter : public OMPClauseVisitor { + ASTWriter &Writer; + ASTWriter::RecordData &Record; +public: + OMPClauseWriter(ASTWriter &W, ASTWriter::RecordData &Record) + : Writer(W), Record(Record) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + void writeClause(OMPClause *C); +}; + /// \brief AST and semantic-analysis consumer that generates a /// precompiled header from the parsed source code. class PCHGenerator : public SemaConsumer { diff -uNr clang-3.4/include/clang-c/Index.h clang/include/clang-c/Index.h --- clang-3.4/include/clang-c/Index.h 2013-11-17 04:46:45.000000000 -0500 +++ clang/include/clang-c/Index.h 2014-06-09 10:05:34.000000000 -0400 @@ -2066,11 +2066,41 @@ */ CXCursor_DeclStmt = 231, - /** \brief OpenMP parallel directive. + /** \brief OpenMP directives. */ CXCursor_OMPParallelDirective = 232, + CXCursor_OMPForDirective = 233, + CXCursor_OMPSectionsDirective = 234, + CXCursor_OMPSectionDirective = 235, + CXCursor_OMPSingleDirective = 236, + CXCursor_OMPTaskDirective = 237, + CXCursor_OMPTaskyieldDirective = 238, + CXCursor_OMPMasterDirective = 239, + CXCursor_OMPCriticalDirective = 240, + CXCursor_OMPBarrierDirective = 241, + CXCursor_OMPTaskwaitDirective = 242, + CXCursor_OMPTaskgroupDirective = 243, + CXCursor_OMPAtomicDirective = 244, + CXCursor_OMPFlushDirective = 245, + CXCursor_OMPOrderedDirective = 246, + CXCursor_OMPSimdDirective = 247, + CXCursor_OMPForSimdDirective = 248, + CXCursor_OMPTeamsDirective = 249, + CXCursor_OMPCancelDirective = 250, + CXCursor_OMPCancellationPointDirective = 251, + CXCursor_OMPDistributeDirective = 252, + CXCursor_OMPDistributeSimdDirective = 253, + CXCursor_OMPParallelForDirective = 254, + CXCursor_OMPParallelForSimdDirective = 255, + CXCursor_OMPParallelSectionsDirective = 256, + CXCursor_OMPDistributeParallelForDirective = 257, + CXCursor_OMPDistributeParallelForSimdDirective = 258, + CXCursor_OMPTargetDirective = 259, + CXCursor_OMPTargetDataDirective = 260, + CXCursor_OMPTargetUpdateDirective = 261, + CXCursor_OMPTargetTeamsDirective = 262, - CXCursor_LastStmt = CXCursor_OMPParallelDirective, + CXCursor_LastStmt = CXCursor_OMPTargetDirective, /** * \brief Cursor that represents the translation unit itself. diff -uNr clang-3.4/lib/AST/ASTDumper.cpp clang/lib/AST/ASTDumper.cpp --- clang-3.4/lib/AST/ASTDumper.cpp 2013-11-06 18:31:56.000000000 -0500 +++ clang/lib/AST/ASTDumper.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -254,6 +254,7 @@ void VisitAttributedStmt(const AttributedStmt *Node); void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); + void VisitCapturedStmt(const CapturedStmt *Node); void VisitCXXCatchStmt(const CXXCatchStmt *Node); // Exprs @@ -1487,6 +1488,9 @@ lastChild(); dumpStmt(*CI); } + if (const CapturedStmt *CS = dyn_cast(S)) { + dumpStmt(CS->getCapturedStmt()); + } } void ASTDumper::VisitStmt(const Stmt *Node) { @@ -1531,6 +1535,26 @@ dumpPointer(Node->getLabel()); } +void ASTDumper::VisitCapturedStmt(const CapturedStmt *Node) { + VisitStmt(Node); + for (CapturedStmt::const_capture_iterator I = Node->capture_begin(), + E = Node->capture_end(); + I != E; ++I) { + IndentScope Indent(*this); + OS << "Capture "; + switch (I->getCaptureKind()) { + case CapturedStmt::VCK_This: + OS << "this"; + break; + case CapturedStmt::VCK_ByRef: + OS << "byref "; + dumpBareDeclRef(I->getCapturedVar()); + break; + } + } + dumpDecl(Node->getCapturedDecl()); +} + void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { VisitStmt(Node); dumpDecl(Node->getExceptionDecl()); diff -uNr clang-3.4/lib/AST/CXXInheritance.cpp clang/lib/AST/CXXInheritance.cpp --- clang-3.4/lib/AST/CXXInheritance.cpp 2013-08-23 12:11:15.000000000 -0400 +++ clang/lib/AST/CXXInheritance.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -445,6 +445,24 @@ return false; } +bool CXXRecordDecl::FindOMPDeclareReductionMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = + Specifier->getType()->castAs()->getDecl(); + + const unsigned IDNS = IDNS_OMPDeclareReduction; + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS)) + return true; + } + + return false; +} + void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { SmallVectorImpl &SubobjectOverrides diff -uNr clang-3.4/lib/AST/Decl.cpp clang/lib/AST/Decl.cpp --- clang-3.4/lib/AST/Decl.cpp 2013-12-08 21:00:10.000000000 -0500 +++ clang/lib/AST/Decl.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -17,6 +17,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -1392,6 +1393,9 @@ if (isa(this)) return false; + if (isa(this)) + return false; + if (isa(this) && isa(OldD)) return true; @@ -3579,14 +3583,20 @@ CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC, unsigned NumParams) { unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); - return new (C.Allocate(Size)) CapturedDecl(DC, NumParams); + CapturedDecl *CD = new (C.Allocate(Size)) CapturedDecl(DC, NumParams); + for (unsigned i = 0; i < NumParams; ++i) + CD->setParam(i, 0); + return CD; } CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned NumParams) { unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); void *Mem = AllocateDeserializedDecl(C, ID, Size); - return new (Mem) CapturedDecl(0, NumParams); + CapturedDecl *CD = new (Mem) CapturedDecl(0, NumParams); + for (unsigned i = 0; i < NumParams; ++i) + CD->setParam(i, 0); + return CD; } EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, diff -uNr clang-3.4/lib/AST/DeclBase.cpp clang/lib/AST/DeclBase.cpp --- clang-3.4/lib/AST/DeclBase.cpp 2013-11-13 21:13:03.000000000 -0500 +++ clang/lib/AST/DeclBase.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -555,6 +555,9 @@ case TemplateTemplateParm: return IDNS_Ordinary | IDNS_Tag | IDNS_Type; + case OMPDeclareReduction: + return IDNS_OMPDeclareReduction; + // Never have names. case Friend: case FriendTemplate: @@ -578,6 +581,8 @@ case ObjCCategoryImpl: case Import: case OMPThreadPrivate: + case OMPDeclareSimd: + case OMPDeclareTarget: case Empty: // Never looked up by name. return 0; @@ -802,6 +807,8 @@ return !cast(this)->isScoped(); else if (DeclKind == Decl::LinkageSpec) return true; + else if (DeclKind == Decl::OMPDeclareTarget) + return true; return false; } @@ -840,6 +847,8 @@ case Decl::LinkageSpec: case Decl::Block: case Decl::Captured: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareTarget: // There is only one DeclContext for these entities. return this; diff -uNr clang-3.4/lib/AST/DeclOpenMP.cpp clang/lib/AST/DeclOpenMP.cpp --- clang-3.4/lib/AST/DeclOpenMP.cpp 2013-07-18 23:13:43.000000000 -0400 +++ clang/lib/AST/DeclOpenMP.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements OMPThreadPrivateDecl class. +/// \brief This file implements OMPThreadPrivateDecl, OMPDeclareReduction, +/// OMPDeclareTarget classes. /// //===----------------------------------------------------------------------===// @@ -23,18 +24,17 @@ // OMPThreadPrivateDecl Implementation. //===----------------------------------------------------------------------===// -void OMPThreadPrivateDecl::anchor() { } +void OMPThreadPrivateDecl::anchor() {} OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef VL) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(Expr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf()); - OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, - DC, L); + OMPThreadPrivateDecl *D = + new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, DC, L); D->NumVars = VL.size(); D->setVars(VL); return D; @@ -46,8 +46,8 @@ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); - OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, - 0, SourceLocation()); + OMPThreadPrivateDecl *D = + new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, 0, SourceLocation()); D->NumVars = N; return D; } @@ -59,3 +59,161 @@ std::copy(VL.begin(), VL.end(), Vars); } +//===----------------------------------------------------------------------===// +// OMPDeclareSimd Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareSimdDecl::anchor() {} + +unsigned OMPDeclareSimdDecl::getFirstVariantOffset() { + unsigned Size = sizeof(OMPDeclareSimdDecl); + Size = llvm::RoundUpToAlignment( + Size, llvm::alignOf()); + return Size; +} + +unsigned OMPDeclareSimdDecl::getFirstClauseOffset(unsigned NV) { + unsigned ESize = llvm::RoundUpToAlignment( + sizeof(OMPDeclareSimdDecl::SimdVariant), + llvm::alignOf()); + unsigned Size = getFirstVariantOffset() + ESize * NV; + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf()); + return Size; +} + +unsigned OMPDeclareSimdDecl::getTotalSize(unsigned NV, unsigned NC) { + unsigned ESize = llvm::RoundUpToAlignment(sizeof(OMPClause *), + llvm::alignOf()); + unsigned Size = getFirstClauseOffset(NV) + ESize * NC; + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf()); + return Size; +} + +void +OMPDeclareSimdDecl::setVariants(ArrayRef SV) { + assert(SV.size() == NumVariants && + "Number of variants is not the same as the preallocated buffer"); + unsigned Offset = getFirstVariantOffset(); + OMPDeclareSimdDecl::SimdVariant *Data = + reinterpret_cast( + reinterpret_cast(this) + Offset); + for (unsigned i = 0; i < NumVariants; ++i) + Data[i] = SV[i]; +} + +void OMPDeclareSimdDecl::setClauses(ArrayRef CL) { + assert(CL.size() == NumClauses && + "Number of clauses is not the same as the preallocated buffer"); + unsigned Offset = getFirstClauseOffset(NumVariants); + OMPClause **Data = + reinterpret_cast(reinterpret_cast(this) + Offset); + for (unsigned i = 0; i < NumClauses; ++i) + Data[i] = CL[i]; +} + +OMPDeclareSimdDecl *OMPDeclareSimdDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, Decl *FuncDecl, + unsigned NV, + ArrayRef CL) { + unsigned NC = CL.size(); + unsigned Size = getTotalSize(NV, NC); + void *Mem = C.Allocate(Size, llvm::alignOf()); + OMPDeclareSimdDecl *D = + new (Mem) OMPDeclareSimdDecl(OMPDeclareSimd, DC, L, NV, NC); + D->FuncDecl = FuncDecl; + D->setClauses(CL); + return D; +} + +OMPDeclareSimdDecl *OMPDeclareSimdDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned NV, + unsigned NC) { + unsigned Size = getTotalSize(NV, NC); + void *Mem = AllocateDeserializedDecl(C, ID, Size); + OMPDeclareSimdDecl *D = + new (Mem) OMPDeclareSimdDecl(OMPDeclareSimd, 0, SourceLocation(), NV, NC); + D->FuncDecl = 0; + return D; +} + +//===----------------------------------------------------------------------===// +// OMPDeclareReductionDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareReductionDecl::anchor() {} + +unsigned OMPDeclareReductionDecl::getFirstElementOffset() { + unsigned Size = sizeof(OMPDeclareReductionDecl); + // Realign + Size = llvm::RoundUpToAlignment( + Size, llvm::alignOf()); + return Size; +} + +OMPDeclareReductionDecl *OMPDeclareReductionDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + unsigned N) { + unsigned Size = getFirstElementOffset() + + N * sizeof(OMPDeclareReductionDecl::ReductionData); + + void *Mem = C.Allocate(Size); + OMPDeclareReductionDecl *D = + new (Mem) OMPDeclareReductionDecl(OMPDeclareReduction, DC, L, Name); + D->NumTypes = N; + return D; +} + +OMPDeclareReductionDecl * +OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned N) { + unsigned Size = getFirstElementOffset() + + N * sizeof(OMPDeclareReductionDecl::ReductionData); + + void *Mem = AllocateDeserializedDecl(C, ID, Size); + OMPDeclareReductionDecl *D = new (Mem) OMPDeclareReductionDecl( + OMPDeclareReduction, 0, SourceLocation(), DeclarationName()); + D->NumTypes = N; + return D; +} + +void OMPDeclareReductionDecl::setData( + ArrayRef RD) { + assert(RD.size() == NumTypes && + "Number of inits is not the same as the preallocated buffer"); + unsigned Size = getFirstElementOffset(); + OMPDeclareReductionDecl::ReductionData *Data = + reinterpret_cast( + reinterpret_cast(this) + Size); + for (unsigned i = 0; i < NumTypes; ++i) + Data[i] = RD[i]; + // std::copy(RD.begin(), RD.end(), Data); +} + +//===----------------------------------------------------------------------===// +// OMPDeclareTargetDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareTargetDecl::anchor() {} + +OMPDeclareTargetDecl * +OMPDeclareTargetDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + void *Mem = C.Allocate(sizeof(OMPDeclareTargetDecl), + llvm::alignOf()); + OMPDeclareTargetDecl *D = + new (Mem) OMPDeclareTargetDecl(OMPDeclareTarget, DC, L); + return D; +} + +OMPDeclareTargetDecl *OMPDeclareTargetDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + // Realign + unsigned Size = llvm::RoundUpToAlignment( + sizeof(OMPDeclareTargetDecl), llvm::alignOf()); + void *Mem = AllocateDeserializedDecl(C, ID, Size); + OMPDeclareTargetDecl *D = + new (Mem) OMPDeclareTargetDecl(OMPDeclareTarget, 0, SourceLocation()); + return D; +} diff -uNr clang-3.4/lib/AST/DeclPrinter.cpp clang/lib/AST/DeclPrinter.cpp --- clang-3.4/lib/AST/DeclPrinter.cpp 2013-09-25 23:24:06.000000000 -0400 +++ clang/lib/AST/DeclPrinter.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -83,6 +83,9 @@ void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = 0); @@ -294,8 +297,21 @@ // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = 0; - if (isa(*D)) + if (isa(*D) || isa(*D) || + isa(*D)) Terminator = 0; + else if (isa(*D)) { + if (FunctionDecl *Func = dyn_cast_or_null( + cast(*D)->getFunction())) { + if (Func->isThisDeclarationADefinition()) + Terminator = 0; + else + Terminator = ";"; + } + else { + Terminator = 0; + } + } else if (isa(*D) && cast(*D)->isThisDeclarationADefinition()) Terminator = 0; @@ -1197,3 +1213,86 @@ } } +void DeclPrinter::VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D) { + for (OMPDeclareSimdDecl::simd_variants_iterator + I = D->simd_variants_begin(), + E = D->simd_variants_end(); + I != E; ++I) { + Out << "#pragma omp declare simd"; + for (unsigned J = I->BeginIdx, F = I->EndIdx; J != F; ++J) { + Out << " "; + if (*(D->clauses_begin() + J) && + !(*(D->clauses_begin() + J))->isImplicit()) { + const OMPClause *CurCL = cast_or_null( + *(D->clauses_begin() + J)); + CurCL->printPretty(Out, 0, Policy, Indentation); + } + } + Out << "\n"; + } + Decl *FuncDecl = D->getFunction(); + assert(FuncDecl && "Pragma has no function declaration (omp declare simd)"); + Visit(FuncDecl); +} + + +void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + if (!D->isInvalidDecl() && !D->datalist_empty()) { + for (OMPDeclareReductionDecl::datalist_iterator I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + Out << "#pragma omp declare reduction ("; + D->printName(Out); + Out << " : "; + I->QTy.print(Out, Policy); + Out << " : "; + FunctionDecl *CF = + cast(cast(I->CombinerFunction)->getDecl()); + CompoundStmt::body_iterator BI = + cast(CF->getBody())->body_begin(); + // Skip first 2 DeclStmts; + ++BI; + ++BI; + (*BI)->printPretty(Out, 0, Policy, 0); + Out << ")"; + FunctionDecl *IF = + cast(cast(I->InitFunction)->getDecl()); + if (IF->getBody() == 0) continue; + BI = cast(IF->getBody())->body_begin(); + // Skip first 2 DeclStmts; + ++BI; + if (DeclStmt *DS = dyn_cast(*BI)) { + if (VarDecl *VD = + dyn_cast_or_null(DS->getSingleDecl())) { + if (VD->hasInit() && VD->getInit()->getLocStart().isValid()) { + Out << " initializer(omp_priv "; + if (!Policy.LangOpts.CPlusPlus) { + Out << "= "; + } + VD->getInit()->printPretty(Out, 0, Policy, 0); + Out << ")\n"; + return; + } + } + ++BI; + } + // Skip DeclStmt. + // Check if next stmt is explicit function call. + if (CallExpr *CE = dyn_cast_or_null((*BI)->IgnoreImplicit())) { + if (CE->getLocStart().isValid()) { + Out << " initializer("; + CE->printPretty(Out, 0, Policy, 0); + Out << ")"; + } + } + Out << "\n"; + } + } +} + +void DeclPrinter::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + Out << "#pragma omp declare target\n"; + VisitDeclContext(D); + Out << "#pragma omp end declare target\n"; +} + diff -uNr clang-3.4/lib/AST/Expr.cpp clang/lib/AST/Expr.cpp --- clang-3.4/lib/AST/Expr.cpp 2013-11-14 17:40:45.000000000 -0500 +++ clang/lib/AST/Expr.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -2049,6 +2049,7 @@ case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: + case CEANIndexExprClass: return false; case ConditionalOperatorClass: { @@ -2851,6 +2852,7 @@ case CXXBindTemporaryExprClass: case BlockExprClass: case CUDAKernelCallExprClass: + case CEANIndexExprClass: // These always have a side-effect. return true; diff -uNr clang-3.4/lib/AST/ExprClassification.cpp clang/lib/AST/ExprClassification.cpp --- clang-3.4/lib/AST/ExprClassification.cpp 2013-11-14 13:26:10.000000000 -0500 +++ clang/lib/AST/ExprClassification.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -183,6 +183,7 @@ case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::AtomicExprClass: + case Expr::CEANIndexExprClass: return Cl::CL_PRValue; // Next come the complicated cases. diff -uNr clang-3.4/lib/AST/ExprConstant.cpp clang/lib/AST/ExprConstant.cpp --- clang-3.4/lib/AST/ExprConstant.cpp 2013-11-14 21:10:04.000000000 -0500 +++ clang/lib/AST/ExprConstant.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -8305,6 +8305,7 @@ case Expr::AtomicExprClass: case Expr::InitListExprClass: case Expr::LambdaExprClass: + case Expr::CEANIndexExprClass: return ICEDiag(IK_NotICE, E->getLocStart()); case Expr::SizeOfPackExprClass: diff -uNr clang-3.4/lib/AST/ItaniumMangle.cpp clang/lib/AST/ItaniumMangle.cpp --- clang-3.4/lib/AST/ItaniumMangle.cpp 2013-11-20 01:46:42.000000000 -0500 +++ clang/lib/AST/ItaniumMangle.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -2592,6 +2592,7 @@ case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: + case Expr::CEANIndexExprClass: { // As bad as this diagnostic is, it's better than crashing. DiagnosticsEngine &Diags = Context.getDiags(); diff -uNr clang-3.4/lib/AST/Stmt.cpp clang/lib/AST/Stmt.cpp --- clang-3.4/lib/AST/Stmt.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/lib/AST/Stmt.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -31,7 +31,7 @@ const char *Name; unsigned Counter; unsigned Size; -} StmtClassInfo[Stmt::lastStmtConstant+1]; +} StmtClassInfo[Stmt::lastStmtConstant + 1]; static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { static bool Initialized = false; @@ -41,21 +41,21 @@ // Intialize the table on the first use. Initialized = true; #define ABSTRACT_STMT(STMT) -#define STMT(CLASS, PARENT) \ - StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ +#define STMT(CLASS, PARENT) \ + StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); #include "clang/AST/StmtNodes.inc" return StmtClassInfo[E]; } -void *Stmt::operator new(size_t bytes, const ASTContext& C, +void *Stmt::operator new(size_t bytes, const ASTContext &C, unsigned alignment) { return ::operator new(bytes, C, alignment); } const char *Stmt::getStmtClassName() const { - return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name; + return getStmtInfoTableEntry((StmtClass)StmtBits.sClass).Name; } void Stmt::PrintStats() { @@ -64,33 +64,33 @@ unsigned sum = 0; llvm::errs() << "\n*** Stmt/Expr Stats:\n"; - for (int i = 0; i != Stmt::lastStmtConstant+1; i++) { - if (StmtClassInfo[i].Name == 0) continue; + for (int i = 0; i != Stmt::lastStmtConstant + 1; i++) { + if (StmtClassInfo[i].Name == 0) + continue; sum += StmtClassInfo[i].Counter; } llvm::errs() << " " << sum << " stmts/exprs total.\n"; sum = 0; - for (int i = 0; i != Stmt::lastStmtConstant+1; i++) { - if (StmtClassInfo[i].Name == 0) continue; - if (StmtClassInfo[i].Counter == 0) continue; + for (int i = 0; i != Stmt::lastStmtConstant + 1; i++) { + if (StmtClassInfo[i].Name == 0) + continue; + if (StmtClassInfo[i].Counter == 0) + continue; llvm::errs() << " " << StmtClassInfo[i].Counter << " " << StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size - << " each (" << StmtClassInfo[i].Counter*StmtClassInfo[i].Size + << " each (" + << StmtClassInfo[i].Counter * StmtClassInfo[i].Size << " bytes)\n"; - sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size; + sum += StmtClassInfo[i].Counter * StmtClassInfo[i].Size; } llvm::errs() << "Total bytes = " << sum << "\n"; } -void Stmt::addStmtClass(StmtClass s) { - ++getStmtInfoTableEntry(s).Counter; -} +void Stmt::addStmtClass(StmtClass s) { ++getStmtInfoTableEntry(s).Counter; } bool Stmt::StatisticsEnabled = false; -void Stmt::EnableStatistics() { - StatisticsEnabled = true; -} +void Stmt::EnableStatistics() { StatisticsEnabled = true; } Stmt *Stmt::IgnoreImplicit() { Stmt *s = this; @@ -123,46 +123,40 @@ } namespace { - struct good {}; - struct bad {}; +struct good {}; +struct bad {}; - // These silly little functions have to be static inline to suppress - // unused warnings, and they have to be defined to suppress other - // warnings. - static inline good is_good(good) { return good(); } +// These silly little functions have to be static inline to suppress +// unused warnings, and they have to be defined to suppress other +// warnings. +static inline good is_good(good) { return good(); } - typedef Stmt::child_range children_t(); - template good implements_children(children_t T::*) { - return good(); - } - LLVM_ATTRIBUTE_UNUSED - static inline bad implements_children(children_t Stmt::*) { - return bad(); - } +typedef Stmt::child_range children_t(); +template good implements_children(children_t T::*) { return good(); } +LLVM_ATTRIBUTE_UNUSED +static inline bad implements_children(children_t Stmt::*) { return bad(); } - typedef SourceLocation getLocStart_t() const; - template good implements_getLocStart(getLocStart_t T::*) { - return good(); - } - LLVM_ATTRIBUTE_UNUSED - static inline bad implements_getLocStart(getLocStart_t Stmt::*) { - return bad(); - } +typedef SourceLocation getLocStart_t() const; +template good implements_getLocStart(getLocStart_t T::*) { + return good(); +} +LLVM_ATTRIBUTE_UNUSED +static inline bad implements_getLocStart(getLocStart_t Stmt::*) { + return bad(); +} - typedef SourceLocation getLocEnd_t() const; - template good implements_getLocEnd(getLocEnd_t T::*) { - return good(); - } - LLVM_ATTRIBUTE_UNUSED - static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) { - return bad(); - } +typedef SourceLocation getLocEnd_t() const; +template good implements_getLocEnd(getLocEnd_t T::*) { + return good(); +} +LLVM_ATTRIBUTE_UNUSED +static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) { return bad(); } -#define ASSERT_IMPLEMENTS_children(type) \ +#define ASSERT_IMPLEMENTS_children(type) \ (void) is_good(implements_children(&type::children)) -#define ASSERT_IMPLEMENTS_getLocStart(type) \ +#define ASSERT_IMPLEMENTS_getLocStart(type) \ (void) is_good(implements_getLocStart(&type::getLocStart)) -#define ASSERT_IMPLEMENTS_getLocEnd(type) \ +#define ASSERT_IMPLEMENTS_getLocEnd(type) \ (void) is_good(implements_getLocEnd(&type::getLocEnd)) } @@ -171,20 +165,21 @@ LLVM_ATTRIBUTE_UNUSED static inline void check_implementations() { #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - ASSERT_IMPLEMENTS_children(type); \ - ASSERT_IMPLEMENTS_getLocStart(type); \ +#define STMT(type, base) \ + ASSERT_IMPLEMENTS_children(type); \ + ASSERT_IMPLEMENTS_getLocStart(type); \ ASSERT_IMPLEMENTS_getLocEnd(type); #include "clang/AST/StmtNodes.inc" } Stmt::child_range Stmt::children() { switch (getStmtClass()) { - case Stmt::NoStmtClass: llvm_unreachable("statement without class"); + case Stmt::NoStmtClass: + llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ - return static_cast(this)->children(); +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast(this)->children(); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown statement kind!"); @@ -195,32 +190,32 @@ // // See also Expr.cpp:getExprLoc(). namespace { - /// This implementation is used when a class provides a custom - /// implementation of getSourceRange. - template - SourceRange getSourceRangeImpl(const Stmt *stmt, - SourceRange (T::*v)() const) { - return static_cast(stmt)->getSourceRange(); - } - - /// This implementation is used when a class doesn't provide a custom - /// implementation of getSourceRange. Overload resolution should pick it over - /// the implementation above because it's more specialized according to - /// function template partial ordering. - template - SourceRange getSourceRangeImpl(const Stmt *stmt, - SourceRange (Stmt::*v)() const) { - return SourceRange(static_cast(stmt)->getLocStart(), - static_cast(stmt)->getLocEnd()); - } +/// This implementation is used when a class provides a custom +/// implementation of getSourceRange. +template +SourceRange getSourceRangeImpl(const Stmt *stmt, SourceRange (T::*v)() const) { + return static_cast(stmt)->getSourceRange(); +} + +/// This implementation is used when a class doesn't provide a custom +/// implementation of getSourceRange. Overload resolution should pick it over +/// the implementation above because it's more specialized according to +/// function template partial ordering. +template +SourceRange getSourceRangeImpl(const Stmt *stmt, + SourceRange (Stmt::*v)() const) { + return SourceRange(static_cast(stmt)->getLocStart(), + static_cast(stmt)->getLocEnd()); +} } SourceRange Stmt::getSourceRange() const { switch (getStmtClass()) { - case Stmt::NoStmtClass: llvm_unreachable("statement without class"); + case Stmt::NoStmtClass: + llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ +#define STMT(type, base) \ + case Stmt::type##Class: \ return getSourceRangeImpl(this, &type::getSourceRange); #include "clang/AST/StmtNodes.inc" } @@ -228,13 +223,14 @@ } SourceLocation Stmt::getLocStart() const { -// llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n"; + // llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n"; switch (getStmtClass()) { - case Stmt::NoStmtClass: llvm_unreachable("statement without class"); + case Stmt::NoStmtClass: + llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ - return static_cast(this)->getLocStart(); +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast(this)->getLocStart(); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown statement kind"); @@ -242,19 +238,20 @@ SourceLocation Stmt::getLocEnd() const { switch (getStmtClass()) { - case Stmt::NoStmtClass: llvm_unreachable("statement without class"); + case Stmt::NoStmtClass: + llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ - return static_cast(this)->getLocEnd(); +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast(this)->getLocEnd(); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown statement kind"); } -CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef Stmts, +CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef Stmts, SourceLocation LB, SourceLocation RB) - : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { + : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { CompoundStmtBits.NumStmts = Stmts.size(); assert(CompoundStmtBits.NumStmts == Stmts.size() && "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!"); @@ -264,7 +261,7 @@ return; } - Body = new (C) Stmt*[Stmts.size()]; + Body = new (C) Stmt *[Stmts.size()]; std::copy(Stmts.begin(), Stmts.end(), Body); } @@ -274,7 +271,7 @@ C.Deallocate(Body); this->CompoundStmtBits.NumStmts = NumStmts; - Body = new (C) Stmt*[NumStmts]; + Body = new (C) Stmt *[NumStmts]; memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts); } @@ -283,20 +280,20 @@ } AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc, - ArrayRef Attrs, + ArrayRef Attrs, Stmt *SubStmt) { - void *Mem = C.Allocate(sizeof(AttributedStmt) + - sizeof(Attr*) * (Attrs.size() - 1), - llvm::alignOf()); + void *Mem = + C.Allocate(sizeof(AttributedStmt) + sizeof(Attr *) * (Attrs.size() - 1), + llvm::alignOf()); return new (Mem) AttributedStmt(Loc, Attrs, SubStmt); } AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C, unsigned NumAttrs) { assert(NumAttrs > 0 && "NumAttrs should be greater than zero"); - void *Mem = C.Allocate(sizeof(AttributedStmt) + - sizeof(Attr*) * (NumAttrs - 1), - llvm::alignOf()); + void *Mem = + C.Allocate(sizeof(AttributedStmt) + sizeof(Attr *) * (NumAttrs - 1), + llvm::alignOf()); return new (Mem) AttributedStmt(EmptyShell(), NumAttrs); } @@ -362,9 +359,7 @@ return getClobberStringLiteral(i)->getString(); } -Expr *GCCAsmStmt::getOutputExpr(unsigned i) { - return cast(Exprs[i]); -} +Expr *GCCAsmStmt::getOutputExpr(unsigned i) { return cast(Exprs[i]); } /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either @@ -386,14 +381,10 @@ return getInputConstraintLiteral(i)->getString(); } -void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C, - IdentifierInfo **Names, - StringLiteral **Constraints, - Stmt **Exprs, - unsigned NumOutputs, - unsigned NumInputs, - StringLiteral **Clobbers, - unsigned NumClobbers) { +void GCCAsmStmt::setOutputsAndInputsAndClobbers( + const ASTContext &C, IdentifierInfo **Names, StringLiteral **Constraints, + Stmt **Exprs, unsigned NumOutputs, unsigned NumInputs, + StringLiteral **Clobbers, unsigned NumClobbers) { this->NumOutputs = NumOutputs; this->NumInputs = NumInputs; this->NumClobbers = NumClobbers; @@ -401,19 +392,19 @@ unsigned NumExprs = NumOutputs + NumInputs; C.Deallocate(this->Names); - this->Names = new (C) IdentifierInfo*[NumExprs]; + this->Names = new (C) IdentifierInfo *[NumExprs]; std::copy(Names, Names + NumExprs, this->Names); C.Deallocate(this->Exprs); - this->Exprs = new (C) Stmt*[NumExprs]; + this->Exprs = new (C) Stmt *[NumExprs]; std::copy(Exprs, Exprs + NumExprs, this->Exprs); C.Deallocate(this->Constraints); - this->Constraints = new (C) StringLiteral*[NumExprs]; + this->Constraints = new (C) StringLiteral *[NumExprs]; std::copy(Constraints, Constraints + NumExprs, this->Constraints); C.Deallocate(this->Clobbers); - this->Clobbers = new (C) StringLiteral*[NumClobbers]; + this->Clobbers = new (C) StringLiteral *[NumClobbers]; std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers); } @@ -440,8 +431,9 @@ /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. -unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl&Pieces, - const ASTContext &C, unsigned &DiagOffs) const { +unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl &Pieces, + const ASTContext &C, + unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); @@ -481,10 +473,18 @@ char CurChar = *CurPtr++; switch (CurChar) { - case '$': CurStringPiece += "$$"; continue; - case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; - case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; - case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; + case '$': + CurStringPiece += "$$"; + continue; + case '{': + CurStringPiece += (HasVariants ? "$(" : "{"); + continue; + case '|': + CurStringPiece += (HasVariants ? "$|" : "|"); + continue; + case '}': + CurStringPiece += (HasVariants ? "$)" : "}"); + continue; case '%': break; default: @@ -495,18 +495,18 @@ // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). - DiagOffs = CurPtr-StrStart-1; + DiagOffs = CurPtr - StrStart - 1; return diag::err_asm_invalid_escape; } char EscapedChar = *CurPtr++; - if (EscapedChar == '%') { // %% -> % + if (EscapedChar == '%') { // %% -> % // Escaped percentage sign. CurStringPiece += '%'; continue; } - if (EscapedChar == '=') { // %= -> Generate an unique ID. + if (EscapedChar == '=') { // %= -> Generate an unique ID. CurStringPiece += "${:uid}"; continue; } @@ -522,7 +522,7 @@ char Modifier = '\0'; if (isLetter(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. - DiagOffs = CurPtr-StrStart-1; + DiagOffs = CurPtr - StrStart - 1; return diag::err_asm_invalid_escape; } Modifier = EscapedChar; @@ -535,12 +535,12 @@ --CurPtr; while (CurPtr != StrEnd && isDigit(*CurPtr)) - N = N*10 + ((*CurPtr++)-'0'); + N = N * 10 + ((*CurPtr++) - '0'); unsigned NumOperands = - getNumOutputs() + getNumPlusOperands() + getNumInputs(); + getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { - DiagOffs = CurPtr-StrStart-1; + DiagOffs = CurPtr - StrStart - 1; return diag::err_asm_invalid_operand_number; } @@ -550,10 +550,10 @@ // Handle %[foo], a symbolic operand reference. if (EscapedChar == '[') { - DiagOffs = CurPtr-StrStart-1; + DiagOffs = CurPtr - StrStart - 1; // Find the ']'. - const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); + const char *NameEnd = (const char *)memchr(CurPtr, ']', StrEnd - CurPtr); if (NameEnd == 0) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) @@ -564,16 +564,16 @@ int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. - DiagOffs = CurPtr-StrStart; + DiagOffs = CurPtr - StrStart; return diag::err_asm_unknown_symbolic_operand_name; } Pieces.push_back(AsmStringPiece(N, Modifier)); - CurPtr = NameEnd+1; + CurPtr = NameEnd + 1; continue; } - DiagOffs = CurPtr-StrStart-1; + DiagOffs = CurPtr - StrStart - 1; return diag::err_asm_invalid_escape; } } @@ -605,16 +605,12 @@ return AsmStr; } -Expr *MSAsmStmt::getOutputExpr(unsigned i) { - return cast(Exprs[i]); -} +Expr *MSAsmStmt::getOutputExpr(unsigned i) { return cast(Exprs[i]); } Expr *MSAsmStmt::getInputExpr(unsigned i) { return cast(Exprs[i + NumOutputs]); } -void MSAsmStmt::setInputExpr(unsigned i, Expr *E) { - Exprs[i + NumOutputs] = E; -} +void MSAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } QualType CXXCatchStmt::getCaughtType() const { if (ExceptionDecl) @@ -632,34 +628,34 @@ StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) - : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, - numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { + : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, numclobbers), + RParenLoc(rparenloc), AsmStr(asmstr) { unsigned NumExprs = NumOutputs + NumInputs; - Names = new (C) IdentifierInfo*[NumExprs]; + Names = new (C) IdentifierInfo *[NumExprs]; std::copy(names, names + NumExprs, Names); - Exprs = new (C) Stmt*[NumExprs]; + Exprs = new (C) Stmt *[NumExprs]; std::copy(exprs, exprs + NumExprs, Exprs); - Constraints = new (C) StringLiteral*[NumExprs]; + Constraints = new (C) StringLiteral *[NumExprs]; std::copy(constraints, constraints + NumExprs, Constraints); - Clobbers = new (C) StringLiteral*[NumClobbers]; + Clobbers = new (C) StringLiteral *[NumClobbers]; std::copy(clobbers, clobbers + NumClobbers, Clobbers); } MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, ArrayRef asmtoks, unsigned numoutputs, - unsigned numinputs, - ArrayRef constraints, ArrayRef exprs, - StringRef asmstr, ArrayRef clobbers, - SourceLocation endloc) - : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, - numinputs, clobbers.size()), LBraceLoc(lbraceloc), - EndLoc(endloc), NumAsmToks(asmtoks.size()) { + unsigned numinputs, ArrayRef constraints, + ArrayRef exprs, StringRef asmstr, + ArrayRef clobbers, SourceLocation endloc) + : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, clobbers.size()), + LBraceLoc(lbraceloc), EndLoc(endloc), NumAsmToks(asmtoks.size()) { initialize(C, asmstr, asmtoks, constraints, exprs, clobbers); } @@ -674,7 +670,7 @@ void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr, ArrayRef asmtoks, ArrayRef constraints, - ArrayRef exprs, + ArrayRef exprs, ArrayRef clobbers) { assert(NumAsmToks == asmtoks.size()); assert(NumClobbers == clobbers.size()); @@ -685,7 +681,7 @@ AsmStr = copyIntoContext(C, asmstr); - Exprs = new (C) Stmt*[NumExprs]; + Exprs = new (C) Stmt *[NumExprs]; for (unsigned i = 0, e = NumExprs; i != e; ++i) Exprs[i] = exprs[i]; @@ -706,9 +702,9 @@ } ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, - Stmt *Body, SourceLocation FCL, + Stmt *Body, SourceLocation FCL, SourceLocation RPL) -: Stmt(ObjCForCollectionStmtClass) { + : Stmt(ObjCForCollectionStmtClass) { SubExprs[ELEM] = Elem; SubExprs[COLLECTION] = Collect; SubExprs[BODY] = Body; @@ -719,9 +715,8 @@ ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, Stmt **CatchStmts, unsigned NumCatchStmts, Stmt *atFinallyStmt) - : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), - NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) -{ + : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), + NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) { Stmt **Stmts = getStmts(); Stmts[0] = atTryStmt; for (unsigned I = 0; I != NumCatchStmts; ++I) @@ -732,13 +727,11 @@ } ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context, - SourceLocation atTryLoc, - Stmt *atTryStmt, - Stmt **CatchStmts, - unsigned NumCatchStmts, + SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, Stmt *atFinallyStmt) { unsigned Size = sizeof(ObjCAtTryStmt) + - (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); void *Mem = Context.Allocate(Size, llvm::alignOf()); return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, atFinallyStmt); @@ -747,8 +740,8 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(const ASTContext &Context, unsigned NumCatchStmts, bool HasFinally) { - unsigned Size = sizeof(ObjCAtTryStmt) + - (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + unsigned Size = + sizeof(ObjCAtTryStmt) + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); void *Mem = Context.Allocate(Size, llvm::alignOf()); return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); } @@ -762,7 +755,7 @@ } CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc, - Stmt *tryBlock, ArrayRef handlers) { + Stmt *tryBlock, ArrayRef handlers) { std::size_t Size = sizeof(CXXTryStmt); Size += ((handlers.size() + 1) * sizeof(Stmt)); @@ -780,8 +773,8 @@ } CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, - ArrayRef handlers) - : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) { + ArrayRef handlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) { Stmt **Stmts = reinterpret_cast(this + 1); Stmts[0] = tryBlock; std::copy(handlers.begin(), handlers.end(), Stmts + 1); @@ -791,7 +784,7 @@ Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, SourceLocation FL, SourceLocation CL, SourceLocation RPL) - : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { + : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { SubExprs[RANGE] = Range; SubExprs[BEGINEND] = BeginEndStmt; SubExprs[COND] = Cond; @@ -803,12 +796,12 @@ Expr *CXXForRangeStmt::getRangeInit() { DeclStmt *RangeStmt = getRangeStmt(); VarDecl *RangeDecl = dyn_cast_or_null(RangeStmt->getSingleDecl()); - assert(RangeDecl &&& "for-range should have a single var decl"); + assert(RangeDecl && &"for-range should have a single var decl"); return RangeDecl->getInit(); } const Expr *CXXForRangeStmt::getRangeInit() const { - return const_cast(this)->getRangeInit(); + return const_cast(this)->getRangeInit(); } VarDecl *CXXForRangeStmt::getLoopVariable() { @@ -818,13 +811,12 @@ } const VarDecl *CXXForRangeStmt::getLoopVariable() const { - return const_cast(this)->getLoopVariable(); + return const_cast(this)->getLoopVariable(); } IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL, Stmt *elsev) - : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) -{ + : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) { setConditionVariable(C, var); SubExprs[COND] = cond; SubExprs[THEN] = then; @@ -846,15 +838,14 @@ } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + SubExprs[VAR] = + new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) - : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) -{ + : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) { SubExprs[INIT] = Init; setConditionVariable(C, condVar); SubExprs[COND] = Cond; @@ -877,13 +868,12 @@ } SourceRange VarRange = V->getSourceRange(); - SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + SubExprs[CONDVAR] = + new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond) - : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) -{ + : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) { setConditionVariable(C, Var); SubExprs[COND] = cond; SubExprs[BODY] = NULL; @@ -904,8 +894,8 @@ } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + SubExprs[VAR] = + new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } Stmt *SwitchCase::getSubStmt() { @@ -916,7 +906,7 @@ WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) - : Stmt(WhileStmtClass) { + : Stmt(WhileStmtClass) { setConditionVariable(C, Var); SubExprs[COND] = cond; SubExprs[BODY] = body; @@ -1011,6 +1001,1354 @@ return new(C)SEHFinallyStmt(Loc,Block); } +StmtRange OMPClause::children() { + switch(getClauseKind()) { + default : break; +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : return static_cast(this)->children(); +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("unknown OMPClause"); +} + +void OMPPrivateClause::setDefaultInits(ArrayRef DefaultInits) { + assert(DefaultInits.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(DefaultInits.begin(), DefaultInits.end(), varlist_end()); +} + +OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL, + ArrayRef DefaultInits) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * 2 * VL.size()); + OMPPrivateClause *Clause = + new (Mem) OMPPrivateClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setDefaultInits(DefaultInits); + return Clause; +} + +OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * 2 * N); + return new (Mem) OMPPrivateClause(N); +} + +void OMPFirstPrivateClause::setPseudoVars(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), varlist_end()); +} + +void OMPFirstPrivateClause::setInits(ArrayRef Inits) { + assert(Inits.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(Inits.begin(), Inits.end(), getPseudoVars().end()); +} + +OMPFirstPrivateClause * +OMPFirstPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef PseudoVars, + ArrayRef Inits) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 3); + OMPFirstPrivateClause *Clause = + new (Mem) OMPFirstPrivateClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setPseudoVars(PseudoVars); + Clause->setInits(Inits); + return Clause; +} + +OMPFirstPrivateClause *OMPFirstPrivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * N * 3); + return new (Mem) OMPFirstPrivateClause(N); +} + +void OMPLastPrivateClause::setPseudoVars1(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), varlist_end()); +} + +void OMPLastPrivateClause::setPseudoVars2(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), getPseudoVars1().end()); +} + +void OMPLastPrivateClause::setDefaultInits(ArrayRef DefaultInits) { + assert(DefaultInits.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(DefaultInits.begin(), DefaultInits.end(), getPseudoVars2().end()); +} + +void OMPLastPrivateClause::setAssignments(ArrayRef Assignments) { + assert(Assignments.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(Assignments.begin(), Assignments.end(), getDefaultInits().end()); +} + +OMPLastPrivateClause *OMPLastPrivateClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars1, + ArrayRef PseudoVars2, ArrayRef Assignments) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 5); + OMPLastPrivateClause *Clause = + new (Mem) OMPLastPrivateClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setPseudoVars1(PseudoVars1); + Clause->setPseudoVars2(PseudoVars2); + Clause->setAssignments(Assignments); + llvm::SmallVector DefaultInits(VL.size(), 0); + Clause->setDefaultInits(DefaultInits); + return Clause; +} + +OMPLastPrivateClause *OMPLastPrivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * N * 5); + return new (Mem) OMPLastPrivateClause(N); +} + +OMPSharedClause *OMPSharedClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size()); + OMPSharedClause *Clause = + new (Mem) OMPSharedClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + return Clause; +} + +OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause), + llvm::alignOf()) + + sizeof(Expr *) * N); + return new (Mem) OMPSharedClause(N); +} + +void OMPCopyinClause::setPseudoVars1(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), varlist_end()); +} + +void OMPCopyinClause::setPseudoVars2(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), getPseudoVars1().end()); +} + +void OMPCopyinClause::setAssignments(ArrayRef Assignments) { + assert(Assignments.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(Assignments.begin(), Assignments.end(), getPseudoVars2().end()); +} + +OMPCopyinClause *OMPCopyinClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars1, + ArrayRef PseudoVars2, ArrayRef Assignments) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 4); + OMPCopyinClause *Clause = + new (Mem) OMPCopyinClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setPseudoVars1(PseudoVars1); + Clause->setPseudoVars2(PseudoVars2); + Clause->setAssignments(Assignments); + return Clause; +} + +OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), + llvm::alignOf()) + + sizeof(Expr *) * N * 4); + return new (Mem) OMPCopyinClause(N); +} + +void OMPCopyPrivateClause::setPseudoVars1(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), + varlist_end()); +} + +void OMPCopyPrivateClause::setPseudoVars2(ArrayRef PseudoVars) { + assert(PseudoVars.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(PseudoVars.begin(), PseudoVars.end(), + getPseudoVars1().end()); +} + +void OMPCopyPrivateClause::setAssignments(ArrayRef Assignments) { + assert(Assignments.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(Assignments.begin(), Assignments.end(), + getPseudoVars2().end()); +} + +OMPCopyPrivateClause *OMPCopyPrivateClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PseudoVars1, + ArrayRef PseudoVars2, ArrayRef Assignments) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 4); + OMPCopyPrivateClause *Clause = + new (Mem) OMPCopyPrivateClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setPseudoVars1(PseudoVars1); + Clause->setPseudoVars2(PseudoVars2); + Clause->setAssignments(Assignments); + return Clause; +} + +OMPCopyPrivateClause *OMPCopyPrivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyPrivateClause), + llvm::alignOf()) + + sizeof(Expr *) * N * 4); + return new (Mem) OMPCopyPrivateClause(N); +} + +OMPReductionClause *OMPReductionClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef OpExprs, + ArrayRef HelperParams1, ArrayRef HelperParams2, + ArrayRef DefaultInits, OpenMPReductionClauseOperator Op, + NestedNameSpecifierLoc S, DeclarationNameInfo OpName) { + assert(VL.size() == OpExprs.size() && + "Number of expressions is not the same as number of variables!"); + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), + llvm::alignOf()) + + 5 * sizeof(Expr *) * VL.size()); + OMPReductionClause *Clause = + new (Mem) OMPReductionClause(StartLoc, EndLoc, VL.size(), Op, S, OpName); + Clause->setVars(VL); + Clause->setOpExprs(OpExprs); + Clause->setHelperParameters1st(HelperParams1); + Clause->setHelperParameters2nd(HelperParams2); + Clause->setDefaultInits(DefaultInits); + return Clause; +} + +OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), + llvm::alignOf()) + + 5 * sizeof(Expr *) * N); + return new (Mem) OMPReductionClause(N); +} + +void OMPReductionClause::setOpExprs(ArrayRef OpExprs) { + assert(OpExprs.size() == numberOfVariables() && + "Number of expressions is not the same as the number of variables."); + std::copy(OpExprs.begin(), OpExprs.end(), varlist_end()); +} + +void OMPReductionClause::setHelperParameters1st(ArrayRef HelperParams) { + assert(HelperParams.size() == numberOfVariables() && + "Number of expressions is not the same as the number of variables."); + std::copy(HelperParams.begin(), HelperParams.end(), getOpExprs().end()); +} + +void OMPReductionClause::setHelperParameters2nd(ArrayRef HelperParams) { + assert(HelperParams.size() == numberOfVariables() && + "Number of expressions is not the same as the number of variables."); + std::copy(HelperParams.begin(), HelperParams.end(), + getHelperParameters1st().end()); +} + +void OMPReductionClause::setDefaultInits(ArrayRef DefaultInits) { + assert(DefaultInits.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(DefaultInits.begin(), DefaultInits.end(), + getHelperParameters2nd().end()); +} + +void +OMPMapClause::setWholeStartAddresses(ArrayRef WholeStartAddresses) { + assert(WholeStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeStartAddresses.begin(), WholeStartAddresses.end(), + varlist_end()); +} + +void OMPMapClause::setWholeSizesEndAddresses( + ArrayRef WholeSizesEndAddresses) { + assert(WholeSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeSizesEndAddresses.begin(), WholeSizesEndAddresses.end(), + getWholeStartAddresses().end()); +} + +void +OMPMapClause::setCopyingStartAddresses(ArrayRef CopyingStartAddresses) { + assert(CopyingStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingStartAddresses.begin(), CopyingStartAddresses.end(), + getWholeSizesEndAddresses().end()); +} + +void OMPMapClause::setCopyingSizesEndAddresses( + ArrayRef CopyingSizesEndAddresses) { + assert(CopyingSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingSizesEndAddresses.begin(), CopyingSizesEndAddresses.end(), + getCopyingStartAddresses().end()); +} + +OMPMapClause *OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses, + OpenMPMapClauseKind Kind, + SourceLocation KindLoc) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPMapClause), llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 5); + OMPMapClause *Clause = + new (Mem) OMPMapClause(StartLoc, EndLoc, VL.size(), Kind, KindLoc); + Clause->setVars(VL); + Clause->setWholeStartAddresses(WholeStartAddresses); + Clause->setWholeSizesEndAddresses(WholeSizesEndAddresses); + Clause->setCopyingStartAddresses(CopyingStartAddresses); + Clause->setCopyingSizesEndAddresses(CopyingSizesEndAddresses); + Clause->setKind(Kind); + Clause->setKindLoc(KindLoc); + return Clause; +} + +OMPMapClause *OMPMapClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPMapClause), llvm::alignOf()) + + sizeof(Expr *) * N * 5); + return new (Mem) OMPMapClause(N); +} + +void OMPToClause::setWholeStartAddresses(ArrayRef WholeStartAddresses) { + assert(WholeStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeStartAddresses.begin(), WholeStartAddresses.end(), + varlist_end()); +} + +void OMPToClause::setWholeSizesEndAddresses( + ArrayRef WholeSizesEndAddresses) { + assert(WholeSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeSizesEndAddresses.begin(), WholeSizesEndAddresses.end(), + getWholeStartAddresses().end()); +} + +void +OMPToClause::setCopyingStartAddresses(ArrayRef CopyingStartAddresses) { + assert(CopyingStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingStartAddresses.begin(), CopyingStartAddresses.end(), + getWholeSizesEndAddresses().end()); +} + +void OMPToClause::setCopyingSizesEndAddresses( + ArrayRef CopyingSizesEndAddresses) { + assert(CopyingSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingSizesEndAddresses.begin(), CopyingSizesEndAddresses.end(), + getCopyingStartAddresses().end()); +} + +OMPToClause *OMPToClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPToClause), llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 5); + OMPToClause *Clause = new (Mem) OMPToClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setWholeStartAddresses(WholeStartAddresses); + Clause->setWholeSizesEndAddresses(WholeSizesEndAddresses); + Clause->setCopyingStartAddresses(CopyingStartAddresses); + Clause->setCopyingSizesEndAddresses(CopyingSizesEndAddresses); + return Clause; +} + +OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPToClause), llvm::alignOf()) + + sizeof(Expr *) * N * 5); + return new (Mem) OMPToClause(N); +} + +void +OMPFromClause::setWholeStartAddresses(ArrayRef WholeStartAddresses) { + assert(WholeStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeStartAddresses.begin(), WholeStartAddresses.end(), + varlist_end()); +} + +void OMPFromClause::setWholeSizesEndAddresses( + ArrayRef WholeSizesEndAddresses) { + assert(WholeSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(WholeSizesEndAddresses.begin(), WholeSizesEndAddresses.end(), + getWholeStartAddresses().end()); +} + +void OMPFromClause::setCopyingStartAddresses( + ArrayRef CopyingStartAddresses) { + assert(CopyingStartAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingStartAddresses.begin(), CopyingStartAddresses.end(), + getWholeSizesEndAddresses().end()); +} + +void OMPFromClause::setCopyingSizesEndAddresses( + ArrayRef CopyingSizesEndAddresses) { + assert(CopyingSizesEndAddresses.size() == varlist_size() && + "Number of vars is not the same as the preallocated buffer"); + std::copy(CopyingSizesEndAddresses.begin(), CopyingSizesEndAddresses.end(), + getCopyingStartAddresses().end()); +} + +OMPFromClause * +OMPFromClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef WholeStartAddresses, + ArrayRef WholeSizesEndAddresses, + ArrayRef CopyingStartAddresses, + ArrayRef CopyingSizesEndAddresses) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPFromClause), llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 5); + OMPFromClause *Clause = new (Mem) OMPFromClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + Clause->setWholeStartAddresses(WholeStartAddresses); + Clause->setWholeSizesEndAddresses(WholeSizesEndAddresses); + Clause->setCopyingStartAddresses(CopyingStartAddresses); + Clause->setCopyingSizesEndAddresses(CopyingSizesEndAddresses); + return Clause; +} + +OMPFromClause *OMPFromClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPFromClause), llvm::alignOf()) + + sizeof(Expr *) * N * 5); + return new (Mem) OMPFromClause(N); +} + +OMPFlushClause *OMPFlushClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size()); + OMPFlushClause *Clause = + new (Mem) OMPFlushClause(StartLoc, EndLoc, VL.size()); + Clause->setVars(VL); + return Clause; +} + +OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause), + llvm::alignOf()) + + sizeof(Expr *) * N); + return new (Mem) OMPFlushClause(N); +} + +OMPDependClause * +OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef VL, + ArrayRef Begins, ArrayRef SizeInBytes, + OpenMPDependClauseType Ty, SourceLocation TyLoc) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() * 3); + OMPDependClause *Clause = + new (Mem) OMPDependClause(StartLoc, EndLoc, VL.size(), Ty, TyLoc); + Clause->setVars(VL); + Clause->setBegins(Begins); + Clause->setSizeInBytes(SizeInBytes); + return Clause; +} + +OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDependClause), + llvm::alignOf()) + + sizeof(Expr *) * N * 3); + OMPDependClause *Clause = new (Mem) OMPDependClause(N); + return Clause; +} + +void OMPDependClause::setBegins(ArrayRef Begins) { + assert(Begins.size() == varlist_size() && + "Number of exprs is not the same as the preallocated buffer"); + std::copy(Begins.begin(), Begins.end(), varlist_end()); +} + +void OMPDependClause::setSizeInBytes(ArrayRef SizeInBytes) { + assert(SizeInBytes.size() == varlist_size() && + "Number of exprs is not the same as the preallocated buffer"); + std::copy(SizeInBytes.begin(), SizeInBytes.end(), + varlist_end() + varlist_size()); +} + +Expr *OMPDependClause::getBegins(unsigned Index) { + assert(Index < varlist_size() && + "Index greter or equal maximum number of expressions."); + return varlist_end()[Index]; +} + +Expr *OMPDependClause::getSizeInBytes(unsigned Index) { + assert(Index < varlist_size() && + "Index greter or equal maximum number of expressions."); + return varlist_end()[varlist_size() + Index]; +} + +OMPUniformClause *OMPUniformClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPUniformClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size()); + OMPUniformClause *Clause = new (Mem) OMPUniformClause(StartLoc, + EndLoc, + VL.size()); + Clause->setVars(VL); + return Clause; +} + +OMPUniformClause * +OMPUniformClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPUniformClause), + llvm::alignOf()) + + sizeof(Expr *) * N); + return new (Mem) OMPUniformClause(N); +} + +OMPLinearClause *OMPLinearClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL, Expr *St, + SourceLocation StLoc) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() + sizeof(Expr *)); + OMPLinearClause *Clause = + new (Mem) OMPLinearClause(StartLoc, EndLoc, VL.size(), StLoc); + Clause->setVars(VL); + Clause->setStep(St); + return Clause; +} + +OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause), + llvm::alignOf()) + + sizeof(Expr *) * (N + 1)); + return new (Mem) OMPLinearClause(N); +} + +OMPAlignedClause *OMPAlignedClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef VL, + Expr *A, + SourceLocation ALoc) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause), + llvm::alignOf()) + + sizeof(Expr *) * VL.size() + + sizeof(Expr *)); + OMPAlignedClause *Clause = new (Mem) OMPAlignedClause(StartLoc, + EndLoc, + VL.size(), + ALoc); + Clause->setVars(VL); + Clause->setAlignment(A); + return Clause; +} + +OMPAlignedClause * +OMPAlignedClause::CreateEmpty(const ASTContext &C, unsigned N) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause), + llvm::alignOf()) + + sizeof(Expr *) * (N + 1)); + return new (Mem) OMPAlignedClause(N); +} + +void OMPExecutableDirective::setClauses(ArrayRef CL) { + assert(CL.size() == NumClauses && + "Number of clauses is not the same as the preallocated buffer"); + std::copy(CL.begin(), CL.end(), Clauses); +} + +OMPParallelDirective *OMPParallelDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPParallelDirective *Dir = + new (Mem) OMPParallelDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPParallelDirective * +OMPParallelDirective::CreateEmpty(const ASTContext &C, unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPParallelDirective(N); +} + +OMPForDirective *OMPForDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPForDirective *Dir = new (Mem) + OMPForDirective(StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPForDirective *OMPForDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPForDirective(CollapsedNum, N); +} + +OMPParallelForDirective *OMPParallelForDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPParallelForDirective *Dir = new (Mem) + OMPParallelForDirective(StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPParallelForDirective * +OMPParallelForDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPParallelForDirective(CollapsedNum, N); +} + +OMPSimdDirective *OMPSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPSimdDirective *Dir = new (Mem) + OMPSimdDirective(StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum, + llvm::alignOf()); + return new (Mem) OMPSimdDirective(CollapsedNum, N); +} + +OMPForSimdDirective *OMPForSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPForSimdDirective *Dir = new (Mem) + OMPForSimdDirective(StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPForSimdDirective *OMPForSimdDirective::CreateEmpty(const ASTContext &C, + unsigned N, + unsigned CollapsedNum, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPForSimdDirective(CollapsedNum, N); +} + +OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPParallelForSimdDirective *Dir = new (Mem) OMPParallelForSimdDirective( + StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPParallelForSimdDirective * +OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPParallelForSimdDirective(CollapsedNum, N); +} + +OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDistributeSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPDistributeSimdDirective *Dir = new (Mem) OMPDistributeSimdDirective( + StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPDistributeSimdDirective * +OMPDistributeSimdDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDistributeSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPDistributeSimdDirective(CollapsedNum, N); +} + +OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, Expr *LowerBound, + Expr *UpperBound, ArrayRef VarCnts) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPDistributeParallelForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 7 + + sizeof(Stmt *) * VarCnts.size() + 2); + OMPDistributeParallelForDirective *Dir = new (Mem) + OMPDistributeParallelForDirective(StartLoc, EndLoc, VarCnts.size(), + Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setLowerBound(LowerBound); + Dir->setUpperBound(UpperBound); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPDistributeParallelForDirective * +OMPDistributeParallelForDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, + EmptyShell) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPDistributeParallelForDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 7 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPDistributeParallelForDirective(CollapsedNum, N); +} + +OMPDistributeParallelForSimdDirective * +OMPDistributeParallelForSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, Expr *LowerBound, + Expr *UpperBound, ArrayRef VarCnts) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPDistributeParallelForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 7 + + sizeof(Stmt *) * VarCnts.size() + 2); + OMPDistributeParallelForSimdDirective *Dir = new (Mem) + OMPDistributeParallelForSimdDirective(StartLoc, EndLoc, VarCnts.size(), + Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setLowerBound(LowerBound); + Dir->setUpperBound(UpperBound); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPDistributeParallelForSimdDirective * +OMPDistributeParallelForSimdDirective::CreateEmpty(const ASTContext &C, + unsigned N, + unsigned CollapsedNum, + EmptyShell) { + void *Mem = C.Allocate( + llvm::RoundUpToAlignment(sizeof(OMPDistributeParallelForSimdDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 7 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPDistributeParallelForSimdDirective(CollapsedNum, N); +} + +OMPSectionsDirective *OMPSectionsDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPSectionsDirective *Dir = + new (Mem) OMPSectionsDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPSectionsDirective * +OMPSectionsDirective::CreateEmpty(const ASTContext &C, unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPSectionsDirective(N); +} + +OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPParallelSectionsDirective *Dir = + new (Mem) OMPParallelSectionsDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPParallelSectionsDirective * +OMPParallelSectionsDirective::CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPParallelSectionsDirective(N); +} + +OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSectionDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + OMPSectionDirective *Dir = new (Mem) OMPSectionDirective(StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPSectionDirective *OMPSectionDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSectionDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + return new (Mem) OMPSectionDirective(); +} + +OMPSingleDirective *OMPSingleDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSingleDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPSingleDirective *Dir = + new (Mem) OMPSingleDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPSingleDirective *OMPSingleDirective::CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSingleDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPSingleDirective(N); +} + +OMPTaskDirective *OMPTaskDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTaskDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTaskDirective *Dir = + new (Mem) OMPTaskDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTaskDirective *OMPTaskDirective::CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTaskDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPTaskDirective(N); +} + +OMPTaskyieldDirective *OMPTaskyieldDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OMPTaskyieldDirective), + llvm::alignOf()); + return new (Mem) OMPTaskyieldDirective(StartLoc, EndLoc); +} + +OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPTaskyieldDirective), + llvm::alignOf()); + return new (Mem) OMPTaskyieldDirective(); +} + +OMPMasterDirective *OMPMasterDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPMasterDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + OMPMasterDirective *Dir = new (Mem) OMPMasterDirective(StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPMasterDirective *OMPMasterDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPMasterDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + return new (Mem) OMPMasterDirective(); +} + +OMPCriticalDirective *OMPCriticalDirective::Create(const ASTContext &C, + DeclarationNameInfo Name, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + OMPCriticalDirective *Dir = + new (Mem) OMPCriticalDirective(Name, StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setDirectiveName(Name); + return Dir; +} + +OMPCriticalDirective *OMPCriticalDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + return new (Mem) OMPCriticalDirective(); +} + +OMPBarrierDirective *OMPBarrierDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OMPBarrierDirective), + llvm::alignOf()); + return new (Mem) OMPBarrierDirective(StartLoc, EndLoc); +} + +OMPBarrierDirective *OMPBarrierDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPBarrierDirective), + llvm::alignOf()); + return new (Mem) OMPBarrierDirective(); +} + +OMPTaskwaitDirective *OMPTaskwaitDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OMPTaskwaitDirective), + llvm::alignOf()); + return new (Mem) OMPTaskwaitDirective(StartLoc, EndLoc); +} + +OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPTaskwaitDirective), + llvm::alignOf()); + return new (Mem) OMPTaskwaitDirective(); +} + +OMPTaskgroupDirective *OMPTaskgroupDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + OMPTaskgroupDirective *Dir = + new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTaskgroupDirective *OMPTaskgroupDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTaskgroupDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + return new (Mem) OMPTaskgroupDirective(); +} + +OMPAtomicDirective *OMPAtomicDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *V, Expr *X, + Expr *OpExpr, BinaryOperatorKind Op, bool CaptureAfter, bool Reversed) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 4); + OMPAtomicDirective *Dir = + new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setOperator(Op); + Dir->setV(V); + Dir->setX(X); + Dir->setExpr(OpExpr); + Dir->setCaptureAfter(CaptureAfter); + Dir->setReversed(Reversed); + return Dir; +} + +OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 4); + return new (Mem) OMPAtomicDirective(N); +} + +OMPFlushDirective *OMPFlushDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size()); + OMPFlushDirective *Dir = + new (Mem) OMPFlushDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + return Dir; +} + +OMPFlushDirective *OMPFlushDirective::CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N); + return new (Mem) OMPFlushDirective(N); +} + +OMPOrderedDirective *OMPOrderedDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + OMPOrderedDirective *Dir = new (Mem) OMPOrderedDirective(StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + llvm::alignOf()) + + sizeof(Stmt *)); + return new (Mem) OMPOrderedDirective(); +} + +OMPTeamsDirective *OMPTeamsDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTeamsDirective *Dir = + new (Mem) OMPTeamsDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTeamsDirective *OMPTeamsDirective::CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPTeamsDirective(N); +} + +OMPDistributeDirective *OMPDistributeDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt, Expr *NewIterVar, + Expr *NewIterEnd, Expr *Init, Expr *Final, ArrayRef VarCnts) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDistributeDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * VarCnts.size()); + OMPDistributeDirective *Dir = new (Mem) + OMPDistributeDirective(StartLoc, EndLoc, VarCnts.size(), Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setNewIterVar(NewIterVar); + Dir->setNewIterEnd(NewIterEnd); + Dir->setInit(Init); + Dir->setFinal(Final); + Dir->setCounters(VarCnts); + return Dir; +} + +OMPDistributeDirective * +OMPDistributeDirective::CreateEmpty(const ASTContext &C, unsigned N, + unsigned CollapsedNum, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPDistributeDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *) * 5 + + sizeof(Stmt *) * CollapsedNum); + return new (Mem) OMPDistributeDirective(CollapsedNum, N); +} + +OMPCancelDirective * +OMPCancelDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef Clauses, + OpenMPDirectiveKind ConstructType) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size()); + OMPCancelDirective *Dir = new (Mem) + OMPCancelDirective(StartLoc, EndLoc, Clauses.size(), ConstructType); + Dir->setClauses(Clauses); + return Dir; +} + +OMPCancelDirective * +OMPCancelDirective::CreateEmpty(const ASTContext &C, unsigned N, + OpenMPDirectiveKind ConstructType, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCancelDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N); + return new (Mem) OMPCancelDirective(N, ConstructType); +} + +OMPCancellationPointDirective *OMPCancellationPointDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType) { + void *Mem = C.Allocate(sizeof(OMPCancellationPointDirective), + llvm::alignOf()); + OMPCancellationPointDirective *Dir = + new (Mem) OMPCancellationPointDirective(StartLoc, EndLoc, ConstructType); + return Dir; +} + +OMPCancellationPointDirective *OMPCancellationPointDirective::CreateEmpty( + const ASTContext &C, OpenMPDirectiveKind ConstructType, EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPCancellationPointDirective), + llvm::alignOf()); + return new (Mem) OMPCancellationPointDirective(ConstructType); +} + +OMPTargetDirective *OMPTargetDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTargetDirective *Dir = + new (Mem) OMPTargetDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTargetDirective *OMPTargetDirective::CreateEmpty(const ASTContext &C, + unsigned N, EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPTargetDirective(N); +} + +OMPTargetDataDirective *OMPTargetDataDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTargetDataDirective *Dir = + new (Mem) OMPTargetDataDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTargetDataDirective *OMPTargetDataDirective::CreateEmpty(const ASTContext &C, + unsigned N, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetDataDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPTargetDataDirective(N); +} + CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const { unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); @@ -1023,13 +2361,61 @@ + FirstCaptureOffset); } +OMPTargetUpdateDirective * +OMPTargetUpdateDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetUpdateDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size()); + OMPTargetUpdateDirective *Dir = + new (Mem) OMPTargetUpdateDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + return Dir; +} + +OMPTargetUpdateDirective * +OMPTargetUpdateDirective::CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetUpdateDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N); + return new (Mem) OMPTargetUpdateDirective(N); +} + +OMPTargetTeamsDirective *OMPTargetTeamsDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *AssociatedStmt) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetTeamsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTargetTeamsDirective *Dir = + new (Mem) OMPTargetTeamsDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTargetTeamsDirective * +OMPTargetTeamsDirective::CreateEmpty(const ASTContext &C, unsigned N, + EmptyShell) { + void *Mem = + C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPTargetTeamsDirective), + llvm::alignOf()) + + sizeof(OMPClause *) * N + sizeof(Stmt *)); + return new (Mem) OMPTargetTeamsDirective(N); +} + CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind, ArrayRef Captures, ArrayRef CaptureInits, CapturedDecl *CD, RecordDecl *RD) : Stmt(CapturedStmtClass), NumCaptures(Captures.size()), - CapDeclAndKind(CD, Kind), TheRecordDecl(RD) { + TheCapturedDecl(CD), RegionKind(Kind), TheRecordDecl(RD) { assert( S && "null captured statement"); assert(CD && "null captured declaration for captured statement"); assert(RD && "null record declaration for captured statement"); @@ -1048,8 +2434,8 @@ } CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) - : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), - CapDeclAndKind(0, CR_Default), TheRecordDecl(0) { + : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), + TheCapturedDecl(0), RegionKind(CR_Default), TheRecordDecl(0) { getStoredStmts()[NumCaptures] = 0; } @@ -1057,8 +2443,7 @@ CapturedRegionKind Kind, ArrayRef Captures, ArrayRef CaptureInits, - CapturedDecl *CD, - RecordDecl *RD) { + CapturedDecl *CD, RecordDecl *RD) { // The layout is // // ----------------------------------------------------------- @@ -1100,8 +2485,8 @@ } bool CapturedStmt::capturesVariable(const VarDecl *Var) const { - for (const_capture_iterator I = capture_begin(), - E = capture_end(); I != E; ++I) { + for (const_capture_iterator I = capture_begin(), E = capture_end(); I != E; + ++I) { if (!I->capturesVariable()) continue; @@ -1115,106 +2500,3 @@ return false; } -StmtRange OMPClause::children() { - switch(getClauseKind()) { - default : break; -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_ ## Name : return static_cast(this)->children(); -#include "clang/Basic/OpenMPKinds.def" - } - llvm_unreachable("unknown OMPClause"); -} - -OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { - void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(), - llvm::alignOf()); - OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, - EndLoc, VL.size()); - Clause->setVarRefs(VL); - return Clause; -} - -OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, - unsigned N) { - void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N, - llvm::alignOf()); - return new (Mem) OMPPrivateClause(N); -} - -OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { - void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + - sizeof(Expr *) * VL.size(), - llvm::alignOf()); - 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()); - return new (Mem) OMPFirstprivateClause(N); -} - -OMPSharedClause *OMPSharedClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { - void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * VL.size(), - llvm::alignOf()); - OMPSharedClause *Clause = new (Mem) OMPSharedClause(StartLoc, LParenLoc, - EndLoc, VL.size()); - Clause->setVarRefs(VL); - return Clause; -} - -OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, - unsigned N) { - void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * N, - llvm::alignOf()); - return new (Mem) OMPSharedClause(N); -} - -void OMPExecutableDirective::setClauses(ArrayRef Clauses) { - assert(Clauses.size() == this->Clauses.size() && - "Number of clauses is not the same as the preallocated buffer"); - std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin()); -} - -OMPParallelDirective *OMPParallelDirective::Create( - const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc, - ArrayRef Clauses, - Stmt *AssociatedStmt) { - void *Mem = C.Allocate(sizeof(OMPParallelDirective) + - sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *), - llvm::alignOf()); - OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc, - Clauses.size()); - Dir->setClauses(Clauses); - Dir->setAssociatedStmt(AssociatedStmt); - return Dir; -} - -OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C, - unsigned N, - EmptyShell) { - void *Mem = C.Allocate(sizeof(OMPParallelDirective) + - sizeof(OMPClause *) * N + sizeof(Stmt *), - llvm::alignOf()); - return new (Mem) OMPParallelDirective(N); -} diff -uNr clang-3.4/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtPrinter.cpp --- clang-3.4/lib/AST/StmtPrinter.cpp 2013-11-06 18:31:56.000000000 -0500 +++ clang/lib/AST/StmtPrinter.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -32,6 +32,7 @@ namespace { class StmtPrinter : public StmtVisitor { + friend class OMPClausePrinter; raw_ostream &OS; unsigned IndentLevel; clang::PrinterHelper* Helper; @@ -102,6 +103,7 @@ #define STMT(CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); #include "clang/AST/StmtNodes.inc" + void VisitOMPExecutableDirective(OMPExecutableDirective *Node); }; } @@ -584,45 +586,84 @@ //===----------------------------------------------------------------------===// namespace { + +/// \brief OMPClausePrinter class implements clause printing. +/// It is used by OMPClause::printPretty(). class OMPClausePrinter : public OMPClauseVisitor { raw_ostream &OS; - /// \brief Process clauses with list of variables. - template - void VisitOMPClauseList(T *Node, char StartSym); + const PrintingPolicy &Policy; + public: - OMPClausePrinter(raw_ostream &OS) : OS(OS) { } -#define OPENMP_CLAUSE(Name, Class) \ - void Visit##Class(Class *S); + OMPClausePrinter(raw_ostream &OS, const PrintingPolicy &P) + : OS(OS), Policy(P) {} +#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *S); #include "clang/Basic/OpenMPKinds.def" }; +void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) { + OS << "if("; + Node->getCondition()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) { + OS << "num_threads("; + Node->getNumThreads()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPFinalClause(OMPFinalClause *Node) { + OS << "final("; + Node->getCondition()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) { + OS << "collapse("; + Node->getNumForLoops()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPDeviceClause(OMPDeviceClause *Node) { + OS << "device("; + Node->getDevice()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { OS << "default(" << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind()) << ")"; } -template -void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { - for (typename T::varlist_iterator I = Node->varlist_begin(), - E = Node->varlist_end(); - I != E; ++I) - OS << (I == Node->varlist_begin() ? StartSym : ',') - << *cast(cast(*I)->getDecl()); +void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) { + OS << "proc_bind(" + << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getThreadAffinity()) + << ")"; } void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { if (!Node->varlist_empty()) { OS << "private"; - VisitOMPClauseList(Node, '('); + for (OMPPrivateClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } OS << ")"; } } -void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) { +void OMPClausePrinter::VisitOMPFirstPrivateClause(OMPFirstPrivateClause *Node) { if (!Node->varlist_empty()) { OS << "firstprivate"; - VisitOMPClauseList(Node, '('); + for (OMPFirstPrivateClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } OS << ")"; } } @@ -630,36 +671,485 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { if (!Node->varlist_empty()) { OS << "shared"; - VisitOMPClauseList(Node, '('); + for (OMPSharedClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) { + if (!Node->varlist_empty()) { + OS << "copyin"; + for (OMPCopyinClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPCopyPrivateClause(OMPCopyPrivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "copyprivate"; + for (OMPCopyinClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { + if (!Node->varlist_empty()) { + OS << "reduction("; + if (Node->getOperator() == OMPC_REDUCTION_custom) { + if (NestedNameSpecifier *Qual = Node->getSpec().getNestedNameSpecifier()) + Qual->print(OS, Policy); + OS << Node->getOpName(); + } else { + OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getOperator()); + } + OS << ':'; + + for (OMPReductionClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? ' ' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPLastPrivateClause(OMPLastPrivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "lastprivate"; + for (OMPLastPrivateClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) { + if (!Node->varlist_empty()) { + OS << "map("; + OS << getOpenMPSimpleClauseTypeName(OMPC_map, Node->getKind()); + OS << ':'; + + for (OMPMapClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? ' ' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) { + if (!Node->varlist_empty()) { + OS << "to"; + for (OMPToClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPFromClause(OMPFromClause *Node) { + if (!Node->varlist_empty()) { + OS << "from"; + for (OMPFromClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } OS << ")"; } } +void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) { + OS << "schedule(" + << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind()); + if (Node->getChunkSize()) { + OS << ", "; + Node->getChunkSize()->printPretty(OS, 0, Policy, 0); + } + OS << ")"; +} + +void OMPClausePrinter::VisitOMPDistScheduleClause(OMPDistScheduleClause *Node) { + OS << "dist_schedule(" + << getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, + Node->getDistScheduleKind()); + if (Node->getDistChunkSize()) { + OS << ", "; + Node->getDistChunkSize()->printPretty(OS, 0, Policy, 0); + } + OS << ")"; +} + +void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *Node) { + OS << "ordered"; +} + +void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *Node) { + OS << "nowait"; +} + +void OMPClausePrinter::VisitOMPUntiedClause(OMPUntiedClause *Node) { + OS << "untied"; +} + +void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *Node) { + OS << "mergeable"; +} + +void OMPClausePrinter::VisitOMPReadClause(OMPReadClause *Node) { OS << "read"; } + +void OMPClausePrinter::VisitOMPWriteClause(OMPWriteClause *Node) { + OS << "write"; +} + +void OMPClausePrinter::VisitOMPUpdateClause(OMPUpdateClause *Node) { + OS << "update"; +} + +void OMPClausePrinter::VisitOMPCaptureClause(OMPCaptureClause *Node) { + OS << "capture"; +} + +void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *Node) { + OS << "seq_cst"; +} + +void OMPClausePrinter::VisitOMPInBranchClause(OMPInBranchClause *Node) { + OS << "inbranch"; +} + +void OMPClausePrinter::VisitOMPNotInBranchClause(OMPNotInBranchClause *Node) { + OS << "notinbranch"; +} + +void OMPClausePrinter::VisitOMPFlushClause(OMPFlushClause *Node) { + if (!Node->varlist_empty()) { + for (OMPFlushClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) { + if (!Node->varlist_empty()) { + OS << "depend("; + OS << getOpenMPSimpleClauseTypeName(OMPC_depend, Node->getType()); + OS << ':'; + + for (OMPDependClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? ' ' : ','); + /// static_cast(Printer)->PrintExpr(*I); + (*I)->printPretty(OS, 0, Policy, 0); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPUniformClause(OMPUniformClause *Node) { + if (!Node->varlist_empty()) { + OS << "uniform"; + for (OMPUniformClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) { + OS << "safelen("; + Node->getSafelen()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) { + OS << "simdlen("; + Node->getSimdlen()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPNumTeamsClause(OMPNumTeamsClause *Node) { + OS << "num_teams("; + Node->getNumTeams()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPThreadLimitClause(OMPThreadLimitClause *Node) { + OS << "thread_limit("; + Node->getThreadLimit()->printPretty(OS, 0, Policy, 0); + OS << ")"; +} + +void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) { + if (!Node->varlist_empty()) { + OS << "linear"; + for (OMPLinearClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + if (Node->getStep() != 0) { + OS << ": "; + Node->getStep()->printPretty(OS, 0, Policy, 0); + } + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPAlignedClause(OMPAlignedClause *Node) { + if (!Node->varlist_empty()) { + OS << "aligned"; + for (OMPAlignedClause::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) { + OS << (I == Node->varlist_begin() ? '(' : ',') + << *cast(cast(*I)->getDecl()); + } + if (Node->getAlignment() != 0) { + OS << ": "; + Node->getAlignment()->printPretty(OS, 0, Policy, 0); + } + OS << ")"; + } +} +} + +void OMPClause::printPretty(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation) const { + if (this == 0) { + OS << ""; + return; + } + + OMPClausePrinter P(OS, Policy); + P.Visit(const_cast(this)); } //===----------------------------------------------------------------------===// // OpenMP directives printing methods //===----------------------------------------------------------------------===// -void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { - Indent() << "#pragma omp parallel "; - - OMPClausePrinter Printer(OS); +void StmtPrinter::VisitOMPExecutableDirective(OMPExecutableDirective *Node) { ArrayRef Clauses = Node->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) if (*I && !(*I)->isImplicit()) { - Printer.Visit(*I); + const OMPClause *CurCL = cast_or_null(*I); + CurCL->printPretty(OS, Helper, Policy, IndentLevel); OS << ' '; } OS << "\n"; - if (Node->getAssociatedStmt()) { + if (Node->hasAssociatedStmt() && Node->getAssociatedStmt()) { assert(isa(Node->getAssociatedStmt()) && "Expected captured statement!"); Stmt *CS = cast(Node->getAssociatedStmt())->getCapturedStmt(); PrintStmt(CS); } } + +void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { + Indent() << "#pragma omp parallel "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) { + Indent() << "#pragma omp parallel for "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPParallelForSimdDirective( + OMPParallelForSimdDirective *Node) { + Indent() << "#pragma omp parallel for simd "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { + Indent() << "#pragma omp for "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) { + Indent() << "#pragma omp sections "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPParallelSectionsDirective( + OMPParallelSectionsDirective *Node) { + Indent() << "#pragma omp parallel sections "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPSectionDirective(OMPSectionDirective *Node) { + Indent() << "#pragma omp section"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPSingleDirective(OMPSingleDirective *Node) { + Indent() << "#pragma omp single "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTaskDirective(OMPTaskDirective *Node) { + Indent() << "#pragma omp task "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *Node) { + Indent() << "#pragma omp taskyield"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPMasterDirective(OMPMasterDirective *Node) { + Indent() << "#pragma omp master"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) { + Indent() << "#pragma omp critical"; + if (Node->getDirectiveName().getName()) { + OS << " ("; + Node->getDirectiveName().printName(OS); + OS << ")"; + } + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPBarrierDirective(OMPBarrierDirective *Node) { + Indent() << "#pragma omp barrier"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) { + Indent() << "#pragma omp taskwait"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) { + Indent() << "#pragma omp taskgroup"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) { + Indent() << "#pragma omp atomic "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) { + Indent() << "#pragma omp flush"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) { + Indent() << "#pragma omp ordered"; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) { + Indent() << "#pragma omp simd "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPForSimdDirective(OMPForSimdDirective *Node) { + Indent() << "#pragma omp for simd "; + VisitOMPExecutableDirective(Node); +} + +void +StmtPrinter::VisitOMPDistributeSimdDirective(OMPDistributeSimdDirective *Node) { + Indent() << "#pragma omp distribute simd "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPDistributeParallelForDirective( + OMPDistributeParallelForDirective *Node) { + Indent() << "#pragma omp distribute parallel for "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPDistributeParallelForSimdDirective( + OMPDistributeParallelForSimdDirective *Node) { + Indent() << "#pragma omp distribute parallel for simd "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTeamsDirective(OMPTeamsDirective *Node) { + Indent() << "#pragma omp teams "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { + Indent() << "#pragma omp distribute "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) { + Indent() << "#pragma omp cancel " + << getOpenMPDirectiveName(Node->getConstructType()) << " "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPCancellationPointDirective( + OMPCancellationPointDirective *Node) { + Indent() << "#pragma omp cancellation point " + << getOpenMPDirectiveName(Node->getConstructType()); + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTargetDirective(OMPTargetDirective *Node) { + Indent() << "#pragma omp target "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTargetDataDirective(OMPTargetDataDirective *Node) { + Indent() << "#pragma omp target data "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *Node) { + Indent() << "#pragma omp target update "; + VisitOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *Node) { + Indent() << "#pragma omp target teams "; + VisitOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// @@ -976,6 +1466,14 @@ OS << "]"; } +void StmtPrinter::VisitCEANIndexExpr(CEANIndexExpr *Node) { + if (Node->getLowerBound() && Node->getLowerBound()->getLocStart().isValid()) + PrintExpr(Node->getLowerBound()); + OS << ":"; + if (Node->getLength() && Node->getLength()->getLocStart().isValid()) + PrintExpr(Node->getLength()); +} + void StmtPrinter::PrintCallArgs(CallExpr *Call) { for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { if (isa(Call->getArg(i))) { diff -uNr clang-3.4/lib/AST/StmtProfile.cpp clang/lib/AST/StmtProfile.cpp --- clang-3.4/lib/AST/StmtProfile.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/lib/AST/StmtProfile.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -255,40 +255,20 @@ namespace { class OMPClauseProfiler : public ConstOMPClauseVisitor { StmtProfiler *Profiler; - /// \brief Process clauses with list of variables. - template - void VisitOMPClauseList(T *Node); public: OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { } #define OPENMP_CLAUSE(Name, Class) \ - void Visit##Class(const Class *C); + void Visit##Class(const Class *S) { \ + for (ConstStmtRange Range = static_cast(S)->children(); \ + Range; ++Range) \ + Profiler->VisitStmt(*Range); \ + } #include "clang/Basic/OpenMPKinds.def" }; - -void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } - -template -void OMPClauseProfiler::VisitOMPClauseList(T *Node) { - for (typename T::varlist_const_iterator I = Node->varlist_begin(), - E = Node->varlist_end(); - I != E; ++I) - Profiler->VisitStmt(*I); -} - -void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { - VisitOMPClauseList(C); -} -void OMPClauseProfiler::VisitOMPFirstprivateClause( - const OMPFirstprivateClause *C) { - VisitOMPClauseList(C); -} -void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { - VisitOMPClauseList(C); -} } void -StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { +StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) { VisitStmt(S); OMPClauseProfiler P(this); ArrayRef Clauses = S->clauses(); @@ -298,6 +278,141 @@ P.Visit(*I); } +void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { + VisitOMPExecutableDirective(S); +} + +void +StmtProfiler::VisitOMPParallelForDirective(const OMPParallelForDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPParallelForSimdDirective( + const OMPParallelForSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPForSimdDirective(const OMPForSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPDistributeSimdDirective( + const OMPDistributeSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPDistributeParallelForDirective( + const OMPDistributeParallelForDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPDistributeParallelForSimdDirective( + const OMPDistributeParallelForSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPSectionsDirective(const OMPSectionsDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPParallelSectionsDirective( + const OMPParallelSectionsDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPSectionDirective(const OMPSectionDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPSingleDirective(const OMPSingleDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTaskDirective(const OMPTaskDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPMasterDirective(const OMPMasterDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPCriticalDirective(const OMPCriticalDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPBarrierDirective(const OMPBarrierDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPAtomicDirective(const OMPAtomicDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPCancelDirective(const OMPCancelDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPCancellationPointDirective( + const OMPCancellationPointDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPOrderedDirective(const OMPOrderedDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTeamsDirective(const OMPTeamsDirective *S) { + VisitOMPExecutableDirective(S); +} + +void +StmtProfiler::VisitOMPDistributeDirective(const OMPDistributeDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTargetDirective(const OMPTargetDirective *S) { + VisitOMPExecutableDirective(S); +} + +void +StmtProfiler::VisitOMPTargetDataDirective(const OMPTargetDataDirective *S) { + VisitOMPExecutableDirective(S); +} + +void +StmtProfiler::VisitOMPTargetUpdateDirective(const OMPTargetUpdateDirective *S) { + VisitOMPExecutableDirective(S); +} + +void +StmtProfiler::VisitOMPTargetTeamsDirective(const OMPTargetTeamsDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } @@ -396,6 +511,10 @@ VisitExpr(S); } +void StmtProfiler::VisitCEANIndexExpr(const CEANIndexExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } diff -uNr clang-3.4/lib/Basic/OpenMPKinds.cpp clang/lib/Basic/OpenMPKinds.cpp --- clang-3.4/lib/Basic/OpenMPKinds.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/lib/Basic/OpenMPKinds.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -22,10 +22,10 @@ OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) { return llvm::StringSwitch(Str) -#define OPENMP_DIRECTIVE(Name) \ - .Case(#Name, OMPD_##Name) +#define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name) +#define OPENMP_DIRECTIVE_EXT(Name, Str) .Case(Str, OMPD_##Name) #include "clang/Basic/OpenMPKinds.def" - .Default(OMPD_unknown); + .Default(OMPD_unknown); } const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { @@ -33,10 +33,14 @@ switch (Kind) { case OMPD_unknown: return "unknown"; -#define OPENMP_DIRECTIVE(Name) \ - case OMPD_##Name : return #Name; +#define OPENMP_DIRECTIVE(Name) \ + case OMPD_##Name: \ + return #Name; +#define OPENMP_DIRECTIVE_EXT(Name, Str) \ + case OMPD_##Name: \ + return Str; #include "clang/Basic/OpenMPKinds.def" - case NUM_OPENMP_DIRECTIVES: + default: break; } llvm_unreachable("Invalid OpenMP directive kind"); @@ -44,10 +48,9 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { return llvm::StringSwitch(Str) -#define OPENMP_CLAUSE(Name, Class) \ - .Case(#Name, OMPC_##Name) +#define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name) #include "clang/Basic/OpenMPKinds.def" - .Default(OMPC_unknown); + .Default(OMPC_unknown); } const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) { @@ -55,12 +58,13 @@ switch (Kind) { case OMPC_unknown: return "unknown"; -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_##Name : return #Name; +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return #Name; #include "clang/Basic/OpenMPKinds.def" case OMPC_threadprivate: return "threadprivate or thread local"; - case NUM_OPENMP_CLAUSES: + default: break; } llvm_unreachable("Invalid OpenMP clause kind"); @@ -71,16 +75,41 @@ switch (Kind) { case OMPC_default: return llvm::StringSwitch(Str) -#define OPENMP_DEFAULT_KIND(Name) \ - .Case(#Name, OMPC_DEFAULT_##Name) +#define OPENMP_DEFAULT_KIND(Name) .Case(#Name, OMPC_DEFAULT_##Name) #include "clang/Basic/OpenMPKinds.def" - .Default(OMPC_DEFAULT_unknown); - case OMPC_unknown: - case OMPC_threadprivate: - case OMPC_private: - case OMPC_firstprivate: - case OMPC_shared: - case NUM_OPENMP_CLAUSES: + .Default(OMPC_DEFAULT_unknown); + case OMPC_proc_bind: + return llvm::StringSwitch(Str) +#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_PROC_BIND_unknown); + case OMPC_reduction: + return llvm::StringSwitch(Str) +#define OPENMP_REDUCTION_OPERATOR(Name, Symbol) \ + .Case(Symbol, OMPC_REDUCTION_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_REDUCTION_unknown); + case OMPC_depend: + return llvm::StringSwitch(Str) +#define OPENMP_DEPENDENCE_TYPE(Name, Type) .Case(Type, OMPC_DEPEND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEPEND_unknown); + case OMPC_map: + return llvm::StringSwitch(Str) +#define OPENMP_MAP_KIND(Name, Kind) .Case(Kind, OMPC_MAP_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_MAP_unknown); + case OMPC_schedule: + return llvm::StringSwitch(Str) +#define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_SCHEDULE_unknown); + case OMPC_dist_schedule: + return llvm::StringSwitch(Str) +#define OPENMP_DIST_SCHEDULE_KIND(Name) .Case(#Name, OMPC_DIST_SCHEDULE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DIST_SCHEDULE_unknown); + default: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -93,17 +122,87 @@ switch (Type) { case OMPC_DEFAULT_unknown: return "unknown"; -#define OPENMP_DEFAULT_KIND(Name) \ - case OMPC_DEFAULT_##Name : return #Name; +#define OPENMP_DEFAULT_KIND(Name) \ + case OMPC_DEFAULT_##Name: \ + return #Name; #include "clang/Basic/OpenMPKinds.def" + default: + break; } llvm_unreachable("Invalid OpenMP 'default' clause type"); - case OMPC_unknown: - case OMPC_threadprivate: - case OMPC_private: - case OMPC_firstprivate: - case OMPC_shared: - case NUM_OPENMP_CLAUSES: + case OMPC_proc_bind: + switch (Type) { + case OMPC_PROC_BIND_unknown: + return "unknown"; +#define OPENMP_PROC_BIND_KIND(Name) \ + case OMPC_PROC_BIND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'proc_bind' clause type"); + case OMPC_reduction: + switch (Type) { + case OMPC_REDUCTION_unknown: + return "unknown"; +#define OPENMP_REDUCTION_OPERATOR(Name, Symbol) \ + case OMPC_REDUCTION_##Name: \ + return Symbol; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'reduction' clause operator"); + case OMPC_depend: + switch (Type) { + case OMPC_DEPEND_unknown: + return "unknown"; +#define OPENMP_DEPENDENCE_TYPE(Name, Type) \ + case OMPC_DEPEND_##Name: \ + return Type; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'depend' clause dependence type"); + case OMPC_map: + switch (Type) { + case OMPC_MAP_unknown: + return "unknown"; +#define OPENMP_MAP_KIND(Name, Kind) \ + case OMPC_MAP_##Name: \ + return Kind; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'map' clause mapping kind"); + case OMPC_schedule: + switch (Type) { + case OMPC_SCHEDULE_unknown: + return "unknown"; +#define OPENMP_SCHEDULE_KIND(Name) \ + case OMPC_SCHEDULE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'schedule' clause operator"); + case OMPC_dist_schedule: + switch (Type) { + case OMPC_DIST_SCHEDULE_unknown: + return "unknown"; +#define OPENMP_DIST_SCHEDULE_KIND(Name) \ + case OMPC_DIST_SCHEDULE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'dist_schedule' clause operator"); + default: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -116,18 +215,243 @@ switch (DKind) { case OMPD_parallel: switch (CKind) { -#define OPENMP_PARALLEL_CLAUSE(Name) \ - case OMPC_##Name: return true; +#define OPENMP_PARALLEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_for: + switch (CKind) { +#define OPENMP_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_simd: + switch (CKind) { +#define OPENMP_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_for_simd: + switch (CKind) { +#define OPENMP_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_simd: + switch (CKind) { +#define OPENMP_DISTRIBUTE_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_parallel_for: + switch (CKind) { +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_parallel_for_simd: + switch (CKind) { +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_for_simd: + switch (CKind) { +#define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_declare_simd: + switch (CKind) { +#define OPENMP_DECLARE_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + // No clauses allowed for 'omp [end] declare target' constructs. + case OMPD_declare_target: + case OMPD_end_declare_target: + break; + case OMPD_sections: + switch (CKind) { +#define OPENMP_SECTIONS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_single: + switch (CKind) { +#define OPENMP_SINGLE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; #include "clang/Basic/OpenMPKinds.def" default: break; } break; - case OMPD_unknown: - case OMPD_threadprivate: case OMPD_task: - case NUM_OPENMP_DIRECTIVES: + switch (CKind) { +#define OPENMP_TASK_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_atomic: + switch (CKind) { +#define OPENMP_ATOMIC_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_flush: + switch (CKind) { +#define OPENMP_FLUSH_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_for: + switch (CKind) { +#define OPENMP_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_sections: + switch (CKind) { +#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams: + switch (CKind) { +#define OPENMP_TEAMS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute: + switch (CKind) { +#define OPENMP_DISTRIBUTE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_cancel: + switch (CKind) { +#define OPENMP_CANCEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_cancellation_point: + return false; + case OMPD_target: + switch (CKind) { +#define OPENMP_TARGET_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_data: + switch (CKind) { +#define OPENMP_TARGET_DATA_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_update: + switch (CKind) { +#define OPENMP_TARGET_UPDATE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + default: break; } return false; } + diff -uNr clang-3.4/lib/CodeGen/CGBuilder.h clang/lib/CodeGen/CGBuilder.h --- clang-3.4/lib/CodeGen/CGBuilder.h 2013-01-02 06:45:17.000000000 -0500 +++ clang/lib/CodeGen/CGBuilder.h 2014-05-19 19:58:57.000000000 -0400 @@ -15,11 +15,35 @@ namespace clang { namespace CodeGen { +class CodeGenFunction; + +/// IRBuilder inserter which forwards to CodeGenFunction::InsertHelper. +template +class CGBuilderInserter + : protected llvm::IRBuilderDefaultInserter { +public: + CGBuilderInserter() : CGF(0) {} + explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {} + +protected: + void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const; +private: + void operator=(const CGBuilderInserter &) LLVM_DELETED_FUNCTION; + + CodeGenFunction *CGF; +}; + // Don't preserve names on values in an optimized build. #ifdef NDEBUG -typedef llvm::IRBuilder CGBuilderTy; +typedef CGBuilderInserter CGBuilderInserterTy; +typedef llvm::IRBuilder + CGBuilderTy; #else -typedef llvm::IRBuilder<> CGBuilderTy; +typedef CGBuilderInserter CGBuilderInserterTy; +typedef llvm::IRBuilder + CGBuilderTy; #endif } // end namespace CodeGen diff -uNr clang-3.4/lib/CodeGen/CGClass.cpp clang/lib/CodeGen/CGClass.cpp --- clang-3.4/lib/CodeGen/CGClass.cpp 2013-11-05 04:12:18.000000000 -0500 +++ clang/lib/CodeGen/CGClass.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -592,7 +592,7 @@ CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes); } -void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, +void CodeGenFunction::EmitInitializerForField(const FieldDecl *Field, LValue LHS, Expr *Init, ArrayRef ArrayIndexes) { QualType FieldType = Field->getType(); diff -uNr clang-3.4/lib/CodeGen/CGDecl.cpp clang/lib/CodeGen/CGDecl.cpp --- clang-3.4/lib/CodeGen/CGDecl.cpp 2013-10-30 17:53:58.000000000 -0400 +++ clang/lib/CodeGen/CGDecl.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -19,6 +19,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -77,6 +78,7 @@ case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: case Decl::UsingShadow: + case Decl::OMPDeclareTarget: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; @@ -86,7 +88,6 @@ case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; case Decl::Import: - case Decl::OMPThreadPrivate: case Decl::Empty: // None of these decls require codegen support. return; @@ -99,6 +100,15 @@ if (CGDebugInfo *DI = getDebugInfo()) DI->EmitUsingDecl(cast(D)); return; + case Decl::OMPThreadPrivate: + CGM.EmitOMPThreadPrivate(cast(&D)); + break; + case Decl::OMPDeclareReduction: + CGM.EmitOMPDeclareReduction(cast(&D)); + break; + case Decl::OMPDeclareSimd: + CGM.EmitOMPDeclareSimd(cast(&D)); + break; case Decl::UsingDirective: // using namespace X; [C++] if (CGDebugInfo *DI = getDebugInfo()) DI->EmitUsingDirective(cast(D)); diff -uNr clang-3.4/lib/CodeGen/CGDeclCXX.cpp clang/lib/CodeGen/CGDeclCXX.cpp --- clang-3.4/lib/CodeGen/CGDeclCXX.cpp 2013-10-02 12:03:16.000000000 -0400 +++ clang/lib/CodeGen/CGDeclCXX.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -520,3 +520,357 @@ return fn; } + +void CodeGenModule::CreateOpenMPCXXInit(const VarDecl *Var, + CXXRecordDecl *Ty, + llvm::Function *&InitFunction, + llvm::Value *&Ctor, + llvm::Value *&CCtor, + llvm::Value *&Dtor) { + // Find default constructor, copy constructor and destructor. + Ctor = 0; + CCtor = 0; + Dtor = 0; + InitFunction = 0; +// CXXConstructorDecl *CtorDecl = 0;//, *CCtorDecl = 0; +// CXXDestructorDecl *DtorDecl = 0; +/* for (CXXRecordDecl::ctor_iterator CI = Ty->ctor_begin(), + CE = Ty->ctor_end(); + CI != CE; ++CI) { + unsigned Quals; + if ((*CI)->isDefaultConstructor()) + CtorDecl = *CI; +// else if ((*CI)->isCopyConstructor(Quals) && +// ((Quals & Qualifiers::Const) == Qualifiers::Const)) +// CCtorDecl = *CI; + }*/ +// if (CXXDestructorDecl *D = Ty->getDestructor()) +// DtorDecl = D; + // Generate wrapper for default constructor. + const Expr *Init = Var->getAnyInitializer(); + if (Init) { + CodeGenFunction CGF(*this); + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_ctor_", + getMangledName(Var))); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); +// CGF.EmitCXXConstructExpr(cast(Var->getInit()), +// AggValueSlot::forAddr(Fn->arg_begin(), +// CGF.getContext().getTypeAlignInChars(Var->getType()), +// Var->getType().getQualifiers(), +// AggValueSlot::IsNotDestructed, +// AggValueSlot::DoesNotNeedGCBarriers, +// AggValueSlot::IsNotAliased)); +// //CGF.EmitCXXConstructorCall(CtorDecl, Ctor_Complete, false, false, +// // Fn->arg_begin(), 0, 0); + llvm::Value *Arg = CGF.EmitScalarConversion(Fn->arg_begin(), getContext().VoidPtrTy, getContext().getPointerType(Var->getType())); + CGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(), true); + CGF.Builder.CreateStore(Fn->arg_begin(), CGF.ReturnValue); + CGF.FinishFunction(); + Ctor = Fn; + } +/* if (CCtorDecl) { + FunctionArgList Args; + if (!OpenMPCCtorHelperDecl) { + llvm::SmallVector TArgs(2, getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + OpenMPCCtorHelperDecl = + FunctionDecl::Create(getContext(), Ty->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + DeclarationName(), + getContext().getFunctionType( + getContext().VoidPtrTy, + TArgs, EPI), + 0, SC_None, SC_None, false, false); + } + ImplicitParamDecl Dst1(OpenMPCCtorHelperDecl, SourceLocation(), 0, + getContext().VoidPtrTy); + ImplicitParamDecl Dst2(OpenMPCCtorHelperDecl, SourceLocation(), 0, + getContext().VoidPtrTy); + DeclRefExpr E(&Dst2, true, getContext().VoidPtrTy, VK_LValue, + SourceLocation()); + ImplicitCastExpr ECast(ImplicitCastExpr::OnStack, + CCtorDecl->getThisType(getContext()), CK_BitCast, + &E, VK_LValue); + UnaryOperator EUn(&ECast, UO_Deref, getContext().getRecordType(Ty), + VK_LValue, OK_Ordinary, SourceLocation()); + Stmt *S = &EUn; + CallExpr::const_arg_iterator EI(&S); + Args.push_back(&Dst1); + Args.push_back(&Dst2); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_cctor_", + Var->getName())); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); + CGF.EmitCXXConstructorCall(CCtorDecl, Ctor_Complete, false, false, + Fn->arg_begin(), EI, EI + 1); + CGF.Builder.CreateStore(&Fn->getArgumentList().back(), CGF.ReturnValue); + CGF.FinishFunction(); + CCtor = Fn; + }*/ + QualType QTy = Var->getType(); + QualType::DestructionKind DtorKind = QTy.isDestructedType(); + if (DtorKind != QualType::DK_none && !Ty->hasTrivialDestructor()) { + CodeGenFunction CGF(*this); + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_dtor_", + getMangledName(Var))); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); + //CGF.EmitCXXDestructorCall(DtorDecl, Dtor_Complete, false, false, + // Fn->arg_begin()); + CGF.emitDestroy(Fn->arg_begin(), QTy, CGF.getDestroyer(DtorKind), CGF.needsEHCleanup(DtorKind)); + CGF.Builder.CreateStore(Fn->arg_begin(), CGF.ReturnValue); + CGF.FinishFunction(); + Dtor = Fn; + }// else { + //DtorDecl = 0; + //} + + if (Init || (DtorKind != QualType::DK_none && !Ty->hasTrivialDestructor())) { + if (!Ctor) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + Ctor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + if (!CCtor) { + FunctionArgList Args; + ImplicitParamDecl Dst1(0, SourceLocation(), 0, + getContext().VoidPtrTy); + ImplicitParamDecl Dst2(0, SourceLocation(), 0, + getContext().VoidPtrTy); + Args.push_back(&Dst1); + Args.push_back(&Dst2); + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + CCtor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + if (DtorKind == QualType::DK_none || Ty->hasTrivialDestructor()) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + Dtor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + InitFunction = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__omp_threadprivate_", + getMangledName(Var))); + } +} + +void CodeGenModule::CreateOpenMPArrCXXInit(const VarDecl *Var, + CXXRecordDecl *Ty, + llvm::Function *&InitFunction, + llvm::Value *&Ctor, + llvm::Value *&CCtor, + llvm::Value *&Dtor) { + // Find default constructor, copy constructor and destructor. + Ctor = 0; + CCtor = 0; + Dtor = 0; + InitFunction = 0; + //CXXConstructorDecl *CtorDecl = 0, *CCtorDecl = 0; + CXXDestructorDecl *DtorDecl = 0; +/* for (CXXRecordDecl::ctor_iterator CI = Ty->ctor_begin(), + CE = Ty->ctor_end(); + CI != CE; ++CI) { + unsigned Quals; + if ((*CI)->isDefaultConstructor()) + CtorDecl = *CI; + else if ((*CI)->isCopyConstructor(Quals) && + ((Quals & Qualifiers::Const) == Qualifiers::Const)) + CCtorDecl = *CI; + } +*/ + if (CXXDestructorDecl *D = Ty->getDestructor()) + DtorDecl = D; + // Generate wrapper for default constructor. + const Expr *Init = Var->getAnyInitializer(); + if (Init) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_ctor_vec_", + getMangledName(Var))); + CodeGenFunction CGF(*this); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); +// CGF.EmitAggExpr(Var->getInit(), +// AggValueSlot::forAddr(Fn->arg_begin(), +// CGF.getContext().getTypeAlignInChars(Var->getType()), +// Var->getType().getQualifiers(), +// AggValueSlot::IsNotDestructed, +// AggValueSlot::DoesNotNeedGCBarriers, +// AggValueSlot::IsNotAliased)); +// CGF.Builder.CreateStore(Fn->arg_begin(), CGF.ReturnValue); + llvm::Value *Arg = CGF.EmitScalarConversion(Fn->arg_begin(), getContext().VoidPtrTy, getContext().getPointerType(Var->getType())); + CGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(), true); + CGF.Builder.CreateStore(Fn->arg_begin(), CGF.ReturnValue); + CGF.FinishFunction(); + Ctor = Fn; + } +/* if (CCtorDecl) { + FunctionArgList Args; + if (!OpenMPCCtorHelperDecl) { + llvm::SmallVector TArgs(2, getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + OpenMPCCtorHelperDecl = + FunctionDecl::Create(getContext(), Ty->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + DeclarationName(), + getContext().getFunctionType( + getContext().VoidPtrTy, + TArgs, EPI), + 0, SC_None, SC_None, false, false); + } + ImplicitParamDecl Dst1(OpenMPCCtorHelperDecl, SourceLocation(), 0, + getContext().VoidPtrTy); + ImplicitParamDecl Dst2(OpenMPCCtorHelperDecl, SourceLocation(), 0, + getContext().VoidPtrTy); + DeclRefExpr E(&Dst2, true, getContext().VoidPtrTy, VK_LValue, + SourceLocation()); + ImplicitCastExpr ECast(ImplicitCastExpr::OnStack, + CCtorDecl->getThisType(getContext()), CK_BitCast, + &E, VK_LValue); + UnaryOperator EUn(&ECast, UO_Deref, getContext().getRecordType(Ty), + VK_LValue, OK_Ordinary, SourceLocation()); + Stmt *S = &EUn; + CallExpr::const_arg_iterator EI(&S); + Args.push_back(&Dst1); + Args.push_back(&Dst2); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_cctor_", + Var->getName())); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); + CGF.EmitCXXConstructorCall(CCtorDecl, Ctor_Complete, false, false, + Fn->arg_begin(), EI, EI + 1); + CGF.Builder.CreateStore(&Fn->getArgumentList().back(), CGF.ReturnValue); + CGF.FinishFunction(); + CCtor = Fn; + }*/ + if (DtorDecl && !DtorDecl->isTrivial()) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__kmpc_dtor_vec_", + getMangledName(Var))); + CodeGenFunction CGF(*this); + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, + Args, SourceLocation()); + CGF.emitDestroy(Fn->arg_begin(), Var->getType(), + CGF.getDestroyer(QualType::DK_cxx_destructor), + false + /*CGF.needsEHCleanup(QualType::DK_cxx_destructor)*/); + CGF.Builder.CreateStore(Fn->arg_begin(), CGF.ReturnValue); + CGF.FinishFunction(); + Dtor = Fn; + } else { + DtorDecl = 0; + } + + if (Init || DtorDecl) { + if (!Ctor) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + Ctor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + if (!CCtor) { + FunctionArgList Args; + ImplicitParamDecl Dst1(0, SourceLocation(), 0, + getContext().VoidPtrTy); + ImplicitParamDecl Dst2(0, SourceLocation(), 0, + getContext().VoidPtrTy); + Args.push_back(&Dst1); + Args.push_back(&Dst2); + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + CCtor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + if (!Dtor) { + FunctionArgList Args; + ImplicitParamDecl Dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = + getTypes().arrangeFunctionDeclaration(getContext().VoidPtrTy, Args, + FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = getTypes().GetFunctionType(FI); + Dtor = llvm::Constant::getNullValue(FTy->getPointerTo()); + } + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + InitFunction = + CreateGlobalInitOrDestructFunction(*this, FTy, + Twine("__omp_threadprivate_vec_", + getMangledName(Var))); + } +} + diff -uNr clang-3.4/lib/CodeGen/CGDeclOpenMP.cpp clang/lib/CodeGen/CGDeclOpenMP.cpp --- clang-3.4/lib/CodeGen/CGDeclOpenMP.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/lib/CodeGen/CGDeclOpenMP.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -0,0 +1,437 @@ +//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Decl nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CGDebugInfo.h" +#include "CGOpenCLRuntime.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/TypeBuilder.h" +using namespace clang; +using namespace CodeGen; + +namespace { +struct ident_t {}; +struct target_size_t {}; +typedef void *(*kmpc_ctor)(void *); +typedef void *(*kmpc_cctor)(void *, void *); +typedef void *(*kmpc_dtor)(void *); +typedef void(__kmpc_threadprivate_register)(ident_t *loc, void *data, + kmpc_ctor ctor, kmpc_cctor cctor, + kmpc_dtor dtor); +typedef int32_t(__kmpc_global_thread_num)(ident_t *loc); +typedef void *(__kmpc_threadprivate_cached)(ident_t *loc, int32_t global_tid, + void *data, target_size_t size, + void ***cache); +} + +namespace llvm { +/// Specializations of llvm::TypeBuilder for: +/// ident_t +template class TypeBuilder { +public: + static StructType *get(LLVMContext &C) { + return StructType::get( + TypeBuilder, X>::get(C), // reserved_1 + TypeBuilder, X>::get(C), // flags + TypeBuilder, X>::get(C), // reserved_2 + TypeBuilder, X>::get(C), // reserved_3 + TypeBuilder *, X>::get(C), // psource + NULL); + } + enum { + reserved_1, + flags, + reserved_2, + reserved_3, + psource + }; +}; +} + +#define OPENMPRTL_FUNC(name) Get__kmpc_##name(this) + +#define DEFAULT_GET_OPENMP_FUNC(name) \ + static llvm::Value *Get__kmpc_##name(clang::CodeGen::CodeGenModule *CGM) { \ + return CGM->CreateRuntimeFunction( \ + llvm::TypeBuilder<__kmpc_##name, false>::get(CGM->getLLVMContext()), \ + "__kmpc_" #name); \ + } + +// Special processing for __kmpc_threadprivate_cached +// DEFAULT_GET_OPENMP_FUNC(threadprivate_cached) +static llvm::Value * +Get__kmpc_threadprivate_cached(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = { llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + CGM->SizeTy, + llvm::TypeBuilder::get(C) }; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_threadprivate_cached"); +} + +DEFAULT_GET_OPENMP_FUNC(threadprivate_register) +DEFAULT_GET_OPENMP_FUNC(global_thread_num) + +typedef llvm::TypeBuilder IdentTBuilder; + +static llvm::Value *GEP(CGBuilderTy &B, llvm::Value *Base, int field) { + return B.CreateConstInBoundsGEP2_32(Base, 0, field); +} + +static void StoreField(CGBuilderTy &B, llvm::Value *Val, llvm::Value *Dst, + int field) { + B.CreateStore(Val, GEP(B, Dst, field)); +} + +// static llvm::Value *LoadField(CGBuilderTy &B, llvm::Value *Src, int field) { +// return B.CreateLoad(GEP(B, Src, field)); +//} + +llvm::Value *CodeGenModule::CreateIntelOpenMPRTLLoc(SourceLocation Loc, + CodeGenFunction &CGF, + unsigned Flags) { + llvm::Value *Tmp; + // ident_t tmp; + llvm::AllocaInst *AI = 0; + llvm::BasicBlock &EntryBB = CGF.CurFn->getEntryBlock(); + std::string VarName = ".__kmpc_ident_t." + llvm::utostr(Flags) + "."; + std::string DefaultLoc = ".omp.default.loc."; + std::string DefaultConstName = DefaultLoc + llvm::utostr(Flags) + "."; + llvm::Value *DefaultString; + if (!(DefaultString = TheModule.getNamedValue(DefaultLoc))) { + DefaultString = + CGF.Builder.CreateGlobalString(";unknown;unknown;0;0;;", DefaultLoc); + } + for (llvm::BasicBlock::iterator I = EntryBB.begin(), E = EntryBB.end(); + I != E; ++I) + if (I->getName().startswith(VarName)) { + AI = cast(I); + break; + } + if (!AI) { + llvm::StructType *StTy = IdentTBuilder::get(getLLVMContext()); + AI = CGF.CreateTempAlloca(StTy, VarName); + AI->setAlignment(PointerAlignInBytes); + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP(); + assert(SavedIP.isSet() && "No insertion point is set!"); + CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); + llvm::Value *DefaultVal; + if (!(DefaultVal = TheModule.getNamedValue(DefaultConstName))) { + llvm::Constant *Zero = CGF.Builder.getInt32(0); + llvm::Value *Args[] = { Zero, Zero }; + llvm::Constant *Values[] = { Zero, CGF.Builder.getInt32(Flags), Zero, + Zero, cast( + CGF.Builder.CreateInBoundsGEP( + DefaultString, Args)) }; + llvm::Constant *Init = + llvm::ConstantStruct::get(StTy, llvm::makeArrayRef(Values)); + llvm::GlobalVariable *ConstVar = new llvm::GlobalVariable( + TheModule, StTy, true, llvm::GlobalValue::PrivateLinkage, Init, + DefaultConstName); + ConstVar->setUnnamedAddr(true); + DefaultVal = ConstVar; + } + CGF.Builder.CreateMemCpy(AI, DefaultVal, + llvm::ConstantExpr::getSizeOf(StTy), + PointerAlignInBytes); + CGF.Builder.restoreIP(SavedIP); + } + Tmp = AI; + if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo && + Loc.isValid()) { + PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc); + std::string Res = ";"; + Res += PLoc.getFilename(); + Res += ";"; + if (const FunctionDecl *FD = + dyn_cast_or_null(CGF.CurFuncDecl)) { + Res += FD->getQualifiedNameAsString(); + } + Res += ";"; + Res += llvm::utostr(PLoc.getLine()) + ";" + llvm::utostr(PLoc.getColumn()) + + ";;"; + // tmp.psource = ";file;func;line;col;;"; + StoreField(CGF.Builder, CGF.Builder.CreateGlobalStringPtr(Res), Tmp, + IdentTBuilder::psource); + } else if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo) { + llvm::Value *Zero = CGF.Builder.getInt32(0); + llvm::Value *Args[] = { Zero, Zero }; + StoreField(CGF.Builder, CGF.Builder.CreateInBoundsGEP(DefaultString, Args), + Tmp, IdentTBuilder::psource); + } + return Tmp; +} + +llvm::Value *CodeGenModule::CreateOpenMPGlobalThreadNum(SourceLocation Loc, + CodeGenFunction &CGF) { + llvm::BasicBlock &EntryBB = CGF.CurFn->getEntryBlock(); + for (llvm::BasicBlock::iterator I = EntryBB.begin(), E = EntryBB.end(); + I != E; ++I) + if (I->getName().startswith(".__kmpc_global_thread_num.")) + return CGF.Builder.CreateLoad(I, ".gtid."); + llvm::AllocaInst *AI = + CGF.CreateTempAlloca(Int32Ty, ".__kmpc_global_thread_num."); + AI->setAlignment(4); + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP(); + assert(SavedIP.isSet() && "No insertion point is set!"); + CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); + llvm::Value *IdentT = CreateIntelOpenMPRTLLoc(Loc, CGF); + llvm::Value *Res = + CGF.EmitRuntimeCall(OPENMPRTL_FUNC(global_thread_num), + llvm::makeArrayRef(&IdentT, 1)); + CGF.Builder.CreateStore(Res, AI); + CGF.Builder.restoreIP(SavedIP); + return CGF.Builder.CreateLoad(AI, ".gtid."); +} + +llvm::Value *CodeGenModule::CreateOpenMPThreadPrivateCached( + const VarDecl *VD, SourceLocation Loc, CodeGenFunction &CGF, bool NoCast) { + if (OpenMPSupport.hasThreadPrivateVar(VD)) { + llvm::Type *VDTy = getTypes().ConvertTypeForMem(VD->getType()); + llvm::PointerType *PTy = llvm::PointerType::get( + VDTy, getContext().getTargetAddressSpace(VD->getType())); + CharUnits SZ = GetTargetTypeStoreSize(VDTy); + std::string VarCache = getMangledName(VD).str() + ".cache."; + + llvm::Value *Args[] = { + CreateIntelOpenMPRTLLoc(Loc, CGF), CreateOpenMPGlobalThreadNum(Loc, CGF), + CGF.Builder.CreateBitCast(VD->isStaticLocal() + ? getStaticLocalDeclAddress(VD) + : GetAddrOfGlobal(VD), + Int8PtrTy), + llvm::ConstantInt::get(CGF.SizeTy, SZ.getQuantity()), + GetGlobalValue(VarCache) + }; + llvm::Value *Call = + CGF.EmitRuntimeCall(OPENMPRTL_FUNC(threadprivate_cached), Args); + if (NoCast) + return Call; + return CGF.Builder.CreateBitCast(Call, PTy); + } + return 0; +} + +void CodeGenModule::EmitOMPThreadPrivate(const VarDecl *VD, const Expr *TPE) { + // Create cache memory for threadprivate variable void **Var.cache; + std::string VarCache = getMangledName(VD).str() + ".cache."; + llvm::GlobalVariable *GV; + if (!(GV = + dyn_cast_or_null(GetGlobalValue(VarCache)))) { + llvm::GlobalVariable *GV = cast( + CreateRuntimeVariable(Int8PtrPtrTy, VarCache)); + GV->setInitializer(llvm::Constant::getNullValue(Int8PtrPtrTy)); + GV->setLinkage(llvm::GlobalValue::CommonLinkage); + } + // Do not define constructors/destructors for declaration, they are defined + // for definitions. + if (!VD->isLocalVarDecl() && !getContext().DeclMustBeEmitted(VD)) + return; + llvm::Value *Val = + VD->isStaticLocal() ? getStaticLocalDeclAddress(VD) : GetAddrOfGlobal(VD); + bool isArray = false; + const Type *TypePtr = VD->getType().getCanonicalType().getTypePtr(); + while (TypePtr->isArrayType()) { + isArray = true; + TypePtr = TypePtr->getArrayElementTypeNoTypeQual(); + } + CXXRecordDecl *Ty = TypePtr->getAsCXXRecordDecl(); + if (isArray && Ty) { + // void __omp_threadprivate_Var(); + llvm::Value *Ctor, *CCtor, *Dtor; + llvm::Function *InitFn; + CreateOpenMPArrCXXInit(VD, Ty, InitFn, Ctor, CCtor, Dtor); + if (InitFn) { + CodeGenFunction CGF(*this); + FunctionArgList ArgList; + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, InitFn, + getTypes().arrangeNullaryFunction(), ArgList, + SourceLocation()); + // ident_t tmp; + llvm::Value *Tmp = CreateIntelOpenMPRTLLoc(TPE->getExprLoc(), CGF); + llvm::Value *Args[5] = { Tmp, CGF.Builder.CreateBitCast( + Val, CGF.Builder.getInt8PtrTy()), + Ctor, CCtor, Dtor }; + // __kmpc_threadprivate_register(&tmp, &var, ctor, cctor, dtor); + CGF.EmitRuntimeCall(OPENMPRTL_FUNC(threadprivate_register), Args); + CGF.FinishFunction(); + CXXGlobalInits.push_back(InitFn); + } + } else if (Ty) { + // void __omp_threadprivate_Var(); + llvm::Value *Ctor, *CCtor, *Dtor; + llvm::Function *InitFn; + CreateOpenMPCXXInit(VD, Ty, InitFn, Ctor, CCtor, Dtor); + if (InitFn) { + CodeGenFunction CGF(*this); + FunctionArgList ArgList; + CGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, InitFn, + getTypes().arrangeNullaryFunction(), ArgList, + SourceLocation()); + // ident_t tmp; + llvm::Value *Tmp = CreateIntelOpenMPRTLLoc(TPE->getExprLoc(), CGF); + llvm::Value *Args[5] = { Tmp, CGF.Builder.CreateBitCast( + Val, CGF.Builder.getInt8PtrTy()), + Ctor, CCtor, Dtor }; + // __kmpc_threadprivate_register(&tmp, &var, ctor, cctor, dtor); + CGF.EmitRuntimeCall(OPENMPRTL_FUNC(threadprivate_register), Args); + CGF.FinishFunction(); + CXXGlobalInits.push_back(InitFn); + } + } +} + +void CodeGenModule::EmitOMPThreadPrivate(const OMPThreadPrivateDecl *D) { + for (OMPThreadPrivateDecl::varlist_const_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) { + const VarDecl *VD = cast(cast(*I)->getDecl()); + OpenMPSupport.addThreadPrivateVar(VD, *I); + EmitOMPThreadPrivate(VD, *I); + } +} + +void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D) { + for (OMPDeclareReductionDecl::datalist_const_iterator I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + if (!I->CombinerFunction || !I->InitFunction) + continue; + Decl *D = cast(I->CombinerFunction)->getDecl(); + EmitGlobal(cast(D)); + D = cast(I->InitFunction)->getDecl(); + EmitGlobal(cast(D)); + } +} + +void CodeGenModule::EmitOMPDeclareSimd(const OMPDeclareSimdDecl *D) { + // 1) Emit function, extract FunctionDecl, Function, CGFunctionInfo. + // 2) Prepare input (Groups) for metadata generation. + // 3) Do the metadata generation -- call EmitVectorVariantsMetadata. + + // Make sure that the function is emitted. + const FunctionDecl *FD = dyn_cast_or_null(D->getFunction()); + + if (!FD) { + return; + } + + EmitGlobal(FD); + + const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(FD); + llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); + llvm::Function *Fn = cast(GetAddrOfFunction(FD, Ty)); + + if (FD->isVariadic()) + return; + + if (!Fn) + return; + + // Prepare input for the metadata emission. + GroupMap Groups; + static unsigned key = 0; + + for (OMPDeclareSimdDecl::simd_variants_const_iterator + I = D->simd_variants_begin(), + E = D->simd_variants_end(); + I != E; ++I) { + Groups.FindAndConstruct(++key); + unsigned BeginIdx = I->BeginIdx; + unsigned EndIdx = I->EndIdx; + for (unsigned Idx = BeginIdx; Idx < EndIdx; ++Idx) { + OMPDeclareSimdDecl::clauses_const_iterator J = D->clauses_begin() + Idx; + if (!*J) + continue; + if (isa(*J)) { + Groups[key].Mask.push_back(1); + } else if (isa(*J)) { + Groups[key].Mask.push_back(0); + } else if (OMPSimdlenClause *C = dyn_cast(*J)) { + const Expr *LengthExpr = C->getSimdlen(); + assert(isa(LengthExpr) && "integer literal expected"); + unsigned VLen = + cast(LengthExpr)->getValue().getZExtValue(); + Groups[key].VecLength.push_back(VLen); + } else if (OMPLinearClause *C = dyn_cast(*J)) { + const Expr *StepExpr = C->getStep(); + int Step = 0; + if (const IntegerLiteral *IL = + dyn_cast_or_null(StepExpr)) { + Step = IL->getValue().getZExtValue(); + } else { + Step = 1; + } + for (OMPLinearClause::varlist_const_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + const DeclRefExpr *DRE = cast(*I); + const std::string Name = DRE->getDecl()->getDeclName().getAsString(); + Groups[key].setLinear(Name, "", Step); + } + } else if (OMPAlignedClause *C = dyn_cast(*J)) { + const Expr *AlignExpr = C->getAlignment(); + int Align = 0; + if (const IntegerLiteral *IL = + dyn_cast_or_null(AlignExpr)) { + Align = IL->getValue().getZExtValue(); + } + for (OMPAlignedClause::varlist_const_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + const DeclRefExpr *DRE = cast(*I); + const std::string Name = DRE->getDecl()->getDeclName().getAsString(); + Groups[key].setAligned(Name, Align); + } + } else if (OMPUniformClause *C = dyn_cast(*J)) { + for (OMPUniformClause::varlist_const_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + const DeclRefExpr *DRE = cast(*I); + Groups[key].setUniform(DRE->getDecl()->getDeclName().getAsString()); + } + } else { + llvm_unreachable("Unknown clause on 'omp declare simd' directive"); + } + } + } + + EmitVectorVariantsMetadata(FI, FD, Fn, Groups); +} + +void CodeGenModule::EmitOMPDeclareTarget(const OMPDeclareTargetDecl *D) { + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I != E; ++I) { + if (const VarDecl *VD = dyn_cast(*I)) + if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && + VD->getTemplateSpecializationKind() != TSK_Undeclared) + continue; + EmitTopLevelDecl(*I); + } +} diff -uNr clang-3.4/lib/CodeGen/CGElementalFunction.cpp clang/lib/CodeGen/CGElementalFunction.cpp --- clang-3.4/lib/CodeGen/CGElementalFunction.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/lib/CodeGen/CGElementalFunction.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -0,0 +1,822 @@ +//===----- CGElementalFunction.cpp - CodeGen for Elemental Functions ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This files implements code generation for Cilk Plus elemental +/// functions. +/// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Support/Debug.h" + +using namespace clang; +using namespace CodeGen; +typedef CodeGenModule::CilkElementalGroup CilkElementalGroup; + +static llvm::MDNode *MakeVecLengthMetadata(CodeGenModule &CGM, StringRef Name, + QualType T, uint64_t VL) { + llvm::LLVMContext &Context = CGM.getLLVMContext(); + llvm::Value *attrMDArgs[] = { + llvm::MDString::get(Context, Name), + llvm::UndefValue::get(CGM.getTypes().ConvertType(T)), + llvm::ConstantInt::get(CGM.Int32Ty, VL) + }; + return llvm::MDNode::get(Context, attrMDArgs); +} + +static bool CheckElementalArguments(CodeGenModule &CGM, const FunctionDecl *FD, + llvm::Function *Fn, bool &HasThis) { + // Check the return type. + QualType RetTy = FD->getResultType(); + if (RetTy->isAggregateType()) { + CGM.Error(FD->getLocation(), "the return type for this elemental " + "function is not supported yet"); + return false; + } + + // Check each parameter type. + for (unsigned I = 0, E = FD->param_size(); I < E; ++I) { + const ParmVarDecl *VD = FD->getParamDecl(I); + QualType Ty = VD->getType(); + assert(!Ty->isIncompleteType() && "incomplete type"); + if (Ty->isAggregateType()) { + CGM.Error(VD->getLocation(), "the parameter type for this elemental " + "function is not supported yet"); + return false; + } + } + + HasThis = isa(FD) && cast(FD)->isInstance(); + + // At this point, no passing struct arguments by value. + unsigned NumArgs = FD->param_size(); + unsigned NumLLVMArgs = Fn->arg_size(); + + // There is a single implicit 'this' parameter. + if (HasThis && (NumArgs + 1 == NumLLVMArgs)) + return true; + + return NumArgs == NumLLVMArgs; +} + +/// \brief Generates a properstep argument for each function parameter. +/// Returns true if this is a non-linear and non-uniform variable. +/// Otherwise returns false. +static bool handleParameter(CodeGenModule &CGM, CilkElementalGroup &G, + StringRef ParmName, + SmallVectorImpl &StepArgs, + SmallVectorImpl &AligArgs) { + // Update the alignment args. + unsigned Alignment; + if (G.getAlignedAttr(ParmName, &Alignment)) { + AligArgs.push_back(llvm::ConstantInt::get(CGM.IntTy, Alignment)); + } + else { + AligArgs.push_back(llvm::UndefValue::get(CGM.IntTy)); + } + // Update the step args. + std::pair LinStep; + if (G.getUniformAttr(ParmName)) { + // If this is uniform, then use step 0 as placeholder. + StepArgs.push_back(llvm::ConstantInt::get(CGM.IntTy, 0)); + return false; + } + else if (G.getLinearAttr(ParmName, &LinStep)) { + if (LinStep.first != 0) { + StepArgs.push_back(llvm::ConstantInt::get(CGM.IntTy, LinStep.first)); + } + else { + StepArgs.push_back(llvm::MDString::get(CGM.getLLVMContext(), + LinStep.second)); + } + return false; + } + // If this is non-linear and non-uniform, use undefined step as placeholder. + StepArgs.push_back(llvm::UndefValue::get(CGM.IntTy)); + return true; +} + +// The following is common part for 'cilk vector functions' and +// 'omp declare simd' functions metadata generation. +// +void CodeGenModule::EmitVectorVariantsMetadata(const CGFunctionInfo &FnInfo, + const FunctionDecl *FD, + llvm::Function *Fn, + GroupMap &Groups) { + + // Do not emit any vector variant if there is an unsupported feature. + bool HasImplicitThis = false; + if (!CheckElementalArguments(*this, FD, Fn, HasImplicitThis)) + return; + + llvm::LLVMContext &Context = getLLVMContext(); + ASTContext &C = getContext(); + + // Common metadata nodes. + llvm::NamedMDNode *CilkElementalMetadata = + getModule().getOrInsertNamedMetadata("cilk.functions"); + llvm::Value *ElementalMDArgs[] = { + llvm::MDString::get(Context, "elemental") + }; + llvm::MDNode *ElementalNode = llvm::MDNode::get(Context, ElementalMDArgs); + llvm::Value *MaskMDArgs[] = { + llvm::MDString::get(Context, "mask"), + llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(Context), 1) + }; + llvm::MDNode *MaskNode = llvm::MDNode::get(Context, MaskMDArgs); + MaskMDArgs[1] = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(Context), 0); + llvm::MDNode *NoMaskNode = llvm::MDNode::get(Context, MaskMDArgs); + SmallVector ParameterNameArgs; + ParameterNameArgs.push_back(llvm::MDString::get(Context, "arg_name")); + llvm::MDNode *ParameterNameNode = 0; + +// // Vector variant metadata. +// llvm::Value *VariantMDArgs[] = { +// llvm::MDString::get(Context, "variant"), +// llvm::UndefValue::get(llvm::Type::getVoidTy(Context)) +// }; +// llvm::MDNode *VariantNode = llvm::MDNode::get(Context, VariantMDArgs); + + for (GroupMap::iterator GI = Groups.begin(), GE = Groups.end(); + GI != GE; + ++GI) { + CilkElementalGroup &G = GI->second; + + // Parameter information. + QualType FirstNonStepParmType; + SmallVector AligArgs; + SmallVector StepArgs; + AligArgs.push_back(llvm::MDString::get(Context, "arg_alig")); + StepArgs.push_back(llvm::MDString::get(Context, "arg_step")); + + // Handle implicit 'this' parameter if necessary. + if (HasImplicitThis) { + ParameterNameArgs.push_back(llvm::MDString::get(Context, "this")); + bool IsNonStepParm = handleParameter(*this, G, "this", + StepArgs, AligArgs); + if (IsNonStepParm) + FirstNonStepParmType = cast(FD)->getThisType(C); + } + + // Handle explicit paramenters. + for (unsigned I = 0; I != FD->getNumParams(); ++I) { + const ParmVarDecl *Parm = FD->getParamDecl(I); + StringRef ParmName = Parm->getName(); + if (!ParameterNameNode) + ParameterNameArgs.push_back(llvm::MDString::get(Context, ParmName)); + bool IsNonStepParm = handleParameter(*this, G, ParmName, + StepArgs, AligArgs); + if (IsNonStepParm && FirstNonStepParmType.isNull()) + FirstNonStepParmType = Parm->getType(); + } + + llvm::MDNode *StepNode = llvm::MDNode::get(Context, StepArgs); + llvm::MDNode *AligNode = llvm::MDNode::get(Context, AligArgs); + if (!ParameterNameNode) + ParameterNameNode = llvm::MDNode::get(Context, ParameterNameArgs); + + // If there is no vectorlengthfor() in this group, determine the + // characteristic type. This can depend on the linear/uniform attributes, + // so it can differ between groups. + // + // The rules for computing the characteristic type are: + // + // a) For a non-void function, the characteristic data type is the + // return type. + // + // b) If the function has any non-uniform, non-linear parameters, the + // the characteristic data type is the type of the first such parameter. + // + // c) If the characteristic data type determined by a) or b) above is + // struct, union, or class type which is pass-by-value (except fo + // the type that maps to the built-in complex data type) + // the characteristic data type is int. + // + // d) If none of the above three cases is applicable, + // the characteristic data type is int. + // + // e) For Intel Xeon Phi native and offload compilation, if the resulting + // characteristic data type is 8-bit or 16-bit integer data type + // the characteristic data type is int. + // + // These rules missed the reference types and we use their pointer types. + // + if (G.VecLengthFor.empty()) { + QualType FnRetTy = FD->getResultType(); + QualType CharacteristicType; + if (!FnRetTy->isVoidType()) + CharacteristicType = FnRetTy; + else if (!FirstNonStepParmType.isNull()) + CharacteristicType = FirstNonStepParmType.getCanonicalType(); + else + CharacteristicType = C.IntTy; + + if (CharacteristicType->isReferenceType()) { + QualType BaseTy = CharacteristicType.getNonReferenceType(); + CharacteristicType = C.getPointerType(BaseTy); + } else if (CharacteristicType->isAggregateType()) + CharacteristicType = C.IntTy; + // FIXME: handle Xeon Phi targets. + G.VecLengthFor.push_back(CharacteristicType); + } + +// // If no mask variants are specified, generate both. +// if (G.Mask.empty()) { +// G.Mask.push_back(1); +// G.Mask.push_back(0); +// } + + // If no vector length is specified, push a dummy value to iterate over. + if (G.VecLength.empty()) + G.VecLength.push_back(0); + + for (CilkElementalGroup::VecLengthForVector::iterator + TI = G.VecLengthFor.begin(), + TE = G.VecLengthFor.end(); + TI != TE; + ++TI) { + + + uint64_t VectorRegisterBytes = 0; + // Inspect the current target features to determine the + // appropriate vector size. + // This is currently X86 specific. + if (Target.hasFeature("avx2")) + VectorRegisterBytes = 64; + else if (Target.hasFeature("avx")) + VectorRegisterBytes = 32; + else if (Target.hasFeature("sse2")) + VectorRegisterBytes = 16; + else if (Target.hasFeature("sse") && + (*TI)->isFloatingType() && + C.getTypeSizeInChars(*TI).getQuantity() == 4) + VectorRegisterBytes = 16; + else if (Target.hasFeature("mmx") && (*TI)->isIntegerType()) + VectorRegisterBytes = 8; + for (CilkElementalGroup::VecLengthVector::iterator + LI = G.VecLength.begin(), + LE = G.VecLength.end(); + LI != LE; + ++LI) { + + uint64_t VL = *LI ? *LI : + (CharUnits::fromQuantity(VectorRegisterBytes) + / C.getTypeSizeInChars(*TI)); + + llvm::MDNode *VecTypeNode + = MakeVecLengthMetadata(*this, "vec_length", *TI, VL); + + { + SmallVector kernelMDArgs; + kernelMDArgs.push_back(Fn); + kernelMDArgs.push_back(ElementalNode); + kernelMDArgs.push_back(ParameterNameNode); + kernelMDArgs.push_back(StepNode); + kernelMDArgs.push_back(AligNode); + kernelMDArgs.push_back(VecTypeNode); + if (!G.Mask.empty()) + kernelMDArgs.push_back((G.Mask.back()==0)?(NoMaskNode):(MaskNode)); + llvm::MDNode *KernelMD = llvm::MDNode::get(Context, kernelMDArgs); + CilkElementalMetadata->addOperand(KernelMD); + } +// for (CilkElementalGroup::MaskVector::iterator +// MI = G.Mask.begin(), +// ME = G.Mask.end(); +// MI != ME; +// ++MI) { +// +// SmallVector kernelMDArgs; +// kernelMDArgs.push_back(Fn); +// kernelMDArgs.push_back(ElementalNode); +// kernelMDArgs.push_back(ParameterNameNode); +// kernelMDArgs.push_back(StepNode); +// kernelMDArgs.push_back(AligNode); +// kernelMDArgs.push_back(VecTypeNode); +// kernelMDArgs.push_back((*MI==0)?(NoMaskNode):(MaskNode)); +// if (ProcessorNode) +// kernelMDArgs.push_back(ProcessorNode); +// kernelMDArgs.push_back(VariantNode); +// llvm::MDNode *KernelMD = llvm::MDNode::get(Context, kernelMDArgs); +// CilkElementalMetadata->addOperand(KernelMD); +// ElementalVariantToEmit.push_back( +// ElementalVariantInfo(&FnInfo, FD, Fn, KernelMD)); +// } + } + } + } +} + + + +// Vector variants CodeGen for elemental functions. +namespace { + +enum ISAClass { + IC_XMM, + IC_YMM1, + IC_YMM2, + IC_ZMM, + IC_Unknown +}; + +enum ParamKind { + PK_Vector, + PK_LinearConst, + PK_Linear, + PK_Uniform +}; + +struct ParamInfo { + ParamKind Kind; + llvm::Value *Step; + + ParamInfo(ParamKind Kind) + : Kind(Kind), Step(0) + {} + + ParamInfo(ParamKind Kind, llvm::Value *Step) + : Kind(Kind), Step(Step) + {} +}; + +} // end anonymous namespace + +static ISAClass getISAClass(StringRef Processor) { + return llvm::StringSwitch(Processor) + // SSE2 + .Case("pentium_4", IC_XMM) + .Case("pentium_4_sse3", IC_XMM) + .Case("core_2_duo_ssse3", IC_XMM) + .Case("core_2_duo_sse4_1", IC_XMM) + .Case("core_i7_sse4_2", IC_XMM) + // AVX + .Case("core_2nd_gen_avx", IC_YMM1) + .Case("core_3rd_gen_avx", IC_YMM1) + // AVX2 + .Case("core_4th_gen_avx", IC_YMM2) + // MIC + .Case("mic", IC_ZMM) + .Default(IC_Unknown); +} + +static char encodeISAClass(ISAClass ISA) { + switch (ISA) { + case IC_XMM: return 'x'; + case IC_YMM1: return 'y'; + case IC_YMM2: return 'Y'; + case IC_ZMM: return 'z'; + case IC_Unknown: llvm_unreachable("ISA unknwon"); + } + llvm_unreachable("unknown isa"); + return 0; +} + +// Return a constant vector <0, 1, ..., N - 1> +static llvm::Constant *getIndicesVector(llvm::Type *Ty, unsigned N) { + SmallVector Indices; + for (unsigned i = 0; i < N; ++i) + Indices.push_back(llvm::ConstantInt::get(Ty, i)); + return llvm::ConstantVector::get(Indices); +} + +// Return a value representing: +// + * <0, 1, ..., VLen - 1> +static llvm::Value *buildLinearArg(llvm::IRBuilder<> &B, unsigned VLen, + llvm::Value *Arg, llvm::Value *Step) { + llvm::Type *Ty = Arg->getType(); + llvm::Value *Base = B.CreateVectorSplat(VLen, Arg); + llvm::Value *Offset = B.CreateMul(getIndicesVector(Step->getType(), VLen), + B.CreateVectorSplat(VLen, Step)); + if (Ty->isPointerTy()) + return B.CreateGEP(Base, Offset); + assert(Ty->isIntegerTy() && "expected an integer type"); + return B.CreateAdd(Base, B.CreateIntCast(Offset, Base->getType(), false)); +} + +static llvm::Value *buildMask(llvm::IRBuilder<> &B, unsigned VL, + llvm::Value *Mask) { + llvm::Type *Ty = Mask->getType()->getVectorElementType(); + if (Ty->isFloatTy()) + Mask = B.CreateBitCast(Mask, llvm::VectorType::get(B.getInt32Ty(), VL)); + else if (Ty->isDoubleTy()) + Mask = B.CreateBitCast(Mask, llvm::VectorType::get(B.getInt64Ty(), VL)); + else + assert((Ty->isIntegerTy()|| Ty->isPointerTy()) && "unexpected type"); + + return B.CreateICmpNE(Mask, llvm::Constant::getNullValue(Mask->getType())); +} + +static llvm::FunctionType *encodeParameters(llvm::Function *Func, + llvm::MDNode *ArgName, + llvm::MDNode *ArgStep, + bool Mask, + llvm::Type *VectorDataTy, + SmallVectorImpl &Info, + llvm::raw_svector_ostream &MangledParams) { + assert(Func && "Func is null"); + unsigned ArgSize = Func->arg_size(); + + assert((ArgName->getNumOperands() == 1 + ArgSize) && "invalid metadata"); + assert((ArgStep->getNumOperands() == 1 + ArgSize) && "invalid metadata"); + + SmallVector Tys; + llvm::Function::const_arg_iterator Arg = Func->arg_begin(); + for (unsigned i = 1, ie = 1 + ArgSize; i < ie; ++i, ++Arg) { + llvm::Value *Step = ArgStep->getOperand(i); + if (isa(Step)) { + MangledParams << "v"; + unsigned VL = VectorDataTy->getVectorNumElements(); + Tys.push_back(llvm::VectorType::get(Arg->getType(), VL)); + Info.push_back(ParamInfo(PK_Vector)); + } else if (llvm::ConstantInt *C = dyn_cast(Step)) { + if (C->isZero()) { + MangledParams << "u"; + Tys.push_back(Arg->getType()); + Info.push_back(ParamInfo(PK_Uniform)); + } else { + MangledParams << "l"; + if (!C->isOne()) + MangledParams << C->getZExtValue(); + Tys.push_back(Arg->getType()); + Info.push_back(ParamInfo(PK_LinearConst, C)); + } + } else if (llvm::MDString *StepName = dyn_cast(Step)) { + // Search parameter names for StepName to determine the index. + unsigned Idx = 0, NumParams = ArgName->getNumOperands() - 1; + for (; Idx < NumParams; ++Idx) { + // The first operand is the argument name kind metadata. + llvm::Value *V = ArgName->getOperand(Idx + 1); + assert(isa(V) && "invalid metadata"); + llvm::MDString *MS = cast(V); + if (MS->getString().equals(StepName->getString())) + break; + } + assert((Idx < NumParams) && "step parameter not found"); + + MangledParams << "s" << Idx; + Tys.push_back(Arg->getType()); + llvm::LLVMContext &Context = Func->getContext(); + Step = llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), Idx); + Info.push_back(ParamInfo(PK_Linear, Step)); + } else + llvm_unreachable("invalid step metadata"); + } + + if (Mask) + Tys.push_back(VectorDataTy); + + llvm::Type *RetTy = Func->getReturnType(); + RetTy = RetTy->isVoidTy() ? RetTy : VectorDataTy; + return llvm::FunctionType::get(RetTy, Tys, false); +} + +static void setVectorVariantAttributes(llvm::Function *Func, + llvm::Function *NewFunc, + const std::string &Processor) { + llvm::AttrBuilder NewFuncAttrs(Func->getAttributes(), + llvm::AttributeSet::FunctionIndex); + + std::string CPU = llvm::StringSwitch(Processor) + .Case("pentium_4", "pentium4") + .Case("pentium_4_sse3", "yonah") + .Case("core_2_duo_ssse3", "core2") + .Case("core_2_duo_sse4_1", "penryn") + .Case("core_i7_sse4_2", "corei7") + .Case("core_2nd_gen_avx", "corei7-avx") + .Case("core_3rd_gen_avx", "core-avx-i") + .Case("core_4th_gen_avx", "core-avx2") + .Case("mic", "") + .Default(""); + + if (!CPU.empty()) + NewFuncAttrs.addAttribute("cpu", CPU); + + if (NewFuncAttrs.hasAttributes()) + NewFunc->setAttributes( + llvm::AttributeSet::get(NewFunc->getContext(), + llvm::AttributeSet::FunctionIndex, + NewFuncAttrs)); +} + +static void createVectorVariantWrapper(llvm::Function *ScalarFunc, + llvm::Function *VectorFunc, + unsigned VLen, + const SmallVectorImpl &Info) { + assert(ScalarFunc->arg_size() == Info.size() && + "Wrong number of parameter infos"); + assert((VLen & (VLen - 1)) == 0 && "VLen must be a power-of-2"); + + bool IsMasked = VectorFunc->arg_size() == ScalarFunc->arg_size() + 1; + llvm::LLVMContext &Context = ScalarFunc->getContext(); + llvm::BasicBlock *Entry + = llvm::BasicBlock::Create(Context, "entry", VectorFunc); + llvm::BasicBlock *LoopCond + = llvm::BasicBlock::Create(Context, "loop.cond", VectorFunc); + llvm::BasicBlock *LoopBody + = llvm::BasicBlock::Create(Context, "loop.body", VectorFunc); + llvm::BasicBlock *MaskOn + = IsMasked ? llvm::BasicBlock::Create(Context, "mask_on", VectorFunc) : 0; + llvm::BasicBlock *MaskOff + = IsMasked ? llvm::BasicBlock::Create(Context, "mask_off", VectorFunc) : 0; + llvm::BasicBlock *LoopStep + = llvm::BasicBlock::Create(Context, "loop.step", VectorFunc); + llvm::BasicBlock *LoopEnd + = llvm::BasicBlock::Create(Context, "loop.end", VectorFunc); + + llvm::Value *VectorRet = 0; + SmallVector VectorArgs; + + // The loop counter. + llvm::Type *IndexTy = llvm::Type::getInt32Ty(Context); + llvm::Value *Index = 0; + llvm::Value *Mask = 0; + + // Copy the names from the scalar args to the vector args. + { + llvm::Function::arg_iterator SI = ScalarFunc->arg_begin(), + SE = ScalarFunc->arg_end(), + VI = VectorFunc->arg_begin(); + for ( ; SI != SE; ++SI, ++VI) + VI->setName(SI->getName()); + if (IsMasked) + VI->setName("mask"); + } + + llvm::IRBuilder<> Builder(Entry); + { + if (!VectorFunc->getReturnType()->isVoidTy()) + VectorRet = Builder.CreateAlloca(VectorFunc->getReturnType()); + + Index = Builder.CreateAlloca(IndexTy, 0, "index"); + Builder.CreateStore(llvm::ConstantInt::get(IndexTy, 0), Index); + + llvm::Function::arg_iterator VI = VectorFunc->arg_begin(); + for (SmallVectorImpl::const_iterator I = Info.begin(), + IE = Info.end(); I != IE; ++I, ++VI) { + llvm::Value *Arg = VI; + switch (I->Kind) { + case PK_Vector: + assert(Arg->getType()->isVectorTy() && "Not a vector"); + assert(VLen == Arg->getType()->getVectorNumElements() && + "Wrong number of elements"); + break; + case PK_LinearConst: + Arg = buildLinearArg(Builder, VLen, Arg, I->Step); + Arg->setName(VI->getName() + ".linear"); + break; + case PK_Linear: { + unsigned Number = cast(I->Step)->getZExtValue(); + llvm::Function::arg_iterator ArgI = VectorFunc->arg_begin(); + std::advance(ArgI, Number); + llvm::Value *Step = ArgI; + Arg = buildLinearArg(Builder, VLen, Arg, Step); + Arg->setName(VI->getName() + ".linear"); + } break; + case PK_Uniform: + Arg = Builder.CreateVectorSplat(VLen, Arg); + Arg->setName(VI->getName() + ".uniform"); + break; + } + VectorArgs.push_back(Arg); + } + + if (IsMasked) + Mask = buildMask(Builder, VLen, VI); + + Builder.CreateBr(LoopCond); + } + + Builder.SetInsertPoint(LoopCond); + { + llvm::Value *Cond = Builder.CreateICmpULT( + Builder.CreateLoad(Index), llvm::ConstantInt::get(IndexTy, VLen)); + Builder.CreateCondBr(Cond, LoopBody, LoopEnd); + } + + llvm::Value *VecIndex = 0; + + Builder.SetInsertPoint(LoopBody); + { + VecIndex = Builder.CreateLoad(Index); + if (IsMasked) { + llvm::Value *ScalarMask = Builder.CreateExtractElement(Mask, VecIndex); + Builder.CreateCondBr(ScalarMask, MaskOn, MaskOff); + } + } + + Builder.SetInsertPoint(IsMasked ? MaskOn : LoopBody); + { + // Build the argument list for the scalar function by extracting element + // 'VecIndex' from the vector arguments. + SmallVector ScalarArgs; + for (SmallVectorImpl::iterator VI = VectorArgs.begin(), + VE = VectorArgs.end(); VI != VE; ++VI) { + assert((*VI)->getType()->isVectorTy() && "Not a vector"); + ScalarArgs.push_back(Builder.CreateExtractElement(*VI, VecIndex)); + } + + // Call the scalar function with the extracted scalar arguments. + llvm::Value *ScalarRet = Builder.CreateCall(ScalarFunc, ScalarArgs); + + // If the function returns a value insert the scalar return value into the + // vector return value. + if (VectorRet) { + llvm::Value *V = Builder.CreateLoad(VectorRet); + V = Builder.CreateInsertElement(V, ScalarRet, VecIndex); + Builder.CreateStore(V, VectorRet); + } + + Builder.CreateBr(LoopStep); + } + + if (IsMasked) { + Builder.SetInsertPoint(MaskOff); + if (VectorRet) { + llvm::Value *V = Builder.CreateLoad(VectorRet); + llvm::Value *Zero + = llvm::Constant::getNullValue(ScalarFunc->getReturnType()); + V = Builder.CreateInsertElement(V, Zero, VecIndex); + Builder.CreateStore(V, VectorRet); + } + Builder.CreateBr(LoopStep); + } + + Builder.SetInsertPoint(LoopStep); + { + // Index = Index + 1 + VecIndex = Builder.CreateAdd(VecIndex, llvm::ConstantInt::get(IndexTy, 1)); + Builder.CreateStore(VecIndex, Index); + Builder.CreateBr(LoopCond); + } + + Builder.SetInsertPoint(LoopEnd); + { + if (VectorRet) + Builder.CreateRet(Builder.CreateLoad(VectorRet)); + else + Builder.CreateRetVoid(); + } +} + +static bool createVectorVariant(llvm::MDNode *Root, + const FunctionDecl *FD, + llvm::Function *F) { + llvm::Module &M = *F->getParent(); + + if (Root->getNumOperands() == 0) + return false; + llvm::Function *Func = dyn_cast(Root->getOperand(0)); + if (Func != F) + return false; + + bool Elemental = false; + + unsigned VariantIndex = 0; + llvm::MDNode *ArgName = 0, + *ArgStep = 0, + *VecLength = 0, + *Processor = 0, + *Mask = 0, + *Variant = 0; + + for (unsigned i = 1, ie = Root->getNumOperands(); i < ie; ++i) { + llvm::MDNode *Node = dyn_cast(Root->getOperand(i)); + if (!Node || Node->getNumOperands() < 1) + return false; + llvm::MDString *Name = dyn_cast(Node->getOperand(0)); + if (!Name) + return false; + + if (Name->getString() == "elemental") { + Elemental = true; + } else if (Name->getString() == "arg_name") { + ArgName = Node; + } else if (Name->getString() == "arg_step") { + ArgStep = Node; + } else if (Name->getString() == "vec_length") { + VecLength = Node; + } else if (Name->getString() == "processor") { + Processor = Node; + } else if (Name->getString() == "mask") { + Mask = Node; + } else if (Name->getString() == "variant") { + VariantIndex = i; + Variant = Node; + } else { + DEBUG(llvm::dbgs() << "Unknown metadata " << Name->getString() << "\n"); + return false; + } + } + + if (!Elemental || !ArgName || !ArgStep || !VecLength || !Variant) { + DEBUG(llvm::dbgs() << "Missing necessary metadata node" << "\n"); + return false; + } + + if (llvm::Value *V = Variant->getOperand(1)) + if (!V->getType()->isVoidTy()) + return false; + + // The default processor is pentium_4. + std::string ProcessorName = "pentium_4"; + if (Processor) { + if (Processor->getNumOperands() != 2) + return false; + llvm::MDString *Name = dyn_cast(Processor->getOperand(1)); + if (!Name) + return false; + ProcessorName = Name->getString().str(); + } + ISAClass ISA = getISAClass(ProcessorName); + if (ISA == IC_Unknown) + return false; + + bool IsMasked = true; + if (Mask) { + if (Mask->getNumOperands() != 2) + return false; + llvm::ConstantInt *C = dyn_cast(Mask->getOperand(1)); + if (!C) + return false; + IsMasked = C->isOne(); + } + + llvm::Type *VectorDataTy = 0; + uint64_t VLen = 0; + { + if (VecLength->getNumOperands() != 3) + return false; + llvm::Type *Ty = VecLength->getOperand(1)->getType(); + if (!llvm::VectorType::isValidElementType(Ty)) + return false; + + llvm::Value *VL = VecLength->getOperand(2); + assert(isa(VL) && "vector length constant expected"); + VLen = cast(VL)->getZExtValue(); + VectorDataTy = llvm::VectorType::get(Ty, VLen); + } + + SmallVector Info; + SmallString<16> ParamStr; + llvm::raw_svector_ostream MangledParams(ParamStr); + llvm::FunctionType *NewFuncTy = encodeParameters(Func, ArgName, ArgStep, + IsMasked, VectorDataTy, + Info, MangledParams); + if (!NewFuncTy) + return false; + + // Generate the mangled name. + SmallString<32> NameStr; + llvm::raw_svector_ostream MangledName(NameStr); + MangledName << "_ZGV" // Magic prefix + << encodeISAClass(ISA) + << (IsMasked ? 'M' : 'N') + << VLen + << MangledParams.str() + << "_" + << Func->getName(); + + DEBUG(llvm::dbgs() << "Creating elemental function " + << MangledName.str() << "\n"); + + // Declare the vector variant function in to the module. + llvm::Function *NewFunc = + dyn_cast(M.getOrInsertFunction(MangledName.str(), NewFuncTy)); + if (!NewFunc || !NewFunc->empty()) + return false; + + setVectorVariantAttributes(Func, NewFunc, ProcessorName); + + // Define the vector variant if the scalar function is not a declaration. + if (FD->hasBody()) + createVectorVariantWrapper(Func, NewFunc, VLen, Info); + + // Update the vector variant metadata. + { + assert(VariantIndex && "invalid variant index"); + llvm::LLVMContext &Context = Func->getContext(); + llvm::Value *VariantMDArgs[] = { + llvm::MDString::get(Context, "variant"), + NewFunc + }; + llvm::MDNode *VariantNode = llvm::MDNode::get(Context, VariantMDArgs); + Root->replaceOperandWith(VariantIndex, VariantNode); + } + + return true; +} + +void CodeGenModule::EmitCilkElementalVariants() { + for (SmallVectorImpl::iterator + I = ElementalVariantToEmit.begin(), + E = ElementalVariantToEmit.end(); I != E; ++I) + createVectorVariant(I->KernelMD, I->FD, I->Fn); +} diff -uNr clang-3.4/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExpr.cpp --- clang-3.4/lib/CodeGen/CGExpr.cpp 2013-11-21 18:33:07.000000000 -0500 +++ clang/lib/CodeGen/CGExpr.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1742,6 +1742,20 @@ // A DeclRefExpr for a reference initialized by a constant expression can // appear without being odr-used. Directly emit the constant initializer. if (const VarDecl *VD = dyn_cast(ND)) { + + // CodeGen for threadprivate variables. + if (getLangOpts().OpenMP) { + if (llvm::Value *Val = + CGM.CreateOpenMPThreadPrivateCached(VD, E->getExprLoc(), *this)) + return MakeAddrLValue(Val, T, Alignment); + // CodeGen for OpenMP private variables - works only in CapturedStmt. + else if (llvm::Value *Val = CGM.OpenMPSupport.getOpenMPPrivateVar(VD)) + return MakeAddrLValue(Val, T, Alignment); + else if (CapturedStmtInfo) + if (llvm::Value *Val = CapturedStmtInfo->getCachedVar(VD)) + return MakeAddrLValue(Val, T, Alignment); + } + const Expr *Init = VD->getAnyInitializer(VD); if (Init && !isa(VD) && VD->getType()->isReferenceType() && VD->isUsableInConstantExpressions(getContext()) && @@ -1980,7 +1994,8 @@ GlobalVarName += FnName; // If this is outside of a function use the top level decl. - const Decl *CurDecl = CurCodeDecl; + const Decl *CurDecl = + OpenMPRoot ? OpenMPRoot->CurCodeDecl : CurCodeDecl; if (CurDecl == 0 || isa(CurDecl)) CurDecl = getContext().getTranslationUnitDecl(); diff -uNr clang-3.4/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGExprScalar.cpp --- clang-3.4/lib/CodeGen/CGExprScalar.cpp 2013-11-08 18:00:12.000000000 -0500 +++ clang/lib/CodeGen/CGExprScalar.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -224,6 +224,11 @@ return CGF.getOpaqueRValueMapping(E).getScalarVal(); } + Value *VisitCEANIndexExpr(CEANIndexExpr *E) { + assert (E->getIndexExpr() && "Index expr is not set"); + return CGF.EmitScalarExpr(E->getIndexExpr()); + } + // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { diff -uNr clang-3.4/lib/CodeGen/CGLoopInfo.cpp clang/lib/CodeGen/CGLoopInfo.cpp --- clang-3.4/lib/CodeGen/CGLoopInfo.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/lib/CodeGen/CGLoopInfo.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -0,0 +1,156 @@ +//===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CGLoopInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Metadata.h" +using namespace clang; +using namespace CodeGen; + +static llvm::MDNode *CreateMetadata(llvm::LLVMContext &Ctx, + const LoopAttributes &Attrs) { + using namespace llvm; + + if (!Attrs.IsParallel && + Attrs.VectorizerWidth == 0 && + Attrs.VectorizerEnable == LoopAttributes::LVEC_UNSPECIFIED) + return 0; + + SmallVector Args; + // Reserve operand 0 for loop id self reference. + MDNode *TempNode = MDNode::getTemporary(Ctx, None); + Args.push_back(TempNode); + + // Setting vectorizer.width + // TODO: For a correct implementation of 'safelen' clause + // we need to update the value somewhere (based on target info). + if (Attrs.VectorizerWidth > 0) { + Value *Vals[] = { + MDString::get(Ctx, "llvm.vectorizer.width"), + ConstantInt::get(Type::getInt32Ty(Ctx), Attrs.VectorizerWidth) + }; + Args.push_back(MDNode::get(Ctx, Vals)); + } + + // Setting vectorizer.enable + int EnableLoopVectorizer = 0; + switch (Attrs.VectorizerEnable) { + case LoopAttributes::LVEC_UNSPECIFIED: + break; + case LoopAttributes::LVEC_ENABLE: + EnableLoopVectorizer = 1; + // Fall-through + case LoopAttributes::LVEC_DISABLE: + Value *Vals[] = { + MDString::get(Ctx, "llvm.vectorizer.enable"), + ConstantInt::get(Type::getInt1Ty(Ctx), EnableLoopVectorizer) + }; + Args.push_back(MDNode::get(Ctx, Vals)); + break; + } + + MDNode *LoopID = MDNode::get(Ctx, Args); + assert(LoopID->use_empty() && "LoopID should not be used"); + + // Set the first operand to itself. + LoopID->replaceOperandWith(0, LoopID); + MDNode::deleteTemporary(TempNode); + return LoopID; +} + +LoopAttributes::LoopAttributes(bool IsParallel) + : IsParallel(IsParallel), + VectorizerEnable(LoopAttributes::LVEC_UNSPECIFIED), + VectorizerWidth(0) { } + +void LoopAttributes::Clear() { + IsParallel = false; + VectorizerWidth = 0; + VectorizerEnable = LoopAttributes::LVEC_UNSPECIFIED; +} + +LoopInfo::LoopInfo(llvm::BasicBlock *Header, const LoopAttributes &Attrs) + : LoopID(0), Header(Header), Attrs(Attrs) { + LoopID = CreateMetadata(Header->getContext(), Attrs); +} + +LoopInfo::LoopInfo(llvm::MDNode *LoopID, const LoopAttributes &Attrs) + : LoopID(LoopID), Header(0), Attrs(Attrs) { } + +void LoopInfoStack::Push(llvm::BasicBlock *Header) { + Active.push_back(LoopInfo(Header, StagedAttrs)); + // Clear the attributes so nested loops do not inherit them. + StagedAttrs.Clear(); +} + +void LoopInfoStack::Pop() { + assert(!Active.empty()); + Active.pop_back(); +} + +void LoopInfoStack::AddAligned(const llvm::Value *Val, int Align) { + // The following restriction should be enforced by Sema, so + // check it with assertion. + assert(Aligneds.find(Val) == Aligneds.end() || + Aligneds.find(Val)->second == Align); + Aligneds.insert(std::make_pair(Val, Align)); +} + +int LoopInfoStack::GetAligned(const llvm::Value *Val) const { + llvm::DenseMap::const_iterator It = + Aligneds.find(Val); + if (It == Aligneds.end()) return 0; + return It->second; +} + +void LoopInfoStack::InsertHelper(llvm::Instruction *I) const { + if (!HasInfo()) + return; + + const LoopInfo &L = GetInfo(); + + if (!L.GetLoopID()) + return; + + if (llvm::TerminatorInst *TI = llvm::dyn_cast(I)) { + for (unsigned i = 0, ie = TI->getNumSuccessors(); i < ie; ++i) + if (TI->getSuccessor(i) == L.GetHeader()) { + TI->setMetadata("llvm.loop", L.GetLoopID()); + break; + } + return; + } + + if (L.GetAttributes().IsParallel) { + if (llvm::StoreInst *SI = llvm::dyn_cast(I)) { + SI->setMetadata("llvm.mem.parallel_loop_access", L.GetLoopID()); + } + else if (llvm::LoadInst *LI = llvm::dyn_cast(I)) { + LI->setMetadata("llvm.mem.parallel_loop_access", L.GetLoopID()); + if (int Align = GetAligned(LI->getOperand(0))) { + llvm::Value *AlignVal = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(LI->getContext()), Align); + llvm::SmallVector Args; + Args.push_back(AlignVal); + llvm::MDNode *Node = llvm::MDNode::get(LI->getContext(), Args); + LI->setMetadata("llvm.mem.aligned", Node); + } + } + } +} + +void LoopInfoStack::Push(llvm::MDNode *LoopID, bool IsParallel) { + assert(Active.empty() && "cannot have an active loop"); + Active.push_back(LoopInfo(LoopID, LoopAttributes(IsParallel))); + StagedAttrs.Clear(); +} + diff -uNr clang-3.4/lib/CodeGen/CGLoopInfo.h clang/lib/CodeGen/CGLoopInfo.h --- clang-3.4/lib/CodeGen/CGLoopInfo.h 1969-12-31 19:00:00.000000000 -0500 +++ clang/lib/CodeGen/CGLoopInfo.h 2014-05-19 19:58:57.000000000 -0400 @@ -0,0 +1,147 @@ +//===---- CGLoopInfo.h - LLVM CodeGen for loop metadata -*- C++ -*---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the internal state used for llvm translation for loop statement +// metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGLOOPINFO_H +#define CLANG_CODEGEN_CGLOOPINFO_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Compiler.h" +#include "llvm/IR/Value.h" + +namespace llvm { +class BasicBlock; +class Instruction; +class MDNode; +} // end namespace llvm + +namespace clang { +namespace CodeGen { + +/// LoopAttributes - Per loop attributes. +struct LoopAttributes { + explicit LoopAttributes(bool IsParallel = false); + void Clear(); + + /// llvm.loop.parallel metadata generation for loads and stores. + bool IsParallel; + + /// llvm.vectorizer.enable value: + enum LVEnableState { + LVEC_UNSPECIFIED, + LVEC_ENABLE, + LVEC_DISABLE + }; + + LVEnableState VectorizerEnable; + + /// llvm.vectorizer.width value + unsigned VectorizerWidth; +}; + +/// LoopInfo - Information used when generating a structured loop. +class LoopInfo { +public: + /// Construct a new LoopInfo for the loop with entry Header. + LoopInfo(llvm::BasicBlock *Header, const LoopAttributes &Attrs); + + /// Construct a new LoopInfo with a given loop id metadata. + LoopInfo(llvm::MDNode *LoopID, const LoopAttributes &Attrs); + + /// Get the loop id metadata for this loop. + llvm::MDNode *GetLoopID() const { return LoopID; } + + /// Get the header block of this loop. + llvm::BasicBlock *GetHeader() const { return Header; } + + /// Get the set of attributes active for this loop. + const LoopAttributes &GetAttributes() const { return Attrs; } + +private: + /// Loop ID metadata. + mutable llvm::MDNode *LoopID; + /// Header block of this loop. + llvm::BasicBlock *Header; + /// The attributes for this loop. + LoopAttributes Attrs; +}; + +/// LoopInfoStack - A stack of loop information corresponding to loop +/// nesting levels. This stack can be used to prepare attributes which are +/// applied when a loop is emitted. +class LoopInfoStack { + LoopInfoStack(const LoopInfoStack &) LLVM_DELETED_FUNCTION; + void operator=(const LoopInfoStack &) LLVM_DELETED_FUNCTION; +public: + LoopInfoStack() {} + + /// Begin a new structured loop. The set of applied attributes will be applied + /// to the loop and the attributes will be cleared. + void Push(llvm::BasicBlock *Header); + + /// Extend the code region as part of a parallel loop which might be inside + /// another llvm function. + void Push(llvm::MDNode *LoopID, bool IsParallel); + + /// End the current loop. + void Pop(); + + /// Return the top loop id metadata. + llvm::MDNode *GetCurLoopID() const { return GetInfo().GetLoopID(); } + + /// Return true if the top loop is parallel. + bool GetCurLoopParallel() const { + return HasInfo() ? + GetInfo().GetAttributes().IsParallel : false; + } + + /// Function called by the CodeGenFunction when an instruction is created. + void InsertHelper(llvm::Instruction *I) const; + + /// Set the next pushed loop as parallel. + void SetParallel(bool Enable = true) { StagedAttrs.IsParallel = Enable; } + + /// Set the next pushed loop 'vectorizer.enable' + void SetVectorizerEnable(bool Enable = true) { + StagedAttrs.VectorizerEnable = Enable ? LoopAttributes::LVEC_ENABLE : + LoopAttributes::LVEC_DISABLE; + } + + /// Set the vectorizer width for the next loop pushed. + void SetVectorizerWidth(unsigned W) { StagedAttrs.VectorizerWidth = W; } + + /// Add an aligned variable for 'aligned' clause. + void AddAligned(const llvm::Value *Val, int Align); + + /// Get alignment of given pointer based on 'aligned' clause. + int GetAligned(const llvm::Value *Val) const; + +private: + /// Returns true if there is LoopInfo on the stack. + bool HasInfo() const { return !Active.empty(); } + /// Return the LoopInfo for the current loop. HasInfo should be called first + /// to ensure LoopInfo is present. + const LoopInfo &GetInfo() const { return Active.back(); } + /// The set of attributes that will be applied to the next pushed loop. + LoopAttributes StagedAttrs; + /// Stack of active loops. + llvm::SmallVector Active; + // 'Aligned' information. + llvm::DenseMap Aligneds; +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif // CLANG_CODEGEN_CGLOOPINFO_H diff -uNr clang-3.4/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CGStmt.cpp --- clang-3.4/lib/CodeGen/CGStmt.cpp 2013-11-04 11:13:21.000000000 -0500 +++ clang/lib/CodeGen/CGStmt.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -16,6 +16,7 @@ #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/CapturedStmt.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/TargetInfo.h" @@ -23,6 +24,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/TypeBuilder.h" #include "llvm/Support/CallSite.h" using namespace clang; using namespace CodeGen; @@ -75,7 +77,6 @@ case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: case Stmt::MSDependentExistsStmtClass: - case Stmt::OMPParallelDirectiveClass: llvm_unreachable("invalid statement class to emit generically"); case Stmt::NullStmtClass: case Stmt::CompoundStmtClass: @@ -141,6 +142,106 @@ EmitCapturedStmt(*CS, CS->getCapturedRegionKind()); } break; + // "One-call" OMP Directives + case Stmt::OMPBarrierDirectiveClass: + EmitOMPBarrierDirective(cast(*S)); + break; + case Stmt::OMPTaskyieldDirectiveClass: + EmitOMPTaskyieldDirective(cast(*S)); + break; + case Stmt::OMPTaskwaitDirectiveClass: + EmitOMPTaskwaitDirective(cast(*S)); + break; + case Stmt::OMPFlushDirectiveClass: + EmitOMPFlushDirective(cast(*S)); + break; + // Atomic OMP Directive -- pattern match and emit one call + case Stmt::OMPAtomicDirectiveClass: + EmitOMPAtomicDirective(cast(*S)); + break; + // "Two-calls" OMP Directives + case Stmt::OMPMasterDirectiveClass: + EmitOMPMasterDirective(cast(*S)); + break; + case Stmt::OMPSingleDirectiveClass: + EmitOMPSingleDirective(cast(*S)); + break; + case Stmt::OMPCriticalDirectiveClass: + EmitOMPCriticalDirective(cast(*S)); + break; + case Stmt::OMPOrderedDirectiveClass: + EmitOMPOrderedDirective(cast(*S)); + break; + // A more advanced stuff + case Stmt::OMPParallelDirectiveClass: + EmitOMPParallelDirective(cast(*S)); + break; + case Stmt::OMPParallelForDirectiveClass: + EmitOMPParallelForDirective(cast(*S)); + break; + case Stmt::OMPSimdDirectiveClass: + EmitOMPSimdDirective(cast(*S)); + break; + case Stmt::OMPForSimdDirectiveClass: + EmitOMPForSimdDirective(cast(*S)); + break; + case Stmt::OMPParallelForSimdDirectiveClass: + EmitOMPParallelForSimdDirective(cast(*S)); + break; + case Stmt::OMPDistributeSimdDirectiveClass: + EmitOMPDistributeSimdDirective(cast(*S)); + break; + case Stmt::OMPDistributeParallelForDirectiveClass: + EmitOMPDistributeParallelForDirective( + cast(*S)); + break; + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + EmitOMPDistributeParallelForSimdDirective( + cast(*S)); + break; + case Stmt::OMPTaskDirectiveClass: + EmitOMPTaskDirective(cast(*S)); + break; + case Stmt::OMPForDirectiveClass: + EmitOMPForDirective(cast(*S)); + break; + case Stmt::OMPSectionsDirectiveClass: + EmitOMPSectionsDirective(cast(*S)); + break; + case Stmt::OMPParallelSectionsDirectiveClass: + EmitOMPParallelSectionsDirective(cast(*S)); + break; + case Stmt::OMPSectionDirectiveClass: + EmitOMPSectionDirective(cast(*S)); + break; + case Stmt::OMPTaskgroupDirectiveClass: + EmitOMPTaskgroupDirective(cast(*S)); + break; + case Stmt::OMPTeamsDirectiveClass: + EmitOMPTeamsDirective(cast(*S)); + break; + case Stmt::OMPDistributeDirectiveClass: + EmitOMPDistributeDirective(cast(*S)); + break; + case Stmt::OMPCancelDirectiveClass: + EmitOMPCancelDirective(cast(*S)); + break; + case Stmt::OMPCancellationPointDirectiveClass: + EmitOMPCancellationPointDirective( + cast(*S)); + break; + case Stmt::OMPTargetDirectiveClass: + EmitOMPTargetDirective(cast(*S)); + break; + case Stmt::OMPTargetDataDirectiveClass: + EmitOMPTargetDataDirective(cast(*S)); + break; + case Stmt::OMPTargetUpdateDirectiveClass: + EmitOMPTargetUpdateDirective(cast(*S)); + break; + case Stmt::OMPTargetTeamsDirectiveClass: + EmitOMPTargetTeamsDirective(cast(*S)); + break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast(*S)); break; @@ -497,6 +598,7 @@ // the continue target. JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); EmitBlock(LoopHeader.getBlock()); + LoopStack.Push(LoopHeader.getBlock()); // Create an exit block for when the condition fails, which will // also become the break target. @@ -560,6 +662,8 @@ // Branch to the loop header again. EmitBranch(LoopHeader.getBlock()); + LoopStack.Pop(); + // Emit the exit block. EmitBlock(LoopExit.getBlock(), true); @@ -578,6 +682,8 @@ // Emit the body of the loop. llvm::BasicBlock *LoopBody = createBasicBlock("do.body"); + LoopStack.Push(LoopBody); + EmitBlock(LoopBody); { RunCleanupsScope BodyScope(*this); @@ -607,6 +713,8 @@ if (EmitBoolCondBranch) Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock()); + LoopStack.Pop(); + // Emit the exit block. EmitBlock(LoopExit.getBlock()); @@ -635,6 +743,7 @@ JumpDest Continue = getJumpDestInCurrentScope("for.cond"); llvm::BasicBlock *CondBlock = Continue.getBlock(); EmitBlock(CondBlock); + LoopStack.Push(CondBlock); // Create a cleanup scope for the condition variable cleanups. RunCleanupsScope ConditionScope(*this); @@ -703,6 +812,8 @@ if (DI) DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); + LoopStack.Pop(); + // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); } @@ -1772,20 +1883,24 @@ } } -static LValue InitCapturedStruct(CodeGenFunction &CGF, const CapturedStmt &S) { +LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) { const RecordDecl *RD = S.getCapturedRecordDecl(); - QualType RecordTy = CGF.getContext().getRecordType(RD); + QualType RecordTy = getContext().getRecordType(RD); // Initialize the captured struct. - LValue SlotLV = CGF.MakeNaturalAlignAddrLValue( - CGF.CreateMemTemp(RecordTy, "agg.captured"), RecordTy); + LValue SlotLV = MakeNaturalAlignAddrLValue( + CreateMemTemp(RecordTy, "agg.captured"), RecordTy); RecordDecl::field_iterator CurField = RD->field_begin(); + CapturedStmt::const_capture_iterator C = S.capture_begin(); for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(), E = S.capture_init_end(); - I != E; ++I, ++CurField) { - LValue LV = CGF.EmitLValueForFieldInitialization(SlotLV, *CurField); - CGF.EmitInitializerForField(*CurField, LV, *I, ArrayRef()); + I != E; ++I, ++C, ++CurField) { + if ((*CurField)->getType()->isVariablyModifiedType()) { + EmitVariablyModifiedType((*CurField)->getType()); + } + LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField); + EmitInitializerForField(*CurField, LV, *I, ArrayRef()); } return SlotLV; @@ -1799,7 +1914,7 @@ const RecordDecl *RD = S.getCapturedRecordDecl(); assert(CD->hasBody() && "missing CapturedDecl body"); - LValue CapStruct = InitCapturedStruct(*this, S); + LValue CapStruct = InitCapturedStruct(S); // Emit the CapturedDecl CodeGenFunction CGF(CGM, true); @@ -1818,6 +1933,8 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD, const RecordDecl *RD, SourceLocation Loc) { + CGM.OpenMPSupport.startOpenMPRegion(true); + assert(CapturedStmtInfo && "CapturedStmtInfo should be set when generating the captured function"); @@ -1855,8 +1972,330 @@ CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal(); } + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); + I != E; ++I) { + if ((*I)->getType()->isVariablyModifiedType()) { + EmitVariablyModifiedType((*I)->getType()); + } + } + CapturedStmtInfo->EmitBody(*this, CD->getBody()); FinishFunction(CD->getBodyRBrace()); + CGM.OpenMPSupport.endOpenMPRegion(); + return F; } + +void CodeGenFunction::EmitSIMDForHelperCall(llvm::Function *BodyFunc, + LValue CapStruct, + llvm::Value *LoopIndex, + bool IsLastIter) { + // Emit call to the helper function. + SmallVector HelperArgs; + HelperArgs.push_back(CapStruct.getAddress()); + HelperArgs.push_back(Builder.CreateLoad(LoopIndex)); + + llvm::Value *LastIter = 0; + if (IsLastIter) + LastIter = llvm::ConstantInt::getTrue(BodyFunc->getContext()); + else + LastIter = llvm::ConstantInt::getFalse(BodyFunc->getContext()); + HelperArgs.push_back(LastIter); + + disableExceptions(); + EmitCallOrInvoke(BodyFunc, HelperArgs); + enableExceptions(); +} + +llvm::Function *CodeGenFunction::EmitSimdFunction(CGPragmaSimdWrapper &W) { + const CapturedStmt &CS = *W.getAssociatedStmt(); + CapturedDecl *CD = const_cast(CS.getCapturedDecl()); + const RecordDecl *RD = CS.getCapturedRecordDecl(); + + CGSIMDForStmtInfo CSInfo(W, LoopStack.GetCurLoopID(), + LoopStack.GetCurLoopParallel()); + CodeGenFunction CGF(CGM, true); + CGF.CapturedStmtInfo = &CSInfo; + + CGF.disableExceptions(); + llvm::Function *BodyFunction = CGF.GenerateCapturedStmtFunction( + CD, RD, CS.getLocStart()); + CGF.enableExceptions(); + + // Always inline this function back to the call site. + BodyFunction->addFnAttr(llvm::Attribute::AlwaysInline); + return BodyFunction; +} + +void CodeGenFunction::EmitPragmaSimd(CodeGenFunction::CGPragmaSimdWrapper &W) { + if (W.isOmp()) { + // Start a region for loop index and loops' counters + // (there will be another one region inside __simd_helper routine). + CGM.OpenMPSupport.startOpenMPRegion(false); + CGM.OpenMPSupport.setNoWait(false); + CGM.OpenMPSupport.setMergeable(true); + CGM.OpenMPSupport.setOrdered(false); + } + RunCleanupsScope SIMDForScope(*this); + + // Emit 'safelen' clause and decide if we want to separate last iteration. + bool SeparateLastIter = W.emitSafelen(this); + + // Update debug info. + CGDebugInfo *DI = getDebugInfo(); + if (DI) + DI->EmitLexicalBlockStart(Builder, W.getForLoc()); + + // Emit the for-loop. + llvm::Value *LoopIndex = 0; + llvm::Value *LoopCount = 0; + + // Emit the loop control variable and cache its initial value and the + // stride value. + // Also emit loop index and loop count, depending on stmt. + + W.emitInit(*this, LoopIndex, LoopCount); + + // Only run the SIMD loop if the loop condition is true + llvm::BasicBlock *ContBlock = createBasicBlock("if.end"); + llvm::BasicBlock *ThenBlock = createBasicBlock("if.then"); + + // The following condition is zero trip test to skip last iteration if + // the loopcount is zero. + // In the 'omp simd' we may have more than one loop counter due to + // 'collapse', so we check loopcount instead of loop counter. + if (!W.isOmp()) { + EmitBranchOnBoolExpr(W.getCond(), ThenBlock, ContBlock); + EmitBlock(ThenBlock); + } + else { + llvm::Value *BoolCondVal = Builder.CreateICmpSLT( + llvm::ConstantInt::get(LoopCount->getType(), 0), LoopCount); + Builder.CreateCondBr(BoolCondVal, ThenBlock, ContBlock); + EmitBlock(ThenBlock); + } + + // Initialize the captured struct. + LValue CapStruct = InitCapturedStruct(*W.getAssociatedStmt()); + + { + JumpDest LoopExit = getJumpDestInCurrentScope("for.end"); + RunCleanupsScope ForScope(*this); + + Builder.CreateStore(llvm::ConstantInt::get(LoopCount->getType(), 0), + LoopIndex); + + if (SeparateLastIter) + // Lastprivate or linear variable present, remove last iteration. + LoopCount = Builder.CreateSub( + LoopCount, llvm::ConstantInt::get(LoopCount->getType(), 1)); + + // Start the loop with a block that tests the condition. + // If there's an increment, the continue scope will be overwritten + // later. + JumpDest Continue = getJumpDestInCurrentScope("for.cond"); + llvm::BasicBlock *CondBlock = Continue.getBlock(); + LoopStack.Push(CondBlock); + + EmitBlock(CondBlock); + + llvm::Value *BoolCondVal = 0; + { + // If the for statement has a condition scope, emit the local variable + // declaration. + llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); + + // If there are any cleanups between here and the loop-exit scope, + // create a block to stage a loop exit along. + if (ForScope.requiresCleanups()) + ExitBlock = createBasicBlock("for.cond.cleanup"); + + // As long as the condition is true, iterate the loop. + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Use LoopCount and LoopIndex for iteration. + BoolCondVal = Builder.CreateICmpULT(Builder.CreateLoad(LoopIndex), + LoopCount); + + // C99 6.8.5p2/p4: The first substatement is executed if the expression + // compares unequal to 0. The condition must be a scalar type. + Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock); + + if (ExitBlock != LoopExit.getBlock()) { + EmitBlock(ExitBlock); + EmitBranchThroughCleanup(LoopExit); + } + + EmitBlock(ForBody); + } + + Continue = getJumpDestInCurrentScope("for.inc"); + + // Store the blocks to use for break and continue. + BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); + + W.emitIncrement(*this, LoopIndex); + + // Emit the call to the loop body. + llvm::Function *BodyFunction = EmitSimdFunction(W); + EmitSIMDForHelperCall(BodyFunction, CapStruct, LoopIndex, false); + + // Emit the increment block. + EmitBlock(Continue.getBlock()); + + { + llvm::Value *NewLoopIndex = + Builder.CreateAdd(Builder.CreateLoad(LoopIndex), + llvm::ConstantInt::get(LoopCount->getType(), 1)); + Builder.CreateStore(NewLoopIndex, LoopIndex); + } + + BreakContinueStack.pop_back(); + + EmitBranch(CondBlock); + + ForScope.ForceCleanup(); + + if (DI) + DI->EmitLexicalBlockEnd(Builder, W.getSourceRange().getEnd()); + + LoopStack.Pop(); + + // Emit the fall-through block. + EmitBlock(LoopExit.getBlock(), true); + + // Increment again, for last iteration. + W.emitIncrement(*this, LoopIndex); + + if (SeparateLastIter) { + // This helper call makes updates to linear or lastprivate variables. + // In the case of openmp, only for lastprivate ones. + EmitSIMDForHelperCall(BodyFunction, CapStruct, LoopIndex, true); + } + + W.emitLinearFinal(*this); + } + + EmitBlock(ContBlock, true); + + if (W.isOmp()) + CGM.OpenMPSupport.endOpenMPRegion(); +} +void CodeGenFunction::EmitSIMDForHelperBody(const Stmt *S) { + assert(CapturedStmtInfo && "Should be only called inside a CapturedStmt"); + CGSIMDForStmtInfo *Info = cast(CapturedStmtInfo); + + // Mark the loop body as an extended region of this SIMD loop. + LoopStack.Push(Info->getLoopID(), Info->getLoopParallel()); + { + RunCleanupsScope Scope(*this); + + // Emit all SIMD local variables and update the codegen info. + Info->walkLocalVariablesToEmit(this); + + // Emit the SIMD for loop body. + { + RunCleanupsScope BodyScope(*this); + // It is not allowed to have return or break in a SIMD loop body. + // Continue statements are allowed and updates to the data + // privatization variables will be emitted in a unified continue block. + JumpDest LoopContinue = getJumpDestInCurrentScope("for.continue"); + BreakContinueStack.push_back(BreakContinue(JumpDest(), LoopContinue)); + + EmitStmt(S); + + EmitBlock(LoopContinue.getBlock()); + + // If an update is required, emit those update expressions to be run on + // the last iteration of the loop. + // + // if (IsLastIter) { + // [[ Update Expressions ]] + // } + // + // IsLastIter will only be true if this is a second output of the helper + // body, after the intial for-loop. + // Since IsLastIter is constant, it will be optimized out, and the if + // statement will not be a part of the SIMD For loop, thus allowing + // vectorization. + + // Note that the final values of linear variables are to be calculated + // outside of __simd_helper function (together with loop indices). + if (Info->isOmp()) { + const OMPExecutableDirective *SimdOmp = cast( + Info->getStmt()); + const CapturedDecl *CD = cast( + SimdOmp->getAssociatedStmt())->getCapturedDecl(); + llvm::Value *IsLastIter = LocalDeclMap.lookup(CD->getParam(2)); + // Save the 'last-iteration' flag for 'lastprivate'. + CGM.OpenMPSupport.setLastIterVar(IsLastIter); + + // Emit destructors/required copyings for private/lastprivate. + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); I != E; ++I) { + assert(*I); + if (isa(*I) || isa(*I)) { + EmitPostOMPClause(*(*I), *SimdOmp); + } + } + // Emit closure of lastprivate clauses. + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); I != E; ++I) { + assert(*I); + if (isa(*I)) { + EmitCloseOMPClause(*(*I), *SimdOmp); + } + } + // Clean up the OpenMP local vars stack + CGM.OpenMPSupport.endOpenMPRegion(); + } + BreakContinueStack.pop_back(); + } + } + + // Leave the loop body. + LoopStack.Pop(); +} + +llvm::Value * +CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) { + LValue CapStruct = InitCapturedStruct(S); + return CapStruct.getAddress(); +} + +void CodeGenFunction::InitOpenMPFunction(llvm::Value *Context, + const CapturedStmt &S) { + CapturedStmtInfo = + new CGOpenMPCapturedStmtInfo(Context, S, CGM, S.getCapturedRegionKind()); + + const RecordDecl *RD = S.getCapturedRecordDecl(); + + QualType TagType = getContext().getTagDeclType(RD); + LValue Base = MakeNaturalAlignAddrLValue(Context, TagType); + RecordDecl::field_iterator CurField = RD->field_begin(); + CapturedStmt::const_capture_iterator C = S.capture_begin(); + for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(), + E = S.capture_init_end(); + I != E; ++I, ++C, ++CurField) { + QualType QTy = (*CurField)->getType(); + if (QTy->isVariablyModifiedType()) { + EmitVariablyModifiedType(QTy); + } + if (C->capturesVariable()) { + const VarDecl *VD = C->getCapturedVar(); + LValue LV = EmitLValueForField(Base, CapturedStmtInfo->lookup(VD)); + CapturedStmtInfo->addCachedVar(VD, LV.getAddress()); + } + } + + // If 'this' is captured, load it into CXXThisValue. + if (CapturedStmtInfo->isCXXThisExprCaptured()) { + FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl(); + LValue LV = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(), + getContext().getTagDeclType(RD)); + LValue ThisLValue = EmitLValueForField(LV, FD); + CXXThisValue = EmitLoadOfLValue(ThisLValue, FD->getLocStart()).getScalarVal(); + } +} diff -uNr clang-3.4/lib/CodeGen/CGStmtOpenMP.cpp clang/lib/CodeGen/CGStmtOpenMP.cpp --- clang-3.4/lib/CodeGen/CGStmtOpenMP.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/lib/CodeGen/CGStmtOpenMP.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,5556 @@ +//===--- CGStmtOpenMP.cpp - Emit LLVM Code for declarations ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Decl nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CGDebugInfo.h" +#include "CGOpenCLRuntime.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/TypeBuilder.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CallSite.h" +using namespace clang; +using namespace CodeGen; + +namespace { +struct ident_t {}; +enum sched_type {}; +enum kmp_proc_bind_t {}; +enum target_size_t {}; +enum target_intptr_t {}; +typedef void (*kmpc_micro)(int32_t *global_tid, int32_t *bound_tid, ...); +typedef void(__kmpc_fork_call)(ident_t *loc, int32_t argc, kmpc_micro microtask, + ...); +typedef void(__kmpc_push_num_threads)(ident_t *loc, int32_t global_tid, + int32_t num_threads); +typedef void(__kmpc_push_proc_bind)(ident_t *loc, int32_t global_tid, + kmp_proc_bind_t proc_bind); +typedef void(__kmpc_push_num_teams)(ident_t *loc, int32_t global_tid, + int32_t num_teams, int32_t num_threads); +typedef void(__kmpc_fork_teams)(ident_t *loc, int32_t argc, + kmpc_micro microtask, ...); +// const int KMP_PROC_BIND_FALSE = 0; +// const int KMP_PROC_BIND_TRUE = 1; +const int KMP_PROC_BIND_MASTER = 2; +const int KMP_PROC_BIND_CLOSE = 3; +const int KMP_PROC_BIND_SPREAD = 4; +// const int KMP_PROC_BIND_DISABLED = 5; +// const int KMP_PROC_BIND_INTEL = 6; +// const int KMP_PROC_BIND_DEFAULT = 7; +const int KMP_IDENT_BARRIER_EXPL = 0x20; +const int KMP_IDENT_BARRIER_IMPL = 0x0040; +const int KMP_IDENT_BARRIER_IMPL_FOR = 0x0040; +const int KMP_IDENT_BARRIER_IMPL_SECTIONS = 0x00C0; +const int KMP_IDENT_BARRIER_IMPL_SINGLE = 0x0140; +typedef int32_t(__kmpc_cancel_barrier)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_barrier)(ident_t *loc, int32_t global_tid); +const int KMP_CANCEL_NOREQ = 0; +const int KMP_CANCEL_PARALLEL = 1; +const int KMP_CANCEL_LOOP = 2; +const int KMP_CANCEL_SECTIONS = 3; +const int KMP_CANCEL_TASKGROUP = 4; +typedef int32_t(__kmpc_cancellationpoint)(ident_t *loc, int32_t global_tid, + int32_t cncl_kind); +typedef int32_t(__kmpc_cancel)(ident_t *loc, int32_t global_tid, + int32_t cncl_kind); +typedef int32_t kmp_critical_name[8]; +typedef int32_t(__kmpc_omp_taskyield)(ident_t *loc, int32_t global_tid, + int32_t end_part); +typedef int32_t(__kmpc_omp_taskwait)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_flush)(ident_t *loc, ...); +typedef int32_t(__kmpc_master)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_end_master)(ident_t *loc, int32_t global_tid); +typedef int32_t(__kmpc_single)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_end_single)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_critical)(ident_t *loc, int32_t global_tid, + kmp_critical_name *lck); +typedef void(__kmpc_end_critical)(ident_t *loc, int32_t global_tid, + kmp_critical_name *lck); +typedef void(__kmpc_ordered)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_end_ordered)(ident_t *loc, int32_t global_tid); +typedef void (*kmp_copy_func)(void *lhs_data, void *rhs_data); +typedef void(__kmpc_copyprivate)(ident_t *loc, int32_t global_tid, + target_size_t cpy_size, void *cpy_data, + kmp_copy_func cpy_func, int32_t didit); +typedef void (*kmp_reduce_func)(void *lhs_data, void *rhs_data); +typedef int32_t(__kmpc_reduce_nowait)(ident_t *loc, int32_t global_tid, + int32_t num_vars, + target_size_t reduce_size, + void *reduce_data, + kmp_reduce_func reduce_func, + kmp_critical_name *lck); +typedef void(__kmpc_end_reduce_nowait)(ident_t *loc, int32_t global_tid, + kmp_critical_name *lck); +typedef int32_t(__kmpc_reduce)(ident_t *loc, int32_t global_tid, + int32_t num_vars, target_size_t reduce_size, + void *reduce_data, kmp_reduce_func reduce_func, + kmp_critical_name *lck); +typedef void(__kmpc_end_reduce)(ident_t *loc, int32_t global_tid, + kmp_critical_name *lck); +const int KMP_IDENT_ATOMIC_REDUCE = 0x10; +typedef void(__kmpc_atomic_start)(); +typedef void(__kmpc_atomic_end)(); +typedef void(__kmpc_dispatch_init_4)(ident_t *loc, int32_t global_tid, + sched_type schedule, int32_t lb, + int32_t ub, int32_t st, int32_t chunk); +typedef void(__kmpc_dispatch_init_4u)(ident_t *loc, int32_t global_tid, + sched_type schedule, uint32_t lb, + uint32_t ub, uint32_t st, uint32_t chunk); +typedef void(__kmpc_dispatch_init_8)(ident_t *loc, int32_t global_tid, + sched_type schedule, int64_t lb, + int64_t ub, int64_t st, int64_t chunk); +typedef void(__kmpc_dispatch_init_8u)(ident_t *loc, int32_t global_tid, + sched_type schedule, uint64_t lb, + uint64_t ub, uint64_t st, uint64_t chunk); +typedef int(__kmpc_dispatch_next_4)(ident_t *loc, int32_t global_tid, + int32_t *p_last, int32_t *p_lb, + int32_t *p_ub, int32_t *p_st); +typedef int(__kmpc_dispatch_next_4u)(ident_t *loc, int32_t global_tid, + int32_t *p_last, uint32_t *p_lb, + uint32_t *p_ub, int32_t *p_st); +typedef int(__kmpc_dispatch_next_8)(ident_t *loc, int32_t global_tid, + int32_t *p_last, int64_t *p_lb, + int64_t *p_ub, int64_t *p_st); +typedef int(__kmpc_dispatch_next_8u)(ident_t *loc, int32_t global_tid, + int32_t *p_last, uint64_t *p_lb, + uint64_t *p_ub, int64_t *p_st); +typedef void(__kmpc_dispatch_fini_4)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_dispatch_fini_4u)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_dispatch_fini_8)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_dispatch_fini_8u)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_for_static_init_4)(ident_t *loc, int32_t global_tid, + int32_t schedule, int32_t *pliter, + int32_t *plb, int32_t *pub, int32_t *pst, + int32_t incr, int32_t chunk); +typedef void(__kmpc_for_static_init_4u)(ident_t *loc, int32_t global_tid, + int32_t schedule, int32_t *pliter, + int32_t *plb, int32_t *pub, + int32_t *pst, int32_t incr, + int32_t chunk); +typedef void(__kmpc_for_static_init_8)(ident_t *loc, int32_t global_tid, + int32_t schedule, int32_t *pliter, + int64_t *plb, int64_t *pub, int64_t *pst, + int64_t incr, int64_t chunk); +typedef void(__kmpc_for_static_init_8u)(ident_t *loc, int32_t global_tid, + int32_t schedule, int32_t *pliter, + int64_t *plb, int64_t *pub, + int64_t *pst, int64_t incr, + int64_t chunk); +typedef void(__kmpc_for_static_fini)(ident_t *loc, int32_t global_tid); +const int KMP_SCH_STATIC_CHUNKED = 33; +const int KMP_SCH_STATIC = 34; +const int KMP_SCH_DYNAMIC_CHUNKED = 35; +const int KMP_SCH_GUIDED_CHUNKED = 36; +const int KMP_SCH_RUNTIME = 37; +const int KMP_SCH_AUTO = 38; +const int KMP_ORD_STATIC_CHUNKED = 65; +// const int KMP_ORD_STATIC = 66; +// const int KMP_ORD_DYNAMIC_CHUNKED = 67; +// const int KMP_ORD_GUIDED_CHUNKED = 68; +// const int KMP_ORD_RUNTIME = 69; +// const int KMP_ORD_AUTO = 70; +const int KMP_NM_STATIC_CHUNKED = 161; +// const int KMP_NM_STATIC = 162; +// const int KMP_NM_DYNAMIC_CHUNKED = 163; +// const int KMP_NM_GUIDED_CHUNKED = 164; +// const int KMP_NM_RUNTIME = 165; +// const int KMP_NM_AUTO = 166; +const int KMP_NM_ORD_STATIC_CHUNKED = 193; +// const int KMP_NM_ORD_STATIC = 194; +// const int KMP_NM_ORD_DYNAMIC_CHUNKED = 195; +// const int KMP_NM_ORD_GUIDED_CHUNKED = 196; +// const int KMP_NM_ORD_RUNTIME = 197; +// const int KMP_NM_ORD_AUTO = 198; +const int KMP_SCH_DEFAULT = KMP_SCH_STATIC; +const int SCH_ORD = KMP_ORD_STATIC_CHUNKED - KMP_SCH_STATIC_CHUNKED; +const int SCH_NM = KMP_NM_STATIC_CHUNKED - KMP_SCH_STATIC_CHUNKED; +const int SCH_NM_ORD = KMP_NM_ORD_STATIC_CHUNKED - KMP_SCH_STATIC_CHUNKED; +const int KMP_SCH_DISTRIBUTE_STATIC_CHUNKED = 91; +const int KMP_SCH_DISTRIBUTE_STATIC = 92; +typedef int32_t (*kmp_routine_entry_t)(int32_t, void *); +struct kmp_task_t {}; +const int OMP_TASK_UNTIED = 0; +const int OMP_TASK_TIED = 1; +const int OMP_TASK_FINAL = 2; +const int OMP_TASK_DESTRUCTORS_THUNK = 8; +const int OMP_TASK_CURRENT_QUEUED = 1; +struct kmp_depend_info_t {}; +const unsigned char IN = 1; +const unsigned char OUT = 2; +const unsigned char INOUT = 3; +typedef int32_t(__kmpc_omp_task_with_deps)(ident_t *loc, int32_t gtid, + kmp_task_t *task, int32_t ndeps, + kmp_depend_info_t *dep_list, + int32_t ndeps_noalias, + kmp_depend_info_t *noalias_dep_list); +typedef void(__kmpc_omp_wait_deps)(ident_t *loc, int32_t gtid, int32_t ndeps, + kmp_depend_info_t *dep_list, + int32_t ndeps_noalias, + kmp_depend_info_t *noalias_dep_list); +typedef kmp_task_t *(__kmpc_omp_task_alloc)(ident_t *loc, int32_t gtid, + int32_t flags, + target_size_t sizeof_kmp_task_t, + target_size_t sizeof_shareds, + kmp_routine_entry_t task_entry); +typedef void(__kmpc_omp_task_begin_if0)(ident_t *loc, int32_t gtid, + kmp_task_t *task); +typedef void(__kmpc_omp_task_complete_if0)(ident_t *loc, int32_t gtid, + kmp_task_t *task); +typedef int32_t(__kmpc_omp_task_parts)(ident_t *loc, int32_t gtid, + kmp_task_t *task); +typedef void(__kmpc_taskgroup)(ident_t *loc, int32_t global_tid); +typedef void(__kmpc_end_taskgroup)(ident_t *loc, int32_t global_tid); +} + +namespace llvm { +/// Specializations of llvm::TypeBuilder for: +/// ident_t +template class TypeBuilder { +public: + static StructType *get(LLVMContext &C) { + return StructType::get( + TypeBuilder, X>::get(C), // reserved_1 + TypeBuilder, X>::get(C), // flags + TypeBuilder, X>::get(C), // reserved_2 + TypeBuilder, X>::get(C), // reserved_3 + TypeBuilder *, X>::get(C), // psource + NULL); + } + enum { reserved_1, flags, reserved_2, reserved_3, psource }; +}; +/// ident_t +template class TypeBuilder { +public: + static StructType *get(LLVMContext &C) { + return StructType::get( + TypeBuilder::get(C), // shareds + TypeBuilder::get(C), // routine + TypeBuilder, X>::get(C), // part_id + TypeBuilder::get(C), // destructors + TypeBuilder, X>::get(C), // firstprivate_locker + NULL); + } + enum { shareds, routine, part_id, destructors, firstprivate_locker }; +}; +template +class TypeBuilder { +public: + static FunctionType *get(LLVMContext &Context) { + Type *params[] = { + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + }; + return FunctionType::get(TypeBuilder::get(Context), params, + false); + } +}; +template +class TypeBuilder { +public: + static FunctionType *get(LLVMContext &Context) { + Type *params[] = { + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + }; + return FunctionType::get(TypeBuilder::get(Context), params, + false); + } +}; +template +class TypeBuilder { +public: + static FunctionType *get(LLVMContext &Context) { + Type *params[] = { + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), + }; + return FunctionType::get(TypeBuilder::get(Context), params, + false); + } +}; +template class TypeBuilder { +public: + static IntegerType *get(LLVMContext &C) { + return TypeBuilder, X>::get(C); + } +}; +template class TypeBuilder { +public: + static IntegerType *get(LLVMContext &C) { + return TypeBuilder, X>::get(C); + } +}; + +struct LLVContextCGM { + llvm::LLVMContext &VMContext; + CodeGenModule *CGM; + LLVContextCGM(llvm::LLVMContext &VMContext, CodeGenModule *CGM) + : VMContext(VMContext), CGM(CGM) {} +}; + +typedef llvm::TypeBuilder TaskTBuilder; +typedef llvm::TypeBuilder ProcBindTBuilder; +} + +namespace { +// Getters for fields of the loop-like directives. We may want to add a +// common parent to all the loop-like directives to get rid of these. +// + +static bool isLoopDirective(const OMPExecutableDirective *ED) { + return isa(ED) || isa(ED) || + isa(ED) || isa(ED) || + isa(ED) || isa(ED) || + isa(ED) || + isa(ED) || + isa(ED); +} + +static const Expr *getInitFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getInit(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getInit(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const Expr *getFinalFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getFinal(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getFinal(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const Expr * +getNewIterVarFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getNewIterVar(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterVar(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const Expr * +getNewIterEndFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getNewIterEnd(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getNewIterEnd(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const Expr * +getLowerBoundFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getLowerBound(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getLowerBound(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const Expr * +getUpperBoundFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getUpperBound(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getUpperBound(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static const ArrayRef +getCountersFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getCounters(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getCounters(); + } + assert(0 && "bad loop directive"); + return 0; +} + +static unsigned +getCollapsedNumberFromLoopDirective(const OMPExecutableDirective *ED) { + if (const OMPForDirective *D = dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPParallelForDirective *D = + dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPSimdDirective *D = dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPForSimdDirective *D = dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPDistributeDirective *D = dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPDistributeSimdDirective *D = + dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPDistributeParallelForDirective *D = + dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + if (const OMPDistributeParallelForSimdDirective *D = + dyn_cast(ED)) { + return D->getCollapsedNumber(); + } + assert(0 && "bad loop directive"); + return 0; +} +} + +#define OPENMPRTL_FUNC(name) Get__kmpc_##name(&CGM) +#define OPENMPRTL_ATOMIC_FUNC(QTy, Op) getAtomicFunc(*this, QTy, Op) +#define OPENMPRTL_ATOMIC_FUNC_GENERAL(QTyRes, QTyIn, Aop, Capture, Reverse) \ + getAtomicFuncGeneral(*this, QTyRes, QTyIn, Aop, Capture, Reverse) + +#define DEFAULT_GET_OPENMP_FUNC(name) \ + static llvm::Value *Get__kmpc_##name(clang::CodeGen::CodeGenModule *CGM) { \ + return CGM->CreateRuntimeFunction( \ + llvm::TypeBuilder<__kmpc_##name, false>::get(CGM->getLLVMContext()), \ + "__kmpc_" #name); \ + } + +// Special processing for __kmpc_copyprivate +// DEFAULT_GET_OPENMP_FUNC(copyprivate) +static llvm::Value *Get__kmpc_copyprivate(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = {llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + CGM->SizeTy, + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C)}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_copyprivate"); +} +// Special processing for __kmpc_reduce_nowait +// DEFAULT_GET_OPENMP_FUNC(reduce_nowait) +static llvm::Value * +Get__kmpc_reduce_nowait(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = { + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + CGM->SizeTy, + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C)}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_reduce_nowait"); +} +// Special processing for __kmpc_reduce +// DEFAULT_GET_OPENMP_FUNC(reduce) +static llvm::Value *Get__kmpc_reduce(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = { + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + CGM->SizeTy, + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C)}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_reduce"); +} +// Special processing for __kmpc_omp_task_alloc +// DEFAULT_GET_OPENMP_FUNC(omp_task_alloc) +static llvm::Value * +Get__kmpc_omp_task_alloc(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = { + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + CGM->SizeTy, + CGM->SizeTy, + llvm::TypeBuilder::get(C)}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_omp_task_alloc"); +} +static llvm::Type *getKMPDependInfoType(CodeGenModule *CGM) { + llvm::Type *Ty = CGM->OpenMPSupport.getKMPDependInfoType(); + if (Ty) + return Ty; + IdentifierInfo *II = &CGM->getContext().Idents.get("__kmp_depend_info_t"); + DeclContext *DC = CGM->getContext().getTranslationUnitDecl(); + RecordDecl *RD = RecordDecl::Create(CGM->getContext(), TTK_Struct, DC, + SourceLocation(), SourceLocation(), II); + RD->startDefinition(); + DC->addHiddenDecl(RD); + II = &CGM->getContext().Idents.get("base_addr"); + FieldDecl *FD = FieldDecl::Create( + CGM->getContext(), RD, SourceLocation(), SourceLocation(), II, + CGM->getContext().getIntPtrType(), + CGM->getContext().getTrivialTypeSourceInfo( + CGM->getContext().getIntPtrType(), SourceLocation()), + 0, false, ICIS_NoInit); + FD->setAccess(AS_public); + RD->addDecl(FD); + II = &CGM->getContext().Idents.get("len"); + FD = FieldDecl::Create(CGM->getContext(), RD, SourceLocation(), + SourceLocation(), II, CGM->getContext().getSizeType(), + CGM->getContext().getTrivialTypeSourceInfo( + CGM->getContext().getSizeType(), SourceLocation()), + 0, false, ICIS_NoInit); + FD->setAccess(AS_public); + RD->addDecl(FD); + II = &CGM->getContext().Idents.get("flags"); + FD = FieldDecl::Create(CGM->getContext(), RD, SourceLocation(), + SourceLocation(), II, CGM->getContext().BoolTy, + CGM->getContext().getTrivialTypeSourceInfo( + CGM->getContext().BoolTy, SourceLocation()), + 0, false, ICIS_NoInit); + FD->setAccess(AS_public); + RD->addDecl(FD); + RD->completeDefinition(); + QualType QTy = CGM->getContext().getRecordType(RD); + Ty = CGM->getTypes().ConvertTypeForMem(QTy); + CGM->OpenMPSupport.setKMPDependInfoType( + Ty, CGM->getContext().getTypeAlignInChars(QTy).getQuantity()); + return Ty; +} +// Special processing for __kmpc_omp_task_with_deps +// DEFAULT_GET_OPENMP_FUNC(omp_task_with_deps) +static llvm::Value * +Get__kmpc_omp_task_with_deps(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = {llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + getKMPDependInfoType(CGM)->getPointerTo(), + llvm::TypeBuilder::get(C), + getKMPDependInfoType(CGM)->getPointerTo()}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_omp_task_with_deps"); +} + +// Special processing for __kmpc_omp_wait_deps +// DEFAULT_GET_OPENMP_FUNC(omp_wait_deps) +static llvm::Value * +Get__kmpc_omp_wait_deps(clang::CodeGen::CodeGenModule *CGM) { + llvm::LLVMContext &C = CGM->getLLVMContext(); + llvm::Type *Params[] = {llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + llvm::TypeBuilder::get(C), + getKMPDependInfoType(CGM)->getPointerTo(), + llvm::TypeBuilder::get(C), + getKMPDependInfoType(CGM)->getPointerTo()}; + + llvm::FunctionType *FT = llvm::FunctionType::get( + llvm::TypeBuilder::get(C), Params, false); + return CGM->CreateRuntimeFunction(FT, "__kmpc_omp_wait_deps"); +} + +enum EAtomicOperation { + OMP_Atomic_add, + OMP_Atomic_sub, + OMP_Atomic_mul, + OMP_Atomic_div, + OMP_Atomic_andb, + OMP_Atomic_shl, + OMP_Atomic_shr, + OMP_Atomic_orb, + OMP_Atomic_xor, + OMP_Atomic_andl, + OMP_Atomic_orl, + OMP_Atomic_max, + OMP_Atomic_min, + OMP_Atomic_eqv, + OMP_Atomic_neqv, + OMP_Atomic_rd, + OMP_Atomic_wr, + OMP_Atomic_swp, + OMP_Atomic_assign, + OMP_Atomic_invalid +}; + +static QualType getAtomicType(CodeGenFunction &CGF, QualType QTy) { + if (!QTy->isArithmeticType()) + return QualType(); + if (QTy->isRealFloatingType()) + return QTy + ->getCanonicalTypeUnqualified(); // CGF.ConvertTypeForMem(QTy->getCanonicalTypeUnqualified()); + uint64_t TySize = CGF.getContext().getTypeSize(QTy); + if (CGF.getContext().getTypeSize(CGF.getContext().CharTy) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedCharTy + : CGF.getContext().SignedCharTy; + else if (CGF.getContext().getTypeSize(CGF.getContext().ShortTy) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedShortTy + : CGF.getContext().ShortTy; + else if (CGF.getContext().getTypeSize(CGF.getContext().IntTy) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedIntTy + : CGF.getContext().IntTy; + else if (CGF.getContext().getTypeSize(CGF.getContext().LongTy) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedLongTy + : CGF.getContext().LongTy; + else if (CGF.getContext().getTypeSize(CGF.getContext().LongLongTy) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedLongLongTy + : CGF.getContext().LongLongTy; + else if (CGF.getContext().getTypeSize(CGF.getContext().Int128Ty) == TySize) + return QTy->isUnsignedIntegerOrEnumerationType() + ? CGF.getContext().UnsignedInt128Ty + : CGF.getContext().Int128Ty; + return QualType(); +} + +static llvm::Value *getAtomicFuncGeneral(CodeGenFunction &CGF, QualType QTyRes, + QualType QTyIn, EAtomicOperation Aop, + bool Capture, bool Reverse) { + SmallString<40> Str; + llvm::raw_svector_ostream OS(Str); + + if (QTyRes.isVolatileQualified() || QTyIn.isVolatileQualified()) + return 0; + + int64_t TySize = CGF.CGM.GetTargetTypeStoreSize(CGF.ConvertTypeForMem(QTyRes)) + .getQuantity(); + if (QTyRes->isRealFloatingType()) { + OS << "__kmpc_atomic_float"; + if (TySize != 4 && TySize != 8 && TySize != 10 && TySize != 16) + return 0; + } else if (QTyRes->isScalarType()) { + OS << "__kmpc_atomic_fixed"; + if (TySize != 1 && TySize != 2 && TySize != 4 && TySize != 8) + return 0; + } else + return 0; + OS << TySize; + switch (Aop) { + case OMP_Atomic_orl: + OS << "_orl"; + break; + case OMP_Atomic_orb: + OS << "_orb"; + break; + case OMP_Atomic_andl: + OS << "_andl"; + break; + case OMP_Atomic_andb: + OS << "_andb"; + break; + case OMP_Atomic_xor: + OS << "_xor"; + break; + case OMP_Atomic_sub: + OS << "_sub"; + break; + case OMP_Atomic_add: + OS << "_add"; + break; + case OMP_Atomic_mul: + OS << "_mul"; + break; + case OMP_Atomic_div: + if (QTyRes->hasUnsignedIntegerRepresentation() || QTyRes->isPointerType()) { + if (!CGF.getContext().hasSameType(QTyIn, QTyRes)) + return 0; + OS << "u"; + } + OS << "_div"; + break; + case OMP_Atomic_min: + OS << "_min"; + break; + case OMP_Atomic_max: + OS << "_max"; + break; + case OMP_Atomic_shl: + OS << "_shl"; + break; + case OMP_Atomic_shr: + if (QTyRes->hasUnsignedIntegerRepresentation() || QTyRes->isPointerType()) { + if (!CGF.getContext().hasSameType(QTyIn, QTyRes)) + return 0; + OS << "u"; + } + OS << "_shr"; + break; + case OMP_Atomic_wr: + OS << "_wr"; + break; + case OMP_Atomic_rd: + OS << "_rd"; + break; + case OMP_Atomic_assign: + return 0; + case OMP_Atomic_invalid: + default: + llvm_unreachable("Unknown atomic operation."); + } + if (Capture) { + OS << "_cpt"; + if (!CGF.getContext().hasSameType(QTyIn, QTyRes)) + return 0; + } + if (Reverse && (Aop == OMP_Atomic_sub || Aop == OMP_Atomic_div || + Aop == OMP_Atomic_shr || Aop == OMP_Atomic_shl)) { + OS << "_rev"; + if (!CGF.getContext().hasSameType(QTyIn, QTyRes)) + return 0; + } + int64_t TyInSize = CGF.CGM.GetTargetTypeStoreSize( + CGF.ConvertTypeForMem(QTyIn)).getQuantity(); + if (!CGF.getContext().hasSameType(QTyIn, QTyRes)) { + if (QTyRes->isScalarType() && QTyIn->isRealFloatingType() && TyInSize == 8) + OS << "_float8"; + else + return 0; + } + SmallVector Params; + Params.push_back(llvm::TypeBuilder::get( + CGF.CGM.getLLVMContext())->getPointerTo()); + Params.push_back(CGF.Int32Ty); + llvm::Type *Ty = CGF.ConvertTypeForMem(getAtomicType(CGF, QTyRes)); + Params.push_back(Ty->getPointerTo()); + if (Aop != OMP_Atomic_rd) + Params.push_back(CGF.ConvertTypeForMem(getAtomicType(CGF, QTyIn))); + if (Capture) { + Params.push_back(CGF.Int32Ty); + } + llvm::Type *RetTy = CGF.VoidTy; + if (Capture || Aop == OMP_Atomic_rd) + RetTy = Ty; + llvm::FunctionType *FunTy = llvm::FunctionType::get(RetTy, Params, false); + return CGF.CGM.CreateRuntimeFunction(FunTy, OS.str()); +} + +static llvm::Value *getAtomicFunc(CodeGenFunction &CGF, QualType QTy, + OpenMPReductionClauseOperator Op) { + + if (QTy.isVolatileQualified()) + return 0; + + EAtomicOperation Aop = OMP_Atomic_invalid; + switch (Op) { + case OMPC_REDUCTION_or: + Aop = OMP_Atomic_orl; + break; + case OMPC_REDUCTION_bitor: + Aop = OMP_Atomic_orb; + break; + case OMPC_REDUCTION_and: + Aop = OMP_Atomic_andl; + break; + case OMPC_REDUCTION_bitand: + Aop = OMP_Atomic_andb; + break; + case OMPC_REDUCTION_bitxor: + Aop = OMP_Atomic_xor; + break; + case OMPC_REDUCTION_sub: + Aop = OMP_Atomic_add; + break; + case OMPC_REDUCTION_add: + Aop = OMP_Atomic_add; + break; + case OMPC_REDUCTION_mult: + Aop = OMP_Atomic_mul; + break; + case OMPC_REDUCTION_min: + Aop = OMP_Atomic_min; + break; + case OMPC_REDUCTION_max: + Aop = OMP_Atomic_max; + break; + case OMPC_REDUCTION_custom: + return 0; + case OMPC_REDUCTION_unknown: + case NUM_OPENMP_REDUCTION_OPERATORS: + llvm_unreachable("Unknown reduction operation."); + } + return getAtomicFuncGeneral(CGF, QTy, QTy, Aop, false, false); +} + +DEFAULT_GET_OPENMP_FUNC(fork_call) +DEFAULT_GET_OPENMP_FUNC(push_num_threads) +DEFAULT_GET_OPENMP_FUNC(push_proc_bind) +DEFAULT_GET_OPENMP_FUNC(fork_teams) +DEFAULT_GET_OPENMP_FUNC(push_num_teams) +DEFAULT_GET_OPENMP_FUNC(cancel_barrier) +DEFAULT_GET_OPENMP_FUNC(barrier) +DEFAULT_GET_OPENMP_FUNC(cancellationpoint) +DEFAULT_GET_OPENMP_FUNC(cancel) +DEFAULT_GET_OPENMP_FUNC(omp_taskyield) +DEFAULT_GET_OPENMP_FUNC(omp_taskwait) +DEFAULT_GET_OPENMP_FUNC(flush) +DEFAULT_GET_OPENMP_FUNC(master) +DEFAULT_GET_OPENMP_FUNC(end_master) +DEFAULT_GET_OPENMP_FUNC(single) +DEFAULT_GET_OPENMP_FUNC(end_single) +DEFAULT_GET_OPENMP_FUNC(critical) +DEFAULT_GET_OPENMP_FUNC(end_critical) +DEFAULT_GET_OPENMP_FUNC(ordered) +DEFAULT_GET_OPENMP_FUNC(end_ordered) +DEFAULT_GET_OPENMP_FUNC(end_reduce_nowait) +DEFAULT_GET_OPENMP_FUNC(end_reduce) +DEFAULT_GET_OPENMP_FUNC(atomic_start) +DEFAULT_GET_OPENMP_FUNC(atomic_end) +DEFAULT_GET_OPENMP_FUNC(dispatch_init_4) +DEFAULT_GET_OPENMP_FUNC(dispatch_init_4u) +DEFAULT_GET_OPENMP_FUNC(dispatch_init_8) +DEFAULT_GET_OPENMP_FUNC(dispatch_init_8u) +DEFAULT_GET_OPENMP_FUNC(dispatch_next_4) +DEFAULT_GET_OPENMP_FUNC(dispatch_next_4u) +DEFAULT_GET_OPENMP_FUNC(dispatch_next_8) +DEFAULT_GET_OPENMP_FUNC(dispatch_next_8u) +DEFAULT_GET_OPENMP_FUNC(dispatch_fini_4) +DEFAULT_GET_OPENMP_FUNC(dispatch_fini_4u) +DEFAULT_GET_OPENMP_FUNC(dispatch_fini_8) +DEFAULT_GET_OPENMP_FUNC(dispatch_fini_8u) +DEFAULT_GET_OPENMP_FUNC(for_static_init_4) +DEFAULT_GET_OPENMP_FUNC(for_static_init_4u) +DEFAULT_GET_OPENMP_FUNC(for_static_init_8) +DEFAULT_GET_OPENMP_FUNC(for_static_init_8u) +DEFAULT_GET_OPENMP_FUNC(for_static_fini) +DEFAULT_GET_OPENMP_FUNC(omp_task_begin_if0) +DEFAULT_GET_OPENMP_FUNC(omp_task_complete_if0) +DEFAULT_GET_OPENMP_FUNC(omp_task_parts) +DEFAULT_GET_OPENMP_FUNC(taskgroup) +DEFAULT_GET_OPENMP_FUNC(end_taskgroup) + +static void EmitCancelArgs(CodeGenFunction &CGF, + OpenMPDirectiveKind ConstructType, + SourceLocation SLoc, llvm::Value *&Loc, + llvm::Value *>id, llvm::Value *&Kind) { + Loc = CGF.CGM.CreateIntelOpenMPRTLLoc(SLoc, CGF); + GTid = CGF.CGM.CreateOpenMPGlobalThreadNum(SLoc, CGF); + int CKind = KMP_CANCEL_NOREQ; + switch (ConstructType) { + case OMPD_parallel: + CKind = KMP_CANCEL_PARALLEL; + break; + case OMPD_for: + CKind = KMP_CANCEL_LOOP; + break; + case OMPD_sections: + CKind = KMP_CANCEL_SECTIONS; + break; + case OMPD_taskgroup: + CKind = KMP_CANCEL_TASKGROUP; + break; + default: + llvm_unreachable("Unknown construct type in cancel directive"); + break; + } + Kind = CGF.Builder.getInt32(CKind); +} + +static void EmitCancellationPoint( + CodeGenFunction &CGF, SourceLocation Loc, ArrayRef Args, + llvm::BasicBlock *ExitBB, llvm::BasicBlock *ContBB, + CodeGenFunction::JumpDest FinalBB = CodeGenFunction::JumpDest()) { + CodeGenModule &CGM = CGF.CGM; + llvm::Value *CallRes = CGF.Builder.CreateIsNotNull( + CGF.EmitRuntimeCall(OPENMPRTL_FUNC(cancellationpoint), Args)); + CGF.Builder.CreateCondBr(CallRes, ExitBB, ContBB); + if (FinalBB.isValid()) { + CGF.EmitBlock(ExitBB); + CGF.EmitOMPCancelBarrier(Loc, KMP_IDENT_BARRIER_IMPL, true); + CGF.EmitBranchThroughCleanup(FinalBB); + CGF.EmitBlock(ContBB); + } +} + +namespace { +/// \brief RAII object that save current insert position and then restores it. +class BuilderInsertPositionRAII { + CGBuilderTy &Builder; + CGBuilderTy::InsertPoint SavedIP; + +public: + BuilderInsertPositionRAII(CGBuilderTy &Builder, + llvm::Instruction *NewInsertPoint) + : Builder(Builder), SavedIP(Builder.saveIP()) { + assert(SavedIP.isSet() && "No insertion point is set!"); + Builder.SetInsertPoint(NewInsertPoint); + } + ~BuilderInsertPositionRAII() { Builder.restoreIP(SavedIP); } +}; + +/// \brief RAII object for OpenMP region. +class OpenMPRegionRAII { + CodeGenFunction &CGF; + +public: + OpenMPRegionRAII(CodeGenFunction &CGF, llvm::Value *Context, + const CapturedStmt &CS) + : CGF(CGF) { + CGF.InitOpenMPFunction(Context, CS); + } + ~OpenMPRegionRAII() { delete CGF.CapturedStmtInfo; } +}; + +static void SetFirstprivateInsertPt(CodeGenFunction &CGF) { + if (CGF.FirstprivateInsertPt) { + llvm::Instruction *Ptr = CGF.FirstprivateInsertPt; + CGF.FirstprivateInsertPt = 0; + Ptr->eraseFromParent(); + } + llvm::Value *Undef = llvm::UndefValue::get(CGF.Int32Ty); + CGF.FirstprivateInsertPt = new llvm::BitCastInst( + Undef, CGF.Int32Ty, "", CGF.Builder.GetInsertBlock()); +} + +static void EmitFirstprivateInsert(CodeGenFunction &CGF, SourceLocation Loc) { + if (CGF.FirstprivateInsertPt) { + BuilderInsertPositionRAII PosRAII(CGF.Builder, CGF.FirstprivateInsertPt); + CGF.EmitOMPBarrier(Loc, KMP_IDENT_BARRIER_IMPL); + } +} +} + +static llvm::GlobalVariable *CreateRuntimeVariable(CodeGenModule &CGM, + StringRef MangledName, + llvm::Type *Ty) { + llvm::PointerType *PtrTy = llvm::PointerType::getUnqual(Ty); + unsigned AddrSpace = PtrTy->getAddressSpace(); + return new llvm::GlobalVariable( + CGM.getModule(), Ty, false, llvm::GlobalValue::PrivateLinkage, + llvm::Constant::getNullValue(Ty), MangledName, 0, + llvm::GlobalVariable::NotThreadLocal, AddrSpace); +} + +void CodeGenFunction::EmitOMPBarrier(SourceLocation L, unsigned Flags) { + EmitOMPCallWithLocAndTidHelper(OPENMPRTL_FUNC(barrier), L, Flags); +} + +void CodeGenFunction::EmitOMPCancelBarrier(SourceLocation L, unsigned Flags, + bool IgnoreResult) { + if (OMPCancelMap.empty()) { + EmitOMPBarrier(L, Flags); + } else { + llvm::Value *CallRes = EmitOMPCallWithLocAndTidHelper( + OPENMPRTL_FUNC(cancel_barrier), L, Flags); + if (!IgnoreResult) { + JumpDest FinalBB; + if (OMPCancelMap.count(OMPD_for)) + FinalBB = OMPCancelMap[OMPD_for]; + else if (OMPCancelMap.count(OMPD_sections)) + FinalBB = OMPCancelMap[OMPD_sections]; + else if (OMPCancelMap.count(OMPD_parallel)) + FinalBB = OMPCancelMap[OMPD_parallel]; + else + FinalBB = OMPCancelMap[OMPD_taskgroup]; + + llvm::BasicBlock *ExitBB = createBasicBlock("omp.cancel_barrier.exit"); + llvm::BasicBlock *ContBB = + createBasicBlock("omp.cancel_barrier.continue"); + llvm::Value *Cond = Builder.CreateIsNotNull(CallRes); + Builder.CreateCondBr(Cond, ExitBB, ContBB); + EmitBlock(ExitBB); + EmitBranchThroughCleanup(FinalBB); + EmitBlock(ContBB); + } + } +} + +void +CodeGenFunction::EmitOMPDirectiveWithParallel(OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S) { + // Generate shared args for captured stmt. + CapturedStmt *CS = cast(S.getAssociatedStmt()); + llvm::Value *Arg = GenerateCapturedStmtArgument(*CS); + + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(true); + CGM.OpenMPSupport.setMergeable(false); + CGM.OpenMPSupport.setOrdered(false); + CGM.OpenMPSupport.setScheduleChunkSize(KMP_SCH_DEFAULT, 0); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitInitOMPClause(*(*I), S); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitAfterInitOMPClause(*(*I), S); + + // Generate microtask. + // void .omp_microtask.(int32_t *, int32_t *, void */*AutoGenRecord **/arg3) { + // captured_stmt(arg3); + // } + IdentifierInfo *Id = &getContext().Idents.get(".omp_microtask."); + QualType PtrIntTy = getContext().getPointerType(getContext().IntTy); + SmallVector FnArgTypes; + FnArgTypes.push_back(PtrIntTy); + FnArgTypes.push_back(PtrIntTy); + FnArgTypes.push_back(getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_BasicNoexcept; + QualType FnTy = + getContext().getFunctionType(getContext().VoidTy, FnArgTypes, EPI); + TypeSourceInfo *TI = + getContext().getTrivialTypeSourceInfo(FnTy, SourceLocation()); + FunctionDecl *FD = FunctionDecl::Create( + getContext(), getContext().getTranslationUnitDecl(), CS->getLocStart(), + SourceLocation(), Id, FnTy, TI, SC_Static, false, false, false); + TypeSourceInfo *PtrIntTI = + getContext().getTrivialTypeSourceInfo(PtrIntTy, SourceLocation()); + TypeSourceInfo *PtrVoidTI = getContext().getTrivialTypeSourceInfo( + getContext().VoidPtrTy, SourceLocation()); + ParmVarDecl *Arg1 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, PtrIntTy, PtrIntTI, SC_Auto, 0); + ParmVarDecl *Arg2 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, PtrIntTy, PtrIntTI, SC_Auto, 0); + ParmVarDecl *Arg3 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, getContext().VoidPtrTy, PtrVoidTI, SC_Auto, 0); + CodeGenFunction CGF(CGM, true); + const CGFunctionInfo &FI = getTypes().arrangeFunctionDeclaration(FD); + llvm::Function *Fn = llvm::Function::Create(getTypes().GetFunctionType(FI), + llvm::GlobalValue::PrivateLinkage, + FD->getName(), &CGM.getModule()); + CGM.SetInternalFunctionAttributes(CurFuncDecl, Fn, FI); + FunctionArgList FnArgs; + FnArgs.push_back(Arg1); + FnArgs.push_back(Arg2); + FnArgs.push_back(Arg3); + CGF.OpenMPRoot = OpenMPRoot ? OpenMPRoot : this; + CGF.StartFunction(FD, getContext().VoidTy, Fn, FI, FnArgs, SourceLocation()); + + CGF.OMPCancelMap[OMPD_parallel] = CGF.ReturnBlock; + + CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Arg1), + ".__kmpc_global_thread_num."); + + // Emit call to the helper function. + llvm::Value *Arg3Val = + CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Arg3), "arg3"); + QualType QTy = getContext().getRecordType(CS->getCapturedRecordDecl()); + llvm::Type *ConvertedType = + CGF.getTypes().ConvertTypeForMem(QTy)->getPointerTo(); + llvm::Value *RecArg = + CGF.Builder.CreatePointerCast(Arg3Val, ConvertedType, "(anon)arg3"); + + // CodeGen for clauses (call start). + { + OpenMPRegionRAII OMPRegion(CGF, RecArg, *CS); + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && (!isAllowedClauseForDirective(SKind, (*I)->getClauseKind()) || + (*I)->getClauseKind() == OMPC_firstprivate)) + CGF.EmitPreOMPClause(*(*I), S); + + switch (DKind) { + case OMPD_parallel: + CGF.EmitStmt(CS->getCapturedStmt()); + break; + case OMPD_parallel_sections: + CGF.EmitOMPSectionsDirective(DKind, SKind, S); + break; + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + CGF.EmitOMPDirectiveWithLoop(DKind, SKind, S); + break; + default: + break; + } + CGF.EnsureInsertPoint(); + + // CodeGen for clauses (call end). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + CGF.EmitPostOMPClause(*(*I), S); + + // CodeGen for clauses (closing steps). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + CGF.EmitCloseOMPClause(*(*I), S); + } + + CGF.EnsureInsertPoint(); + // Implicit barrier for simple parallel region only. + // Others (combined) directives already has implicit barriers. + if (DKind == OMPD_parallel) { + CGF.EmitOMPCancelBarrier(S.getLocEnd(), KMP_IDENT_BARRIER_IMPL); + } + + EmitFirstprivateInsert(CGF, S.getLocStart()); + + CGF.FinishFunction(); + + // CodeGen for "omp parallel {Associated statement}". + { + RunCleanupsScope MainBlock(*this); + + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Type *KmpcMicroTy = + llvm::TypeBuilder::get(getLLVMContext()); + llvm::Value *RealArgs[] = { + Loc, Builder.getInt32(2), + CGF.Builder.CreateBitCast(Fn, KmpcMicroTy, "(kmpc_micro_ty)helper"), + Arg}; + // __kmpc_fork_call(&loc, argc/*2*/, microtask, arg); + EmitRuntimeCall(OPENMPRTL_FUNC(fork_call), makeArrayRef(RealArgs)); + } + + // CodeGen for clauses (task finalize). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitFinalOMPClause(*(*I), S); + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); +} + +/// Generate an instructions for '#pragma omp parallel' directive. +void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { + EmitOMPDirectiveWithParallel(OMPD_parallel, OMPD_unknown, S); +} + +/// Generate an instructions for '#pragma omp parallel for' directive. +void +CodeGenFunction::EmitOMPParallelForDirective(const OMPParallelForDirective &S) { + EmitOMPDirectiveWithParallel(OMPD_parallel_for, OMPD_for, S); +} + +/// Generate an instructions for '#pragma omp parallel for simd' directive. +void CodeGenFunction::EmitOMPParallelForSimdDirective( + const OMPParallelForSimdDirective &S) { + EmitOMPDirectiveWithParallel(OMPD_parallel_for_simd, OMPD_for_simd, S); +} + +/// Generate an instructions for '#pragma omp parallel sections' directive. +void CodeGenFunction::EmitOMPParallelSectionsDirective( + const OMPParallelSectionsDirective &S) { + EmitOMPDirectiveWithParallel(OMPD_parallel_sections, OMPD_sections, S); +} + +/// Generate instruction for OpenMP loop-like directives. +void +CodeGenFunction::EmitOMPDirectiveWithLoop(OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S) { + + // Several Simd-specific vars are declared here. + // OMPD_distribute_parallel_for_simd is not included because it separates to + // OMPD_distribute and OMPD_parallel_for_simd directives intentionally and + // HasSimd is processed for OMPD_parallel_for_simd part. + bool HasSimd = DKind == OMPD_parallel_for_simd || DKind == OMPD_for_simd || + DKind == OMPD_distribute_simd; + CGPragmaOmpSimd SimdWrapper(&S); + llvm::Function *BodyFunction = 0; + bool SeparateLastIter = false; + LValue CapStruct; + + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(false); + CGM.OpenMPSupport.setNoWait(false); + CGM.OpenMPSupport.setMergeable(true); + CGM.OpenMPSupport.setOrdered(false); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitInitOMPClause(*(*I), S); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitAfterInitOMPClause(*(*I), S); + + bool IsDistributeLoop = DKind == OMPD_distribute || + DKind == OMPD_distribute_simd || + DKind == OMPD_distribute_parallel_for || + DKind == OMPD_distribute_parallel_for_simd; + int Schedule = KMP_SCH_DEFAULT; + if (!IsDistributeLoop) { + bool Ordered = CGM.OpenMPSupport.getOrdered(); + bool Merge = CGM.OpenMPSupport.getMergeable(); + int Offset = 0; + if (Ordered && Merge) + Offset = SCH_ORD; + else if (!Ordered && !Merge) + Offset = SCH_NM; + else if (Ordered && !Merge) + Offset = SCH_NM_ORD; + Schedule += Offset; + } else { + Schedule = KMP_SCH_DISTRIBUTE_STATIC; + } + CGM.OpenMPSupport.setScheduleChunkSize(Schedule, 0); + + { + RunCleanupsScope ExecutedScope(*this); + // CodeGen for clauses (call start). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitPreOMPClause(*(*I), S); + + const Expr *ChunkSize; + CGM.OpenMPSupport.getScheduleChunkSize(Schedule, ChunkSize); + OpenMPDirectiveKind Kind = S.getDirectiveKind(); + bool IsComplexParallelLoop = Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd; + bool IsInnerLoopGen = IsComplexParallelLoop && DKind != Kind; + bool IsStaticSchedule = Schedule == KMP_SCH_STATIC_CHUNKED || + Schedule == KMP_SCH_STATIC || + Schedule == KMP_SCH_DISTRIBUTE_STATIC_CHUNKED || + Schedule == KMP_SCH_DISTRIBUTE_STATIC; + // CodeGen for "omp for {Associated statement}". + { + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + const Expr *IterVar = getNewIterVarFromLoopDirective(&S); + QualType QTy = IterVar->getType(); + uint64_t TypeSize = 32; + if (getContext().getTypeSize(QTy) > TypeSize) + TypeSize = 64; + bool isSigned = true; + if (QTy->hasUnsignedIntegerRepresentation()) + isSigned = false; + llvm::Type *VarTy = TypeSize == 32 ? Int32Ty : Int64Ty; + llvm::Value *LB = 0; + llvm::Value *UB = 0; + llvm::Value *GlobalUB = 0; + // Generate loop for inner 'for' directive + if (IsInnerLoopGen) { + LB = EmitScalarExpr(getLowerBoundFromLoopDirective(&S)); + UB = EmitScalarExpr(getUpperBoundFromLoopDirective(&S)); + } else { + LB = llvm::Constant::getNullValue(VarTy); + UB = EmitScalarExpr(getNewIterEndFromLoopDirective(&S)); + } + GlobalUB = UB; +#ifdef DEBUG + llvm::AllocaInst *DebugUB = CreateMemTemp( + getNewIterEndFromLoopDirective(&S)->getType(), "debug.ub"); + Builder.CreateStore(UB, DebugUB); +#endif + UB = Builder.CreateIntCast(UB, VarTy, isSigned); + llvm::Value *Chunk; + if (ChunkSize) { + Chunk = EmitScalarExpr(ChunkSize); + Chunk = Builder.CreateIntCast(Chunk, VarTy, true); + } else { + Chunk = llvm::Constant::getNullValue(VarTy); + } + llvm::BasicBlock *EndBB = createBasicBlock("omp.loop.end"); + llvm::BasicBlock *OMPLoopBB = 0; // createBasicBlock("omp.loop.begin"); + llvm::AllocaInst *PLast = CreateTempAlloca(Int32Ty, "last"); + PLast->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(Int32Ty)); + InitTempAlloca(PLast, IsStaticSchedule ? Builder.getInt32(1) + : Builder.getInt32(0)); + llvm::AllocaInst *PLB = CreateTempAlloca(VarTy, "lb"); + PLB->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(VarTy)); + Builder.CreateStore(LB, PLB); + llvm::AllocaInst *PUB = CreateTempAlloca(VarTy, "ub"); + PUB->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(VarTy)); + Builder.CreateStore(UB, PUB); + llvm::AllocaInst *PSt = CreateTempAlloca(VarTy, "st"); + PSt->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(VarTy)); + InitTempAlloca(PSt, TypeSize == 32 ? Builder.getInt32(1) + : Builder.getInt64(1)); + llvm::AllocaInst *Private = CreateMemTemp(QTy, ".idx."); + llvm::Type *IdxTy = + cast(Private->getType())->getElementType(); + llvm::BasicBlock *MainBB; + llvm::BasicBlock *FiniBB = 0; + + const Stmt *Body = S.getAssociatedStmt(); + ArrayRef Arr = getCountersFromLoopDirective(&S); + if (const CapturedStmt *CS = dyn_cast_or_null(Body)) + Body = CS->getCapturedStmt(); + for (unsigned I = 0; I < getCollapsedNumberFromLoopDirective(&S); ++I) { + const VarDecl *VD = cast(cast(Arr[I])->getDecl()); + bool SkippedContainers = false; + while (!SkippedContainers) { + if (const AttributedStmt *AS = dyn_cast_or_null(Body)) + Body = AS->getSubStmt(); + else if (const CompoundStmt *CS = + dyn_cast_or_null(Body)) { + if (CS->size() != 1) { + SkippedContainers = true; + } else { + Body = CS->body_back(); + } + } else + SkippedContainers = true; + } + const ForStmt *For = dyn_cast_or_null(Body); + Body = For->getBody(); + if (CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) + continue; + QualType QTy = Arr[I]->getType(); + llvm::AllocaInst *Private = + CreateMemTemp(QTy, CGM.getMangledName(VD) + ".private."); + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } + while (const CapturedStmt *CS = dyn_cast_or_null(Body)) + Body = CS->getCapturedStmt(); + const VarDecl *VD = cast(cast(IterVar)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + + if (IsStaticSchedule) { + llvm::Value *RealArgs[] = { + Loc, + GTid, + Builder.getInt32(Schedule), + PLast, + PLB, + PUB, + PSt, + TypeSize == 32 ? Builder.getInt32(1) : Builder.getInt64(1), + Chunk}; + if (TypeSize == 32 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_4), RealArgs); + else if (TypeSize == 32 && !isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_4u), RealArgs); + else if (TypeSize == 64 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_8), RealArgs); + else + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_8u), RealArgs); + OMPLoopBB = createBasicBlock("omp.loop.begin"); + EmitBlock(OMPLoopBB); + LB = Builder.CreateLoad(PLB); + Builder.CreateStore(LB, Private); + UB = Builder.CreateLoad(PUB); + llvm::Value *Cond = Builder.CreateICmp( + isSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT, UB, + GlobalUB); + UB = Builder.CreateSelect(Cond, UB, GlobalUB); + Builder.CreateStore(UB, PUB); + MainBB = createBasicBlock("omp.loop.main"); + FiniBB = createBasicBlock("omp.loop.fini"); + } else { + llvm::IntegerType *SchedTy = + llvm::TypeBuilder::get(getLLVMContext()); + llvm::Value *RealArgs[] = { + Loc, + GTid, + llvm::ConstantInt::get(SchedTy, Schedule), + LB, + UB, + TypeSize == 32 ? Builder.getInt32(1) : Builder.getInt64(1), + Chunk}; + // __kmpc_dispatch_init{4, 8}(&loc, gtid, sched_type, lb, ub, st, + // chunk); + if (TypeSize == 32 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_init_4), RealArgs); + else if (TypeSize == 32 && !isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_init_4u), RealArgs); + else if (TypeSize == 64 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_init_8), RealArgs); + else + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_init_8u), RealArgs); + llvm::Value *RealArgsNext[] = {Loc, GTid, PLast, PLB, PUB, PSt}; + OMPLoopBB = createBasicBlock("omp.loop.begin"); + EmitBlock(OMPLoopBB); + llvm::Value *CallRes; + if (TypeSize == 32 && isSigned) + CallRes = + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_next_4), RealArgsNext); + else if (TypeSize == 32 && !isSigned) + CallRes = + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_next_4u), RealArgsNext); + else if (TypeSize == 64 && isSigned) + CallRes = + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_next_8), RealArgsNext); + else + CallRes = + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_next_8u), RealArgsNext); + llvm::BasicBlock *OMPInitBB = createBasicBlock("omp.loop.init"); + llvm::SwitchInst *Switch = Builder.CreateSwitch( + Builder.CreateIntCast(CallRes, Int32Ty, false), EndBB, 1); + Switch->addCase(llvm::ConstantInt::get(Int32Ty, 1), OMPInitBB); + EmitBranch(OMPInitBB); + EmitBlock(OMPInitBB); + LB = Builder.CreateLoad(PLB); + UB = Builder.CreateLoad(PUB); + Builder.CreateStore(LB, Private); + MainBB = createBasicBlock("omp.loop.main"); + FiniBB = createBasicBlock("omp.loop.fini"); + } + if (HasSimd) { + // Update vectorizer width on the loop stack. + SeparateLastIter = SimdWrapper.emitSafelen(this); + + if (SeparateLastIter) { + // Emit the following for the lastprivate vars update: + // --UB; + // It is unclear if putting it under "if (*PLast)" will be + // more or less efficient, this needs to be investigated. + UB = Builder.CreateSub(UB, llvm::ConstantInt::get(UB->getType(), 1)); + Builder.CreateStore(UB, PUB); + } + + // Initialize the captured struct. + CapStruct = InitCapturedStruct(*SimdWrapper.getAssociatedStmt()); + } + + EmitBranch(MainBB); + EmitBlock(MainBB); + + if (IsStaticSchedule) { + llvm::Value *Cond = Builder.CreateICmp( + isSigned ? llvm::CmpInst::ICMP_SLE : llvm::CmpInst::ICMP_ULE, LB, + GlobalUB); + llvm::BasicBlock *ContBB = createBasicBlock("omp.lb.le.global_ub."); + Builder.CreateCondBr(Cond, ContBB, EndBB); + EmitBlock(ContBB); + } + + if (HasSimd) { + // Push current LoopInfo onto the LoopStack. + LoopStack.Push(MainBB); + } + + { + RunCleanupsScope ThenScope(*this); + EmitStmt(getInitFromLoopDirective(&S)); +#ifdef DEBUG + // CodeGen for clauses (call start). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (const OMPLastPrivateClause *Clause = + dyn_cast_or_null(*I)) { + for (OMPLastPrivateClause::varlist_const_iterator + I1 = Clause->varlist_begin(), + E1 = Clause->varlist_end(); + I1 != E1; ++I1) { + const VarDecl *VD = + cast(cast(*I1)->getDecl()); + if (VD->getName() == "IDX") + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + else if (VD->getName() == "UB") + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, DebugUB); + else if (VD->getName() == "LUB") + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, PUB); + else if (VD->getName() == "LLB") + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, PLB); + } + } +#endif + llvm::Value *Idx = Builder.CreateLoad(Private, ".idx."); + llvm::BasicBlock *UBLBCheckBB = + createBasicBlock("omp.lb_ub.check_pass"); + UB = Builder.CreateLoad(PUB); + llvm::Value *UBLBCheck = + isSigned ? Builder.CreateICmpSLE(Idx, UB, "omp.idx.le.ub") + : Builder.CreateICmpULE(Idx, UB, "omp.idx.le.ub"); + // llvm::BasicBlock *PrevBB = Builder.GetInsertBlock(); + Builder.CreateCondBr(UBLBCheck, UBLBCheckBB, FiniBB); + EmitBlock(UBLBCheckBB); + llvm::BasicBlock *ContBlock = createBasicBlock("omp.cont.block"); + + BreakContinueStack.push_back( + BreakContinue(getJumpDestInCurrentScope(EndBB), + getJumpDestInCurrentScope(ContBlock))); + if (HasSimd) { + RunCleanupsScope Scope(*this); + BodyFunction = EmitSimdFunction(SimdWrapper); + EmitSIMDForHelperCall(BodyFunction, CapStruct, Private, false); + } else { + RunCleanupsScope Scope(*this); + if (IsInnerLoopGen || !IsComplexParallelLoop) { + if (SKind == OMPD_for) + OMPCancelMap[OMPD_for] = getJumpDestInCurrentScope(EndBB); + EmitStmt(Body); + OMPCancelMap.erase(OMPD_for); + } else { + const Expr *LowerBound = getLowerBoundFromLoopDirective(&S); + const Expr *UpperBound = getUpperBoundFromLoopDirective(&S); + EmitStoreOfScalar(Builder.CreateLoad(PLB), EmitLValue(LowerBound)); + EmitStoreOfScalar(Builder.CreateLoad(PUB), EmitLValue(UpperBound)); + // Special codegen for distribute parallel for [simd] constructs + if (Kind == OMPD_distribute_parallel_for) + EmitOMPDirectiveWithParallel(OMPD_parallel_for, OMPD_for, S); + else if (Kind == OMPD_distribute_parallel_for_simd) + EmitOMPDirectiveWithParallel(OMPD_parallel_for_simd, + OMPD_for_simd, S); + } + } + BreakContinueStack.pop_back(); + EnsureInsertPoint(); + EmitBranch(ContBlock); + EmitBlock(ContBlock); + Idx = Builder.CreateLoad(Private, ".idx."); + llvm::Value *NextIdx = Builder.CreateAdd( + Idx, llvm::ConstantInt::get(IdxTy, 1), ".next.idx.", false, + QTy->isSignedIntegerOrEnumerationType()); + Builder.CreateStore(NextIdx, Private); + if (!IsStaticSchedule && CGM.OpenMPSupport.getOrdered()) { + // Emit _dispatch_fini for ordered loops + llvm::Value *RealArgsFini[] = {Loc, GTid}; + if (TypeSize == 32 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_fini_4), RealArgsFini); + else if (TypeSize == 32 && !isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_fini_4u), RealArgsFini); + else if (TypeSize == 64 && isSigned) + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_fini_8), RealArgsFini); + else + EmitRuntimeCall(OPENMPRTL_FUNC(dispatch_fini_8u), RealArgsFini); + } + // for(llvm::SmallVector::const_iterator II = + // Incs.begin(), + // EE = + // Incs.end(); + // II != EE; ++II) { + // EmitIgnoredExpr(*II); + // EnsureInsertPoint(); + // } + EmitBranch(MainBB); + if (HasSimd) { + LoopStack.Pop(); + } + EmitBlock(FiniBB); + if (IsStaticSchedule && ChunkSize != 0) { + llvm::Value *St = Builder.CreateLoad(PSt); + LB = Builder.CreateLoad(PLB); + LB = Builder.CreateAdd(LB, St); + Builder.CreateStore(LB, PLB); + UB = Builder.CreateLoad(PUB); + UB = Builder.CreateAdd(UB, St); + Builder.CreateStore(UB, PUB); + } + if (SeparateLastIter) { + // Emit the following for the lastprivate vars update: + // call __simd_helper(cs, idx, 1) + // + EmitSIMDForHelperCall(BodyFunction, CapStruct, Private, true); + } + EmitBranch(!IsStaticSchedule || ChunkSize != 0 ? OMPLoopBB : EndBB); + // EmitStmt(getInitFromLoopDirective(&S)); + // EnsureInsertPoint(); + // UBLBCheck = isSigned ? + // Builder.CreateICmpSLE(NextIdx, UB, + // "omp.idx.le.ub") + // : + // Builder.CreateICmpULE(NextIdx, UB, + // "omp.idx.le.ub"); + // PrevBB = Builder.GetInsertBlock(); + // Builder.CreateCondBr(UBLBCheck, UBLBCheckBB, OMPLoopBB); + } + EmitBlock(EndBB, true); + if (IsStaticSchedule) { + llvm::Value *RealArgsFini[] = {Loc, GTid}; + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_fini), RealArgsFini); + } + CGM.OpenMPSupport.setLastIterVar(PLast); + } + + if (!IsDistributeLoop && + (CGM.OpenMPSupport.hasLastPrivate() || !CGM.OpenMPSupport.getNoWait())) + EmitOMPCancelBarrier(S.getLocEnd(), KMP_IDENT_BARRIER_IMPL_FOR); + // CodeGen for clauses (call end). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitPostOMPClause(*(*I), S); + } + + // CodeGen for clauses (closing steps). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitCloseOMPClause(*(*I), S); + + // CodeGen for clauses (task finalize). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitFinalOMPClause(*(*I), S); + + EnsureInsertPoint(); + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); + + if (HasSimd) { + // Emit the final values of 'linear' variables. + SimdWrapper.emitLinearFinal(*this); + } +} + +/// Generate an instructions for '#pragma omp for' directive. +void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { + EmitOMPDirectiveWithLoop(OMPD_for, OMPD_for, S); +} + +/// Generate an instructions for '#pragma omp distribute' directive. +void +CodeGenFunction::EmitOMPDistributeDirective(const OMPDistributeDirective &S) { + EmitOMPDirectiveWithLoop(OMPD_distribute, OMPD_distribute, S); +} + +/// Generate an instructions for directive with 'teams' region. +void +CodeGenFunction::EmitOMPDirectiveWithTeams(OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S) { + // Generate shared args for captured stmt. + CapturedStmt *CS = cast(S.getAssociatedStmt()); + llvm::Value *Arg = GenerateCapturedStmtArgument(*CS); + + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(true); + CGM.OpenMPSupport.setMergeable(false); + CGM.OpenMPSupport.setOrdered(false); + CGM.OpenMPSupport.setNoWait(true); + CGM.OpenMPSupport.setScheduleChunkSize(KMP_SCH_DEFAULT, 0); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitInitOMPClause(*(*I), S); + llvm::Value *NumTeams = CGM.OpenMPSupport.getNumTeams(); + llvm::Value *ThreadLimit = CGM.OpenMPSupport.getThreadLimit(); + if (NumTeams && ThreadLimit) { + // __kmpc_push_num_teams(&loc, global_tid, num_threads, thread_limit); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + llvm::Value *RealArgs[] = {Loc, GTid, + NumTeams ? NumTeams : Builder.getInt32(0), + ThreadLimit ? ThreadLimit : Builder.getInt32(0)}; + EmitRuntimeCall(OPENMPRTL_FUNC(push_num_teams), RealArgs); + } + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitAfterInitOMPClause(*(*I), S); + + // Generate microtask. + // void .omp_microtask.(int32_t *, int32_t *, void */*AutoGenRecord **/arg3) { + // captured_stmt(arg3); + // } + IdentifierInfo *Id = &getContext().Idents.get(".omp_microtask."); + QualType PtrIntTy = getContext().getPointerType(getContext().IntTy); + SmallVector FnArgTypes; + FnArgTypes.push_back(PtrIntTy); + FnArgTypes.push_back(PtrIntTy); + FnArgTypes.push_back(getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_BasicNoexcept; + QualType FnTy = + getContext().getFunctionType(getContext().VoidTy, FnArgTypes, EPI); + TypeSourceInfo *TI = + getContext().getTrivialTypeSourceInfo(FnTy, SourceLocation()); + FunctionDecl *FD = FunctionDecl::Create( + getContext(), getContext().getTranslationUnitDecl(), CS->getLocStart(), + SourceLocation(), Id, FnTy, TI, SC_Static, false, false, false); + TypeSourceInfo *PtrIntTI = + getContext().getTrivialTypeSourceInfo(PtrIntTy, SourceLocation()); + TypeSourceInfo *PtrVoidTI = getContext().getTrivialTypeSourceInfo( + getContext().VoidPtrTy, SourceLocation()); + ParmVarDecl *Arg1 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, PtrIntTy, PtrIntTI, SC_Auto, 0); + ParmVarDecl *Arg2 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, PtrIntTy, PtrIntTI, SC_Auto, 0); + ParmVarDecl *Arg3 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, getContext().VoidPtrTy, PtrVoidTI, SC_Auto, 0); + CodeGenFunction CGF(CGM, true); + const CGFunctionInfo &FI = getTypes().arrangeFunctionDeclaration(FD); + llvm::Function *Fn = llvm::Function::Create(getTypes().GetFunctionType(FI), + llvm::GlobalValue::PrivateLinkage, + FD->getName(), &CGM.getModule()); + CGM.SetInternalFunctionAttributes(CurFuncDecl, Fn, FI); + llvm::AttributeSet Set = CurFn->getAttributes(); + for (unsigned i = 0; i < Set.getNumSlots(); ++i) { + if (Set.getSlotIndex(i) == llvm::AttributeSet::FunctionIndex) { + for (llvm::AttributeSet::iterator I = Set.begin(i), E = Set.end(i); + I != E; ++I) { + if (I->isStringAttribute() && I->getKindAsString().startswith("INTEL:")) + Fn->addFnAttr(I->getKindAsString()); + } + } + } + FunctionArgList FnArgs; + FnArgs.push_back(Arg1); + FnArgs.push_back(Arg2); + FnArgs.push_back(Arg3); + CGF.OpenMPRoot = OpenMPRoot ? OpenMPRoot : this; + CGF.StartFunction(FD, getContext().VoidTy, Fn, FI, FnArgs, SourceLocation()); + CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Arg1), + ".__kmpc_global_thread_num."); + + // Emit call to the helper function. + llvm::Value *Arg3Val = + CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Arg3), "arg3"); + QualType QTy = getContext().getRecordType(CS->getCapturedRecordDecl()); + llvm::Type *ConvertedType = + CGF.getTypes().ConvertTypeForMem(QTy)->getPointerTo(); + llvm::Value *RecArg = + CGF.Builder.CreatePointerCast(Arg3Val, ConvertedType, "(anon)arg3"); + + // CodeGen for clauses (call start). + { + OpenMPRegionRAII OMPRegion(CGF, RecArg, *CS); + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + CGF.EmitPreOMPClause(*(*I), S); + + switch (DKind) { + case OMPD_target_teams: + case OMPD_teams: + CGF.EmitStmt(CS->getCapturedStmt()); + break; + default: + break; + } + CGF.EnsureInsertPoint(); + + // CodeGen for clauses (call end). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + CGF.EmitPostOMPClause(*(*I), S); + + // CodeGen for clauses (closing steps). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + CGF.EmitCloseOMPClause(*(*I), S); + } + + CGF.FinishFunction(); + + // CodeGen for "omp parallel {Associated statement}". + { + RunCleanupsScope MainBlock(*this); + + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Type *KmpcMicroTy = + llvm::TypeBuilder::get(getLLVMContext()); + llvm::Value *RealArgs[] = { + Loc, Builder.getInt32(2), + CGF.Builder.CreateBitCast(Fn, KmpcMicroTy, "(kmpc_micro_ty)helper"), + Arg}; + // __kmpc_fork_teams(&loc, argc/*2*/, microtask, arg); + EmitRuntimeCall(OPENMPRTL_FUNC(fork_teams), makeArrayRef(RealArgs)); + } + + // CodeGen for clauses (task finalize). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && !isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitFinalOMPClause(*(*I), S); + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); +} + +static void EmitUntiedPartIdInc(CodeGenFunction &CGF) { + if (CGF.CGM.OpenMPSupport.getUntied()) { + llvm::Value *PartIdAddr; + llvm::Value *UntiedSwitch; + llvm::BasicBlock *UntiedEnd; + unsigned UntiedCounter; + CGF.CGM.OpenMPSupport.getUntiedData(PartIdAddr, UntiedSwitch, UntiedEnd, + UntiedCounter); + ++UntiedCounter; + CGF.Builder.CreateStore(CGF.Builder.getInt32(UntiedCounter), PartIdAddr); + CGF.CGM.OpenMPSupport.setUntiedData(PartIdAddr, UntiedSwitch, UntiedEnd, + UntiedCounter, &CGF); + } +} + +static void EmitUntiedBranchEnd(CodeGenFunction &CGF) { + if (CGF.CGM.OpenMPSupport.getUntied()) { + llvm::Value *PartIdAddr; + llvm::Value *UntiedSwitch; + llvm::BasicBlock *UntiedEnd; + unsigned UntiedCounter; + CGF.CGM.OpenMPSupport.getUntiedData(PartIdAddr, UntiedSwitch, UntiedEnd, + UntiedCounter); + CGF.EmitBranch(UntiedEnd); + } +} + +static void EmitUntiedTaskSwitch(CodeGenFunction &CGF, bool EmitBranch) { + if (CGF.CGM.OpenMPSupport.getUntied()) { + llvm::Value *PartIdAddr; + llvm::Value *UntiedSwitch; + llvm::BasicBlock *UntiedEnd; + unsigned UntiedCounter; + CGF.CGM.OpenMPSupport.getUntiedData(PartIdAddr, UntiedSwitch, UntiedEnd, + UntiedCounter); + llvm::BasicBlock *NextBlock = CGF.createBasicBlock("untied.sw.next"); + cast(UntiedSwitch) + ->addCase(CGF.Builder.getInt32(UntiedCounter), NextBlock); + if (EmitBranch) + CGF.EmitBranch(NextBlock); + CGF.EmitBlock(NextBlock); + } +} + +namespace { +struct CallStackRestore : EHScopeStack::Cleanup { + llvm::Value *Stack; + CallStackRestore(llvm::Value *Stack) : Stack(Stack) {} + void Emit(CodeGenFunction &CGF, Flags flags) { + llvm::Value *V = CGF.Builder.CreateLoad(Stack); + llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore); + CGF.Builder.CreateCall(F, V); + } +}; +} + +static std::pair +ProcessDependAddresses(CodeGenFunction &CGF, const OMPTaskDirective &S) { + CodeGenModule &CGM = CGF.CGM; + + llvm::Value *DependenceAddresses = 0; + unsigned ArraySize = 0; + + SmallVector DependClauses; + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + if (OMPDependClause *ODC = dyn_cast_or_null(*I)) { + ArraySize += ODC->varlist_size(); + DependClauses.push_back(ODC); + } + } + if (ArraySize > 0) { + llvm::Type *IntPtrTy = + CGF.ConvertTypeForMem(CGF.getContext().getIntPtrType()); + llvm::Type *BoolTy = CGF.ConvertTypeForMem(CGF.getContext().BoolTy); + llvm::Type *DepTy = getKMPDependInfoType(&CGM); + llvm::ArrayType *DepListTy = llvm::ArrayType::get(DepTy, ArraySize); + + llvm::AllocaInst *Addresses = CGF.CreateTempAlloca(DepListTy, ".dep.list."); + Addresses->setAlignment(CGM.OpenMPSupport.getKMPDependInfoTypeAlign()); + DependenceAddresses = + CGF.Builder.CreateConstInBoundsGEP2_32(Addresses, 0, 0); + + unsigned FieldCounter = 0; + for (SmallVectorImpl::iterator + I = DependClauses.begin(), + E = DependClauses.end(); + I != E; ++I) { + unsigned DepType = IN; + switch ((*I)->getType()) { + case OMPC_DEPEND_in: + DepType = IN; + break; + case OMPC_DEPEND_out: + DepType = OUT; + break; + case OMPC_DEPEND_inout: + DepType = INOUT; + break; + case OMPC_DEPEND_unknown: + case NUM_OPENMP_DEPENDENCE_TYPE: + llvm_unreachable("Unknown kind of dependency"); + break; + } + for (unsigned i = 0, e = (*I)->varlist_size(); i < e; + ++i, ++FieldCounter) { + llvm::Value *DepElPtr = + CGF.Builder.CreateConstInBoundsGEP2_32(Addresses, 0, FieldCounter); + // [CounterVal].base_addr = &expr; + llvm::Value *DepBaseAddr = + CGF.Builder.CreateConstGEP2_32(DepElPtr, 0, 0); + llvm::Value *BaseAddr = + CGF.EmitAnyExpr((*I)->getBegins(i)).getScalarVal(); + BaseAddr = CGF.Builder.CreatePointerCast(BaseAddr, IntPtrTy); + CGF.Builder.CreateStore(BaseAddr, DepBaseAddr); + // [CounterVal].len = size; + llvm::Value *DepLen = CGF.Builder.CreateConstGEP2_32(DepElPtr, 0, 1); + const Expr *Size = (*I)->getSizeInBytes(i); + if (Size->getType()->isAnyPointerType()) { + // Size is not a size, but the ending pointer + // Calculate the real size + llvm::Value *EndAddr = CGF.EmitScalarExpr(Size); + llvm::Value *BaseVal = + CGF.Builder.CreatePtrToInt(BaseAddr, CGF.SizeTy); + llvm::Value *EndVal = CGF.Builder.CreatePtrToInt(EndAddr, CGF.SizeTy); + llvm::Value *Cond = CGF.Builder.CreateICmpUGT(EndVal, BaseVal); + llvm::Value *Res = CGF.Builder.CreateSelect( + Cond, CGF.Builder.CreateSub(EndVal, BaseVal), + llvm::Constant::getNullValue(CGF.SizeTy)); + CGF.Builder.CreateStore(Res, DepLen); + } else { + CGF.Builder.CreateStore(CGF.EmitScalarExpr(Size), DepLen); + } + // [CounterVal].flags = size; + llvm::Value *DepFlags = CGF.Builder.CreateConstGEP2_32(DepElPtr, 0, 2); + CGF.Builder.CreateStore(llvm::ConstantInt::get(BoolTy, DepType), + DepFlags); + } + } + } else { + llvm::Type *DepTy = getKMPDependInfoType(&CGM); + DependenceAddresses = llvm::Constant::getNullValue(DepTy->getPointerTo()); + } + return std::make_pair(DependenceAddresses, ArraySize); +} + +/// Generate an instructions for '#pragma omp task' directive. +void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) { + // Generate shared args for captured stmt. + CapturedStmt *CS = cast(S.getAssociatedStmt()); + llvm::Value *Arg = GenerateCapturedStmtArgument(*CS); + + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(true); + CGM.OpenMPSupport.setMergeable(false); + CGM.OpenMPSupport.setOrdered(false); + CGM.OpenMPSupport.setUntied(false); + CGM.OpenMPSupport.setScheduleChunkSize(KMP_SCH_DEFAULT, 0); + + RecordDecl *RD; + if (!getContext().getLangOpts().CPlusPlus) + RD = RecordDecl::Create(getContext(), TTK_Struct, + getContext().getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &getContext().Idents.get(".omp.task.priv.")); + else + RD = CXXRecordDecl::Create(getContext(), TTK_Struct, + getContext().getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &getContext().Idents.get(".omp.task.priv.")); + RD->startDefinition(); + SmallVector FieldsWithDestructors; + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + if (OMPPrivateClause *C = dyn_cast_or_null(*I)) { + for (OMPPrivateClause::varlist_const_iterator II = C->varlist_begin(), + EE = C->varlist_end(); + II != EE; ++II) { + const ValueDecl *D = cast(*II)->getDecl(); + FieldDecl *FD = FieldDecl::Create( + getContext(), RD, SourceLocation(), SourceLocation(), + D->getIdentifier(), (*II)->getType(), 0, 0, false, ICIS_NoInit); + FD->setAccess(AS_public); + RD->addDecl(FD); + CGM.OpenMPSupport.getTaskFields()[D] = FD; + QualType ASTType = D->getType(); + if (CXXRecordDecl *RD = + ASTType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { + if (!RD->hasTrivialDestructor()) + FieldsWithDestructors.push_back(FD); + } + } + } else if (OMPFirstPrivateClause *C = + dyn_cast_or_null(*I)) { + for (OMPFirstPrivateClause::varlist_const_iterator + II = C->varlist_begin(), + EE = C->varlist_end(); + II != EE; ++II) { + const ValueDecl *D = cast(*II)->getDecl(); + FieldDecl *FD = FieldDecl::Create( + getContext(), RD, SourceLocation(), SourceLocation(), + D->getIdentifier(), (*II)->getType(), 0, 0, false, ICIS_NoInit); + FD->setAccess(AS_public); + RD->addDecl(FD); + CGM.OpenMPSupport.getTaskFields()[D] = FD; + QualType ASTType = D->getType(); + if (CXXRecordDecl *RD = + ASTType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { + if (!RD->hasTrivialDestructor()) + FieldsWithDestructors.push_back(FD); + } + } + } + } + RD->completeDefinition(); + QualType PrivateRecord = getContext().getRecordType(RD); + llvm::Type *LPrivateTy = getTypes().ConvertTypeForMem(PrivateRecord); + + llvm::Function *Destructors = 0; + if (!FieldsWithDestructors.empty()) { + IdentifierInfo *Id = &getContext().Idents.get(".omp_ptask_destructors."); + SmallVector FnArgTypes; + FnArgTypes.push_back(getContext().getIntTypeForBitwidth(32, 1)); + FnArgTypes.push_back(getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_BasicNoexcept; + QualType FnTy = getContext().getFunctionType( + getContext().getIntTypeForBitwidth(32, 1), FnArgTypes, EPI); + TypeSourceInfo *TI = + getContext().getTrivialTypeSourceInfo(FnTy, SourceLocation()); + FunctionDecl *FD = FunctionDecl::Create( + getContext(), getContext().getTranslationUnitDecl(), CS->getLocStart(), + SourceLocation(), Id, FnTy, TI, SC_Static, false, false, false); + TypeSourceInfo *IntTI = getContext().getTrivialTypeSourceInfo( + getContext().getIntTypeForBitwidth(32, 1), SourceLocation()); + TypeSourceInfo *PtrVoidTI = getContext().getTrivialTypeSourceInfo( + getContext().VoidPtrTy, SourceLocation()); + ParmVarDecl *Arg1 = ParmVarDecl::Create( + getContext(), FD, SourceLocation(), SourceLocation(), 0, + getContext().getIntTypeForBitwidth(32, 1), IntTI, SC_Auto, 0); + ParmVarDecl *Arg2 = ParmVarDecl::Create( + getContext(), FD, SourceLocation(), SourceLocation(), 0, + getContext().VoidPtrTy, PtrVoidTI, SC_Auto, 0); + CodeGenFunction CGF(CGM); + const CGFunctionInfo &FI = getTypes().arrangeFunctionDeclaration(FD); + Destructors = llvm::Function::Create(getTypes().GetFunctionType(FI), + llvm::GlobalValue::PrivateLinkage, + FD->getName(), &CGM.getModule()); + FunctionArgList FnArgs; + FnArgs.push_back(Arg1); + FnArgs.push_back(Arg2); + CGF.StartFunction(FD, getContext().getIntTypeForBitwidth(32, 1), + Destructors, FI, FnArgs, SourceLocation()); + llvm::Type *TaskTTy = llvm::TaskTBuilder::get(getLLVMContext()); + llvm::Value *TaskTPtr = CGF.Builder.CreatePointerCast( + CGF.GetAddrOfLocalVar(Arg2), TaskTTy->getPointerTo()->getPointerTo()); + // Emit call to the helper function. + llvm::Value *Locker = + CGF.Builder.CreateConstGEP1_32(CGF.Builder.CreateLoad(TaskTPtr), 1); + Locker = CGF.Builder.CreatePointerCast(Locker, LPrivateTy->getPointerTo()); + for (ArrayRef::iterator I = FieldsWithDestructors.begin(), + E = FieldsWithDestructors.end(); + I != E; ++I) { + QualType ASTType = (*I)->getType(); + if (CXXRecordDecl *RD = + ASTType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { + if (!RD->hasTrivialDestructor()) { + llvm::Value *Private = + CGF.EmitLValueForField( + CGF.MakeNaturalAlignAddrLValue(Locker, PrivateRecord), *I) + .getAddress(); + QualType::DestructionKind DtorKind = ASTType.isDestructedType(); + CGF.emitDestroy(Private, ASTType, CGF.getDestroyer(DtorKind), + CGF.needsEHCleanup(DtorKind)); + } + } + } + CGF.FinishFunction(SourceLocation()); + } + + // llvm::Type *PTaskFnTy = llvm::TypeBuilder::get(getLLVMContext()); + // llvm::AllocaInst *FnPtr = CreateTempAlloca(PTaskFnTy); + // FnPtr->setAlignment(llvm::ConstantExpr::getAlignOf(PTaskFnTy)); + + // CodeGen for clauses (task init). + llvm::AllocaInst *Flags = + CreateMemTemp(getContext().getIntTypeForBitwidth(32, 1), ".flags.addr"); + CGM.OpenMPSupport.setTaskFlags(Flags); + + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + EmitInitOMPClause(*(*I), S); + + uint64_t InitFlags = + CGM.OpenMPSupport.getUntied() ? OMP_TASK_UNTIED : OMP_TASK_TIED; + if (Destructors) { + InitFlags |= OMP_TASK_DESTRUCTORS_THUNK; + } + InitTempAlloca(Flags, Builder.getInt32(InitFlags)); + + // Generate microtask. + // int32 .omp_ptask.(int32_t arg1, void */*kmp_task_t **/arg2) { + // captured_stmt(arg2->shareds); + // } + IdentifierInfo *Id = &getContext().Idents.get(".omp_ptask."); + SmallVector FnArgTypes; + FnArgTypes.push_back(getContext().getIntTypeForBitwidth(32, 1)); + FnArgTypes.push_back(getContext().VoidPtrTy); + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_BasicNoexcept; + QualType FnTy = getContext().getFunctionType( + getContext().getIntTypeForBitwidth(32, 1), FnArgTypes, EPI); + TypeSourceInfo *TI = + getContext().getTrivialTypeSourceInfo(FnTy, SourceLocation()); + FunctionDecl *FD = FunctionDecl::Create( + getContext(), getContext().getTranslationUnitDecl(), CS->getLocStart(), + SourceLocation(), Id, FnTy, TI, SC_Static, false, false, false); + TypeSourceInfo *IntTI = getContext().getTrivialTypeSourceInfo( + getContext().getIntTypeForBitwidth(32, 1), SourceLocation()); + TypeSourceInfo *PtrVoidTI = getContext().getTrivialTypeSourceInfo( + getContext().VoidPtrTy, SourceLocation()); + ParmVarDecl *Arg1 = ParmVarDecl::Create( + getContext(), FD, SourceLocation(), SourceLocation(), 0, + getContext().getIntTypeForBitwidth(32, 1), IntTI, SC_Auto, 0); + ParmVarDecl *Arg2 = + ParmVarDecl::Create(getContext(), FD, SourceLocation(), SourceLocation(), + 0, getContext().VoidPtrTy, PtrVoidTI, SC_Auto, 0); + CodeGenFunction CGF(CGM, true); + const CGFunctionInfo &FI = getTypes().arrangeFunctionDeclaration(FD); + llvm::Function *Fn = llvm::Function::Create(getTypes().GetFunctionType(FI), + llvm::GlobalValue::PrivateLinkage, + FD->getName(), &CGM.getModule()); + CGM.SetInternalFunctionAttributes(CurFuncDecl, Fn, FI); + FunctionArgList FnArgs; + FnArgs.push_back(Arg1); + FnArgs.push_back(Arg2); + CGF.OpenMPRoot = OpenMPRoot ? OpenMPRoot : this; + CGF.StartFunction(FD, getContext().getIntTypeForBitwidth(32, 1), Fn, FI, + FnArgs, SourceLocation()); + + CGF.OMPCancelMap[OMPD_taskgroup] = CGF.ReturnBlock; + + llvm::AllocaInst *GTid = CGF.CreateMemTemp( + getContext().getIntTypeForBitwidth(32, 1), ".__kmpc_global_thread_num."); + CGF.EmitStoreOfScalar(CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Arg1)), + MakeNaturalAlignAddrLValue( + GTid, getContext().getIntTypeForBitwidth(32, 1)), + false); + llvm::Type *TaskTTy = llvm::TaskTBuilder::get(getLLVMContext()); + llvm::Value *TaskTPtr = CGF.Builder.CreatePointerCast( + CGF.GetAddrOfLocalVar(Arg2), TaskTTy->getPointerTo()->getPointerTo()); + + // Emit call to the helper function. + llvm::Value *Addr = CGF.Builder.CreateConstInBoundsGEP2_32( + CGF.Builder.CreateLoad(TaskTPtr, ".arg2.shareds"), 0, + llvm::TaskTBuilder::shareds, ".arg2.shareds.addr"); + llvm::Value *Arg2Val = CGF.Builder.CreateLoad(Addr, ".arg2.shareds."); + QualType QTy = getContext().getRecordType(CS->getCapturedRecordDecl()); + llvm::Type *ConvertedType = + CGF.getTypes().ConvertTypeForMem(QTy)->getPointerTo(); + llvm::Value *RecArg = + CGF.Builder.CreatePointerCast(Arg2Val, ConvertedType, "(anon)shared"); + + llvm::Value *Locker = + CGF.Builder.CreateConstGEP1_32(CGF.Builder.CreateLoad(TaskTPtr), 1); + CGM.OpenMPSupport.setPTask(Fn, Arg2Val, LPrivateTy, PrivateRecord, Locker); + + // CodeGen for clauses (call start). + { + OpenMPRegionRAII OMPRegion(CGF, RecArg, *CS); + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + CGF.EmitPreOMPClause(*(*I), S); + + llvm::BasicBlock *UntiedEnd = 0; + if (CGM.OpenMPSupport.getUntied()) { + llvm::Value *Addr = CGF.Builder.CreateConstInBoundsGEP2_32( + CGF.Builder.CreateLoad(TaskTPtr, ".arg2.part_id."), 0, + llvm::TaskTBuilder::part_id, ".part_id.addr"); + llvm::Value *PartId = CGF.Builder.CreateLoad(Addr, ".part_id."); + UntiedEnd = CGF.createBasicBlock("untied.sw.end"); + llvm::SwitchInst *UntiedSwitch = + CGF.Builder.CreateSwitch(PartId, UntiedEnd); + llvm::BasicBlock *InitBlock = CGF.createBasicBlock("untied.sw.init"); + CGF.EmitBlock(InitBlock); + UntiedSwitch->addCase(CGF.Builder.getInt32(0), InitBlock); + CGM.OpenMPSupport.setUntiedData(Addr, UntiedSwitch, UntiedEnd, 0, &CGF); + } + CGF.EmitStmt(CS->getCapturedStmt()); + CGF.EnsureInsertPoint(); + if (UntiedEnd) + CGF.EmitBlock(UntiedEnd); + + // CodeGen for clauses (call end). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + CGF.EmitPostOMPClause(*(*I), S); + + // CodeGen for clauses (closing steps). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + CGF.EmitCloseOMPClause(*(*I), S); + } + + CGF.FinishFunction(); + + llvm::DenseMap SavedFields = + CGM.OpenMPSupport.getTaskFields(); + CGM.OpenMPSupport.endOpenMPRegion(); + + // CodeGen for 'depend' clause. + llvm::Value *DependenceAddresses = 0; + unsigned ArraySize = 0; + if (!CGM.OpenMPSupport.getUntied()) { + llvm::tie(DependenceAddresses, ArraySize) = + ProcessDependAddresses(*this, S); + } + // CodeGen for "omp task {Associated statement}". + CGM.OpenMPSupport.startOpenMPRegion(false); + CGM.OpenMPSupport.getTaskFields() = SavedFields; + { + RunCleanupsScope MainBlock(*this); + + EmitUntiedPartIdInc(*this); + + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + llvm::Value *RealArgs[] = { + Loc, GTid, Builder.CreateLoad(Flags, ".flags."), + Builder.CreateAdd( + Builder.CreateIntCast(llvm::ConstantExpr::getSizeOf(TaskTTy), + SizeTy, false), + llvm::ConstantInt::get( + SizeTy, + getContext().getTypeSizeInChars(PrivateRecord).getQuantity())), + llvm::ConstantInt::get( + SizeTy, getContext().getTypeSizeInChars(QTy).getQuantity()), + Fn}; + // kmpc_task_t val = __kmpc_omp_task_alloc(&loc, gtid, flags, + // sizeof(kmpc_task_t), sizeof(shareds), task_entry); + llvm::Value *TaskTVal = + EmitRuntimeCall(OPENMPRTL_FUNC(omp_task_alloc), makeArrayRef(RealArgs), + ".task_t.val.addr"); + llvm::Value *SharedAddr = Builder.CreateConstInBoundsGEP2_32( + TaskTVal, 0, llvm::TaskTBuilder::shareds, ".shared.addr"); + EmitAggregateAssign(Builder.CreateLoad(SharedAddr), Arg, QTy); + if (Destructors) { + llvm::Value *DestructorsAddr = Builder.CreateConstInBoundsGEP2_32( + TaskTVal, 0, llvm::TaskTBuilder::destructors, ".destructors.addr"); + Builder.CreateStore(Destructors, DestructorsAddr); + } + llvm::Value *Locker = Builder.CreateConstGEP1_32(TaskTVal, 1); + CGM.OpenMPSupport.setPTask(Fn, TaskTVal, LPrivateTy, PrivateRecord, Locker); + { + RunCleanupsScope ExecutedScope(*this); + // Skip firstprivate sync for tasks. + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && (isa(*I) || isa(*I))) + EmitPreOMPClause(*(*I), S); + + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + EmitAfterInitOMPClause(*(*I), S); + + if (CGM.OpenMPSupport.getUntied()) { + llvm::Value *RealArgs1[] = {Loc, GTid, TaskTVal}; + llvm::Value *Res = EmitRuntimeCall(OPENMPRTL_FUNC(omp_task_parts), + RealArgs1, ".task.res."); + llvm::Value *Cond = Builder.CreateICmpEQ( + Res, Builder.getInt32(OMP_TASK_CURRENT_QUEUED)); + llvm::BasicBlock *ThenBB = createBasicBlock("task.parts.then"); + llvm::BasicBlock *EndBB = createBasicBlock("task.parts.end"); + Builder.CreateCondBr(Cond, ThenBB, EndBB); + EmitBlock(ThenBB); + EmitUntiedBranchEnd(*this); + EmitBlock(EndBB, true); + } else { + llvm::Type *PtrDepTy = getKMPDependInfoType(&CGM)->getPointerTo(); + llvm::Value *RealArgs1[] = {Loc, + GTid, + TaskTVal, + llvm::ConstantInt::get(Int32Ty, ArraySize), + DependenceAddresses, + llvm::ConstantInt::get(Int32Ty, 0), + llvm::Constant::getNullValue(PtrDepTy)}; + EmitRuntimeCall(OPENMPRTL_FUNC(omp_task_with_deps), RealArgs1, + ".task.res."); + llvm::Value *WaitDepsArgs[] = { + Loc, + GTid, + llvm::ConstantInt::get(Int32Ty, ArraySize), + DependenceAddresses, + llvm::ConstantInt::get(Int32Ty, 0), + llvm::Constant::getNullValue(PtrDepTy)}; + CGM.OpenMPSupport.setWaitDepsArgs(WaitDepsArgs); + } + EmitUntiedTaskSwitch(*this, true); + } + } + + // CodeGen for clauses (task finalize). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I) + EmitFinalOMPClause(*(*I), S); + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); +} + +/// Generate an instructions for '#pragma omp sections' directive. +void +CodeGenFunction::EmitOMPSectionsDirective(OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S) { + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(false); + CGM.OpenMPSupport.setNoWait(false); + CGM.OpenMPSupport.setMergeable(true); + CGM.OpenMPSupport.setOrdered(false); + + // Generate shared args for captured stmt. + // CapturedStmt *CS = cast(S.getAssociatedStmt()); + // llvm::Value *Arg = GenerateCapturedStmtArgument(*CS); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitInitOMPClause(*(*I), S); + + // CodeGen for clauses (task init). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitAfterInitOMPClause(*(*I), S); + + int Schedule = KMP_SCH_DEFAULT; + bool Ordered = CGM.OpenMPSupport.getOrdered(); + bool Merge = CGM.OpenMPSupport.getMergeable(); + int Offset = 0; + if (Ordered && Merge) + Offset = SCH_ORD; + else if (!Ordered && !Merge) + Offset = SCH_NM; + else if (Ordered && !Merge) + Offset = SCH_NM_ORD; + Schedule += Offset; + CGM.OpenMPSupport.setScheduleChunkSize(Schedule, 0); + + { + RunCleanupsScope ExecutedScope(*this); + // CodeGen for clauses (call start). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitPreOMPClause(*(*I), S); + + // CodeGen for "omp sections {Associated statement}". + // Calculate number of sections. + CompoundStmt *AStmt = cast( + cast(S.getAssociatedStmt())->getCapturedStmt()); + unsigned NumberOfSections = AStmt->size() - 1; + + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + uint64_t TypeSize = getContext().getTypeSize(getContext().UnsignedIntTy); + llvm::IntegerType *UnsignedTy = + cast(ConvertTypeForMem(getContext().UnsignedIntTy)); + llvm::AllocaInst *IterVar = + CreateMemTemp(getContext().UnsignedIntTy, ".idx.addr"); + InitTempAlloca(IterVar, llvm::Constant::getNullValue(UnsignedTy)); + const Expr *ChunkSize; + CGM.OpenMPSupport.getScheduleChunkSize(Schedule, ChunkSize); + llvm::Value *Chunk; + if (ChunkSize) { + Chunk = EmitScalarExpr(ChunkSize); + Chunk = Builder.CreateIntCast( + Chunk, TypeSize == 32 ? Builder.getInt32Ty() : Builder.getInt64Ty(), + true); + } else { + Chunk = (TypeSize == 32) ? Builder.getInt32(0) : Builder.getInt64(0); + } + llvm::Value *UBVal = llvm::ConstantInt::get(UnsignedTy, NumberOfSections); + llvm::AllocaInst *PLast = CreateTempAlloca(Int32Ty, "last"); + PLast->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(Int32Ty)); + InitTempAlloca(PLast, Builder.getInt32(0)); + llvm::AllocaInst *PLB = CreateMemTemp(getContext().UnsignedIntTy, "lb"); + InitTempAlloca(PLB, llvm::ConstantInt::get(UnsignedTy, 0)); + llvm::AllocaInst *PUB = CreateMemTemp(getContext().UnsignedIntTy, "ub"); + InitTempAlloca(PUB, UBVal); + llvm::AllocaInst *PSt = CreateMemTemp(getContext().UnsignedIntTy, "st"); + InitTempAlloca(PSt, llvm::ConstantInt::get(UnsignedTy, 1)); + + llvm::Value *RealArgs[] = { + Loc, + GTid, + Builder.getInt32(Schedule), + PLast, + PLB, + PUB, + PSt, + TypeSize == 32 ? Builder.getInt32(1) : Builder.getInt64(1), + Chunk}; + if (TypeSize == 32) + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_4u), RealArgs); + else + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_init_8u), RealArgs); + + llvm::BasicBlock *OMPSectionsBB = createBasicBlock("omp.sections.begin"); + EmitBranch(OMPSectionsBB); + EmitBlock(OMPSectionsBB); + llvm::Value *UB = Builder.CreateLoad(PUB); + llvm::Value *Cond = Builder.CreateICmpULT(UB, UBVal); + UB = Builder.CreateSelect(Cond, UB, UBVal); + Builder.CreateStore(UB, PUB); + + llvm::BasicBlock *EndBB = createBasicBlock("omp.sections.end"); + llvm::Value *LB = Builder.CreateLoad(PLB); + Builder.CreateStore(LB, IterVar); + llvm::BasicBlock *UBLBCheckBB = createBasicBlock("omp.lb_ub.check_pass"); + llvm::Value *UBLBCheck = Builder.CreateICmpULE(LB, UB, "omp.lb.le.ub"); + Builder.CreateCondBr(UBLBCheck, UBLBCheckBB, EndBB); + EmitBlock(UBLBCheckBB); + + llvm::Value *Idx = Builder.CreateLoad(IterVar, ".idx."); + llvm::BasicBlock *SectionEndBB = createBasicBlock("omp.section.fini"); + llvm::SwitchInst *SectionSwitch = + Builder.CreateSwitch(Idx, SectionEndBB, NumberOfSections + 1); + if (SKind == OMPD_sections) + OMPCancelMap[OMPD_sections] = getJumpDestInCurrentScope(EndBB); + CompoundStmt::const_body_iterator I = AStmt->body_begin(); + for (unsigned i = 0; i <= NumberOfSections; ++i, ++I) { + RunCleanupsScope ThenScope(*this); + llvm::BasicBlock *SectionBB = createBasicBlock("omp.section"); + SectionSwitch->addCase(llvm::ConstantInt::get(UnsignedTy, i), SectionBB); + EmitBlock(SectionBB); + EmitStmt(*I); + EnsureInsertPoint(); + EmitBranch(SectionEndBB); + } + EmitBlock(SectionEndBB, true); + OMPCancelMap.erase(SKind); + + llvm::Value *NextIdx = Builder.CreateAdd( + Idx, llvm::ConstantInt::get(UnsignedTy, 1), ".next.idx."); + Builder.CreateStore(NextIdx, IterVar); + UBLBCheck = Builder.CreateICmpULE(NextIdx, UB, "omp.idx.le.ub"); + if (ChunkSize != 0) { + llvm::BasicBlock *OMPSectionsNB = createBasicBlock("omp.sections.next"); + Builder.CreateCondBr(UBLBCheck, UBLBCheckBB, OMPSectionsNB); + EmitBlock(OMPSectionsNB); + llvm::Value *St = Builder.CreateLoad(PSt); + LB = Builder.CreateAdd(LB, St); + Builder.CreateStore(LB, PLB); + UB = Builder.CreateAdd(UB, St); + Builder.CreateStore(UB, PUB); + EmitBranch(OMPSectionsBB); + } else { + Builder.CreateCondBr(UBLBCheck, UBLBCheckBB, EndBB); + } + EmitBlock(EndBB); + llvm::Value *RealArgsFini[] = {Loc, GTid}; + EmitRuntimeCall(OPENMPRTL_FUNC(for_static_fini), RealArgsFini); + CGM.OpenMPSupport.setLastIterVar(PLast); + + if (CGM.OpenMPSupport.hasLastPrivate() || !CGM.OpenMPSupport.getNoWait()) + EmitOMPCancelBarrier(S.getLocEnd(), KMP_IDENT_BARRIER_IMPL_SECTIONS); + + // CodeGen for clauses (call end). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitPostOMPClause(*(*I), S); + } + + // CodeGen for clauses (closing steps). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitCloseOMPClause(*(*I), S); + + // CodeGen for clauses (task finalize). + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) + if (*I && isAllowedClauseForDirective(SKind, (*I)->getClauseKind())) + EmitFinalOMPClause(*(*I), S); + + EnsureInsertPoint(); + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); +} + +/// Generate an instructions for '#pragma omp sections' directive. +void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { + EmitOMPSectionsDirective(OMPD_sections, OMPD_sections, S); +} + +/// Generate an instructions for '#pragma omp section' directive. +void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) { + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); +} + +void CodeGenFunction::EmitInitOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_num_threads: + EmitInitOMPNumThreadsClause(cast(C), S); + break; + case OMPC_num_teams: + EmitInitOMPNumTeamsClause(cast(C), S); + break; + case OMPC_thread_limit: + EmitInitOMPThreadLimitClause(cast(C), S); + break; + case OMPC_proc_bind: + EmitInitOMPProcBindClause(cast(C), S); + break; + case OMPC_reduction: + EmitInitOMPReductionClause(cast(C), S); + break; + case OMPC_nowait: + EmitInitOMPNowaitClause(cast(C), S); + break; + case OMPC_ordered: + EmitInitOMPOrderedClause(cast(C), S); + break; + case OMPC_untied: + EmitInitOMPUntiedClause(cast(C), S); + break; + case OMPC_final: + EmitInitOMPFinalClause(cast(C), S); + break; + case OMPC_mergeable: + EmitInitOMPMergeableClause(cast(C), S); + break; + case OMPC_device: + case OMPC_default: + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_shared: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_map: + case OMPC_collapse: + case OMPC_if: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + break; + } +} + +void CodeGenFunction::EmitAfterInitOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_if: + EmitAfterInitOMPIfClause(cast(C), S); + break; + case OMPC_reduction: + case OMPC_nowait: + case OMPC_ordered: + case OMPC_untied: + case OMPC_final: + case OMPC_mergeable: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_num_threads: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_device: + case OMPC_copyin: + case OMPC_shared: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_map: + case OMPC_collapse: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + break; + } +} + +void CodeGenFunction::EmitPreOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_num_threads: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_device: + case OMPC_if: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_shared: + case OMPC_collapse: + case OMPC_nowait: + case OMPC_ordered: + case OMPC_copyprivate: + case OMPC_untied: + case OMPC_final: + case OMPC_mergeable: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + case OMPC_map: + break; + case OMPC_copyin: + EmitPreOMPCopyinClause(cast(C), S); + break; + case OMPC_private: + EmitPreOMPPrivateClause(cast(C), S); + break; + case OMPC_firstprivate: + EmitPreOMPFirstPrivateClause(cast(C), S); + break; + case OMPC_lastprivate: + EmitPreOMPLastPrivateClause(cast(C), S); + break; + case OMPC_reduction: + EmitPreOMPReductionClause(cast(C), S); + break; + case OMPC_schedule: + EmitPreOMPScheduleClause(cast(C), S); + break; + case OMPC_dist_schedule: + EmitPreOMPDistScheduleClause(cast(C), S); + break; + } +} + +void CodeGenFunction::EmitPostOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_num_threads: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_device: + case OMPC_if: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_shared: + case OMPC_collapse: + case OMPC_nowait: + case OMPC_ordered: + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_untied: + case OMPC_final: + case OMPC_mergeable: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_map: + break; + case OMPC_lastprivate: + EmitPostOMPLastPrivateClause(cast(C), S); + break; + case OMPC_reduction: + EmitPostOMPReductionClause(cast(C), S); + break; + } +} + +void CodeGenFunction::EmitCloseOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_num_threads: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_device: + case OMPC_if: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_shared: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_collapse: + case OMPC_nowait: + case OMPC_ordered: + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_untied: + case OMPC_final: + case OMPC_mergeable: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + case OMPC_map: + break; + case OMPC_lastprivate: + EmitCloseOMPLastPrivateClause(cast(C), S); + break; + case OMPC_reduction: + EmitCloseOMPReductionClause(cast(C), S); + break; + } +} + +void CodeGenFunction::EmitFinalOMPClause(const OMPClause &C, + const OMPExecutableDirective &S) { + switch (C.getClauseKind()) { + default: + llvm_unreachable("Unknown clause kind!"); + case OMPC_num_threads: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_device: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_shared: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_map: + case OMPC_collapse: + case OMPC_nowait: + case OMPC_ordered: + case OMPC_schedule: + case OMPC_dist_schedule: + case OMPC_untied: + case OMPC_final: + case OMPC_mergeable: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_update: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_safelen: + break; + case OMPC_if: + EmitFinalOMPIfClause(cast(C), S); + break; + case OMPC_reduction: + EmitFinalOMPReductionClause(cast(C), S); + break; + } +} + +void CodeGenFunction::EmitInitOMPNowaitClause(const OMPNowaitClause &C, + const OMPExecutableDirective &S) { + CGM.OpenMPSupport.setNoWait(true); +} + +void +CodeGenFunction::EmitInitOMPOrderedClause(const OMPOrderedClause &C, + const OMPExecutableDirective &S) { + CGM.OpenMPSupport.setOrdered(true); +} + +void CodeGenFunction::EmitInitOMPUntiedClause(const OMPUntiedClause &C, + const OMPExecutableDirective &S) { + CGM.OpenMPSupport.setUntied(true); +} + +void +CodeGenFunction::EmitInitOMPMergeableClause(const OMPMergeableClause &C, + const OMPExecutableDirective &S) { + CGM.OpenMPSupport.setMergeable(true); +} + +void CodeGenFunction::EmitInitOMPFinalClause(const OMPFinalClause &C, + const OMPExecutableDirective &S) { + llvm::Value *Flags = CGM.OpenMPSupport.getTaskFlags(); + llvm::BasicBlock *ThenBlock = createBasicBlock("task.final.then"); + llvm::BasicBlock *EndBlock = createBasicBlock("task.final.end"); + EmitBranchOnBoolExpr(C.getCondition(), ThenBlock, EndBlock); + EmitBlock(ThenBlock); + llvm::Value *Val = + Builder.CreateOr(Builder.CreateLoad(Flags, ".flags."), OMP_TASK_FINAL); + Builder.CreateStore(Val, Flags); + EmitBranch(EndBlock); + EmitBlock(EndBlock, true); +} + +void +CodeGenFunction::EmitInitOMPNumThreadsClause(const OMPNumThreadsClause &C, + const OMPExecutableDirective &S) { + // __kmpc_push_num_threads(&loc, global_tid, num_threads); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(C.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(C.getLocStart(), *this); + // num_threads = num_threads...; + llvm::Value *NumThreads = EmitScalarExpr(C.getNumThreads(), true); + llvm::Value *RealArgs[] = {Loc, GTid, NumThreads}; + EmitRuntimeCall(OPENMPRTL_FUNC(push_num_threads), RealArgs); +} + +void +CodeGenFunction::EmitInitOMPNumTeamsClause(const OMPNumTeamsClause &C, + const OMPExecutableDirective &S) { + // num_teams = num_teams...; + llvm::Value *NumTeams = EmitScalarExpr(C.getNumTeams(), true); + CGM.OpenMPSupport.setNumTeams(NumTeams); +} + +void +CodeGenFunction::EmitInitOMPThreadLimitClause(const OMPThreadLimitClause &C, + const OMPExecutableDirective &S) { + // thread_limit = thread_limit...; + llvm::Value *ThreadLimit = EmitScalarExpr(C.getThreadLimit(), true); + CGM.OpenMPSupport.setThreadLimit(ThreadLimit); +} + +void +CodeGenFunction::EmitInitOMPProcBindClause(const OMPProcBindClause &C, + const OMPExecutableDirective &S) { + // __kmpc_push_proc_bind(&loc, global_tid, proc_bind); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(C.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(C.getLocStart(), *this); + // proc_bind = proc_bind...; + llvm::Value *ProcBind = 0; + switch (C.getThreadAffinity()) { + case OMPC_PROC_BIND_master: + ProcBind = llvm::ConstantInt::get( + llvm::ProcBindTBuilder::get(CGM.getLLVMContext()), + KMP_PROC_BIND_MASTER); + break; + case OMPC_PROC_BIND_close: + ProcBind = llvm::ConstantInt::get( + llvm::ProcBindTBuilder::get(CGM.getLLVMContext()), KMP_PROC_BIND_CLOSE); + break; + case OMPC_PROC_BIND_spread: + ProcBind = llvm::ConstantInt::get( + llvm::ProcBindTBuilder::get(CGM.getLLVMContext()), + KMP_PROC_BIND_SPREAD); + break; + case OMPC_PROC_BIND_unknown: + case NUM_OPENMP_PROC_BIND_KINDS: + llvm_unreachable("Unknown thread affinity"); + } + llvm::Value *RealArgs[] = {Loc, GTid, ProcBind}; + EmitRuntimeCall(OPENMPRTL_FUNC(push_proc_bind), RealArgs); +} + +void +CodeGenFunction::EmitAfterInitOMPIfClause(const OMPIfClause &C, + const OMPExecutableDirective &S) { + if (isa(&S)) { + llvm::BasicBlock *ThenBlock = createBasicBlock("omp.if.then"); + llvm::BasicBlock *ElseBlock = createBasicBlock("omp.if.else"); + EmitBranchOnBoolExpr(C.getCondition(), ThenBlock, ElseBlock); + EmitBlock(ThenBlock); + CGM.OpenMPSupport.setIfDest(ElseBlock); + } else { + // if (Cond) { + llvm::BasicBlock *ThenBlock = createBasicBlock("omp.if.then"); + llvm::BasicBlock *ElseBlock = createBasicBlock("omp.if.else"); + llvm::BasicBlock *ContBlock = createBasicBlock("omp.if.end"); + EmitBranchOnBoolExpr(C.getCondition(), ThenBlock, ElseBlock); + EmitBlock(ElseBlock); + { + RunCleanupsScope ElseScope(*this); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EnsureInsertPoint(); + } + EmitBranch(ContBlock); + EmitBlock(ThenBlock); + CGM.OpenMPSupport.setIfDest(ContBlock); + } +} + +void CodeGenFunction::EmitFinalOMPIfClause(const OMPIfClause &C, + const OMPExecutableDirective &S) { + if (isa(&S)) { + llvm::BasicBlock *ContBlock = createBasicBlock("omp.if.end"); + EmitBranch(ContBlock); + EmitBlock(CGM.OpenMPSupport.takeIfDest()); + { + if (CGM.OpenMPSupport.getWaitDepsArgs()) { + EmitRuntimeCall(OPENMPRTL_FUNC(omp_wait_deps), + makeArrayRef(CGM.OpenMPSupport.getWaitDepsArgs(), 6)); + } + llvm::Value *PTask; + llvm::Value *TaskTVal; + llvm::Type *PrivateTy; + QualType PrivateQTy; + llvm::Value *Base; + CGM.OpenMPSupport.getPTask(PTask, TaskTVal, PrivateTy, PrivateQTy, Base); + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + llvm::Value *RealArgs[] = {Loc, GTid, TaskTVal}; + EmitRuntimeCall(OPENMPRTL_FUNC(omp_task_begin_if0), + makeArrayRef(RealArgs)); + llvm::Value *RealArgs1[] = { + GTid, Builder.CreatePointerCast(TaskTVal, VoidPtrTy)}; + EmitCallOrInvoke(PTask, makeArrayRef(RealArgs1)); + EmitRuntimeCall(OPENMPRTL_FUNC(omp_task_complete_if0), + makeArrayRef(RealArgs)); + } + EmitBranch(ContBlock); + EmitBlock(ContBlock, true); + } else { + llvm::BasicBlock *ContBlock = CGM.OpenMPSupport.takeIfDest(); + EmitBranch(ContBlock); + EmitBlock(ContBlock, true); + } +} + +void +CodeGenFunction::EmitPreOMPScheduleClause(const OMPScheduleClause &C, + const OMPExecutableDirective &S) { + int Schedule = KMP_SCH_DEFAULT; + bool Ordered = CGM.OpenMPSupport.getOrdered(); + bool Merge = CGM.OpenMPSupport.getMergeable(); + int Offset = 0; + if (Ordered && Merge) + Offset = SCH_ORD; + else if (!Ordered && !Merge) + Offset = SCH_NM; + else if (Ordered && !Merge) + Offset = SCH_NM_ORD; + const Expr *ChunkSize = C.getChunkSize(); + + switch (C.getScheduleKind()) { + case OMPC_SCHEDULE_static: + Schedule = ChunkSize ? KMP_SCH_STATIC_CHUNKED : KMP_SCH_STATIC; + break; + case OMPC_SCHEDULE_dynamic: + Schedule = KMP_SCH_DYNAMIC_CHUNKED; + break; + case OMPC_SCHEDULE_guided: + Schedule = KMP_SCH_GUIDED_CHUNKED; + break; + case OMPC_SCHEDULE_auto: + Schedule = KMP_SCH_AUTO; + break; + case OMPC_SCHEDULE_runtime: + Schedule = KMP_SCH_RUNTIME; + break; + case OMPC_SCHEDULE_unknown: + case NUM_OPENMP_SCHEDULE_KINDS: + llvm_unreachable("Unknown schedule kind."); + } + Schedule += Offset; + CGM.OpenMPSupport.setScheduleChunkSize(Schedule, ChunkSize); +} + +void +CodeGenFunction::EmitPreOMPDistScheduleClause(const OMPDistScheduleClause &C, + const OMPExecutableDirective &S) { + int Schedule = KMP_SCH_DEFAULT; + const Expr *ChunkSize = C.getDistChunkSize(); + + switch (C.getDistScheduleKind()) { + case OMPC_DIST_SCHEDULE_static: + Schedule = ChunkSize ? KMP_SCH_DISTRIBUTE_STATIC_CHUNKED + : KMP_SCH_DISTRIBUTE_STATIC; + break; + case OMPC_DIST_SCHEDULE_unknown: + case NUM_OPENMP_DIST_SCHEDULE_KINDS: + llvm_unreachable("Unknown dist_schedule kind."); + } + CGM.OpenMPSupport.setScheduleChunkSize(Schedule, ChunkSize); +} + +void CodeGenFunction::EmitUniversalStore(LValue Dst, llvm::Value *Src, + QualType ExprTy) { + switch (getEvaluationKind(ExprTy)) { + case TEK_Complex: { + RValue Val = convertTempToRValue(Src, ExprTy, SourceLocation()); + EmitStoreOfComplex(Val.getComplexVal(), Dst, false); + break; + } + case TEK_Aggregate: + EmitAggregateAssign(Dst.getAddress(), Src, ExprTy); + break; + case TEK_Scalar: + RValue Val = convertTempToRValue(Src, ExprTy, SourceLocation()); + EmitStoreThroughLValue(Val, Dst, false); + break; + } +} + +void CodeGenFunction::EmitUniversalStore(llvm::Value *Dst, llvm::Value *Src, + QualType ExprTy) { + EmitUniversalStore(MakeNaturalAlignAddrLValue(Dst, ExprTy), Src, ExprTy); +} + +// This helper is used for emitting copy-assignments for copyin clause and +// for copy_function generated for copyprivate clause. +void +CodeGenFunction::EmitCopyAssignment(ArrayRef::iterator I, + ArrayRef::iterator AssignIter, + ArrayRef::iterator VarIter1, + ArrayRef::iterator VarIter2, + llvm::Value *Dst, llvm::Value *Src) { + // This is called at each iteration of the loop through the clauses. + { + // Get element type. + QualType QTy = (*I)->getType(); + const Type *MainTy = QTy.getTypePtr(); + // const Type *Ty = MainTy->getArrayElementTypeNoTypeQual(); + // const Type *PrevTy = MainTy; + // while (Ty != 0) { + // PrevTy = Ty; + // Ty = Ty->getArrayElementTypeNoTypeQual(); + //} + // Ty = PrevTy; + + if (!*AssignIter) { + // For trivial assignment operator copy by memcpy. + llvm::Value *VDAddr = Src; + EmitUniversalStore(Builder.CreatePointerCast(Dst, VDAddr->getType()), + VDAddr, QTy); + } else { + RunCleanupsScope InitBlock(*this); + // Copy elements one by one. + if (const ArrayType *ArrayTy = MainTy->getAsArrayTypeUnsafe()) { + // Copy array. + QualType ElementTy; + llvm::Value *SharedVar = Dst; + llvm::Value *NumElements = + emitArrayLength(ArrayTy, ElementTy, SharedVar); + llvm::Value *ArrayEnd = Builder.CreateGEP(SharedVar, NumElements); + llvm::Value *MasterArray = Src; + unsigned AddrSpace = MasterArray->getType()->getPointerAddressSpace(); + llvm::Type *BaseType = ConvertType(ElementTy)->getPointerTo(AddrSpace); + llvm::Value *MasterArrayBegin = Builder.CreatePointerCast( + MasterArray, BaseType, "master.array.begin"); + llvm::Value *MasterArrayEnd = + Builder.CreateGEP(MasterArrayBegin, NumElements); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body"); + llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done"); + llvm::Value *IsEmpty = + Builder.CreateICmpEQ(SharedVar, ArrayEnd, "omp.arraycpy.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + llvm::PHINode *ElementPast = Builder.CreatePHI( + SharedVar->getType(), 2, "omp.arraycpy.elementPast"); + ElementPast->addIncoming(ArrayEnd, EntryBB); + llvm::PHINode *MasterElementPast = Builder.CreatePHI( + MasterArrayBegin->getType(), 2, "omp.arraycpy.masterElementPast"); + MasterElementPast->addIncoming(MasterArrayEnd, EntryBB); + + // Shift the address back by one element. + llvm::Value *NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *Element = + Builder.CreateGEP(ElementPast, NegativeOne, "omp.arraycpy.element"); + llvm::Value *MasterElement = Builder.CreateGEP( + MasterElementPast, NegativeOne, "omp.arraycpy.master.element"); + + const VarDecl *PseudoVar1 = + cast(cast(*VarIter1)->getDecl()); + const VarDecl *PseudoVar2 = + cast(cast(*VarIter2)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar1, Element); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar2, MasterElement); + EmitIgnoredExpr(*AssignIter); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar1); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar2); + + // Check whether we've reached the end. + llvm::Value *Done = + Builder.CreateICmpEQ(Element, SharedVar, "omp.arraycpy.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + ElementPast->addIncoming(Element, Builder.GetInsertBlock()); + MasterElementPast->addIncoming(MasterElement, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } else { + // Copy single object. + const VarDecl *PseudoVar1 = + cast(cast(*VarIter1)->getDecl()); + const VarDecl *PseudoVar2 = + cast(cast(*VarIter2)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar1, Dst); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar2, Src); + EmitIgnoredExpr(*AssignIter); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar1); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar2); + } + } + } +} + +void CodeGenFunction::EmitPreOMPCopyinClause(const OMPCopyinClause &C, + const OMPExecutableDirective &S) { + // copy_data(var1); + // copy_data(var2); + // ... + // __kmpc_barrier(&loc, global_tid); + ArrayRef::iterator AssignIter = C.getAssignments().begin(); + ArrayRef::iterator VarIter1 = C.getPseudoVars1().begin(); + ArrayRef::iterator VarIter2 = C.getPseudoVars2().begin(); + + for (OMPCopyinClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++AssignIter, ++VarIter1, ++VarIter2) { + const VarDecl *VD = cast(cast(*I)->getDecl()); + EmitCopyAssignment(I, AssignIter, VarIter1, VarIter2, + CGM.CreateOpenMPThreadPrivateCached( + VD, (*I)->getExprLoc(), *this, true), + VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) + : CGM.GetAddrOfGlobal(VD)); + } + SetFirstprivateInsertPt(*this); +} + +/// \brief Determine whether the given initializer is trivial in the sense +/// that it requires no code to be generated. +static bool isTrivialInitializer(const Expr *Init) { + if (!Init) + return true; + + if (const CXXConstructExpr *Construct = dyn_cast(Init)) + if (CXXConstructorDecl *Constructor = Construct->getConstructor()) + if (Constructor->isTrivial() && Constructor->isDefaultConstructor() && + !Construct->requiresZeroInitialization()) + return true; + + return false; +} + +void CodeGenFunction::EmitPreOMPPrivateClause(const OMPPrivateClause &C, + const OMPExecutableDirective &S) { + // Type1 tmp1; + // anon.field1 = &tmp1; + // Type2 tmp2; + // anon.field2 = &tmp2; + // ... + // + ArrayRef::iterator InitIter = C.getDefaultInits().begin(); + for (OMPPrivateClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++InitIter) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + if (CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) + continue; + // if (VD->hasLocalStorage() && + // (!CapturedStmtInfo || + // !CapturedStmtInfo->lookup(VD))) { + // LocalDeclMap[VD] = CreateMemTemp(VD->getType(), CGM.getMangledName(VD)); + //} + QualType QTy = (*I)->getType(); + const Type *MainTy = QTy.getTypePtr(); + // const Type *Ty = MainTy->getArrayElementTypeNoTypeQual(); + // const Type *PrevTy = MainTy; + // while (Ty != 0) { + // PrevTy = Ty; + // Ty = Ty->getArrayElementTypeNoTypeQual(); + //} + // Ty = PrevTy; + llvm::Value *Private; + llvm::Value *PTask; + llvm::Value *TaskTVal; + llvm::Type *PrivateTy; + QualType PrivateQTy; + llvm::Value *Base; + CGM.OpenMPSupport.getPTask(PTask, TaskTVal, PrivateTy, PrivateQTy, Base); + if (PTask) { + Base = Builder.CreatePointerCast(Base, PrivateTy->getPointerTo()); + Private = EmitLValueForField(MakeNaturalAlignAddrLValue(Base, PrivateQTy), + CGM.OpenMPSupport.getTaskFields()[VD]) + .getAddress(); + } else { + LocalVarsDeclGuard Grd(*this, true); + AutoVarEmission Emission = EmitAutoVarAlloca(*VD); + Private = Emission.getAllocatedAddress(); + EmitAutoVarCleanups(Emission); + } + // CodeGen for classes with the default constructor. + if (((!PTask || CurFn != PTask) && !isTrivialInitializer(*InitIter)) || + (MainTy->isVariablyModifiedType() && !MainTy->isPointerType())) { + RunCleanupsScope InitBlock(*this); + if (const ArrayType *ArrayTy = MainTy->getAsArrayTypeUnsafe()) { + // Create array. + QualType ElementTy; + llvm::Value *ArrayBeg = Private; + llvm::Value *NumElements = + emitArrayLength(ArrayTy, ElementTy, ArrayBeg); + llvm::Value *ArrayEnd = + Builder.CreateGEP(ArrayBeg, NumElements, "omp.arrayctor.end"); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *BodyBB = createBasicBlock("omp.arrayctor.body"); + llvm::BasicBlock *DoneBB = createBasicBlock("omp.arrayctor.done"); + llvm::Value *IsEmpty = + Builder.CreateICmpEQ(ArrayBeg, ArrayEnd, "omp.arrayctor.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + llvm::PHINode *ElementPast = Builder.CreatePHI( + ArrayBeg->getType(), 2, "omp.arrayctor.elementPast"); + ElementPast->addIncoming(ArrayEnd, EntryBB); + + // Shift the address back by one element. + llvm::Value *NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *Element = Builder.CreateGEP(ElementPast, NegativeOne, + "omp.arrayctor.element"); + EmitAnyExprToMem(*InitIter, Element, + (*InitIter)->getType().getQualifiers(), false); + //// Check whether we've reached the end. + llvm::Value *Done = + Builder.CreateICmpEQ(Element, ArrayBeg, "omp.arrayctor.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + ElementPast->addIncoming(Element, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } else { + EmitAnyExprToMem(*InitIter, Private, + (*InitIter)->getType().getQualifiers(), false); + } + } + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } +} + +void +CodeGenFunction::EmitPreOMPFirstPrivateClause(const OMPFirstPrivateClause &C, + const OMPExecutableDirective &S) { + // Type1 tmp1(var1); + // anon.field1 = &tmp1; + // Type2 tmp2(var2); + // anon.field2 = &tmp2; + // ... + // + llvm::Value *PTask; + llvm::Value *TaskTVal; + llvm::Type *PrivateTy; + QualType PrivateQTy; + llvm::Value *Base; + CGM.OpenMPSupport.getPTask(PTask, TaskTVal, PrivateTy, PrivateQTy, Base); + + ArrayRef::iterator InitIter = C.getInits().begin(); + ArrayRef::iterator VarIter = C.getPseudoVars().begin(); + for (OMPFirstPrivateClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++InitIter, ++VarIter) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + if (CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) + continue; + // if (VD->hasLocalStorage() && + // (!CapturedStmtInfo || + // !CapturedStmtInfo->lookup(VD))) { + // LocalDeclMap[VD] = CreateMemTemp(VD->getType(), CGM.getMangledName(VD)); + //} + QualType QTy = (*I)->getType(); + const Type *MainTy = QTy.getTypePtr(); + // const Type *Ty = MainTy->getArrayElementTypeNoTypeQual(); + // const Type *PrevTy = MainTy; + // while (Ty != 0) { + // PrevTy = Ty; + // Ty = Ty->getArrayElementTypeNoTypeQual(); + //} + llvm::Value *Private = 0; + if (!CGM.OpenMPSupport.isNewTask() && !PTask) { + if (llvm::AllocaInst *Val = dyn_cast_or_null( + CGM.OpenMPSupport.getPrevOpenMPPrivateVar(VD))) { + Private = Val; + CGM.OpenMPSupport.delPrevOpenMPPrivateVar(VD); + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + continue; + } + } + if (PTask) { + Base = Builder.CreatePointerCast(Base, PrivateTy->getPointerTo()); + Private = EmitLValueForField(MakeNaturalAlignAddrLValue(Base, PrivateQTy), + CGM.OpenMPSupport.getTaskFields()[VD]) + .getAddress(); + } else { + LocalVarsDeclGuard Grd(*this, true); + AutoVarEmission Emission = EmitAutoVarAlloca(*VD); + Private = Emission.getAllocatedAddress(); + EmitAutoVarCleanups(Emission); + } + // CodeGen for classes with the copy constructor. + RunCleanupsScope InitBlock(*this); + if (((!PTask || CurFn != PTask) && !isTrivialInitializer(*InitIter)) || + (MainTy->isVariablyModifiedType() && !MainTy->isPointerType())) { + if (const ArrayType *ArrayTy = MainTy->getAsArrayTypeUnsafe()) { + // Create array. + QualType ElementTy; + llvm::Value *ArrayBeg = Private; + llvm::Value *NumElements = + emitArrayLength(ArrayTy, ElementTy, ArrayBeg); + llvm::Value *ArrayEnd = Builder.CreateGEP(ArrayBeg, NumElements); + llvm::Value *MasterArray = EmitLValue(*I).getAddress(); + unsigned AddrSpace = MasterArray->getType()->getPointerAddressSpace(); + llvm::Type *BaseType = ConvertType(ElementTy)->getPointerTo(AddrSpace); + llvm::Value *MasterArrayBegin = Builder.CreatePointerCast( + MasterArray, BaseType, "master.array.begin"); + llvm::Value *MasterArrayEnd = + Builder.CreateGEP(MasterArrayBegin, NumElements); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body"); + llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done"); + llvm::Value *IsEmpty = + Builder.CreateICmpEQ(ArrayBeg, ArrayEnd, "omp.arraycpy.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + llvm::PHINode *MasterElementPast = Builder.CreatePHI( + MasterArrayBegin->getType(), 2, "omp.arraycpy.masterElementPast"); + MasterElementPast->addIncoming(MasterArrayEnd, EntryBB); + llvm::PHINode *ElementPast = Builder.CreatePHI( + ArrayBeg->getType(), 2, "omp.arraycpy.elementPast"); + ElementPast->addIncoming(ArrayEnd, EntryBB); + + // Shift the address back by one element. + llvm::Value *NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *Element = + Builder.CreateGEP(ElementPast, NegativeOne, "omp.arraycpy.element"); + llvm::Value *MasterElement = Builder.CreateGEP( + MasterElementPast, NegativeOne, "omp.arraycpy.master.element"); + + const VarDecl *PseudoVar = + cast(cast(*VarIter)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar, MasterElement); + EmitAnyExprToMem(*InitIter, Element, + (*InitIter)->getType().getQualifiers(), false); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar); + + // Check whether we've reached the end. + llvm::Value *Done = + Builder.CreateICmpEQ(Element, ArrayBeg, "omp.arraycpy.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + ElementPast->addIncoming(Element, Builder.GetInsertBlock()); + MasterElementPast->addIncoming(MasterElement, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } else { + // Create single object. + llvm::Value *RealAddr = EmitLValue(*I).getAddress(); + const VarDecl *PseudoVar = + cast(cast(*VarIter)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar, RealAddr); + EmitAnyExprToMem(*InitIter, Private, + (*InitIter)->getType().getQualifiers(), false); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar); + } + } else if (!PTask || CurFn != PTask) { + EmitAnyExprToMem(*I, Private, QTy.getQualifiers(), false); + } + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } + // Disable marking for tasks. + if (!PTask || PTask == CurFn) + SetFirstprivateInsertPt(*this); +} + +void +CodeGenFunction::EmitPreOMPLastPrivateClause(const OMPLastPrivateClause &C, + const OMPExecutableDirective &S) { + // Type1 tmp1; + // Type2 tmp2; + // ... + // + CGM.OpenMPSupport.setHasLastPrivate(true); + ArrayRef::iterator InitIter = C.getDefaultInits().begin(); + for (OMPLastPrivateClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++InitIter) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + bool FirstPrivateFound = false; + for (ArrayRef::iterator FI = S.clauses().begin(), + FE = S.clauses().end(); + FI != FE; ++FI) { + if (const OMPFirstPrivateClause *FC = + dyn_cast(*FI)) { + for (OMPFirstPrivateClause::varlist_const_iterator + VI = FC->varlist_begin(), + VE = FC->varlist_end(); + VI != VE; ++VI) { + if (VD == cast(*VI)->getDecl()) { + FirstPrivateFound = true; + break; + } + } + } + if (FirstPrivateFound) + break; + } + // Lastprivate init is processed by firstprivate clause. + if (FirstPrivateFound || CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) + continue; + // if (VD->hasLocalStorage() && + // (!CapturedStmtInfo || + // !CapturedStmtInfo->lookup(VD))) { + // LocalDeclMap[VD] = CreateMemTemp(VD->getType(), CGM.getMangledName(VD)); + //} + QualType QTy = (*I)->getType(); + const Type *MainTy = QTy.getTypePtr(); + // const Type *Ty = MainTy->getArrayElementTypeNoTypeQual(); + // const Type *PrevTy = MainTy; + // while (Ty != 0) { + // PrevTy = Ty; + // Ty = Ty->getArrayElementTypeNoTypeQual(); + //} + // Ty = PrevTy; + llvm::Value *Private = 0; + { + LocalVarsDeclGuard Grd(*this, true); + AutoVarEmission Emission = EmitAutoVarAlloca(*VD); + Private = Emission.getAllocatedAddress(); + EmitAutoVarCleanups(Emission); + } + // CodeGen for classes with the default constructor. + if (!isTrivialInitializer(*InitIter) || + (MainTy->isVariablyModifiedType() && !MainTy->isPointerType())) { + RunCleanupsScope InitBlock(*this); + if (const ArrayType *ArrayTy = MainTy->getAsArrayTypeUnsafe()) { + // Create array. + QualType ElementTy; + llvm::Value *ArrayBeg = Private; + llvm::Value *NumElements = + emitArrayLength(ArrayTy, ElementTy, ArrayBeg); + llvm::Value *ArrayEnd = + Builder.CreateGEP(ArrayBeg, NumElements, "omp.arrayctor.end"); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *BodyBB = createBasicBlock("omp.arrayctor.body"); + llvm::BasicBlock *DoneBB = createBasicBlock("omp.arrayctor.done"); + llvm::Value *IsEmpty = + Builder.CreateICmpEQ(ArrayBeg, ArrayEnd, "omp.arrayctor.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + llvm::PHINode *ElementPast = Builder.CreatePHI( + ArrayBeg->getType(), 2, "omp.arrayctor.elementPast"); + ElementPast->addIncoming(ArrayEnd, EntryBB); + + // Shift the address back by one element. + llvm::Value *NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *Element = Builder.CreateGEP(ElementPast, NegativeOne, + "omp.arrayctor.element"); + EmitAnyExprToMem(*InitIter, Element, + (*InitIter)->getType().getQualifiers(), false); + //// Check whether we've reached the end. + llvm::Value *Done = + Builder.CreateICmpEQ(Element, ArrayBeg, "omp.arrayctor.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + ElementPast->addIncoming(Element, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } else { + EmitAnyExprToMem(*InitIter, Private, + (*InitIter)->getType().getQualifiers(), false); + } + } + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } +} + +void +CodeGenFunction::EmitPostOMPLastPrivateClause(const OMPLastPrivateClause &C, + const OMPExecutableDirective &S) { + // ~Type1(tmp1); + // ~Type2(tmp2); + // ... + // + + llvm::BasicBlock *LPBB, *LPEndBB; + llvm::Instruction *LPIP; + CGM.OpenMPSupport.getLastprivateIP(LPBB, LPIP, LPEndBB); + if (!LPBB && !LPIP && !LPEndBB) { + LPBB = createBasicBlock("omp.if.liter.start", CurFn); + LPEndBB = createBasicBlock("omp.if.liter.end", CurFn); + llvm::Value *LiterVal = + Builder.CreateLoad(CGM.OpenMPSupport.getLastIterVar(), "liter"); + Builder.CreateCondBr(Builder.CreateIsNull(LiterVal), LPEndBB, LPBB); + LPIP = LPBB->end(); + if (isLoopDirective(&S)) { + Builder.SetInsertPoint(LPBB); + EmitStmt(getFinalFromLoopDirective(&S)); + EnsureInsertPoint(); + LPBB = Builder.GetInsertBlock(); + LPIP = Builder.GetInsertPoint(); + } + Builder.SetInsertPoint(LPEndBB); + if (!CGM.OpenMPSupport.getNoWait()) + EmitOMPCancelBarrier(S.getLocEnd(), KMP_IDENT_BARRIER_IMPL); + } + ArrayRef::iterator AssignIter = C.getAssignments().begin(); + ArrayRef::iterator VarIter1 = C.getPseudoVars1().begin(); + ArrayRef::iterator VarIter2 = C.getPseudoVars2().begin(); + for (OMPLastPrivateClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++AssignIter, ++VarIter1, ++VarIter2) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + llvm::Value *Private = CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD); + if (!Private) + continue; + QualType QTy = (*I)->getType(); + const Type *MainTy = QTy.getTypePtr(); + const Type *Ty = MainTy->getArrayElementTypeNoTypeQual(); + const Type *PrevTy = MainTy; + while (Ty != 0) { + PrevTy = Ty; + Ty = Ty->getArrayElementTypeNoTypeQual(); + } + Ty = PrevTy; + CGM.OpenMPSupport.delOpenMPPrivateVar(VD); + CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); + Builder.SetInsertPoint(LPBB, LPIP); + // CodeGen for classes with the copy assignment operator. + if (!*AssignIter) { + // For trivial assignment operator copy by memcpy. + // EmitAnyExprToMem(*I, Private, QTy.getQualifiers(), false); + // EmitAggregateAssign(EmitLValue(*I).getAddress(), Private, + // VD->getType()); + EmitUniversalStore(EmitLValue(*I), Private, QTy); + } else { + RunCleanupsScope InitBlock(*this); + // Copy elements one by one. + if (const ArrayType *ArrayTy = MainTy->getAsArrayTypeUnsafe()) { + // Copy array. + QualType ElementTy; + llvm::Value *SharedVar = EmitLValue(*I).getAddress(); + llvm::Value *NumElements = + emitArrayLength(ArrayTy, ElementTy, SharedVar); + llvm::Value *ArrayEnd = Builder.CreateGEP(SharedVar, NumElements); + llvm::Value *MasterArray = Private; + unsigned AddrSpace = MasterArray->getType()->getPointerAddressSpace(); + llvm::Type *BaseType = ConvertType(ElementTy)->getPointerTo(AddrSpace); + llvm::Value *MasterArrayBegin = Builder.CreatePointerCast( + MasterArray, BaseType, "master.array.begin"); + llvm::Value *MasterArrayEnd = + Builder.CreateGEP(MasterArrayBegin, NumElements); + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body"); + llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done"); + llvm::Value *IsEmpty = + Builder.CreateICmpEQ(SharedVar, ArrayEnd, "omp.arraycpy.isempty"); + Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + EmitBlock(BodyBB); + llvm::PHINode *ElementPast = Builder.CreatePHI( + SharedVar->getType(), 2, "omp.arraycpy.elementPast"); + ElementPast->addIncoming(ArrayEnd, EntryBB); + llvm::PHINode *MasterElementPast = Builder.CreatePHI( + MasterArrayBegin->getType(), 2, "omp.arraycpy.masterElementPast"); + MasterElementPast->addIncoming(MasterArrayEnd, EntryBB); + + // Shift the address back by one element. + llvm::Value *NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *Element = + Builder.CreateGEP(ElementPast, NegativeOne, "omp.arraycpy.element"); + llvm::Value *MasterElement = Builder.CreateGEP( + MasterElementPast, NegativeOne, "omp.arraycpy.master.element"); + + const VarDecl *PseudoVar1 = + cast(cast(*VarIter1)->getDecl()); + const VarDecl *PseudoVar2 = + cast(cast(*VarIter2)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar1, MasterElement); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar2, Element); + EmitIgnoredExpr(*AssignIter); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar1); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar2); + + // Check whether we've reached the end. + llvm::Value *Done = + Builder.CreateICmpEQ(Element, SharedVar, "omp.arraycpy.done"); + Builder.CreateCondBr(Done, DoneBB, BodyBB); + ElementPast->addIncoming(Element, Builder.GetInsertBlock()); + MasterElementPast->addIncoming(MasterElement, Builder.GetInsertBlock()); + + // Done. + EmitBlock(DoneBB, true); + } else { + // Copy single object. + const VarDecl *PseudoVar1 = + cast(cast(*VarIter1)->getDecl()); + const VarDecl *PseudoVar2 = + cast(cast(*VarIter2)->getDecl()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar1, + EmitLValue(*I).getAddress()); + CGM.OpenMPSupport.addOpenMPPrivateVar(PseudoVar2, Private); + EmitIgnoredExpr(*AssignIter); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar1); + CGM.OpenMPSupport.delOpenMPPrivateVar(PseudoVar2); + } + } + LPBB = Builder.GetInsertBlock(); + LPIP = Builder.GetInsertPoint(); + Builder.restoreIP(SavedIP); + } + CGM.OpenMPSupport.setLastprivateIP(LPBB, LPIP, LPEndBB); +} + +void CodeGenFunction::EmitCloseOMPLastPrivateClause( + const OMPLastPrivateClause &C, const OMPExecutableDirective &S) { + // ~Type1(tmp1); + // ~Type2(tmp2); + // ... + // + + llvm::BasicBlock *LPBB, *LPEndBB; + llvm::Instruction *LPIP; + CGM.OpenMPSupport.getLastprivateIP(LPBB, LPIP, LPEndBB); + if (LPBB || LPIP || LPEndBB) { + CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); + Builder.SetInsertPoint(LPBB, LPIP); + EmitBranch(LPEndBB); + Builder.restoreIP(SavedIP); + CGM.OpenMPSupport.setLastprivateIP(0, 0, 0); + } +} + +void +CodeGenFunction::EmitInitOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S) { + assert(!isa(S)); // Not yet supported + // Type1 tmp1(var1); + // anon.field1 = &tmp1; + // Type2 tmp2(var2); + // anon.field2 = &tmp2; + // ... + // + // CodeGen for reduction clause. + CodeGenFunction &CGF = CGM.OpenMPSupport.getCGFForReductionFunction(); + llvm::Function *ReductionFunc = CGF.CurFn; + if (!ReductionFunc) { + FunctionArgList Args; + ImplicitParamDecl Arg1(0, SourceLocation(), 0, getContext().VoidPtrTy); + ImplicitParamDecl Arg2(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Arg1); + Args.push_back(&Arg2); + const CGFunctionInfo &FI = CGF.getTypes().arrangeFunctionDeclaration( + getContext().VoidTy, Args, FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = CGF.getTypes().GetFunctionType(FI); + llvm::Function *Fn = llvm::Function::Create( + FTy, llvm::GlobalValue::InternalLinkage, + StringRef(".omp_reduction_op."), &CGM.getModule()); + CGM.SetInternalFunctionAttributes(CurFuncDecl, Fn, FI); + CGF.StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, Args, + SourceLocation()); + ReductionFunc = CGF.CurFn; + } + + for (OMPReductionClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + QualType QTy = (*I)->getType(); + // if (!QTy->isScalarType()) + // llvm_unreachable("Reduction variables with aggregate" + // "types are not supported yet!"); + llvm::Type *PtrType = ConvertType(getContext().getPointerType(QTy)); + CGM.OpenMPSupport.registerReductionVar(VD, PtrType); + } +} + +void +CodeGenFunction::EmitPreOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S) { + assert(!isa(S)); // Not yet supported + // Type1 tmp1(var1); + // anon.field1 = &tmp1; + // Type2 tmp2(var2); + // anon.field2 = &tmp2; + // ... + // + llvm::Value *ReductionRecVar = CGM.OpenMPSupport.getReductionRecVar(*this); + ArrayRef::iterator InitIter = C.getDefaultInits().begin(); + for (OMPReductionClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++InitIter) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + // if (VD->hasLocalStorage() && + // (!CapturedStmtInfo || + // !CapturedStmtInfo->lookup(VD))) { + // LocalDeclMap[VD] = CreateMemTemp(VD->getType(), CGM.getMangledName(VD)); + //} + QualType QTy = (*I)->getType(); + llvm::AllocaInst *Private = 0; + { + LocalVarsDeclGuard Grd(*this, true); + AutoVarEmission Emission = EmitAutoVarAlloca(*VD); + Private = cast(Emission.getAllocatedAddress()); + EmitAutoVarCleanups(Emission); + } + // CreateMemTemp(QTy, CGM.getMangledName(VD) + ".reduction."); + + // CodeGen for classes with the constructor. + // const Type *Ty = QTy.getTypePtr(); + if (!isTrivialInitializer(*InitIter)) { + RunCleanupsScope InitBlock(*this); + const FunctionDecl *FD = 0; + if (const DeclRefExpr *DRE = dyn_cast_or_null(*InitIter)) { + if (const FunctionDecl *D = + dyn_cast_or_null(DRE->getDecl())) + FD = D; + } + if (FD && isa(FD->getDeclContext())) { + llvm::Value *RegularAddr = EmitLValue(*I).getAddress(); + llvm::Value *Args[] = {Private, RegularAddr}; + EmitCallOrInvoke(CGM.GetAddrOfGlobal(FD), Args); + SetFirstprivateInsertPt(*this); + } else { + EmitAnyExprToMem(*InitIter, Private, + (*InitIter)->getType().getQualifiers(), false); + } + } else if (*InitIter) { + switch (C.getOperator()) { + case OMPC_REDUCTION_or: + case OMPC_REDUCTION_bitxor: + case OMPC_REDUCTION_bitor: + case OMPC_REDUCTION_sub: + case OMPC_REDUCTION_add: { + llvm::Value *Zero = + llvm::Constant::getNullValue(Private->getAllocatedType()); + InitTempAlloca(Private, Zero); + break; + } + case OMPC_REDUCTION_and: + case OMPC_REDUCTION_mult: + case OMPC_REDUCTION_bitand: { + llvm::Value *AllOnes = + llvm::Constant::getAllOnesValue(Private->getAllocatedType()); + InitTempAlloca(Private, AllOnes); + break; + } + case OMPC_REDUCTION_min: + case OMPC_REDUCTION_max: + case OMPC_REDUCTION_custom: + llvm_unreachable("Operator kind not allowed."); + case OMPC_REDUCTION_unknown: + case NUM_OPENMP_REDUCTION_OPERATORS: + llvm_unreachable("Unknown operator kind."); + } + } else { + llvm::Type *Ty = ConvertTypeForMem(QTy); + switch (C.getOperator()) { + case OMPC_REDUCTION_or: + case OMPC_REDUCTION_bitxor: + case OMPC_REDUCTION_bitor: + case OMPC_REDUCTION_sub: + case OMPC_REDUCTION_add: { + if (QTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getNullValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isRealFloatingType()) { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal = llvm::APFloat::getZero(FS); + llvm::Value *Init = + llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isPointerType()) { + InitTempAlloca(Private, llvm::ConstantPointerNull::get( + cast(Ty))); + } else if (QTy->isAnyComplexType()) { + const ComplexType *CmplxTy = QTy->castAs(); + QualType ElTy = CmplxTy->getElementType(); + Ty = ConvertTypeForMem(ElTy); + llvm::Value *Init; + if (ElTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getNullValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + Init = llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + } else { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal = llvm::APFloat::getZero(FS); + Init = llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + } + ComplexPairTy Value(Init, Init); + LValue Dst = MakeNaturalAlignAddrLValue(Private, QTy); + EmitStoreOfComplex(Value, Dst, true); + } + break; + } + case OMPC_REDUCTION_and: + case OMPC_REDUCTION_mult: { + if (QTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal(CGM.getDataLayout().getTypeStoreSizeInBits(Ty), + 1); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isRealFloatingType()) { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal(FS, 1); + llvm::Value *Init = + llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isPointerType()) { + llvm::APInt InitVal(CGM.getDataLayout().getTypeStoreSizeInBits(Ty), + 1); + llvm::Constant *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + Init = llvm::ConstantExpr::getCast(llvm::Instruction::IntToPtr, Init, + Ty); + InitTempAlloca(Private, Init); + } else if (QTy->isAnyComplexType()) { + const ComplexType *CmplxTy = QTy->castAs(); + QualType ElTy = CmplxTy->getElementType(); + Ty = ConvertTypeForMem(ElTy); + llvm::Value *Init; + if (ElTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal(CGM.getDataLayout().getTypeStoreSizeInBits(Ty), + 1); + Init = llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + } else { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal(FS, 1); + Init = llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + } + ComplexPairTy Value(Init, Init); + LValue Dst = MakeNaturalAlignAddrLValue(Private, QTy); + EmitStoreOfComplex(Value, Dst, true); + } + break; + } + case OMPC_REDUCTION_bitand: { + if (QTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getAllOnesValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isRealFloatingType()) { + llvm::APFloat InitVal = llvm::APFloat::getAllOnesValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isPointerType()) { + llvm::Value *Init = llvm::Constant::getAllOnesValue(Ty); + InitTempAlloca(Private, Init); + } else if (QTy->isAnyComplexType()) { + const ComplexType *CmplxTy = QTy->castAs(); + QualType ElTy = CmplxTy->getElementType(); + Ty = ConvertTypeForMem(ElTy); + llvm::Value *Init; + if (ElTy->isIntegralOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getAllOnesValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + Init = llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + } else { + llvm::APFloat InitVal = llvm::APFloat::getAllOnesValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + Init = llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + } + ComplexPairTy Value(Init, Init); + LValue Dst = MakeNaturalAlignAddrLValue(Private, QTy); + EmitStoreOfComplex(Value, Dst, true); + } + break; + } + case OMPC_REDUCTION_min: { + if (QTy->isSignedIntegerOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getSignedMaxValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isUnsignedIntegerOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getMaxValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isRealFloatingType()) { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal = llvm::APFloat::getLargest(FS); + llvm::Value *Init = + llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isPointerType()) { + llvm::APInt InitVal = llvm::APInt::getMaxValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Constant *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + Init = llvm::ConstantExpr::getCast(llvm::Instruction::IntToPtr, Init, + Ty); + InitTempAlloca(Private, Init); + } + break; + } + case OMPC_REDUCTION_max: { + if (QTy->isSignedIntegerOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getSignedMinValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isUnsignedIntegerOrEnumerationType()) { + llvm::APInt InitVal = llvm::APInt::getMinValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Value *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isRealFloatingType()) { + const llvm::fltSemantics &FS = Ty->getFltSemantics(); + llvm::APFloat InitVal = llvm::APFloat::getLargest(FS, true); + llvm::Value *Init = + llvm::ConstantFP::get(CGM.getLLVMContext(), InitVal); + InitTempAlloca(Private, Init); + } else if (QTy->isPointerType()) { + llvm::APInt InitVal = llvm::APInt::getMinValue( + CGM.getDataLayout().getTypeStoreSizeInBits(Ty)); + llvm::Constant *Init = + llvm::ConstantInt::get(CGM.getLLVMContext(), InitVal); + Init = llvm::ConstantExpr::getCast(llvm::Instruction::IntToPtr, Init, + Ty); + InitTempAlloca(Private, Init); + } + break; + } + case OMPC_REDUCTION_custom: + llvm_unreachable("Custom initialization cannot be NULLed."); + case OMPC_REDUCTION_unknown: + case NUM_OPENMP_REDUCTION_OPERATORS: + llvm_unreachable("Unkonwn operator kind."); + } + } + llvm::Value *Addr = Builder.CreateConstGEP2_32( + ReductionRecVar, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + ".addr"); + Builder.CreateStore(Private, Addr); + // llvm::Value *Var = Builder.CreateLoad(Addr, CGM.getMangledName(VD)); + CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } +} + +void +CodeGenFunction::EmitPostOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S) { + assert(!isa(S)); // Not yet supported + CodeGenFunction &CGF = CGM.OpenMPSupport.getCGFForReductionFunction(); + llvm::Function *ReduceFunc = CGF.CurFn; + llvm::SwitchInst *Switch = dyn_cast_or_null( + CGM.OpenMPSupport.getReductionSwitch()); + llvm::BasicBlock *RedBB1; + llvm::BasicBlock *RedBB2; + llvm::Instruction *IP1; + llvm::Instruction *IP2; + if (!Switch) { + // __kmpc_reduce[_nowait](ident_t *loc, int32_t global_tid, int32_t + // num_vars, + // size_t reduce_size, void *reduce_data, + // kmp_reduce_func reduce_func, kmp_critical_name *lck); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(C.getLocStart(), *this, + KMP_IDENT_ATOMIC_REDUCE); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(C.getLocStart(), *this); + // int num_vars = c; + unsigned NumVars = CGM.OpenMPSupport.getNumberOfReductionVars(); + llvm::Value *NumVarsVal = llvm::ConstantInt::get(Int32Ty, NumVars); + // size_t reduce_size = sizeof(rec); + uint64_t ReduceSize = CGM.getDataLayout().getTypeAllocSize( + CGM.OpenMPSupport.getReductionRec()); + llvm::Value *ReduceSizeVal = llvm::ConstantInt::get(SizeTy, ReduceSize); + // void *reduce_data = (void *)rec; + llvm::Value *ReduceData = + Builder.CreatePointerCast(CGM.OpenMPSupport.getReductionRecVar(*this), + VoidPtrTy, "(void*)reductionrec"); + // kmpc_reduce_func reduce_func = reduce_func; + // kmp_critical_name lck; + llvm::Type *LckTy = + llvm::TypeBuilder::get(CGM.getLLVMContext()); + + llvm::GlobalVariable *Lck = CreateRuntimeVariable(CGM, ".lck.", LckTy); + CGM.OpenMPSupport.setReductionLockVar(Lck); + llvm::Value *RealArgs[] = { + Loc, GTid, NumVarsVal, ReduceSizeVal, ReduceData, ReduceFunc, Lck}; + llvm::CallInst *Res = EmitRuntimeCall(CGM.OpenMPSupport.getNoWait() + ? OPENMPRTL_FUNC(reduce_nowait) + : OPENMPRTL_FUNC(reduce), + RealArgs); + RedBB1 = createBasicBlock("reduction.case1", CurFn); + RedBB2 = createBasicBlock("reduction.case2", CurFn); + llvm::BasicBlock *DefaultBlock = + createBasicBlock("reduction.continue", CurFn); + Switch = Builder.CreateSwitch(Res, DefaultBlock, 2); + Switch->addCase(llvm::ConstantInt::get(Int32Ty, 1), RedBB1); + Switch->addCase(llvm::ConstantInt::get(Int32Ty, 2), RedBB2); + IP1 = RedBB1->end(); + IP2 = RedBB2->end(); + Builder.SetInsertPoint(DefaultBlock); + CGM.OpenMPSupport.setReductionSwitch(Switch); + } else { + CGM.OpenMPSupport.getReductionIPs(RedBB1, IP1, RedBB2, IP2); + } + llvm::Value *ReductionRecVar = CGM.OpenMPSupport.getReductionRecVar(*this); + ArrayRef::iterator Par1I = C.getHelperParameters1st().begin(); + ArrayRef::iterator Par2I = C.getHelperParameters2nd().begin(); + ArrayRef::iterator OpI = C.getOpExprs().begin(); + for (OMPReductionClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++Par1I, ++Par2I, ++OpI) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + QualType QTy = (*I)->getType(); + llvm::Value *Private = CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD); + if (!Private) + continue; + CGM.OpenMPSupport.delOpenMPPrivateVar(VD); + + CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); + Builder.SetInsertPoint(RedBB1, IP1); + const VarDecl *Par1 = cast(cast(*Par1I)->getDecl()); + const VarDecl *Par2 = cast(cast(*Par2I)->getDecl()); + QualType PtrQTy = getContext().getPointerType(QTy); + llvm::AllocaInst *AI = + CreateMemTemp(PtrQTy, CGM.getMangledName(VD) + ".addr.lhs."); + LValue LVal = MakeNaturalAlignAddrLValue(AI, PtrQTy); + UnaryOperator UOp(const_cast(*I), UO_AddrOf, PtrQTy, VK_LValue, + OK_Ordinary, SourceLocation()); + // EmitExprAsInit(&UOp, VD, LVal, false); + EmitAnyExprToMem(&UOp, AI, UOp.getType().getQualifiers(), false); + llvm::Value *Addr2 = Builder.CreateConstGEP2_32( + ReductionRecVar, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + ".addr.rhs"); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par1, AI); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par2, Addr2); + EmitIgnoredExpr(*OpI); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par1); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par2); + IP1 = Builder.GetInsertPoint(); + RedBB1 = Builder.GetInsertBlock(); + Builder.SetInsertPoint(RedBB2, IP2); + llvm::Value *AtomicFunc = OPENMPRTL_ATOMIC_FUNC(QTy, C.getOperator()); + if (isa((*OpI)->IgnoreImpCasts()) && AtomicFunc) { + // __kmpc_atomic_...(&loc, global_tid, &glob, &reduction); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(C.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(C.getLocStart(), *this); + Addr2 = Builder.CreateConstGEP2_32( + ReductionRecVar, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + ".addr.rhs"); + llvm::Type *ArgTy = ConvertTypeForMem(getAtomicType(*this, QTy)); + llvm::Type *PtrArgTy = ArgTy->getPointerTo(); + llvm::Value *RealArgs[] = { + Loc, GTid, Builder.CreatePointerCast(EmitScalarExpr(&UOp), PtrArgTy), + Builder.CreateLoad(Builder.CreatePointerCast( + Builder.CreateLoad(Addr2, CGM.getMangledName(VD) + ".rhs"), + PtrArgTy))}; + EmitRuntimeCall(AtomicFunc, RealArgs); + } else { + // __kmpc_atomic_start(); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_start)); + AI = CreateMemTemp(PtrQTy, CGM.getMangledName(VD) + ".addr.lhs."); + LVal = MakeNaturalAlignAddrLValue(AI, PtrQTy); + EmitAnyExprToMem(&UOp, AI, UOp.getType().getQualifiers(), false); + // EmitExprAsInit(&UOp, VD, LVal, false); + Addr2 = Builder.CreateConstGEP2_32( + ReductionRecVar, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + "addr.rhs"); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par1, AI); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par2, Addr2); + EmitIgnoredExpr(*OpI); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par1); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par2); + // __kmpc_atomic_end(); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_end)); + } + IP2 = Builder.GetInsertPoint(); + RedBB2 = Builder.GetInsertBlock(); + Builder.restoreIP(SavedIP); + } + CGM.OpenMPSupport.setReductionIPs(RedBB1, IP1, RedBB2, IP2); +} + +llvm::CallInst *CodeGenFunction::EmitOMPCallWithLocAndTidHelper( + llvm::Value *F, SourceLocation L, unsigned Flags) { + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(L, *this, Flags); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(L, *this); + llvm::Value *RealArgs[] = {Loc, GTid}; + return EmitRuntimeCall(F, RealArgs); +} + +void +CodeGenFunction::EmitOMPCapturedBodyHelper(const OMPExecutableDirective &S) { + // TODO: We may inline instead of calling it... + RunCleanupsScope MyScope(*this); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EnsureInsertPoint(); +} + +void CodeGenFunction::EmitOMPConditionalIfHelper( + const OMPExecutableDirective &S, llvm::Value *Func, SourceLocation Loc, + llvm::Value *EndFunc, SourceLocation EndLoc, bool HasClauses, + llvm::AllocaInst *DidIt, const std::string &NameStr) { + + // This is for master and single directives: + // if (__kmpc_Call()) { + // + // __kmpc_EndCall(); + // } + // + RunCleanupsScope ExecutedScope(*this); + if (HasClauses) { + // Pre-process private and firstprivate clauses + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + if (*I) + EmitPreOMPClause(*(*I), S); + } + } + + if (DidIt) { + // Store 0 into .did_it. flag + llvm::Value *Zero = + llvm::Constant::getNullValue(ConvertTypeForMem(getContext().IntTy)); + EmitStoreOfScalar(Zero, DidIt, false, + CGM.getDataLayout().getPrefTypeAlignment( + ConvertTypeForMem(getContext().IntTy)), + getContext().IntTy); + } + + // Start with emission of __kmpc_Call() + llvm::CallInst *Call = EmitOMPCallWithLocAndTidHelper(Func, Loc); + // Convert Call's result to bool, to use in IF-stmt + llvm::Value *CallBool = + EmitScalarConversion(Call, getContext().IntTy, getContext().BoolTy); + // Generate the basic blocks + llvm::BasicBlock *ThenBlock = createBasicBlock((NameStr + ".then").c_str()); + llvm::BasicBlock *ContBlock = createBasicBlock((NameStr + ".end").c_str()); + // Generate the branch (If-stmt) + Builder.CreateCondBr(CallBool, ThenBlock, ContBlock); + EmitBlock(ThenBlock); + // Here we are on Then-branch -- emit captured body and __kmpc_EndCall() + EmitOMPCapturedBodyHelper(S); + if (DidIt) { + // Store 1 into .did_it. flag + llvm::Value *One = llvm::ConstantInt::get( + CGM.getLLVMContext(), + llvm::APInt::getLowBitsSet(CGM.getDataLayout().getTypeStoreSizeInBits( + ConvertTypeForMem(getContext().IntTy)), + 1)); + EmitStoreOfScalar(One, DidIt, false, + CGM.getDataLayout().getPrefTypeAlignment( + DidIt->getType()->getSequentialElementType()), + getContext().IntTy); + } + EmitOMPCallWithLocAndTidHelper(EndFunc, EndLoc); + // Emit the rest of bblocks/branches + EmitBranch(ContBlock); + EmitBlock(ContBlock, true); + + if (HasClauses) { + // Post-process private and firstprivate clauses + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + if (*I) + EmitPostOMPClause(*(*I), S); + } + } +} + +/// "One-call" OMP Directives (barrier, taskyield, taskwait, flush). +/// '#pragma omp barrier' directive. +void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) { + // EmitUntiedPartIdInc(*this); + EmitOMPCancelBarrier(S.getLocStart(), KMP_IDENT_BARRIER_EXPL); + // EmitUntiedBranchEnd(*this); + // EmitUntiedTaskSwitch(*this, false); +} + +/// '#pragma omp taskyield' directive. +void +CodeGenFunction::EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S) { + // EmitUntiedPartIdInc(*this); + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + llvm::Value *RealArgs[] = {Loc, GTid, Builder.getInt32(0)}; + EmitRuntimeCall(OPENMPRTL_FUNC(omp_taskyield), RealArgs); + // EmitUntiedBranchEnd(*this); + // EmitUntiedTaskSwitch(*this, false); +} + +/// '#pragma omp taskwait' directive. +void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { + // If the task is untied, we may want to generate IF-stmt here: + // if (__kmpc_omp_taskwait(loc_task_wait, gtid) == CURRENT_TASK_QUEUED) { + // T-return; // Exit t1 if it was suspended or queued + // } + // But currently RTL always returns TASK_CURRENT_NOT_QUEUED, + // so probably that make no sence. + // + EmitUntiedPartIdInc(*this); + llvm::Value *Res = EmitOMPCallWithLocAndTidHelper( + OPENMPRTL_FUNC(omp_taskwait), S.getLocStart()); + if (CGM.OpenMPSupport.getUntied()) { + llvm::BasicBlock *ThenBB = createBasicBlock("taskwait.then"); + llvm::BasicBlock *EndBB = createBasicBlock("taskwait.end"); + llvm::Value *Cond = + Builder.CreateICmpEQ(Res, Builder.getInt32(OMP_TASK_CURRENT_QUEUED)); + Builder.CreateCondBr(Cond, ThenBB, EndBB); + EmitBlock(ThenBB); + EmitUntiedBranchEnd(*this); + EmitBlock(EndBB); + EmitUntiedTaskSwitch(*this, true); + } +} + +/// '#pragma omp flush' directive. +void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) { + SmallVector Args; + Args.push_back(CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this)); + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + const OMPFlushClause *C = cast(*I); + for (ArrayRef::iterator J = C->varlist_begin(), + F = C->varlist_end(); + J != F; ++J) { + QualType QTy = (*J)->getType(); + QualType PtrQTy = getContext().getPointerType(QTy); + UnaryOperator UOp(const_cast(*J), UO_AddrOf, PtrQTy, VK_LValue, + OK_Ordinary, S.getLocStart()); + llvm::Value *Val = EmitScalarExpr(&UOp); + Args.push_back(Val); + } + } + EmitRuntimeCall(OPENMPRTL_FUNC(flush), Args); +} + +/// '#pragma omp cancel' directive. +void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { + llvm::Value *Loc; + llvm::Value *GTid; + llvm::Value *Kind; + EmitCancelArgs(*this, S.getConstructType(), S.getLocStart(), Loc, GTid, Kind); + + llvm::Value *RealArgs[] = {Loc, GTid, Kind}; + + llvm::BasicBlock *ContBB = createBasicBlock("omp.cancel.continue"); + llvm::BasicBlock *ExitBB = createBasicBlock("omp.cancel.exit"); + if (!S.clauses().empty()) { + assert(S.clauses().size() == 1 && isa(S.clauses().front()) && + "Wrong number or type of clause in omp cancel directive"); + const OMPIfClause *Clause = cast(S.clauses().front()); + llvm::BasicBlock *ThenBB = createBasicBlock("omp.cancel.then"); + llvm::BasicBlock *ElseBB = createBasicBlock("omp.cancel.else"); + EmitBranchOnBoolExpr(Clause->getCondition(), ThenBB, ElseBB); + EmitBlock(ElseBB); + EmitCancellationPoint(*this, S.getLocStart(), RealArgs, ExitBB, ContBB); + EmitBlock(ThenBB); + } + + llvm::Value *CallRes = Builder.CreateIsNotNull( + EmitRuntimeCall(OPENMPRTL_FUNC(cancel), RealArgs)); + Builder.CreateCondBr(CallRes, ExitBB, ContBB); + EmitBlock(ExitBB); + assert(OMPCancelMap.count(S.getConstructType()) && + "No exit point for cancel"); + EmitOMPCancelBarrier(S.getLocStart(), KMP_IDENT_BARRIER_IMPL, true); + EmitBranchThroughCleanup(OMPCancelMap[S.getConstructType()]); + EmitBlock(ContBB); +} + +/// '#pragma omp cancellation point' directive. +void CodeGenFunction::EmitOMPCancellationPointDirective( + const OMPCancellationPointDirective &S) { + llvm::Value *Loc; + llvm::Value *GTid; + llvm::Value *Kind; + EmitCancelArgs(*this, S.getConstructType(), S.getLocStart(), Loc, GTid, Kind); + + llvm::Value *RealArgs[] = {Loc, GTid, Kind}; + + llvm::BasicBlock *ExitBB = createBasicBlock("omp.cancellationpoint.exit"); + llvm::BasicBlock *ContBB = createBasicBlock("omp.cancellationpoint.continue"); + assert(OMPCancelMap.count(S.getConstructType()) && + "No exit point for cancellation point"); + EmitCancellationPoint(*this, S.getLocStart(), RealArgs, ExitBB, ContBB, + OMPCancelMap[S.getConstructType()]); +} + +/// Atomic OMP Directive -- pattern match and emit one RTL call. +/// In the future, we may want to generate some atomic llvm instruction +/// instead of RTL call here for some atomic directives. +void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) { + CGM.OpenMPSupport.startOpenMPRegion(false); + bool IsSeqCst = false; + bool AtLeastOneLoopTaken = false; + OpenMPClauseKind Kind = OMPC_update; + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E || !AtLeastOneLoopTaken; ++I) { + if (I != S.clauses().end()) { + if ((*I)->getClauseKind() == OMPC_seq_cst) { + IsSeqCst = true; + continue; + } + Kind = (*I)->getClauseKind(); + } + LValue X = EmitLValue(S.getX()->IgnoreParenLValueCasts()); + switch (Kind) { + case OMPC_read: { + QualType QTy = S.getX()->getType(); + QualType AQTy = getAtomicType(*this, QTy); + llvm::Value *AtomicFunc = + AQTy.isNull() ? 0 : OPENMPRTL_ATOMIC_FUNC_GENERAL( + AQTy, AQTy, OMP_Atomic_rd, false, false); + if (X.isSimple() && AtomicFunc) { + llvm::Type *ATy = ConvertTypeForMem(AQTy); + llvm::SmallVector Args; + // __kmpc_atomic_..._rd(&loc, global_tid, &x); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + Args.push_back(Loc); + Args.push_back(GTid); + Args.push_back( + Builder.CreatePointerCast(X.getAddress(), ATy->getPointerTo())); + llvm::Value *Res = EmitRuntimeCall(AtomicFunc, Args); + // v = x; + Res = EmitScalarConversion(Res, AQTy, S.getV()->getType()); + EmitStoreOfScalar(Res, EmitLValue(S.getV())); + } else { + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_start)); + RValue Val = EmitLoadOfLValue(X, S.getX()->getExprLoc()); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_end)); + EmitStoreThroughLValue(Val, EmitLValue(S.getV())); + } + } break; + case OMPC_write: { + QualType QTy = S.getX()->getType(); + QualType AQTy = getAtomicType(*this, QTy); + QualType QTyIn = S.getExpr()->getType(); + llvm::Value *AtomicFunc = + AQTy.isNull() ? 0 : OPENMPRTL_ATOMIC_FUNC_GENERAL( + AQTy, AQTy, OMP_Atomic_wr, false, false); + if (X.isSimple() && AtomicFunc && QTyIn->isScalarType() && + !QTyIn->isAnyComplexType()) { + llvm::Type *ATy = ConvertTypeForMem(AQTy); + llvm::SmallVector Args; + // __kmpc_atomic_..._wr(&loc, global_tid, &x, expr); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + Args.push_back(Loc); + Args.push_back(GTid); + Args.push_back( + Builder.CreatePointerCast(X.getAddress(), ATy->getPointerTo())); + Args.push_back( + EmitScalarConversion(EmitAnyExpr(S.getExpr()).getScalarVal(), + S.getExpr()->getType(), AQTy)); + EmitRuntimeCall(AtomicFunc, Args); + } else { + RValue Val = EmitAnyExpr(S.getExpr()); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_start)); + EmitStoreThroughLValue(Val, X); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_end)); + } + } break; + case OMPC_update: { + QualType QTyRes = S.getX()->getType(); + QualType AQTyRes = getAtomicType(*this, QTyRes); + QualType QTyIn = S.getExpr()->getType(); + QualType AQTyIn = getAtomicType(*this, QTyIn); + EAtomicOperation Aop; + switch (S.getOperator()) { + case BO_Add: + Aop = OMP_Atomic_add; + break; + case BO_Sub: + Aop = OMP_Atomic_sub; + break; + case BO_Mul: + Aop = OMP_Atomic_mul; + break; + case BO_Div: + Aop = OMP_Atomic_div; + break; + case BO_And: + Aop = OMP_Atomic_andb; + break; + case BO_Or: + Aop = OMP_Atomic_orb; + break; + case BO_Xor: + Aop = OMP_Atomic_xor; + break; + case BO_Shl: + Aop = OMP_Atomic_shl; + break; + case BO_Shr: + Aop = OMP_Atomic_shr; + break; + default: + Aop = OMP_Atomic_invalid; + break; + } + llvm::Value *AtomicFunc = + (AQTyRes.isNull() || AQTyIn.isNull()) + ? 0 + : OPENMPRTL_ATOMIC_FUNC_GENERAL(AQTyRes, AQTyIn, Aop, false, + S.isReversed()); + if (X.isSimple() && AtomicFunc && QTyIn->isScalarType() && + !QTyIn->isAnyComplexType()) { + llvm::Type *ATyRes = ConvertTypeForMem(AQTyRes); + llvm::SmallVector Args; + // __kmpc_atomic_..._op(&loc, global_tid, &x, expr); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + Args.push_back(Loc); + Args.push_back(GTid); + Args.push_back( + Builder.CreatePointerCast(X.getAddress(), ATyRes->getPointerTo())); + Args.push_back(EmitAnyExpr(S.getExpr()).getScalarVal()); + EmitRuntimeCall(AtomicFunc, Args); + } else { + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_start)); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_end)); + } + } break; + case OMPC_capture: { + QualType QTyRes = S.getX()->getType(); + QualType AQTyRes = getAtomicType(*this, QTyRes); + QualType QTyIn = S.getExpr()->getType(); + QualType AQTyIn = getAtomicType(*this, QTyIn); + EAtomicOperation Aop; + switch (S.getOperator()) { + case BO_Add: + Aop = OMP_Atomic_add; + break; + case BO_Sub: + Aop = OMP_Atomic_sub; + break; + case BO_Mul: + Aop = OMP_Atomic_mul; + break; + case BO_Div: + Aop = OMP_Atomic_div; + break; + case BO_And: + Aop = OMP_Atomic_andb; + break; + case BO_Or: + Aop = OMP_Atomic_orb; + break; + case BO_Xor: + Aop = OMP_Atomic_xor; + break; + case BO_Shl: + Aop = OMP_Atomic_shl; + break; + case BO_Shr: + Aop = OMP_Atomic_shr; + break; + case BO_Assign: + Aop = OMP_Atomic_assign; + break; + default: + Aop = OMP_Atomic_invalid; + break; + } + llvm::Value *AtomicFunc = + (AQTyRes.isNull() || AQTyIn.isNull()) + ? 0 + : OPENMPRTL_ATOMIC_FUNC_GENERAL(AQTyRes, AQTyIn, Aop, true, + S.isReversed()); + if (X.isSimple() && AtomicFunc && QTyIn->isScalarType() && + !QTyIn->isAnyComplexType()) { + llvm::Type *ATy = ConvertTypeForMem(AQTyRes); + llvm::SmallVector Args; + // __kmpc_atomic_..._op(&loc, global_tid, &x, expr); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + Args.push_back(Loc); + Args.push_back(GTid); + Args.push_back( + Builder.CreatePointerCast(X.getAddress(), ATy->getPointerTo())); + Args.push_back(EmitAnyExpr(S.getExpr()).getScalarVal()); + Args.push_back(Builder.getInt32(S.isCaptureAfter() ? 1 : 0)); + llvm::Value *Res = EmitRuntimeCall(AtomicFunc, Args); + // v = x; + Res = EmitScalarConversion(Res, AQTyRes, S.getV()->getType()); + EmitStoreOfScalar(Res, EmitLValue(S.getV())); + } else { + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_start)); + EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EmitRuntimeCall(OPENMPRTL_FUNC(atomic_end)); + } + } break; + case OMPC_seq_cst: + llvm_unreachable("SEQ_CST should be processed already."); + break; + default: + llvm_unreachable("Not allowed operation in atomic directive."); + } + if (I == E && !AtLeastOneLoopTaken) + break; + AtLeastOneLoopTaken = true; + } + if (IsSeqCst) { + SmallVector Args; + Args.push_back(CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this)); + EmitRuntimeCall(OPENMPRTL_FUNC(flush), Args); + } + CGM.OpenMPSupport.endOpenMPRegion(); +} + +/// "Two-calls" OMP Directives (master, single, critical, ordered). +/// '#pragma omp master' directive. +void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { + // if (__kmpc_master()) { + // + // __kmpc_end_master(); + // } + EmitOMPConditionalIfHelper(S, OPENMPRTL_FUNC(master), S.getLocStart(), + OPENMPRTL_FUNC(end_master), S.getLocStart(), + false, // pragma has no clauses + 0, // has no need for "didit" + "omp.master"); +} + +/// '#pragma omp single' directive. +void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) { + + // Init list of private globals in the stack. + CGM.OpenMPSupport.startOpenMPRegion(false); + CGM.OpenMPSupport.setNoWait(false); + bool HasClauses = S.getNumClauses(); + if (HasClauses) { + // Set NoWait flag if the clause nowait is there + for (ArrayRef::iterator I = S.clauses().begin(), + E = S.clauses().end(); + I != E; ++I) { + if (*I) + EmitInitOMPClause(*(*I), S); + } + } + + // did_it = 0; + // if (__kmpc_single()) { + // + // did_it = 1; + // __kmpc_end_single(); + // } + // ... if there is copyprivate clause, call to __kmpc_copyprivate() + // ... if there is no nowait, call to __kmpc_barrier() + // + + // Create a "did_it" temp for passing into copyprivate routine. + llvm::AllocaInst *DidIt = CreateMemTemp(getContext().IntTy, ".did_it."); + InitTempAlloca(DidIt, llvm::Constant::getNullValue( + ConvertTypeForMem(getContext().IntTy))); + + EmitOMPConditionalIfHelper( + S, OPENMPRTL_FUNC(single), S.getLocStart(), OPENMPRTL_FUNC(end_single), + S.getLocStart(), HasClauses, // pragma has clauses (private and + // firstprivate will be processed) + DidIt, // address to store 1 for "the single" thread + "omp.single"); + + // Copyprivate clause. + // Restrictions to copyprivate (from standard): + // The items that appear in copyprivate must be either threadprivate or + // private in the enclosing context. + // A list item that appears in copyprivate clause may not appear in a private + // or firstprivate clause on the single construct. + // + bool HasCopyPrivate = false; + for (ArrayRef::iterator ICL = S.clauses().begin(), + ECL = S.clauses().end(); + ICL != ECL; ++ICL) { + if (*ICL) { + if (const OMPCopyPrivateClause *C = + dyn_cast(*ICL)) { + // Begin copyprivate clause processing + HasCopyPrivate = true; + // Start a copy-function. + CodeGenFunction CGF(CGM, true); + CGF.CurFn = 0; + FunctionArgList Args; + ImplicitParamDecl Arg1(0, SourceLocation(), 0, getContext().VoidPtrTy); + ImplicitParamDecl Arg2(0, SourceLocation(), 0, getContext().VoidPtrTy); + Args.push_back(&Arg1); + Args.push_back(&Arg2); + const CGFunctionInfo &FI = CGF.getTypes().arrangeFunctionDeclaration( + getContext().VoidTy, Args, FunctionType::ExtInfo(), false); + llvm::FunctionType *FTy = CGF.getTypes().GetFunctionType(FI); + llvm::Function *Fn = llvm::Function::Create( + FTy, llvm::GlobalValue::InternalLinkage, + StringRef(".omp_copy_func."), &CGM.getModule()); + CGM.SetInternalFunctionAttributes(CurFuncDecl, Fn, FI); + CGF.StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, Args, + SourceLocation()); + + // Generate the record of pointers - cpy.var + llvm::SmallVector CpyFieldTypes; + for (OMPCopyPrivateClause::varlist_const_iterator + I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + // const VarDecl *VD = + // cast(cast(*I)->getDecl()); + QualType QTy = (*I)->getType(); + llvm::Type *PtrType = ConvertType(getContext().getPointerType(QTy)); + CpyFieldTypes.push_back(PtrType); + } + llvm::StructType *CpyType = + llvm::StructType::get(CGM.getLLVMContext(), CpyFieldTypes); + llvm::AllocaInst *CpyVar = CreateTempAlloca(CpyType, "cpy.var"); + CpyVar->setAlignment(CGM.PointerAlignInBytes); + + // Generate initializaion of our local record with addresses. + int32_t FieldNum = 0; + for (OMPCopyPrivateClause::varlist_const_iterator + I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I, ++FieldNum) { + // Store the address into our record. + Builder.CreateStore(EmitLValue(*I).getAddress(), + Builder.CreateConstGEP2_32(CpyVar, 0, FieldNum)); + } + + // Generate field copying in the copy-function. + { + llvm::Function::arg_iterator ArgIt = CGF.CurFn->arg_begin(); + llvm::Value *DstPtr = ArgIt; + llvm::Value *SrcPtr = ++ArgIt; + llvm::Value *DstBase = CGF.Builder.CreatePointerCast( + DstPtr, CpyType->getPointerTo(), "cpy.dst"); + llvm::Value *SrcBase = CGF.Builder.CreatePointerCast( + SrcPtr, CpyType->getPointerTo(), "cpy.src"); + + ArrayRef::iterator AssignIter = + C->getAssignments().begin(); + ArrayRef::iterator VarIter1 = + C->getPseudoVars1().begin(); + ArrayRef::iterator VarIter2 = + C->getPseudoVars2().begin(); + FieldNum = 0; + for (OMPCopyPrivateClause::varlist_const_iterator + I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I, ++AssignIter, ++VarIter1, ++VarIter2, ++FieldNum) { + // const VarDecl *VD = + // cast(cast(*I)->getDecl()); + QualType QTy = (*I)->getType(); + llvm::Value *Dst = + CGF.Builder.CreateConstGEP2_32(DstBase, 0, FieldNum); + llvm::Value *Src = + CGF.Builder.CreateConstGEP2_32(SrcBase, 0, FieldNum); + llvm::Type *PtrType = ConvertType(getContext().getPointerType(QTy)); + llvm::Value *LoadDst = CGF.EmitLoadOfScalar( + Dst, false, CGM.getDataLayout().getPrefTypeAlignment(PtrType), + getContext().getPointerType(QTy), SourceLocation()); + llvm::Value *LoadSrc = CGF.EmitLoadOfScalar( + Src, false, CGM.getDataLayout().getPrefTypeAlignment(PtrType), + getContext().getPointerType(QTy), SourceLocation()); + CGF.EmitCopyAssignment(I, AssignIter, VarIter1, VarIter2, LoadDst, + LoadSrc); + } + } + + // Generate a call to __kmpc_copyprivate. + { + // __kmpc_copyprivate(ident_t *loc, int32_t global_tid, + // size_t cpy_size, void *cpy_data, + // kmp_copy_func cpy_func, int32_t didit); + llvm::Value *Loc = + CGM.CreateIntelOpenMPRTLLoc(C->getLocStart(), *this); + llvm::Value *GTid = + CGM.CreateOpenMPGlobalThreadNum(C->getLocStart(), *this); + int32_t CpySizeInt = CGM.getDataLayout().getTypeAllocSize(CpyType); + llvm::Value *CpySize = llvm::ConstantInt::get(SizeTy, CpySizeInt); + llvm::Value *LoadDidIt = EmitLoadOfScalar( + DidIt, false, CGM.getDataLayout().getPrefTypeAlignment( + DidIt->getType()->getSequentialElementType()), + getContext().IntTy, SourceLocation()); + llvm::Value *RealArgs[] = { + Loc, + GTid, + CpySize, + Builder.CreateBitCast(CpyVar, VoidPtrTy, "(void*)cpyrec"), + CGF.CurFn, + LoadDidIt}; + EmitRuntimeCall(OPENMPRTL_FUNC(copyprivate), RealArgs); + } + + // Stop the copy-function. + CGF.FinishFunction(); + // End copyprivate clause processing + } + } + } + + if (!HasCopyPrivate && !CGM.OpenMPSupport.getNoWait()) { + // Note: __kmpc_copyprivate already has a couple of barriers internally. + EmitOMPCancelBarrier(S.getLocEnd(), KMP_IDENT_BARRIER_IMPL_SINGLE); + } + + // Remove list of private globals from the stack. + CGM.OpenMPSupport.endOpenMPRegion(); +} + +/// '#pragma omp critical' directive. +void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { + // __kmpc_critical(); + // + // __kmpc_end_critical(); + // + + // Prepare kmp_critical_name -- the name of our critical section. + std::string directive_name = S.getDirectiveName().getAsString(); + std::string name = ".gomp_critical_user_" + directive_name + ".var"; + llvm::Type *LckTy = + llvm::TypeBuilder::get(CGM.getLLVMContext()); + llvm::GlobalVariable *Lck = cast( + CGM.CreateRuntimeVariable(LckTy, name.c_str())); + Lck->setLinkage(llvm::GlobalValue::CommonLinkage); + Lck->setInitializer(llvm::Constant::getNullValue(LckTy)); + + // Prepare other arguments and build a call to __kmpc_critical + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(S.getLocStart(), *this); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(S.getLocStart(), *this); + llvm::Value *RealArgs[] = {Loc, GTid, Lck}; + EmitRuntimeCall(OPENMPRTL_FUNC(critical), RealArgs); + EmitOMPCapturedBodyHelper(S); + EmitRuntimeCall(OPENMPRTL_FUNC(end_critical), RealArgs); +} + +/// '#pragma omp ordered' directive. +void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { + // __kmpc_ordered(); + // + // __kmpc_enc_ordered(); + // + EmitOMPCallWithLocAndTidHelper(OPENMPRTL_FUNC(ordered), S.getLocStart()); + EmitOMPCapturedBodyHelper(S); + EmitOMPCallWithLocAndTidHelper(OPENMPRTL_FUNC(end_ordered), S.getLocStart()); +} + +/// '#pragma omp taskgroup' directive. +void +CodeGenFunction::EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S) { + // __kmpc_taskgroup(); + // + // __kmpc_enc_taskgroup(); + // + EmitOMPCallWithLocAndTidHelper(OPENMPRTL_FUNC(taskgroup), S.getLocStart()); + EmitOMPCapturedBodyHelper(S); + EmitOMPCallWithLocAndTidHelper(OPENMPRTL_FUNC(end_taskgroup), S.getLocEnd()); + + // EmitUntiedPartIdInc(*this); + // EmitUntiedBranchEnd(*this); + // EmitUntiedTaskSwitch(*this, false); +} + +void +CodeGenFunction::EmitCloseOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S) { + assert(!isa(S)); // Not yet supported + llvm::BasicBlock *RedBB1; + llvm::BasicBlock *RedBB2; + llvm::Instruction *IP1; + llvm::Instruction *IP2; + CGM.OpenMPSupport.getReductionIPs(RedBB1, IP1, RedBB2, IP2); + llvm::SwitchInst *Switch = dyn_cast_or_null( + CGM.OpenMPSupport.getReductionSwitch()); + if (Switch && (IP1 || IP2 || RedBB1 || RedBB2)) { + CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); + Builder.SetInsertPoint(RedBB1, IP1); + // __kmpc_end_reduce[_nowait](ident_t *loc, int32_t global_tid, *lck); + // ident_t loc = {...}; + llvm::Value *Loc = CGM.CreateIntelOpenMPRTLLoc(C.getLocStart(), *this); + // global_tid = __kmpc_global_thread_num(...); + llvm::Value *GTid = CGM.CreateOpenMPGlobalThreadNum(C.getLocStart(), *this); + // kmp_critical_name lck; + llvm::Value *RealArgs[] = {Loc, GTid, + CGM.OpenMPSupport.getReductionLockVar()}; + EmitRuntimeCall(CGM.OpenMPSupport.getNoWait() + ? OPENMPRTL_FUNC(end_reduce_nowait) + : OPENMPRTL_FUNC(end_reduce), + RealArgs); + Builder.CreateBr(Switch->getDefaultDest()); + // Switch->addCase(llvm::ConstantInt::get(Int32Ty, 1), RedBB1); + Builder.SetInsertPoint(RedBB2, IP2); + Builder.CreateBr(Switch->getDefaultDest()); + // Switch->addCase(llvm::ConstantInt::get(Int32Ty, 2), RedBB2); + Builder.restoreIP(SavedIP); + CGM.OpenMPSupport.setReductionIPs(0, 0, 0, 0); + } + + CodeGenFunction &CGF = CGM.OpenMPSupport.getCGFForReductionFunction(); + llvm::Value *Arg1; + llvm::Value *Arg2; + CGM.OpenMPSupport.getReductionFunctionArgs(Arg1, Arg2); + ArrayRef::iterator Par1I = C.getHelperParameters1st().begin(); + ArrayRef::iterator Par2I = C.getHelperParameters2nd().begin(); + ArrayRef::iterator OpI = C.getOpExprs().begin(); + for (OMPReductionClause::varlist_const_iterator I = C.varlist_begin(), + E = C.varlist_end(); + I != E; ++I, ++Par1I, ++Par2I, ++OpI) { + // Get element type. + const VarDecl *VD = cast(cast(*I)->getDecl()); + if (VD->hasLocalStorage() && + (!CapturedStmtInfo || !CapturedStmtInfo->lookup(VD))) + continue; + const VarDecl *Par1 = cast(cast(*Par1I)->getDecl()); + const VarDecl *Par2 = cast(cast(*Par2I)->getDecl()); + llvm::Value *Addr1 = CGF.Builder.CreateConstGEP2_32( + Arg1, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + ".addr.lhs"); + llvm::Value *Addr2 = CGF.Builder.CreateConstGEP2_32( + Arg2, 0, CGM.OpenMPSupport.getReductionVarIdx(VD), + CGM.getMangledName(VD) + ".addr.rhs"); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par1, Addr1); + CGM.OpenMPSupport.addOpenMPPrivateVar(Par2, Addr2); + CGF.EmitIgnoredExpr(*OpI); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par1); + CGM.OpenMPSupport.delOpenMPPrivateVar(Par2); + } +} + +void +CodeGenFunction::EmitFinalOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S) { + assert(!isa(S)); // Not yet supported + CodeGenFunction &CGF = CGM.OpenMPSupport.getCGFForReductionFunction(); + if (CGF.CurFn) { + CGF.FinishFunction(); + CGF.CurFn = 0; + } +} + +// Implementation of '#pragma omp simd'. +// + +SourceLocation CodeGenFunction::CGPragmaOmpSimd::getForLoc() const { + const CapturedStmt *Cap = cast(SimdOmp->getAssociatedStmt()); + const ForStmt *For = dyn_cast(Cap->getCapturedStmt()); + if (For) { + return For->getSourceRange().getBegin(); + } + return SimdOmp->getSourceRange().getBegin(); +} + +SourceRange CodeGenFunction::CGPragmaOmpSimd::getSourceRange() const { + return SimdOmp->getSourceRange(); +} + +const Stmt *CodeGenFunction::CGPragmaOmpSimd::getInit() const { + return getInitFromLoopDirective(SimdOmp); +} + +const Expr *CodeGenFunction::CGPragmaOmpSimd::getCond() const { + const CapturedStmt *Cap = dyn_cast_or_null(getAssociatedStmt()); + if (!Cap) + return 0; + const ForStmt *For = dyn_cast_or_null(Cap->getCapturedStmt()); + if (!For) + return 0; + return For->getCond(); +} + +const CapturedStmt * +CodeGenFunction::CGPragmaOmpSimd::getAssociatedStmt() const { + return dyn_cast_or_null(SimdOmp->getAssociatedStmt()); +} + +const Expr *CodeGenFunction::CGPragmaOmpSimd::getLoopCount() const { + const Expr *Op = getNewIterEndFromLoopDirective(SimdOmp); + if (const BinaryOperator *Bop = dyn_cast(Op)) { + // Expected "N-1" here, so why not eat "-1" to get "N". + if (Bop->getOpcode() == BO_Sub) { + const Expr *Op = Bop->getRHS(); + if (const ImplicitCastExpr *Cast = dyn_cast(Op)) { + Op = Cast->getSubExpr(); + } + if (const IntegerLiteral *One = dyn_cast(Op)) { + if (One->getValue() == 1) { + return Bop->getLHS(); + } + } + } + } + assert(0 && "Unexpected loop count expression"); + return Op; +} + +Stmt *CodeGenFunction::CGPragmaOmpSimd::extractLoopBody(Stmt *S) const { + // '#pragma omp simd' stores the full loop nest, and now we are + // going to extract the loop body. + unsigned CollapseNum = getCollapsedNumberFromLoopDirective(SimdOmp); + if (CollapseNum == 0) { + CollapseNum = 1; + } + Stmt *Body = S; + while (CollapseNum > 0) { + if (ForStmt *For = dyn_cast(Body)) { + Body = For->getBody(); + --CollapseNum; + } else if (AttributedStmt *AS = dyn_cast(Body)) { + Body = AS->getSubStmt(); + } else if (CompoundStmt *CS = dyn_cast(Body)) { + if (CS->size() == 1) { + Body = CS->body_back(); + } else { + assert(0 && "Unexpected compound stmt in the loop nest"); + } + } else { + assert(0 && "Unexpected stmt in the loop nest"); + } + } + assert(Body && "Failed to extract the loop body for 'omp simd'"); + return Body; +} + +// Simd wrappers implementation for '#pragma omp simd'. +bool CodeGenFunction::CGPragmaOmpSimd::emitSafelen(CodeGenFunction *CGF) const { + bool SeparateLastIter = false; + CGF->LoopStack.SetParallel(); + CGF->LoopStack.SetVectorizerEnable(true); + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); + I != E; ++I) { + OMPClause *C = dyn_cast(*I); + switch (C->getClauseKind()) { + case OMPC_safelen: { + RValue Len = CGF->EmitAnyExpr(cast(C)->getSafelen(), + AggValueSlot::ignored(), true); + llvm::ConstantInt *Val = dyn_cast(Len.getScalarVal()); + assert(Val); + CGF->LoopStack.SetVectorizerWidth(Val->getZExtValue()); + // In presence of finite 'safelen', it may be unsafe to mark all + // the memory instructions parallel, because loop-carried + // dependences of 'safelen' iterations are possible. + CGF->LoopStack.SetParallel(false); + break; + } + case OMPC_lastprivate: { + SeparateLastIter = true; + break; + } + default: + // Not handled yet + ; + } + } + return SeparateLastIter; +} + +llvm::ConstantInt * +CodeGenFunction::CGPragmaOmpSimd::emitClauseTail(CodeGenFunction *CGF, + Expr *E) const { + // Emit a constant integer for clause's tail expression. + // E can be an integer or NULL. + llvm::ConstantInt *Val = 0; + if (E != 0) { + RValue RVal = CGF->EmitAnyExpr(E, AggValueSlot::ignored(), true); + Val = dyn_cast(RVal.getScalarVal()); + } else { + Val = cast( + llvm::ConstantInt::getNullValue(CGF->CGM.IntTy)); + } + assert(Val); + return Val; +} + +// Walker for '#pragma omp simd' +bool CodeGenFunction::CGPragmaOmpSimd::walkLocalVariablesToEmit( + CodeGenFunction *CGF, CGSIMDForStmtInfo *Info) const { + + // Init the OpenMP local vars stack. + CGF->CGM.OpenMPSupport.startOpenMPRegion(true); + CGF->CGM.OpenMPSupport.setMergeable(false); + CGF->CGM.OpenMPSupport.setOrdered(false); + + // Make sure we have local vars for all the loop counters. + ArrayRef Counters = getCountersFromLoopDirective(SimdOmp); + for (unsigned I = 0; I < getCollapsedNumberFromLoopDirective(SimdOmp); ++I) { + const VarDecl *VD = + cast(cast(Counters[I])->getDecl()); + if (CGF->CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) + continue; + QualType QTy = Counters[I]->getType(); + llvm::AllocaInst *Private = + CGF->CreateMemTemp(QTy, CGF->CGM.getMangledName(VD) + ".counter."); + CGF->CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } + + RunCleanupsScope ExecutedScope(*CGF); + + // Here we push index parameter into openmp map. + // It is useful for loop counters calculation. + const CapturedDecl *CD = + cast(getAssociatedStmt())->getCapturedDecl(); + llvm::Value *LoopIndex = CGF->LocalDeclMap.lookup(CD->getParam(1)); + const VarDecl *IndexVD = cast( + cast(getNewIterVarFromLoopDirective(SimdOmp))->getDecl()); + CGF->CGM.OpenMPSupport.addOpenMPPrivateVar(IndexVD, LoopIndex); + + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); + I != E; ++I) { + OMPClause *C = dyn_cast(*I); + switch (C->getClauseKind()) { + case OMPC_private: { + CGF->EmitPreOMPClause(*(*I), *SimdOmp); + break; + } + case OMPC_lastprivate: { + CGF->EmitPreOMPClause(*(*I), *SimdOmp); + break; + } + case OMPC_linear: { + // Linear vars are calculated from index, similar to loop indices. + OMPLinearClause *L = cast(C); + for (OMPLinearClause::varlist_const_iterator J = L->varlist_begin(), + F = L->varlist_end(); + J != F; ++J) { + const VarDecl *VD = cast(cast(*J)->getDecl()); + if (CGF->CGM.OpenMPSupport.getTopOpenMPPrivateVar(VD)) { + continue; + } + QualType QTy = (*J)->getType(); + llvm::Value *Private = + CGF->CreateMemTemp(QTy, CGF->CGM.getMangledName(VD) + ".linear."); + + // Generate "Private = Index * Step + Start" + llvm::Value *Start = CGF->EmitAnyExprToTemp(*J).getScalarVal(); + llvm::Value *Index = CGF->Builder.CreateLoad(LoopIndex); + llvm::Value *Result = 0; + if (const Expr *StepExpr = L->getStep()) { + Result = CGF->EmitAnyExpr(StepExpr).getScalarVal(); + QualType IndexTy = CD->getParam(1)->getType(); + Result = CGF->Builder.CreateIntCast( + Result, Index->getType(), + IndexTy->hasSignedIntegerRepresentation()); + } else + Result = llvm::ConstantInt::get(Index->getType(), 1); + Result = CGF->Builder.CreateMul(Index, Result); + if (Start->getType()->isPointerTy()) { + Result = CGF->Builder.CreateGEP(Start, Result); + } else { + Result = CGF->Builder.CreateIntCast(Result, Start->getType(), false); + Result = + CGF->Builder.CreateAdd(Start, Result, "add", false, + QTy->isSignedIntegerOrEnumerationType()); + } + CGF->Builder.CreateStore(Result, Private); + + CGF->CGM.OpenMPSupport.addOpenMPPrivateVar(VD, Private); + } + break; + } + default: + break; + } + } + + // Mark 'aligned' variables -- do this after all private variables are + // made 'omp-private' in CGM.OpenMPSupport. + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); + I != E; ++I) { + OMPClause *C = dyn_cast(*I); + switch (C->getClauseKind()) { + case OMPC_aligned: { + OMPAlignedClause *A = cast(C); + // Prepare alignment expression for using it below. + llvm::ConstantInt *AVal = emitClauseTail(CGF, A->getAlignment()); + // Walk the list and push each var's alignment into metadata. + for (OMPAlignedClause::varlist_iterator J = A->varlist_begin(), + F = A->varlist_end(); + J != F; ++J) { + LValue LVal = CGF->EmitLValue(*J); + CGF->LoopStack.AddAligned(LVal.getAddress(), + (int)(AVal->getZExtValue())); + } + break; + } + default: + break; + } + } + + // Emit initializations of loop indices. + CGF->EmitStmt(getInitFromLoopDirective(SimdOmp)); + return false; +} + +void CodeGenFunction::CGPragmaOmpSimd::emitInit(CodeGenFunction &CGF, + llvm::Value *&LoopIndex, + llvm::Value *&LoopCount) { + // Emit loop index + const Expr *IterVar = getNewIterVarFromLoopDirective(SimdOmp); + LoopIndex = CGF.CreateMemTemp(IterVar->getType(), ".idx."); + const VarDecl *VD = cast(cast(IterVar)->getDecl()); + CGF.CGM.OpenMPSupport.addOpenMPPrivateVar(VD, LoopIndex); + + // Emit loop count. + LoopCount = CGF.EmitAnyExpr(getLoopCount()).getScalarVal(); +} + +// Emit the final values of the loop counters and linear vars. +void +CodeGenFunction::CGPragmaOmpSimd::emitLinearFinal(CodeGenFunction &CGF) const { + + // Check if we need to update the loop counters. + bool NeedUpdateLC = true; + ArrayRef Counters = getCountersFromLoopDirective(SimdOmp); + for (unsigned I = 0; I < getCollapsedNumberFromLoopDirective(SimdOmp); ++I) { + const DeclRefExpr *DRE = cast(Counters[I]); + if (!CGF.LocalDeclMap.lookup(DRE->getDecl())) { + NeedUpdateLC = false; + } + } + + // Emit final values of the loop-counters. + if (NeedUpdateLC) + CGF.EmitStmt(getFinalFromLoopDirective(SimdOmp)); + + // Emit final values of the linear vars. + for (ArrayRef::iterator I = SimdOmp->clauses().begin(), + E = SimdOmp->clauses().end(); + I != E; ++I) { + OMPClause *C = dyn_cast(*I); + switch (C->getClauseKind()) { + case OMPC_linear: { + OMPLinearClause *L = cast(C); + for (OMPLinearClause::varlist_const_iterator J = L->varlist_begin(), + F = L->varlist_end(); + J != F; ++J) { + + // Generate "L = LoopCount * Step + L" + const Expr *CountExpr = getLoopCount(); + llvm::Value *Index = CGF.EmitAnyExpr(CountExpr).getScalarVal(); + llvm::Value *Result = 0; + if (const Expr *StepExpr = L->getStep()) { + Result = CGF.EmitAnyExpr(StepExpr).getScalarVal(); + QualType IndexTy = CountExpr->getType(); + Result = CGF.Builder.CreateIntCast( + Result, Index->getType(), + IndexTy->hasSignedIntegerRepresentation()); + } else + Result = llvm::ConstantInt::get(Index->getType(), 1); + Result = CGF.Builder.CreateMul(Index, Result); + + // Prepare destination lvalue to store result into. + LValue LV = CGF.EmitLValue(*J); + llvm::Value *Start = + CGF.EmitLoadOfLValue(LV, (*J)->getExprLoc()).getScalarVal(); + + if (Start->getType()->isPointerTy()) { + Result = CGF.Builder.CreateGEP(Start, Result); + } else { + Result = CGF.Builder.CreateIntCast(Result, Start->getType(), false); + Result = CGF.Builder.CreateAdd( + Start, Result, "add", false, + (*J)->getType()->isSignedIntegerOrEnumerationType()); + } + CGF.EmitStoreOfScalar(Result, LV, false); + } + break; + } + default: + break; + } + } +} + +/// Generate an instructions for '#pragma omp teams' directive. +void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) { + EmitOMPDirectiveWithTeams(OMPD_teams, OMPD_unknown, S); +} + +// Generate the instructions for '#pragma omp simd' directive. +void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { + RunCleanupsScope ExecutedScope(*this); + CGPragmaOmpSimd Wrapper(&S); + EmitPragmaSimd(Wrapper); +} + +// Generate the instructions for '#pragma omp for simd' directive. +void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) { + RunCleanupsScope ExecutedScope(*this); + EmitOMPDirectiveWithLoop(OMPD_for_simd, OMPD_for_simd, S); +} + +// Generate the instructions for '#pragma omp distribute simd' directive. +void CodeGenFunction::EmitOMPDistributeSimdDirective( + const OMPDistributeSimdDirective &S) { + RunCleanupsScope ExecutedScope(*this); + EmitOMPDirectiveWithLoop(OMPD_distribute_simd, OMPD_distribute_simd, S); +} + +// Generate the instructions for '#pragma omp distribute parallel for' +// directive. +void CodeGenFunction::EmitOMPDistributeParallelForDirective( + const OMPDistributeParallelForDirective &S) { + RunCleanupsScope ExecutedScope(*this); + assert(S.getLowerBound() && "No lower bound"); + assert(S.getUpperBound() && "No upper bound"); + EmitAutoVarDecl( + *cast(cast(S.getLowerBound())->getDecl())); + EmitAutoVarDecl( + *cast(cast(S.getUpperBound())->getDecl())); + EmitOMPDirectiveWithLoop(OMPD_distribute_parallel_for, OMPD_distribute, S); +} + +// Generate the instructions for '#pragma omp distribute parallel for simd' +// directive. +void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective( + const OMPDistributeParallelForSimdDirective &S) { + RunCleanupsScope ExecutedScope(*this); + assert(S.getLowerBound() && "No lower bound"); + assert(S.getUpperBound() && "No upper bound"); + EmitAutoVarDecl( + *cast(cast(S.getLowerBound())->getDecl())); + EmitAutoVarDecl( + *cast(cast(S.getUpperBound())->getDecl())); + EmitOMPDirectiveWithLoop(OMPD_distribute_parallel_for_simd, OMPD_distribute, + S); +} + +// Generate the instructions for '#pragma omp target' directive. +void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) { + CapturedStmt *CS = cast(S.getAssociatedStmt()); + EmitStmt(CS->getCapturedStmt()); +} + +// Generate the instructions for '#pragma omp target data' directive. +void +CodeGenFunction::EmitOMPTargetDataDirective(const OMPTargetDataDirective &S) { + // TODO Need to implement proper codegen for target oriented directives. + CapturedStmt *CS = cast(S.getAssociatedStmt()); + EmitStmt(CS->getCapturedStmt()); +} + +// Generate the instructions for '#pragma omp target update' directive. +void CodeGenFunction::EmitOMPTargetUpdateDirective( + const OMPTargetUpdateDirective &S) { + // TODO Need to implement proper codegen for target oriented directives. + ; +} + +// Generate the instructions for '#pragma omp target teams' directive. +void +CodeGenFunction::EmitOMPTargetTeamsDirective(const OMPTargetTeamsDirective &S) { + EmitOMPDirectiveWithTeams(OMPD_target_teams, OMPD_target, S); +} + diff -uNr clang-3.4/lib/CodeGen/CMakeLists.txt clang/lib/CodeGen/CMakeLists.txt --- clang-3.4/lib/CodeGen/CMakeLists.txt 2013-10-30 17:53:58.000000000 -0400 +++ clang/lib/CodeGen/CMakeLists.txt 2014-05-19 19:58:57.000000000 -0400 @@ -15,6 +15,7 @@ CGBlocks.cpp CGBuiltin.cpp CGCall.cpp + CGElementalFunction.cpp CGClass.cpp CGCUDANV.cpp CGCUDARuntime.cpp @@ -24,6 +25,7 @@ CGDebugInfo.cpp CGDecl.cpp CGDeclCXX.cpp + CGDeclOpenMP.cpp CGException.cpp CGExpr.cpp CGExprAgg.cpp @@ -31,6 +33,7 @@ CGExprConstant.cpp CGExprCXX.cpp CGExprScalar.cpp + CGLoopInfo.cpp CGObjC.cpp CGObjCGNU.cpp CGObjCMac.cpp @@ -39,6 +42,7 @@ CGRecordLayoutBuilder.cpp CGRTTI.cpp CGStmt.cpp + CGStmtOpenMP.cpp CGVTables.cpp CGVTT.cpp CodeGenABITypes.cpp diff -uNr clang-3.4/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.cpp --- clang-3.4/lib/CodeGen/CodeGenFunction.cpp 2013-11-05 04:12:18.000000000 -0500 +++ clang/lib/CodeGen/CodeGenFunction.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -34,7 +34,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()), - Builder(cgm.getModule().getContext()), CapturedStmtInfo(0), + Builder(cgm.getModule().getContext(), llvm::ConstantFolder(), + CGBuilderInserterTy(this)), OpenMPRoot(0), + CapturedStmtInfo(0), SanitizePerformTypeCheck(CGM.getSanOpts().Null | CGM.getSanOpts().Alignment | CGM.getSanOpts().ObjectSize | @@ -48,8 +50,8 @@ NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXDefaultInitExprThis(0), CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0), - OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0), - TerminateHandler(0), TrapBB(0) { + OutermostConditional(0), CurLexicalScope(0), ExceptionsDisabled(false), + TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { if (!suppressNewContext) CGM.getCXXABI().getMangleContext().startNewFunction(); @@ -257,6 +259,11 @@ llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = 0; Ptr->eraseFromParent(); + if (FirstprivateInsertPt) { + Ptr = FirstprivateInsertPt; + FirstprivateInsertPt = 0; + Ptr->eraseFromParent(); + } // If someone took the address of a label but never did an indirect goto, we // made a zero entry PHI node, which is illegal, zap it now. @@ -544,6 +551,7 @@ // folded. llvm::Value *Undef = llvm::UndefValue::get(Int32Ty); AllocaInsertPt = new llvm::BitCastInst(Undef, Int32Ty, "", EntryBB); + FirstprivateInsertPt = 0; if (Builder.isNamePreserving()) AllocaInsertPt->setName("allocapt"); @@ -1389,10 +1397,14 @@ break; case Type::Typedef: + type = cast(ty)->desugar(); + break; case Type::Decltype: + type = cast(ty)->desugar(); + break; case Type::Auto: - // Stop walking: nothing to do. - return; + type = cast(ty)->getDeducedType(); + break; case Type::TypeOfExpr: // Stop walking: emit typeof expression. @@ -1403,7 +1415,7 @@ type = cast(ty)->getValueType(); break; } - } while (type->isVariablyModifiedType()); + } while (!type.isNull() && type->isVariablyModifiedType()); } llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { @@ -1495,3 +1507,36 @@ } CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { } + +void +CodeGenFunction::InsertHelper(llvm::Instruction *I, + const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const { + LoopStack.InsertHelper(I); +} + +template +void CGBuilderInserter:: + InsertHelper(llvm::Instruction *I, + const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const { + llvm::IRBuilderDefaultInserter::InsertHelper(I, Name, BB, + InsertPt); + if (CGF) + CGF->InsertHelper(I, Name, BB, InsertPt); +} +#ifdef NDEBUG +template void CGBuilderInserter:: + InsertHelper(llvm::Instruction *I, + const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const; +#else +template void CGBuilderInserter:: + InsertHelper(llvm::Instruction *I, + const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const; +#endif diff -uNr clang-3.4/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenFunction.h --- clang-3.4/lib/CodeGen/CodeGenFunction.h 2013-11-15 12:24:45.000000000 -0500 +++ clang/lib/CodeGen/CodeGenFunction.h 2014-06-09 10:05:34.000000000 -0400 @@ -16,12 +16,15 @@ #include "CGBuilder.h" #include "CGDebugInfo.h" +#include "CGLoopInfo.h" #include "CGValue.h" #include "EHScopeStack.h" #include "CodeGenModule.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/Type.h" #include "clang/Basic/ABI.h" #include "clang/Basic/CapturedStmt.h" @@ -128,13 +131,24 @@ const TargetInfo &Target; typedef std::pair ComplexPairTy; + LoopInfoStack LoopStack; CGBuilderTy Builder; + /// CGBuilder insert helper. This function is called after an instruction is + /// created using Builder. + void InsertHelper(llvm::Instruction *I, + const llvm::Twine &Name, + llvm::BasicBlock *BB, + llvm::BasicBlock::iterator InsertPt) const; + /// CurFuncDecl - Holds the Decl for the current outermost /// non-closure context. const Decl *CurFuncDecl; /// CurCodeDecl - This is the inner-most code context, which includes blocks. const Decl *CurCodeDecl; + /// Root CodeGenFunction for OpenMP context in which current CodeGenFunction + /// was created. + CodeGenFunction *OpenMPRoot; const CGFunctionInfo *CurFnInfo; QualType FnRetTy; llvm::Function *CurFn; @@ -156,6 +170,7 @@ /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. llvm::AssertingVH AllocaInsertPt; + llvm::AssertingVH FirstprivateInsertPt; /// \brief API for captured statement code generation. class CGCapturedStmtInfo { @@ -200,6 +215,11 @@ /// \brief Get the name of the capture helper. virtual StringRef getHelperName() const { return "__captured_stmt"; } + static bool classof(const CGCapturedStmtInfo *) { return true; } + + virtual void addCachedVar(const VarDecl *VD, llvm::Value *Addr) { } + virtual llvm::Value *getCachedVar(const VarDecl *VD) { return 0; } + private: /// \brief The kind of captured statement being generated. CapturedRegionKind Kind; @@ -214,8 +234,165 @@ /// \brief Captured 'this' type. FieldDecl *CXXThisFieldDecl; }; + /// \brief API for captured statement code generation for OpenMP regions. + class CGOpenMPCapturedStmtInfo : public CGCapturedStmtInfo { + //CodeGenModule &CGM; + public: + explicit CGOpenMPCapturedStmtInfo(llvm::Value* Context, + const CapturedStmt &S, + CodeGenModule &CGM, + CapturedRegionKind K = CR_Default) + : CGCapturedStmtInfo(S, K)/*, CGM(CGM)*/ { setContextValue(Context); } + + virtual ~CGOpenMPCapturedStmtInfo() { }; + + virtual void addCachedVar(const VarDecl *VD, llvm::Value *Addr) { CachedVars[VD] = Addr; } + virtual llvm::Value *getCachedVar(const VarDecl *VD) { return CachedVars[VD]; } + private: + + /// \brief Keep the map between VarDecl and FieldDecl. + llvm::SmallDenseMap CachedVars; + + }; + CGCapturedStmtInfo *CapturedStmtInfo; + class CGSIMDForStmtInfo; // Defined below, after simd wrappers. + + /// \brief Wrapper for "#pragma simd" and "#pragma omp simd". + class CGPragmaSimdWrapper { + public: + // \brief Helper for EmitPragmaSimd - process 'safelen' clause. + virtual bool emitSafelen(CodeGenFunction *CGF) const = 0; + + // \brief Emit updates of local variables from clauses + // and loop counters in the beginning of __simd_helper. + virtual bool walkLocalVariablesToEmit( + CodeGenFunction *CGF, + CGSIMDForStmtInfo *Info) const = 0; + + /// \brief Emit the SIMD loop initalization, loop stride expression + /// as loop invariants, and cache those values. + virtual void emitInit(CodeGenFunction &CGF, + llvm::Value *&LoopIndex, llvm::Value *&LoopCount) = 0; + + /// \brief Emit the loop increment. + virtual void emitIncrement(CodeGenFunction &CGF, + llvm::Value *IndexVar) const = 0; + + // \brief Emit final values of loop counters and linear vars. + virtual void emitLinearFinal(CodeGenFunction &CGF) const = 0; + + /// \brief Get the beginning location of for stmt. + virtual SourceLocation getForLoc() const = 0; + + /// \brief Get the source range. + virtual SourceRange getSourceRange() const = 0; + + /// \brief Retrieve the initialization expression. + virtual const Stmt *getInit() const = 0; + + /// \brief Retrieve the loop condition expression. + virtual const Expr *getCond() const = 0; + + /// \brief Retrieve the loop body. + virtual const CapturedStmt *getAssociatedStmt() const = 0; + + /// \brief Retrieve the loop count expression. + virtual const Expr *getLoopCount() const = 0; + + /// \brief Extract the loop body from the collapsed loop nest. + /// Useful for openmp (it is noop for SIMDForStmt). + virtual Stmt *extractLoopBody(Stmt *S) const = 0; + + /// \brief Return true if it is openmp pragma. + virtual bool isOmp() const = 0; + + /// \brief Get the wrapped SIMDForStmt or OMPSimdDirective. + virtual const Stmt *getStmt() const = 0; + + virtual ~CGPragmaSimdWrapper() { }; + }; + + + class CGPragmaOmpSimd : public CGPragmaSimdWrapper { + public: + CGPragmaOmpSimd(const OMPExecutableDirective *S) + : SimdOmp(S) {} + + virtual bool emitSafelen(CodeGenFunction *CGF) const LLVM_OVERRIDE; + virtual bool walkLocalVariablesToEmit( + CodeGenFunction *CGF, + CGSIMDForStmtInfo *Info) const LLVM_OVERRIDE; + + virtual void emitInit(CodeGenFunction &CGF, + llvm::Value *&LoopIndex, llvm::Value *&LoopCount) LLVM_OVERRIDE; + + virtual void emitIncrement(CodeGenFunction &CGF, + llvm::Value *IndexVar) const LLVM_OVERRIDE { } + + virtual void emitLinearFinal(CodeGenFunction &CGF) const LLVM_OVERRIDE; + + virtual SourceLocation getForLoc() const LLVM_OVERRIDE; + virtual SourceRange getSourceRange() const LLVM_OVERRIDE; + virtual const Stmt *getInit() const LLVM_OVERRIDE; + virtual const Expr *getCond() const LLVM_OVERRIDE; + virtual const CapturedStmt *getAssociatedStmt() const LLVM_OVERRIDE; + virtual const Expr *getLoopCount() const LLVM_OVERRIDE; + virtual Stmt *extractLoopBody(Stmt *S) const LLVM_OVERRIDE; + virtual bool isOmp() const LLVM_OVERRIDE { return true; } + virtual const Stmt *getStmt() const LLVM_OVERRIDE { return SimdOmp; } + llvm::ConstantInt *emitClauseTail(CodeGenFunction *CGF, Expr *E) const; + virtual ~CGPragmaOmpSimd() LLVM_OVERRIDE { } + + private: + const OMPExecutableDirective *SimdOmp; + }; + + /// \brief API for SIMD for statement code generation. + /// This class is intended to provide an interface to CG to work in the + /// same manner with "#pragma simd" and "#pragma omp simd", using wrapper + /// (CGPragmaSimdWrapper) for addressing any differences between them. + class CGSIMDForStmtInfo : public CGCapturedStmtInfo { + public: + CGSIMDForStmtInfo(const CGPragmaSimdWrapper &Wr, llvm::MDNode *LoopID, + bool LoopParallel) + : CGCapturedStmtInfo(*(Wr.getAssociatedStmt()), CR_SIMDFor), + Wrapper(Wr), LoopID(LoopID), LoopParallel(LoopParallel) { } + + virtual StringRef getHelperName() const { return "__simd_for_helper"; } + + virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) { + CGF.EmitSIMDForHelperBody(Wrapper.extractLoopBody(S)); + } + + llvm::MDNode *getLoopID() const { return LoopID; } + bool getLoopParallel() const { return LoopParallel; } + + + bool isOmp() const { return Wrapper.isOmp(); } + const Stmt *getStmt() const { return Wrapper.getStmt(); } + + // \brief Emit updates of local variables from clauses + // and loop counters in the beginning of __simd_helper. + bool walkLocalVariablesToEmit(CodeGenFunction *CGF) { + return Wrapper.walkLocalVariablesToEmit(CGF, this); + } + + static bool classof(const CGSIMDForStmtInfo *) { return true; } + static bool classof(const CGCapturedStmtInfo *I) { + return I->getKind() == CR_SIMDFor; + } + private: + /// \brief Wrapper around SIMDForStmt/OMPSimdDirective. + const CGPragmaSimdWrapper &Wrapper; + /// \brief The loop id metadata. + llvm::MDNode *LoopID; + /// \brief Is loop parallel. + bool LoopParallel; + + }; + /// BoundsChecking - Emit run-time bounds checks. Higher values mean /// potentially higher performance penalties. unsigned char BoundsChecking; @@ -826,6 +1003,7 @@ JumpDest ContinueBlock; }; SmallVector BreakContinueStack; + llvm::DenseMap OMPCancelMap; /// SwitchInsn - This is nearest current switch instruction. It is null if /// current context is not in a switch. @@ -862,6 +1040,24 @@ SourceLocation LastStopPoint; public: + /// This class is used for instantiation of local variables, but restores + /// LocalDeclMap state after instantiation. If Empty is true, the LocalDeclMap + /// is cleared completely and then restored to original state upon + /// destruction. + class LocalVarsDeclGuard { + CodeGenFunction &CGF; + DeclMapTy LocalDeclMap; + public: + LocalVarsDeclGuard(CodeGenFunction &CGF, bool Empty = false) + : CGF(CGF), LocalDeclMap() { + if (Empty) { + LocalDeclMap.swap(CGF.LocalDeclMap); + } else { + LocalDeclMap.copyFrom(CGF.LocalDeclMap); + } + } + ~LocalVarsDeclGuard() { CGF.LocalDeclMap.swap(LocalDeclMap); } + }; /// A scope within which we are constructing the fields of an object which /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use /// if we need to evaluate a CXXDefaultInitExpr within the evaluation. @@ -921,6 +1117,9 @@ /// The current lexical scope. LexicalScope *CurLexicalScope; + /// ExceptionsDisabled - Whether exceptions are currently disabled. + bool ExceptionsDisabled; + /// The current source location that should be used for exception /// handling code. SourceLocation CurEHLocation; @@ -944,7 +1143,7 @@ /// "work_group_size_hint", and three 32-bit integers X, Y and Z. /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string /// "reqd_work_group_size", and three 32-bit integers X, Y and Z. - void EmitOpenCLKernelMetadata(const FunctionDecl *FD, + void EmitOpenCLKernelMetadata(const FunctionDecl *FD, llvm::Function *Fn); public: @@ -992,6 +1191,9 @@ return getInvokeDestImpl(); } + void disableExceptions() { ExceptionsDisabled = true; } + void enableExceptions() { ExceptionsDisabled = false; } + const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } @@ -1168,7 +1370,7 @@ void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type, FunctionArgList &Args); - void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init, + void EmitInitializerForField(const FieldDecl *Field, LValue LHS, Expr *Init, ArrayRef ArrayIndexes); /// InitializeVTablePointer - Initialize the vtable pointer of the given @@ -1848,11 +2050,153 @@ void EmitSEHTryStmt(const SEHTryStmt &S); void EmitCXXForRangeStmt(const CXXForRangeStmt &S); + LValue InitCapturedStruct(const CapturedStmt &S); + void InitOpenMPFunction(llvm::Value *Context, const CapturedStmt &S); llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K); llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD, const RecordDecl *RD, SourceLocation Loc); + void EmitPragmaSimd(CGPragmaSimdWrapper &W); + llvm::Function *EmitSimdFunction(CGPragmaSimdWrapper &W); + + void EmitSIMDForHelperCall(llvm::Function *BodyFunc, + LValue CapStruct, llvm::Value *LoopIndex, + bool IsLastIter); + void EmitSIMDForHelperBody(const Stmt *S); + + + llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S); + LValue GetCapturedField(const VarDecl *VD); + void EmitUniversalStore(llvm::Value *Dst, llvm::Value *Src, QualType ExprTy); + void EmitUniversalStore(LValue Dst, llvm::Value *Src, QualType ExprTy); +public: + void EmitOMPParallelDirective(const OMPParallelDirective &S); + void EmitOMPParallelForDirective(const OMPParallelForDirective &S); + void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S); + void EmitOMPForDirective(const OMPForDirective &S); + void EmitOMPSimdDirective(const OMPSimdDirective &S); + void EmitOMPForSimdDirective(const OMPForSimdDirective &S); + void EmitOMPDistributeSimdDirective(const OMPDistributeSimdDirective &S); + void EmitOMPDistributeParallelForDirective( + const OMPDistributeParallelForDirective &S); + void EmitOMPDistributeParallelForSimdDirective( + const OMPDistributeParallelForSimdDirective &S); + void EmitOMPTaskDirective(const OMPTaskDirective &S); + void EmitOMPSectionsDirective(const OMPSectionsDirective &S); + void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S); + void EmitOMPSectionDirective(const OMPSectionDirective &S); + void EmitOMPTeamsDirective(const OMPTeamsDirective &S); + void EmitOMPDistributeDirective(const OMPDistributeDirective &S); + void EmitOMPTargetDirective(const OMPTargetDirective &S); + void EmitOMPTargetDataDirective(const OMPTargetDataDirective &S); + void EmitOMPTargetUpdateDirective(const OMPTargetUpdateDirective &S); + void EmitOMPTargetTeamsDirective(const OMPTargetTeamsDirective &S); + void EmitInitOMPClause(const OMPClause &C, + const OMPExecutableDirective &S); + void EmitAfterInitOMPClause(const OMPClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPClause(const OMPClause &C, + const OMPExecutableDirective &S); + void EmitPostOMPClause(const OMPClause &C, const OMPExecutableDirective &S); + void EmitCloseOMPClause(const OMPClause &C, + const OMPExecutableDirective &S); + void EmitFinalOMPClause(const OMPClause &C, const OMPExecutableDirective &S); + void EmitInitOMPNumThreadsClause(const OMPNumThreadsClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPNumTeamsClause(const OMPNumTeamsClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPThreadLimitClause(const OMPThreadLimitClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPProcBindClause(const OMPProcBindClause &C, + const OMPExecutableDirective &S); + void EmitAfterInitOMPIfClause(const OMPIfClause &C, + const OMPExecutableDirective &S); + void EmitFinalOMPIfClause(const OMPIfClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPNowaitClause(const OMPNowaitClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPOrderedClause(const OMPOrderedClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPUntiedClause(const OMPUntiedClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPFinalClause(const OMPFinalClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPMergeableClause(const OMPMergeableClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPScheduleClause(const OMPScheduleClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPDistScheduleClause(const OMPDistScheduleClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPCopyinClause(const OMPCopyinClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPPrivateClause(const OMPPrivateClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPFirstPrivateClause(const OMPFirstPrivateClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPLastPrivateClause(const OMPLastPrivateClause &C, + const OMPExecutableDirective &S); + void EmitPostOMPLastPrivateClause(const OMPLastPrivateClause &C, + const OMPExecutableDirective &S); + void EmitCloseOMPLastPrivateClause(const OMPLastPrivateClause &C, + const OMPExecutableDirective &S); + void EmitInitOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S); + void EmitPreOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S); + void EmitPostOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S); + void EmitCloseOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S); + void EmitFinalOMPReductionClause(const OMPReductionClause &C, + const OMPExecutableDirective &S); + void EmitOMPBarrierDirective(const OMPBarrierDirective &S); + void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S); + void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S); + void EmitOMPFlushDirective(const OMPFlushDirective &S); + void EmitOMPCancelDirective(const OMPCancelDirective &S); + void EmitOMPCancellationPointDirective( + const OMPCancellationPointDirective &S); + void EmitOMPAtomicDirective(const OMPAtomicDirective &S); + void EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S); + void EmitOMPMasterDirective(const OMPMasterDirective &S); + void EmitOMPSingleDirective(const OMPSingleDirective &S); + void EmitOMPCriticalDirective(const OMPCriticalDirective &S); + void EmitOMPOrderedDirective(const OMPOrderedDirective &S); + llvm::CallInst *EmitOMPCallWithLocAndTidHelper(llvm::Value *F, + SourceLocation L, unsigned Flags = 0x02); + void EmitOMPConditionalIfHelper(const OMPExecutableDirective &S, + llvm::Value *Func, SourceLocation Loc, + llvm::Value *EndFunc, SourceLocation EndLoc, + bool HasClauses, llvm::AllocaInst *DidIt, + const std::string &NameStr); + void EmitOMPCapturedBodyHelper(const OMPExecutableDirective &S); + void EmitCopyAssignment( + ArrayRef::iterator I, + ArrayRef::iterator AssignIter, + ArrayRef::iterator VarIter1, + ArrayRef::iterator VarIter2, + llvm::Value *Dst, + llvm::Value *Src); + void EmitOMPDirectiveWithLoop( + OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S); + void EmitOMPSectionsDirective( + OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S); + void EmitOMPDirectiveWithParallel( + OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S); + void EmitOMPDirectiveWithTeams(OpenMPDirectiveKind DKind, + OpenMPDirectiveKind SKind, + const OMPExecutableDirective &S); + void EmitOMPBarrier(SourceLocation L, unsigned Flags); + void EmitOMPCancelBarrier(SourceLocation L, unsigned Flags, + bool IgnoreResult = false); + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// diff -uNr clang-3.4/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/CodeGenModule.cpp --- clang-3.4/lib/CodeGen/CodeGenModule.cpp 2013-12-09 16:04:35.000000000 -0500 +++ clang/lib/CodeGen/CodeGenModule.cpp 2014-05-27 10:51:22.000000000 -0400 @@ -85,7 +85,8 @@ SanitizerBlacklist( llvm::SpecialCaseList::createOrDie(CGO.SanitizerBlacklistFile)), SanOpts(SanitizerBlacklist->isIn(M) ? SanitizerOptions::Disabled - : LangOpts.Sanitize) { + : LangOpts.Sanitize), + OpenMPSupport(*this) { // Initialize the type cache. llvm::LLVMContext &LLVMContext = M.getContext(); @@ -1028,6 +1029,13 @@ // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D); } + + // Emit deferred openmp directives + while (!DeferredOMP.empty()) { + const OMPDeclareSimdDecl *DSimd = DeferredOMP.back(); + DeferredOMP.pop_back(); + EmitOMPDeclareSimd(DSimd); + } } void CodeGenModule::EmitGlobalAnnotations() { @@ -1362,9 +1370,21 @@ return EmitGlobalFunctionDefinition(GD); } - if (const VarDecl *VD = dyn_cast(D)) - return EmitGlobalVarDefinition(VD); - + if (const VarDecl *VD = dyn_cast(D)) { + EmitGlobalVarDefinition(VD); + for (VarDecl::redecl_iterator I = VD->redecls_begin(), + E = VD->redecls_end(); + I != E; ++I) { + if (*I) + if (const Expr * TPE = OpenMPSupport.hasThreadPrivateVar(*I)) { + OpenMPSupport.addThreadPrivateVar(VD, TPE); + EmitOMPThreadPrivate(VD, TPE); + break; + } + } + return; + } + llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } @@ -2090,6 +2110,20 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const FunctionDecl *D = cast(GD.getDecl()); + // If a method is deffered then defer its omp directive too. + if (const CXXMethodDecl *MD = dyn_cast_or_null(D)) { + const CXXRecordDecl *Parent = MD->getParent(); + for (DeclContext::decl_iterator DI = Parent->decls_begin(), + DE = Parent->decls_end(); + DI != DE; ++DI) { + if (const OMPDeclareSimdDecl *DSimd = + dyn_cast_or_null(*DI)) { + if (dyn_cast_or_null(DSimd->getFunction()) == D) { + DeferredOMP.push_back(DSimd); + } + } + } + } // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); @@ -3049,6 +3083,18 @@ ImportedModules.insert(Import->getImportedModule()); break; } + case Decl::OMPThreadPrivate: + EmitOMPThreadPrivate(cast(D)); + break; + case Decl::OMPDeclareReduction: + EmitOMPDeclareReduction(cast(D)); + break; + case Decl::OMPDeclareSimd: + EmitOMPDeclareSimd(cast(D)); + break; + case Decl::OMPDeclareTarget: + EmitOMPDeclareSimd(cast(D)); + break; default: // Make sure we handled everything we should, every other kind is a @@ -3200,3 +3246,355 @@ return llvm::ConstantStruct::getAnon(Fields); } + +CodeGenModule::OpenMPSupportStackTy::OMPStackElemTy::OMPStackElemTy(CodeGenModule &CGM) + : PrivateVars(), IfEnd(0), ReductionFunc(0), CGM(CGM), RedCGF(0), ReductionTypes(), + ReductionMap(), ReductionRec(0), ReductionRecVar(0), RedArg1(0), RedArg2(0), + ReduceSwitch(0), BB1(0), BB1IP(0), BB2(0), BB2IP(0), LockVar(0), + LastprivateBB(0), LastprivateIP(0), LastprivateEndBB(0), LastIterVar(0), TaskFlags(0), + PTaskTValue(0), PTask(0), UntiedPartIdAddr(0), UntiedCounter(0), UntiedSwitch(0), + UntiedEnd(0), ParentCGF(0), + NoWait(true), Mergeable(false), Schedule(0), ChunkSize(0), NewTask(false), + Untied(false), HasLastPrivate(false), + TaskPrivateTy(0), TaskPrivateQTy(), TaskPrivateBase(0), NumTeams(0), ThreadLimit(0), + WaitDepsArgs(0) { } + +CodeGenFunction &CodeGenModule::OpenMPSupportStackTy::getCGFForReductionFunction() { + if (!OpenMPStack.back().RedCGF) { + OpenMPStack.back().RedCGF = new CodeGenFunction(CGM, true); + OpenMPStack.back().RedCGF->CurFn = 0; + } + return *OpenMPStack.back().RedCGF; +} + +CodeGenModule::OpenMPSupportStackTy::OMPStackElemTy::~OMPStackElemTy() { + if (RedCGF) delete RedCGF; + RedCGF = 0; +} + +void CodeGenModule::OpenMPSupportStackTy::endOpenMPRegion() { + assert(!OpenMPStack.empty() && + "OpenMP private variables region is not started."); + assert(!OpenMPStack.back().IfEnd && "If not closed."); + OpenMPStack.pop_back(); +} + +void CodeGenModule::OpenMPSupportStackTy::registerReductionVar( + const VarDecl *VD, + llvm::Type *Type) { + OpenMPStack.back().ReductionMap[VD] = + OpenMPStack.back().ReductionTypes.size(); + OpenMPStack.back().ReductionTypes.push_back(Type); +} + +llvm::Value * +CodeGenModule::OpenMPSupportStackTy::getReductionRecVar(CodeGenFunction &CGF) { + if (!OpenMPStack.back().ReductionRecVar) { + OpenMPStack.back().ReductionRec = + llvm::StructType::get(CGM.getLLVMContext(), + OpenMPStack.back().ReductionTypes); + llvm::AllocaInst *AI = CGF.CreateTempAlloca(OpenMPStack.back().ReductionRec, + "reduction.rec.var"); + AI->setAlignment(CGF.CGM.PointerAlignInBytes); + OpenMPStack.back().ReductionRecVar = AI; + } + return OpenMPStack.back().ReductionRecVar; +} + +llvm::Type * +CodeGenModule::OpenMPSupportStackTy::getReductionRec() { + assert(OpenMPStack.back().ReductionRec && + "Type is not defined."); + return OpenMPStack.back().ReductionRec; +} + +void CodeGenModule::OpenMPSupportStackTy::getReductionFunctionArgs( + llvm::Value *&Arg1, llvm::Value *&Arg2) { + assert(OpenMPStack.back().RedCGF && OpenMPStack.back().RedCGF->CurFn && + "Reduction function is closed."); + if (!OpenMPStack.back().RedArg1 && !OpenMPStack.back().RedArg2) { + CodeGenFunction &CGF = *OpenMPStack.back().RedCGF; + llvm::Value *Arg1 = &CGF.CurFn->getArgumentList().front(); + llvm::Value *Arg2 = &CGF.CurFn->getArgumentList().back(); + llvm::Type *PtrTy = OpenMPStack.back().ReductionRec->getPointerTo(); + OpenMPStack.back().RedArg1 = CGF.Builder.CreateBitCast(Arg1, PtrTy, + "reduction.lhs"); + OpenMPStack.back().RedArg2 = CGF.Builder.CreateBitCast(Arg2, PtrTy, + "reduction.rhs"); + } + Arg1 = OpenMPStack.back().RedArg1; + Arg2 = OpenMPStack.back().RedArg2; +} + +unsigned +CodeGenModule::OpenMPSupportStackTy::getReductionVarIdx(const VarDecl *VD) { + assert (OpenMPStack.back().ReductionMap.count(VD) > 0 && "No reduction var."); + return OpenMPStack.back().ReductionMap[VD]; +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getReductionSwitch() { + return OpenMPStack.back().ReduceSwitch; +} + +void CodeGenModule::OpenMPSupportStackTy::setReductionSwitch( + llvm::Value *Switch) { + OpenMPStack.back().ReduceSwitch = Switch; +} + +void CodeGenModule::OpenMPSupportStackTy::setReductionIPs( + llvm::BasicBlock *BB1, + llvm::Instruction *IP1, + llvm::BasicBlock *BB2, + llvm::Instruction *IP2) { + OpenMPStack.back().BB1IP = IP1; + OpenMPStack.back().BB2IP = IP2; + OpenMPStack.back().BB1 = BB1; + OpenMPStack.back().BB2 = BB2; +} + +void CodeGenModule::OpenMPSupportStackTy::getReductionIPs( + llvm::BasicBlock *&BB1, + llvm::Instruction *&IP1, + llvm::BasicBlock *&BB2, + llvm::Instruction *&IP2) { + IP1 = OpenMPStack.back().BB1IP; + IP2 = OpenMPStack.back().BB2IP; + BB1 = OpenMPStack.back().BB1; + BB2 = OpenMPStack.back().BB2; +} + +unsigned +CodeGenModule::OpenMPSupportStackTy::getNumberOfReductionVars() { + return OpenMPStack.back().ReductionTypes.size(); +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getReductionLockVar() { + return OpenMPStack.back().LockVar; +} + +void CodeGenModule::OpenMPSupportStackTy::setReductionLockVar(llvm::Value *Var) { + OpenMPStack.back().LockVar = Var; +} + +void CodeGenModule::OpenMPSupportStackTy::setNoWait(bool Flag) { + OpenMPStack.back().NoWait = Flag; +} + +bool CodeGenModule::OpenMPSupportStackTy::getNoWait() { + return OpenMPStack.back().NoWait; +} + +void CodeGenModule::OpenMPSupportStackTy::setScheduleChunkSize( + int Sched, + const Expr *Size) { + OpenMPStack.back().Schedule = Sched; + OpenMPStack.back().ChunkSize = Size; +} + +void CodeGenModule::OpenMPSupportStackTy::getScheduleChunkSize( + int &Sched, + const Expr *&Size) { + Sched = OpenMPStack.back().Schedule; + Size = OpenMPStack.back().ChunkSize; +} + +void CodeGenModule::OpenMPSupportStackTy::setMergeable(bool Flag) { + OpenMPStack.back().Mergeable = Flag; +} + +bool CodeGenModule::OpenMPSupportStackTy::getMergeable() { + return OpenMPStack.back().Mergeable; +} + +void CodeGenModule::OpenMPSupportStackTy::setOrdered(bool Flag) { + OpenMPStack.back().Ordered = Flag; +} + +bool CodeGenModule::OpenMPSupportStackTy::getOrdered() { + return OpenMPStack.back().Ordered; +} + +void CodeGenModule::OpenMPSupportStackTy::setHasLastPrivate(bool Flag) { + OpenMPStack.back().HasLastPrivate = Flag; +} + +bool CodeGenModule::OpenMPSupportStackTy::hasLastPrivate() { + return OpenMPStack.back().HasLastPrivate; +} + +void CodeGenModule::OpenMPSupportStackTy::setLastprivateIP( + llvm::BasicBlock *BB, + llvm::Instruction *IP, + llvm::BasicBlock *EndBB) { + OpenMPStack.back().LastprivateIP = IP; + OpenMPStack.back().LastprivateBB = BB; + OpenMPStack.back().LastprivateEndBB = EndBB; +} + +void CodeGenModule::OpenMPSupportStackTy::getLastprivateIP( + llvm::BasicBlock *&BB, + llvm::Instruction *&IP, + llvm::BasicBlock *&EndBB) { + IP = OpenMPStack.back().LastprivateIP; + BB = OpenMPStack.back().LastprivateBB; + EndBB = OpenMPStack.back().LastprivateEndBB; +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getLastIterVar() { + return OpenMPStack.back().LastIterVar; +} + +void CodeGenModule::OpenMPSupportStackTy::setLastIterVar(llvm::Value *Var) { + OpenMPStack.back().LastIterVar = Var; +} + +bool CodeGenModule::OpenMPSupportStackTy::getUntied() { + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (I->NewTask) { + return I->Untied; + } + } + return false; +} + +bool CodeGenModule::OpenMPSupportStackTy::getParentUntied() { + bool FirstTaskFound = false; + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (FirstTaskFound && I->NewTask) { + return I->Untied; + } + FirstTaskFound = FirstTaskFound || I->NewTask; + } + return false; +} + +void CodeGenModule::OpenMPSupportStackTy::setUntied(bool Flag) { + OpenMPStack.back().Untied = Flag; +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getTaskFlags() { + return OpenMPStack.back().TaskFlags; +} + +void CodeGenModule::OpenMPSupportStackTy::setTaskFlags(llvm::Value *Flags) { + OpenMPStack.back().TaskFlags = Flags; +} + +void CodeGenModule::OpenMPSupportStackTy::setPTask(llvm::Value *Task, llvm::Value *TaskT, llvm::Type *PTy, QualType PQTy, llvm::Value *PB) { + OpenMPStack.back().PTask = Task; + OpenMPStack.back().PTaskTValue = TaskT; + OpenMPStack.back().TaskPrivateTy = PTy; + OpenMPStack.back().TaskPrivateQTy = PQTy; + OpenMPStack.back().TaskPrivateBase = PB; +} + +void CodeGenModule::OpenMPSupportStackTy::getPTask(llvm::Value *&Task, llvm::Value *&TaskT, llvm::Type *&PTy, QualType &PQTy, llvm::Value *&PB) { + Task = OpenMPStack.back().PTask; + TaskT = OpenMPStack.back().PTaskTValue; + PTy = OpenMPStack.back().TaskPrivateTy; + PQTy = OpenMPStack.back().TaskPrivateQTy; + PB = OpenMPStack.back().TaskPrivateBase; +} + +llvm::DenseMap &CodeGenModule::OpenMPSupportStackTy::getTaskFields() { + return OpenMPStack.back().TaskFields; +} + +void CodeGenModule::OpenMPSupportStackTy::setUntiedData(llvm::Value *UntiedPartIdAddr, llvm::Value *UntiedSwitch, + llvm::BasicBlock *UntiedEnd, unsigned UntiedCounter, + CodeGenFunction *CGF) { + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (I->NewTask) { + I->UntiedPartIdAddr = UntiedPartIdAddr; + I->UntiedSwitch = UntiedSwitch; + I->UntiedEnd = UntiedEnd; + I->UntiedCounter = UntiedCounter; + I->ParentCGF = CGF; + return; + } + } +} + +void CodeGenModule::OpenMPSupportStackTy::getUntiedData(llvm::Value *&UntiedPartIdAddr, llvm::Value *&UntiedSwitch, + llvm::BasicBlock *&UntiedEnd, unsigned &UntiedCounter) { + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (I->NewTask) { + UntiedPartIdAddr = I->UntiedPartIdAddr; + UntiedSwitch = I->UntiedSwitch; + UntiedEnd = I->UntiedEnd; + UntiedCounter = I->UntiedCounter; + return; + } + } +} + +void CodeGenModule::OpenMPSupportStackTy::setParentUntiedData(llvm::Value *UntiedPartIdAddr, llvm::Value *UntiedSwitch, + llvm::BasicBlock *UntiedEnd, unsigned UntiedCounter, + CodeGenFunction *CGF) { + bool FirstTaskFound = false; + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (FirstTaskFound && I->NewTask) { + I->UntiedPartIdAddr = UntiedPartIdAddr; + I->UntiedSwitch = UntiedSwitch; + I->UntiedEnd = UntiedEnd; + I->UntiedCounter = UntiedCounter; + I->ParentCGF = CGF; + return; + } + FirstTaskFound = FirstTaskFound || I->NewTask; + } +} + +void CodeGenModule::OpenMPSupportStackTy::getParentUntiedData(llvm::Value *&UntiedPartIdAddr, llvm::Value *&UntiedSwitch, + llvm::BasicBlock *&UntiedEnd, unsigned &UntiedCounter, + CodeGenFunction *&CGF) { + bool FirstTaskFound = false; + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (FirstTaskFound && I->NewTask) { + UntiedPartIdAddr = I->UntiedPartIdAddr; + UntiedSwitch = I->UntiedSwitch; + UntiedEnd = I->UntiedEnd; + UntiedCounter = I->UntiedCounter; + CGF = I->ParentCGF; + return; + } + FirstTaskFound = FirstTaskFound || I->NewTask; + } +} + +void CodeGenModule::OpenMPSupportStackTy::setNumTeams(llvm::Value *Num) { + OpenMPStack.back().NumTeams = Num; +} + +void CodeGenModule::OpenMPSupportStackTy::setThreadLimit(llvm::Value *Num) { + OpenMPStack.back().ThreadLimit = Num; +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getNumTeams() { + return OpenMPStack.back().NumTeams; +} + +llvm::Value *CodeGenModule::OpenMPSupportStackTy::getThreadLimit() { + return OpenMPStack.back().ThreadLimit; +} + +void CodeGenModule::OpenMPSupportStackTy::setWaitDepsArgs(llvm::Value **Args) { + OpenMPStack.back().WaitDepsArgs = Args; +} + +llvm::Value **CodeGenModule::OpenMPSupportStackTy::getWaitDepsArgs() { + return OpenMPStack.back().WaitDepsArgs; +} + diff -uNr clang-3.4/lib/CodeGen/CodeGenModule.h clang/lib/CodeGen/CodeGenModule.h --- clang-3.4/lib/CodeGen/CodeGenModule.h 2013-11-07 20:09:22.000000000 -0500 +++ clang/lib/CodeGen/CodeGenModule.h 2014-05-27 10:51:22.000000000 -0400 @@ -259,6 +259,25 @@ llvm::MDNode *NoObjCARCExceptionsMetadata; RREntrypoints *RRData; + struct ElementalVariantInfo { + /// \brief The CodeGen infomation of this function. + const CGFunctionInfo *FnInfo; + /// \brief The elemental function declaration. + const FunctionDecl *FD; + /// \brief The LLVM function of this declaration. + llvm::Function *Fn; + /// \brief The metadata describing this elemental function. + llvm::MDNode *KernelMD; + + ElementalVariantInfo(const CGFunctionInfo *FnInfo, const FunctionDecl *FD, + llvm::Function *Fn, llvm::MDNode *KernelMD) + : FnInfo(FnInfo), FD(FD), Fn(Fn), KernelMD(KernelMD) { } + }; + + /// ElementalVariantToEmit - This contains all Cilk Plus elemental function + /// variants to be emitted. + llvm::SmallVector ElementalVariantToEmit; + // WeakRefReferences - A set of references that have only been seen via // a weakref so far. This is used to remove the weak of the reference if we // ever see a direct reference or a definition. @@ -275,6 +294,8 @@ /// is done. std::vector DeferredDeclsToEmit; + /// DeferredOMP -- deferred OpenMP directives (e.g. #omp declare simd). + std::vector DeferredOMP; /// List of alias we have emitted. Used to make sure that what they point to /// is defined once we get to the end of the of the translation unit. std::vector Aliases; @@ -385,7 +406,7 @@ /// \brief The type used to describe the state of a fast enumeration in /// Objective-C's for..in loop. QualType ObjCFastEnumerationStateType; - + /// @} /// Lazily create the Objective-C runtime @@ -459,6 +480,75 @@ return *CUDARuntime; } + // A common data structure to represent vector function attributes in + // cilk vector functions and 'omp declare simd' functions. + struct CilkElementalGroup { + typedef SmallVector VecLengthForVector; + typedef SmallVector VecLengthVector; + // Masking: 0-nomask/notinbranch, 1-mask/inbranch + typedef SmallVector MaskVector; + typedef std::map > LinearMap; + typedef std::map AlignedMap; + typedef std::set UniformSet; + + VecLengthVector VecLength; + VecLengthForVector VecLengthFor; + LinearMap LinearParms; + AlignedMap AlignedParms; + UniformSet UniformParms; + MaskVector Mask; + + bool getUniformAttr(std::string Name) const { + return UniformParms.count(Name) != 0; + } + + bool getLinearAttr(std::string Name, std::pair *out_step) const { + const LinearMap::const_iterator it = LinearParms.find(Name); + if (it == LinearParms.end()) return false; + *out_step = it->second; + return true; + } + + bool getAlignedAttr(std::string Name, unsigned *out_alignment) const { + const AlignedMap::const_iterator I = AlignedParms.find(Name); + if (I == AlignedParms.end()) return false; + *out_alignment = I->second; + return true; + } + + void setLinear(std::string Name, std::string Idname, int Step) { + LinearParms[Name].first = Step; + LinearParms[Name].second = Idname; + } + + void setAligned(std::string Name, unsigned Alignment) { + AlignedParms[Name] = Alignment; + } + + void setUniform(std::string Name) { + UniformParms.insert(Name); + } + }; + + typedef llvm::SmallDenseMap GroupMap; + + // The following is common part for 'cilk vector functions' and + // 'omp declare simd' functions metadata generation. + // + void EmitVectorVariantsMetadata(const CGFunctionInfo &FnInfo, + const FunctionDecl *FD, + llvm::Function *Fn, + GroupMap &Groups); + + /// Add an elemental function metadata node to the named metadata node + /// 'cilk.functions'. + void EmitCilkElementalMetadata(const CGFunctionInfo &FnInfo, + const FunctionDecl *FD, llvm::Function *Fn); + + /// Emit all elemental function vector variants in this module. + void EmitCilkElementalVariants(); + + ARCEntrypoints &getARCEntrypoints() const { assert(getLangOpts().ObjCAutoRefCount && ARCData != 0); return *ARCData; @@ -1002,6 +1092,214 @@ DeferredVTables.push_back(RD); } + /// \brief Emit a code for threadprivate variables. + /// + void EmitOMPThreadPrivate(const OMPThreadPrivateDecl *D); + /// \brief Emit a code for threadprivate variable. + /// + void EmitOMPThreadPrivate(const VarDecl *VD, const Expr *TPE); + /// \brief Emit a code for declare reduction variables. + /// + void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D); + /// \brief Emit vector variants and metadata for 'omp declare simd'. + /// + void EmitOMPDeclareSimd(const OMPDeclareSimdDecl *D); + /// \brief Emit declare target decls. + /// + void EmitOMPDeclareTarget(const OMPDeclareTargetDecl *D); + + /// \brief Creates a structure with the location info for Intel OpenMP RTL. + llvm::Value *CreateIntelOpenMPRTLLoc(SourceLocation Loc, + CodeGenFunction &CGF, + unsigned Flags = 0x02); + /// \brief Creates call to "__kmpc_global_thread_num(ident_t *loc)" OpenMP + /// RTL function. + llvm::Value *CreateOpenMPGlobalThreadNum(SourceLocation Loc, + CodeGenFunction &CGF); + + /// \brief Checks if the variable is OpenMP threadprivate and generates code + /// for threadprivate variables. + /// \return 0 if the variable is not threadprivate, or new address otherwise. + llvm::Value *CreateOpenMPThreadPrivateCached(const VarDecl *VD, + SourceLocation Loc, + CodeGenFunction &CGF, + bool NoCast = false); + + class OpenMPSupportStackTy { + /// \brief A set of OpenMP threadprivate variables. + llvm::DenseMap OpenMPThreadPrivate; + /// \brief A set of OpenMP private variables. + typedef llvm::DenseMap OMPPrivateVarsTy; + struct OMPStackElemTy { + OMPPrivateVarsTy PrivateVars; + llvm::BasicBlock *IfEnd; + llvm::Function *ReductionFunc; + CodeGenModule &CGM; + CodeGenFunction *RedCGF; + llvm::SmallVector ReductionTypes; + llvm::DenseMap ReductionMap; + llvm::StructType *ReductionRec; + llvm::Value *ReductionRecVar; + llvm::Value *RedArg1; + llvm::Value *RedArg2; + llvm::Value *ReduceSwitch; + llvm::BasicBlock *BB1; + llvm::Instruction *BB1IP; + llvm::BasicBlock *BB2; + llvm::Instruction *BB2IP; + llvm::Value *LockVar; + llvm::BasicBlock *LastprivateBB; + llvm::Instruction *LastprivateIP; + llvm::BasicBlock *LastprivateEndBB; + llvm::Value *LastIterVar; + llvm::Value *TaskFlags; + llvm::Value *PTaskTValue; + llvm::Value *PTask; + llvm::Value *UntiedPartIdAddr; + unsigned UntiedCounter; + llvm::Value *UntiedSwitch; + llvm::BasicBlock *UntiedEnd; + CodeGenFunction *ParentCGF; + bool NoWait; + bool Mergeable; + bool Ordered; + int Schedule; + const Expr *ChunkSize; + bool NewTask; + bool Untied; + bool HasLastPrivate; + llvm::DenseMap TaskFields; + llvm::Type *TaskPrivateTy; + QualType TaskPrivateQTy; + llvm::Value *TaskPrivateBase; + llvm::Value *NumTeams; + llvm::Value *ThreadLimit; + llvm::Value **WaitDepsArgs; + OMPStackElemTy(CodeGenModule &CGM); + ~OMPStackElemTy(); + }; + typedef llvm::SmallVector OMPStackTy; + OMPStackTy OpenMPStack; + CodeGenModule &CGM; + llvm::Type *KMPDependInfoType; + unsigned KMPDependInfoTypeAlign; + public: + OpenMPSupportStackTy(CodeGenModule &CGM) + : OpenMPThreadPrivate(), OpenMPStack(), CGM(CGM), KMPDependInfoType(0) { } + const Expr *hasThreadPrivateVar(const VarDecl *VD) { + llvm::DenseMap::iterator I = + OpenMPThreadPrivate.find(VD); + if (I != OpenMPThreadPrivate.end()) + return I->second; + return 0; + } + void addThreadPrivateVar(const VarDecl *VD, const Expr *TPE) { + OpenMPThreadPrivate[VD] = TPE; + } + /// \brief Checks, if the specified variable is currently marked as + /// private. + /// \return 0 if the variable is not private, or address of private + /// otherwise. + llvm::Value *getOpenMPPrivateVar(const VarDecl *VD) { + if (OpenMPStack.empty()) return 0; + for (OMPStackTy::reverse_iterator I = OpenMPStack.rbegin(), + E = OpenMPStack.rend(); + I != E; ++I) { + if (I->PrivateVars.count(VD) > 0 && I->PrivateVars[VD]) + return I->PrivateVars[VD]; + if (I->NewTask) return 0; + } + return 0; + } + llvm::Value *getTopOpenMPPrivateVar(const VarDecl *VD) { + if (OpenMPStack.empty()) return 0; + return OpenMPStack.back().PrivateVars.count(VD) > 0 ? OpenMPStack.back().PrivateVars[VD] : 0; + } + llvm::Value *getPrevOpenMPPrivateVar(const VarDecl *VD) { + if (OpenMPStack.size()< 2) return 0; + return OpenMPStack[OpenMPStack.size() - 2].PrivateVars.count(VD) > 0 ? OpenMPStack[OpenMPStack.size() - 2].PrivateVars[VD] : 0; + } + void startOpenMPRegion(bool NewTask) { + OpenMPStack.push_back(OMPStackElemTy(CGM)); + OpenMPStack.back().NewTask = NewTask; + } + bool isNewTask() { return OpenMPStack.back().NewTask; }; + void endOpenMPRegion(); + void addOpenMPPrivateVar(const VarDecl *VD, llvm::Value *Addr) { + assert(!OpenMPStack.empty() && + "OpenMP private variables region is not started."); + OpenMPStack.back().PrivateVars[VD] = Addr; + } + void delOpenMPPrivateVar(const VarDecl *VD) { + assert(!OpenMPStack.empty() && + "OpenMP private variables region is not started."); + OpenMPStack.back().PrivateVars[VD] = 0; + } + void delPrevOpenMPPrivateVar(const VarDecl *VD) { + assert(OpenMPStack.size() >= 2 && + "OpenMP private variables region is not started."); + OpenMPStack[OpenMPStack.size() - 2].PrivateVars[VD] = 0; + } + void setIfDest(llvm::BasicBlock *EndBB) {OpenMPStack.back().IfEnd = EndBB;} + llvm::BasicBlock *takeIfDest() { + llvm::BasicBlock *BB = OpenMPStack.back().IfEnd; + OpenMPStack.back().IfEnd = 0; + return BB; + } + CodeGenFunction &getCGFForReductionFunction(); + void getReductionFunctionArgs(llvm::Value *&Arg1, llvm::Value *&Arg2); + void registerReductionVar(const VarDecl *VD, llvm::Type *Type); + llvm::Value *getReductionRecVar(CodeGenFunction &CGF); + llvm::Type *getReductionRec(); + llvm::Value *getReductionSwitch(); + void setReductionSwitch(llvm::Value *Switch); + void setReductionIPs(llvm::BasicBlock *BB1, llvm::Instruction *IP1, + llvm::BasicBlock *BB2, llvm::Instruction *IP2); + void getReductionIPs(llvm::BasicBlock *&BB1, llvm::Instruction *&IP1, + llvm::BasicBlock *&BB2, llvm::Instruction *&IP2); + llvm::Value *getReductionLockVar(); + void setReductionLockVar(llvm::Value *Var); + void setLastprivateIP(llvm::BasicBlock *BB, llvm::Instruction *IP, llvm::BasicBlock *EndBB); + void getLastprivateIP(llvm::BasicBlock *&BB, llvm::Instruction *&IP, llvm::BasicBlock *&EndBB); + llvm::Value *getLastIterVar(); + void setLastIterVar(llvm::Value *Var); + unsigned getReductionVarIdx(const VarDecl *VD); + unsigned getNumberOfReductionVars(); + void setNoWait(bool Flag); + bool getNoWait(); + void setScheduleChunkSize(int Sched, const Expr *Size); + void getScheduleChunkSize(int &Sched, const Expr *&Size); + void setMergeable(bool Flag); + bool getMergeable(); + void setOrdered(bool Flag); + bool getOrdered(); + void setUntied(bool Flag); + bool getUntied(); + bool getParentUntied(); + void setHasLastPrivate(bool Flag); + bool hasLastPrivate(); + llvm::Value *getTaskFlags(); + void setTaskFlags(llvm::Value *Flags); + void setPTask(llvm::Value *Task, llvm::Value *TaskT, llvm::Type *PTy, QualType PQTy, llvm::Value *PB); + void getPTask(llvm::Value *&Task, llvm::Value *&TaskT, llvm::Type *&PTy, QualType &PQTy, llvm::Value *&PB); + llvm::DenseMap &getTaskFields(); + void setUntiedData(llvm::Value *UntiedPartIdAddr, llvm::Value *UntiedSwitch, llvm::BasicBlock *UntiedEnd, unsigned UntiedCounter, CodeGenFunction *CGF); + void getUntiedData(llvm::Value *&UntiedPartIdAddr, llvm::Value *&UntiedSwitch, llvm::BasicBlock *&UntiedEnd, unsigned &UntiedCounter); + void setParentUntiedData(llvm::Value *UntiedPartIdAddr, llvm::Value *UntiedSwitch, llvm::BasicBlock *UntiedEnd, unsigned UntiedCounter, CodeGenFunction *CGF); + void getParentUntiedData(llvm::Value *&UntiedPartIdAddr, llvm::Value *&UntiedSwitch, llvm::BasicBlock *&UntiedEnd, unsigned &UntiedCounter, CodeGenFunction *&CGF); + void setKMPDependInfoType(llvm::Type *Ty, unsigned Align) { KMPDependInfoType = Ty; KMPDependInfoTypeAlign = Align; } + llvm::Type *getKMPDependInfoType() { return KMPDependInfoType; } + unsigned getKMPDependInfoTypeAlign() { return KMPDependInfoTypeAlign; } + void setNumTeams(llvm::Value *Num); + void setThreadLimit(llvm::Value *Num); + llvm::Value *getNumTeams(); + llvm::Value *getThreadLimit(); + void setWaitDepsArgs(llvm::Value **Args); + llvm::Value **getWaitDepsArgs(); + }; + + OpenMPSupportStackTy OpenMPSupport; + /// EmitGlobal - Emit code for a singal global function or var decl. Forward /// declarations are emitted lazily. void EmitGlobal(GlobalDecl D); @@ -1020,6 +1318,23 @@ const VarDecl *D, bool UnnamedAddr = false); + /// \brief Creates OpenMP threadprivate function for specified variable + /// and returns this function and constructor, copy constructor and + /// destructor. + void CreateOpenMPCXXInit(const VarDecl *Var, CXXRecordDecl *Ty, + llvm::Function *&InitFunction, + llvm::Value *&Ctor, + llvm::Value *&CCtor, + llvm::Value *&Dtor); + + /// \brief Creates OpenMP threadprivate function for specified array variable + /// and returns this function and constructor, copy constructor and + /// destructor. + void CreateOpenMPArrCXXInit(const VarDecl *Var, CXXRecordDecl *Ty, + llvm::Function *&InitFunction, + llvm::Value *&Ctor, + llvm::Value *&CCtor, + llvm::Value *&Dtor); /// SetCommonAttributes - Set attributes which are common to any /// form of a global definition (alias, Objective-C method, /// function, global variable). diff -uNr clang-3.4/lib/CodeGen/ModuleBuilder.cpp clang/lib/CodeGen/ModuleBuilder.cpp --- clang-3.4/lib/CodeGen/ModuleBuilder.cpp 2013-08-19 17:02:26.000000000 -0400 +++ clang/lib/CodeGen/ModuleBuilder.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -16,6 +16,7 @@ #include "CGDebugInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/Expr.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetInfo.h" @@ -98,11 +99,13 @@ for (DeclContext::decl_iterator M = D->decls_begin(), MEnd = D->decls_end(); M != MEnd; ++M) - if (CXXMethodDecl *Method = dyn_cast(*M)) + if (CXXMethodDecl *Method = dyn_cast(*M)) { if (Method->doesThisDeclarationHaveABody() && (Method->hasAttr() || Method->hasAttr())) Builder->EmitTopLevelDecl(Method); + } else if (OMPThreadPrivateDecl *TD = dyn_cast(*M)) + Builder->EmitTopLevelDecl(TD); } } diff -uNr clang-3.4/lib/Driver/Tools.cpp clang/lib/Driver/Tools.cpp --- clang-3.4/lib/Driver/Tools.cpp 2013-12-08 21:59:27.000000000 -0500 +++ clang/lib/Driver/Tools.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -2050,6 +2050,9 @@ // FIXME: Implement custom jobs for internal actions. CmdArgs.push_back("-cc1"); + if (Args.hasArg(options::OPT_fopenmp)) + CmdArgs.push_back("-fopenmp"); + // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); @@ -5030,7 +5033,7 @@ if (Args.hasArg(options::OPT_fopenmp)) // This is more complicated in gcc... - CmdArgs.push_back("-lgomp"); + CmdArgs.push_back("-liomp5"); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); @@ -6595,11 +6598,7 @@ bool OpenMP = Args.hasArg(options::OPT_fopenmp); if (OpenMP) { - CmdArgs.push_back("-lgomp"); - - // FIXME: Exclude this for platforms whith libgomp that doesn't require - // librt. Most modern Linux platfroms require it, but some may not. - CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-liomp5"); } AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args); diff -uNr clang-3.4/lib/Frontend/ASTConsumers.cpp clang/lib/Frontend/ASTConsumers.cpp --- clang-3.4/lib/Frontend/ASTConsumers.cpp 2013-10-07 16:56:34.000000000 -0400 +++ clang/lib/Frontend/ASTConsumers.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -471,12 +471,17 @@ Out << " " << '"' << *I << "\"\n"; break; } + case Decl::OMPDeclareSimd: { + Out << " " << '"' << *I << "\"\n"; + break; + } default: Out << "DeclKind: " << DK << '"' << *I << "\"\n"; llvm_unreachable("decl unhandled"); } } } + ASTConsumer *clang::CreateDeclContextPrinter() { return new DeclContextPrinter(); } diff -uNr clang-3.4/lib/Lex/PPDirectives.cpp clang/lib/Lex/PPDirectives.cpp --- clang-3.4/lib/Lex/PPDirectives.cpp 2013-11-14 23:24:58.000000000 -0500 +++ clang/lib/Lex/PPDirectives.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -2036,8 +2036,6 @@ // confused. if (getLangOpts().AsmPreprocessor && Tok.isNot(tok::eod)) { LastTok.setKind(tok::unknown); - MI->AddTokenToBody(LastTok); - continue; } else { Diag(Tok, diag::err_pp_stringize_not_parameter); ReleaseMacroInfo(MI); diff -uNr clang-3.4/lib/Parse/ParseDeclCXX.cpp clang/lib/Parse/ParseDeclCXX.cpp --- clang-3.4/lib/Parse/ParseDeclCXX.cpp 2013-12-23 05:02:34.000000000 -0500 +++ clang/lib/Parse/ParseDeclCXX.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -2632,7 +2632,10 @@ } if (Tok.is(tok::annot_pragma_openmp)) { - ParseOpenMPDeclarativeDirective(); + if (TagDecl) + LateParseOpenMPDeclarativeDirective(CurAS); + else + ParseOpenMPDeclarativeDirective(CurAS); continue; } diff -uNr clang-3.4/lib/Parse/ParseExpr.cpp clang/lib/Parse/ParseExpr.cpp --- clang-3.4/lib/Parse/ParseExpr.cpp 2013-11-18 03:17:37.000000000 -0500 +++ clang/lib/Parse/ParseExpr.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1349,11 +1349,39 @@ T.consumeOpen(); Loc = T.getOpenLocation(); ExprResult Idx; + + ExprResult CEANLength; + bool IsCEAN = false; + SourceLocation ColonLoc; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); + } else if (IsCEANAllowed && Tok.is(tok::colon)) { + // '[' ':' + IsCEAN = true; + ColonLoc = ConsumeToken(); + ColonProtectionRAIIObject CPRAII(*this); + if (Tok.isNot(tok::r_square)) { + CEANLength = ParseExpression(); + } + } else if (IsCEANAllowed) { + ColonProtectionRAIIObject CPRAII(*this); + Idx = ParseExpression(); + if (IsCEANAllowed && Tok.is(tok::colon)) { + // '[' ':' + IsCEAN = true; + ColonLoc = ConsumeToken(); + // + if (Tok.isNot(tok::colon) && Tok.isNot(tok::r_square)) { + CEANLength = ParseExpression(); + } + } } else Idx = ParseExpression(); + if (IsCEAN && !Idx.isInvalid() && !CEANLength.isInvalid()) { + Idx = Actions.ActOnCEANIndexExpr(getCurScope(), LHS.get(), Idx.take(), + ColonLoc, CEANLength.take()); + } SourceLocation RLoc = Tok.getLocation(); diff -uNr clang-3.4/lib/Parse/ParseOpenMP.cpp clang/lib/Parse/ParseOpenMP.cpp --- clang-3.4/lib/Parse/ParseOpenMP.cpp 2013-11-18 03:17:37.000000000 -0500 +++ clang/lib/Parse/ParseOpenMP.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" @@ -20,6 +21,160 @@ #include "RAIIObjectsForParser.h" using namespace clang; +OpenMPDirectiveKind Parser::ParseOpenMPDirective() { + OpenMPDirectiveKind DKind = Tok.isAnnotation() + ? OMPD_unknown + : getOpenMPDirectiveKind(PP.getSpelling(Tok)); + + switch (DKind) { + case OMPD_declare: { + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + StringRef Spelling = PP.getSpelling(SavedToken); + if (Spelling == "reduction") { + DKind = OMPD_declare_reduction; + ConsumeAnyToken(); + } else if (Spelling == "simd") { + DKind = OMPD_declare_simd; + ConsumeToken(); + } else if (Spelling == "target") { + DKind = OMPD_declare_target; + ConsumeToken(); + } + } + break; + } + case OMPD_for: { + // This is to get correct directive name in the error message below. + // This whole switch actually should be extracted into a helper routine + // and reused in ParseOpenMPDeclarativeOrExecutableDirective below. + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_simd) { + DKind = OMPD_for_simd; + ConsumeAnyToken(); + } + } + break; + } + case OMPD_distribute: { + // This is to get correct directive name in the error message below. + // This whole switch actually should be extracted into a helper routine + // and reused in ParseOpenMPDeclarativeOrExecutableDirective below. + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_simd) { + DKind = OMPD_distribute_simd; + ConsumeAnyToken(); + } else if (SDKind == OMPD_parallel) { + SavedToken = PP.LookAhead(1); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_for) { + DKind = OMPD_distribute_parallel_for; + ConsumeAnyToken(); + ConsumeAnyToken(); + SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_simd) { + DKind = OMPD_distribute_parallel_for_simd; + ConsumeAnyToken(); + } + } + } + } + } + } + break; + } + case OMPD_parallel: { + // This is to get correct directive name in the error message below. + // This whole switch actually should be extracted into a helper routine + // and reused in ParseOpenMPDeclarativeOrExecutableDirective below. + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_for) { + DKind = OMPD_parallel_for; + ConsumeAnyToken(); + SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_simd) { + DKind = OMPD_parallel_for_simd; + ConsumeAnyToken(); + } + } + } else if (SDKind == OMPD_sections) { + DKind = OMPD_parallel_sections; + ConsumeAnyToken(); + } + } + break; + } + case OMPD_target: { + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + StringRef Spelling = PP.getSpelling(SavedToken); + if (Spelling == "data") { + DKind = OMPD_target_data; + ConsumeAnyToken(); + } else if (Spelling == "update") { + DKind = OMPD_target_update; + ConsumeAnyToken(); + } else if (Spelling == "teams") { + DKind = OMPD_target_teams; + ConsumeAnyToken(); + } + } + break; + } + default: + if (!Tok.isAnnotation()) { + StringRef Spelling = PP.getSpelling(Tok); + if (Spelling == "end") { + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_declare) { + Token SavedToken = PP.LookAhead(1); + if (!SavedToken.isAnnotation()) { + OpenMPDirectiveKind SDKind = + getOpenMPDirectiveKind(PP.getSpelling(SavedToken)); + if (SDKind == OMPD_target) { + DKind = OMPD_end_declare_target; + ConsumeAnyToken(); + ConsumeAnyToken(); + } + } + } + } + } else if (Spelling == "cancellation") { + Token SavedToken = PP.LookAhead(0); + if (!SavedToken.isAnnotation()) { + Spelling = PP.getSpelling(SavedToken); + if (Spelling == "point") { + DKind = OMPD_cancellation_point; + ConsumeToken(); + } + } + } + } + break; + } + return DKind; +} + //===----------------------------------------------------------------------===// // OpenMP declarative directives. //===----------------------------------------------------------------------===// @@ -28,48 +183,294 @@ /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SourceLocation Loc = ConsumeToken(); - SmallVector Identifiers; - OpenMPDirectiveKind DKind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); + SourceLocation Loc = ConsumeAnyToken(); + SmallVector Identifiers; + OpenMPDirectiveKind DKind = ParseOpenMPDirective(); switch (DKind) { case OMPD_threadprivate: - ConsumeToken(); + ConsumeAnyToken(); if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + << getOpenMPDirectiveName(OMPD_threadprivate); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); + } + break; + case OMPD_declare_target: { + SourceLocation DTLoc = ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_target); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + + ParseScope OMPDeclareTargetScope(this, Scope::DeclScope); + if (!Actions.ActOnStartOpenMPDeclareTargetDirective(getCurScope(), DTLoc)) + return DeclGroupPtrTy(); + + DKind = ParseOpenMPDirective(); + while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && + Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + Actions.ActOnOpenMPDeclareTargetDecls(ParseExternalDeclaration(attrs)); + if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { + TentativeParsingAction TPA(*this); + ConsumeToken(); + DKind = ParseOpenMPDirective(); + if (DKind != OMPD_end_declare_target) { + TPA.Revert(); + } else { + TPA.Commit(); + } + } + } + if (DKind == OMPD_end_declare_target) { + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_end_declare_target); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + return Actions.ActOnFinishOpenMPDeclareTargetDirective(); + } + Actions.ActOnOpenMPDeclareTargetDirectiveError(); + Diag(Tok, diag::err_expected_end_declare_target); + Diag(DTLoc, diag::note_matching) << "#pragma omp declare target"; + return DeclGroupPtrTy(); + } + case OMPD_declare_simd: { + // The syntax is: + // #pragma omp declare simd + // [ #pragma omp declare simd + // ... ] + // + // + SmallVector TI; // tempopary varlists. + SmallVector SrcRanges; // directives' source ranges. + SmallVector BeginIdx; // first clause index in CL. + SmallVector EndIdx; // end of clauses index in CL. + SmallVector CL; // all the clauses. + + for (;;) { + unsigned CurBegin = CL.size(); + SmallVector, 4> FirstClauses( + NUM_OPENMP_CLAUSES); + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + + // Read the clauses of the current simd variant. + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (CKind == OMPC_uniform || CKind == OMPC_aligned || + CKind == OMPC_linear) { + TI.push_back(OmpDeclareSimdVariantInfo(CKind, -1)); + bool HadError = ParseOpenMPDeclarativeVarListClause( + DKind, CKind, TI.back().NameInfos, // Parsed VarNames. + TI.back().StartLoc, // Source loc start. + TI.back().EndLoc, // Source loc end. + TI.back().TailExpr, // The expr after ':' + TI.back().TailLoc); // Source location of the tail expr. + if (!HadError) { + TI.back().Idx = CL.size(); + CL.push_back(0); + } else { + TI.pop_back(); // Revert due to error. + } + } else { + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); + FirstClauses[CKind].setInt(true); + if (Clause) { + FirstClauses[CKind].setPointer(Clause); + CL.push_back(Clause); + } + } + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } + + // Here we are at the end of current simd variant. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_simd); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; } // Skip the last annot_pragma_openmp_end. ConsumeToken(); - return Actions.ActOnOpenMPThreadprivateDirective(Loc, - Identifiers); + + // Save the current simd variant's info. + { + SrcRanges.push_back(SourceRange()); + BeginIdx.push_back(CurBegin); + EndIdx.push_back(CL.size()); + } + + // Check if we have more variants here. + // If not -- go ahead with parsing the function declaration. + if (!Tok.is(tok::annot_pragma_openmp)) + break; + ConsumeToken(); // eat the annotation token + if (ParseOpenMPDirective() != OMPD_declare_simd) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_simd); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + break; + } + } + // Here we expect to see some function declaration. + // TODO What if not? + ParsedAttributesWithRange attrs(AttrFactory); + ParsingDeclSpec PDS(*this); + // DeclGroupPtrTy Ptr = ParseDeclarationOrFunctionDefinition(attrs); + DeclGroupPtrTy Ptr = ParseExternalDeclaration(attrs, &PDS); + if (!Ptr || !Ptr.get().isSingleDecl()) + return Ptr; + Decl *FuncDecl = dyn_cast(Ptr.get().getSingleDecl()); + // Here we need to convert the saved name-lists to corresponding clauses. + // This is for 'linear', 'aligned' and 'uniform' clauses only (the + // rest kinds of clauses are already done in CL array). + for (unsigned I = 0; I < TI.size(); ++I) { + assert(CL[TI[I].Idx] == 0); + CL[TI[I].Idx] = Actions.ActOnOpenMPDeclarativeVarListClause( + TI[I].CKind, TI[I].NameInfos, TI[I].StartLoc, TI[I].EndLoc, + TI[I].TailExpr, TI[I].TailLoc, FuncDecl); + } + return Actions.ActOnOpenMPDeclareSimdDirective(Loc, FuncDecl, SrcRanges, + BeginIdx, EndIdx, CL); + } + case OMPD_declare_reduction: { + SmallVector Types; + SmallVector TyRanges; + SmallVector Combiners; + SmallVector Inits; + ConsumeAnyToken(); + if (Decl *D = ParseOpenMPDeclareReduction(Types, TyRanges, Combiners, Inits, + AS)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + return Actions.ActOnOpenMPDeclareReductionDirective(D, Types, TyRanges, + Combiners, Inits); } break; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; - case OMPD_parallel: - case OMPD_task: - case NUM_OPENMP_DIRECTIVES: + default: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(DKind); + << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; return DeclGroupPtrTy(); } +/// \brief Late parsing of declarative OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +void Parser::LateParseOpenMPDeclarativeDirective(AccessSpecifier AS) { + assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + LateParsedOpenMPDeclaration *Decl = new LateParsedOpenMPDeclaration(this, AS); + getCurrentClass().LateParsedDeclarations.push_back(Decl); + while (Tok.isNot(tok::annot_pragma_openmp_end) && Tok.isNot(tok::eof)) { + Decl->Tokens.push_back(Tok); + ConsumeAnyToken(); + } + Decl->Tokens.push_back(Tok); + ConsumeAnyToken(); + + if (Decl->Tokens.size() > 3) { + Token SavedToken = Decl->Tokens[1]; + if (!SavedToken.isAnnotation()) { + StringRef Spelling = PP.getSpelling(SavedToken); + if (Spelling == "declare") { + SavedToken = Decl->Tokens[2]; + if (!SavedToken.isAnnotation()) { + Spelling = PP.getSpelling(SavedToken); + if (Spelling == "simd") { + if (Tok.isNot(tok::annot_pragma_openmp)) { + LexTemplateFunctionForLateParsing(Decl->Tokens); + } + } + } + } + } + } +} + +/// \brief Actual parsing of late OpenMP declaration. +void Parser::LateParsedOpenMPDeclaration::ParseLexedMethodDeclarations() { + // Save the current token position. + SourceLocation origLoc = Self->Tok.getLocation(); + + assert(!Tokens.empty() && "Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + Tokens.push_back(Self->Tok); + Self->PP.EnterTokenStream(Tokens.data(), Tokens.size(), true, false); + + // Consume the previously pushed token. + Self->ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + Self->ParseOpenMPDeclarativeDirective(this->AS); + + if (Self->Tok.getLocation() != origLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (Self->PP.getSourceManager().isBeforeInTranslationUnit( + Self->Tok.getLocation(), origLoc)) + while (Self->Tok.getLocation() != origLoc && Self->Tok.isNot(tok::eof)) + Self->ConsumeAnyToken(); + } +} + /// \brief Parsing of declarative or executable OpenMP directives. /// /// threadprivate-directive: @@ -79,52 +480,196 @@ /// parallel-directive: /// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end /// -StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { +/// for-directive: +/// annot_pragma_openmp 'for' {clause} annot_pragma_openmp_end +/// +/// distribute-directive: +/// annot_pragma_openmp 'distribute' {clause} annot_pragma_openmp_end +/// +/// simd-directive: +/// annot_pragma_openmp 'simd' {clause} annot_pragma_openmp_end +/// +/// for-simd-directive: +/// annot_pragma_openmp 'for simd' {clause} annot_pragma_openmp_end +/// +/// distribute-simd-directive: +/// annot_pragma_openmp 'distribute simd' {clause} +/// annot_pragma_openmp_end +/// +/// distribute-parallel-for-directive: +/// annot_pragma_openmp 'distribute parallel for' {clause} +/// annot_pragma_openmp_end +/// +/// distribute-parallel-for-simd-directive: +/// annot_pragma_openmp 'distribute parallel for simd' {clause} +/// annot_pragma_openmp_end +/// +/// sections-directive: +/// annot_pragma_openmp 'sections' {clause} annot_pragma_openmp_end +/// +/// section-directive: +/// annot_pragma_openmp 'section' annot_pragma_openmp_end +/// +/// single-directive: +/// annot_pragma_openmp 'single' {clause} annot_pragma_openmp_end +/// +/// task-directive: +/// annot_pragma_openmp 'task' {clause} annot_pragma_openmp_end +/// +/// taskyield-directive: +/// annot_pragma_openmp 'taskyield' annot_pragma_openmp_end +/// +/// master-directive: +/// annot_pragma_openmp 'master' annot_pragma_openmp_end +/// +/// critical-directive: +/// annot_pragma_openmp 'critical' [ '(' ')' ] +/// annot_pragma_openmp_end +/// +/// barrier-directive: +/// annot_pragma_openmp 'barrier' annot_pragma_openmp_end +/// +/// taskwait-directive: +/// annot_pragma_openmp 'taskwait' annot_pragma_openmp_end +/// +/// taskgroup-directive: +/// annot_pragma_openmp 'taskgroup' annot_pragma_openmp_end +/// +/// atomic-directive: +/// annot_pragma_openmp 'atomic' [clause] [clause] +/// annot_pragma_openmp_end +/// +/// flush-directive: +/// annot_pragma_openmp 'flush' [ '(' list ')' ] +/// annot_pragma_openmp_end +/// +/// ordered-directive: +/// annot_pragma_openmp 'ordered' annot_pragma_openmp_end +/// +StmtResult +Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SmallVector Identifiers; - SmallVector Clauses; - SmallVector, NUM_OPENMP_CLAUSES> - FirstClauses(NUM_OPENMP_CLAUSES); - const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | - Scope::OpenMPDirectiveScope; - SourceLocation Loc = ConsumeToken(), EndLoc; - OpenMPDirectiveKind DKind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); - // Name of critical directive. - DeclarationNameInfo DirName; + const unsigned ScopeFlags = + Scope::FnScope | Scope::OpenMPDirectiveScope | Scope::DeclScope; + SmallVector Identifiers; + SmallVector Clauses; + SmallVector, 4> FirstClauses( + NUM_OPENMP_CLAUSES); + SourceLocation Loc = ConsumeAnyToken(), EndLoc; + OpenMPDirectiveKind ConstructType = OMPD_unknown; StmtResult Directive = StmtError(); + DeclarationNameInfo DirName; + + OpenMPDirectiveKind DKind = ParseOpenMPDirective(); switch (DKind) { case OMPD_threadprivate: - ConsumeToken(); + ConsumeAnyToken(); if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_threadprivate); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + << getOpenMPDirectiveName(OMPD_threadprivate); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; } DeclGroupPtrTy Res = - Actions.ActOnOpenMPThreadprivateDirective(Loc, - Identifiers); + Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); } - SkipUntil(tok::annot_pragma_openmp_end); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; break; - case OMPD_parallel: { - ConsumeToken(); - + case OMPD_declare_reduction: { + SmallVector Types; + SmallVector TyRanges; + SmallVector Combiners; + SmallVector Inits; + ConsumeAnyToken(); + if (Decl *D = ParseOpenMPDeclareReduction(Types, TyRanges, Combiners, Inits, + AS_none)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + DeclGroupPtrTy Res = Actions.ActOnOpenMPDeclareReductionDirective( + D, Types, TyRanges, Combiners, Inits); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; + break; + } + case OMPD_critical: + // Parse name of critical if any. + if (PP.LookAhead(0).is(tok::l_paren)) { + // Consume '('. + ConsumeAnyToken(); + SourceLocation LOpen = Tok.getLocation(); + // Parse . + ConsumeAnyToken(); + if (!Tok.isAnyIdentifier()) { + Diag(Tok, diag::err_expected_ident); + } else { + DirName = + DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeAnyToken(); + } + // Parse ')'. + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Diag(LOpen, diag::note_matching) << "("; + } + } + StandAloneAllowed = true; + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + if (!StandAloneAllowed) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind); + } + case OMPD_parallel: + case OMPD_parallel_for: + case OMPD_parallel_sections: + case OMPD_parallel_for_simd: + case OMPD_teams: + case OMPD_for: + case OMPD_simd: + case OMPD_for_simd: + case OMPD_distribute: + case OMPD_distribute_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_task: + case OMPD_master: + case OMPD_taskgroup: + case OMPD_atomic: + case OMPD_ordered: + case OMPD_target: + case OMPD_target_data: + case OMPD_target_teams: { + // Do not read token if the end of directive or flush directive. + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ParseScope OMPDirectiveScope(this, ScopeFlags); Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); - while (Tok.isNot(tok::annot_pragma_openmp_end)) { - OpenMPClauseKind CKind = Tok.isAnnotation() ? - OMPC_unknown : - getOpenMPClauseKind(PP.getSpelling(Tok)); - OMPClause *Clause = ParseOpenMPClause(DKind, CKind, - !FirstClauses[CKind].getInt()); + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); FirstClauses[CKind].setInt(true); if (Clause) { FirstClauses[CKind].setPointer(Clause); @@ -133,51 +678,140 @@ // Skip ',' if any. if (Tok.is(tok::comma)) - ConsumeToken(); + ConsumeAnyToken(); } // End location of the directive. EndLoc = Tok.getLocation(); // Consume final annot_pragma_openmp_end. - ConsumeToken(); + ConsumeAnyToken(); StmtResult AssociatedStmt; bool CreateDirective = true; - ParseScope OMPDirectiveScope(this, ScopeFlags); - { + if (DKind != OMPD_taskyield && DKind != OMPD_barrier && + DKind != OMPD_taskwait) { + // Parse statement // The body is a block scope like in Lambdas and Blocks. Sema::CompoundScopeRAII CompoundScope(Actions); - Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1); + // Simd has two additional args -- integer index and boolean last_iter. + int NumArgs = (DKind == OMPD_simd || DKind == OMPD_for_simd || + DKind == OMPD_parallel_for_simd || + DKind == OMPD_distribute_parallel_for_simd || + DKind == OMPD_distribute_simd) + ? 3 + : 1; + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, NumArgs); Actions.ActOnStartOfCompoundStmt(); - // Parse statement AssociatedStmt = ParseStatement(); Actions.ActOnFinishOfCompoundStmt(); if (!AssociatedStmt.isUsable()) { Actions.ActOnCapturedRegionError(); CreateDirective = false; } else { + Actions.MarkOpenMPClauses(Clauses); AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take()); CreateDirective = AssociatedStmt.isUsable(); } } - if (CreateDirective) - Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses, - AssociatedStmt.take(), - Loc, EndLoc); + if (CreateDirective) { + Directive = Actions.ActOnOpenMPExecutableDirective( + DKind, DirName, Clauses, AssociatedStmt.take(), Loc, EndLoc, + ConstructType); + } // Exit scope. Actions.EndOpenMPDSABlock(Directive.get()); OMPDirectiveScope.Exit(); + break; + } + case OMPD_cancel: + case OMPD_cancellation_point: + case OMPD_target_update: + case OMPD_flush: { + if (!StandAloneAllowed) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind); } + ParseScope OMPDirectiveScope(this, ScopeFlags); + Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); + if (DKind == OMPD_flush) { + if (PP.LookAhead(0).is(tok::l_paren)) { + // For flush directive set clause kind to pseudo flush clause. + OMPClause *Clause = ParseOpenMPVarListClause(OMPC_flush); + if (Clause) + Clauses.push_back(Clause); + } else { + // Consume directive name. + ConsumeAnyToken(); + } + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ParseOpenMPClause(DKind, OMPC_unknown, true); + } else if (DKind == OMPD_cancel || DKind == OMPD_cancellation_point) { + ConsumeAnyToken(); + ConstructType = ParseOpenMPDirective(); + if (ConstructType != OMPD_parallel && ConstructType != OMPD_sections && + ConstructType != OMPD_for && ConstructType != OMPD_taskgroup) { + Diag(Tok.getLocation(), diag::err_omp_expected_cancel_construct_type); + } + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + ConsumeAnyToken(); + // Skip ',' if any. + if (Tok.is(tok::comma) && DKind == OMPD_cancel) + ConsumeAnyToken(); + } + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); + FirstClauses[CKind].setInt(true); + if (Clause) { + FirstClauses[CKind].setPointer(Clause); + Clauses.push_back(Clause); + } + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeAnyToken(); + } + } else if (DKind == OMPD_target_update) { + ConsumeAnyToken(); + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); + FirstClauses[CKind].setInt(true); + if (Clause) { + FirstClauses[CKind].setPointer(Clause); + Clauses.push_back(Clause); + } + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeAnyToken(); + } + } + Directive = Actions.ActOnOpenMPExecutableDirective( + DKind, DirName, Clauses, 0, Loc, Tok.getLocation(), ConstructType); + // Exit scope. + Actions.EndOpenMPDSABlock(Directive.get()); + // Consume final annot_pragma_openmp_end. + ConsumeAnyToken(); + OMPDirectiveScope.Exit(); break; + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); - SkipUntil(tok::annot_pragma_openmp_end); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; break; - case OMPD_task: - case NUM_OPENMP_DIRECTIVES: + default: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end); + << getOpenMPDirectiveName(DKind); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; break; } return Directive; @@ -187,7 +821,7 @@ /// directive. /// /// simple-variable-list: -/// '(' id-expression {, id-expression} ')' +/// '(' id-expression {',' id-expression} ')' /// bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, SmallVectorImpl &VarList, @@ -195,10 +829,9 @@ VarList.clear(); // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) - return true; - bool IsCorrect = true; + bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind)); + bool IsCorrect = LParen; bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. @@ -213,30 +846,33 @@ if (AllowScopeSpecifier && getLangOpts().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { IsCorrect = false; - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); + while (!SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), TemplateKWLoc, Name)) { IsCorrect = false; - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); + while (!SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { IsCorrect = false; - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); Diag(PrevTok.getLocation(), diag::err_expected_ident) - << SourceRange(PrevTok.getLocation(), PrevTokLocation); + << SourceRange(PrevTok.getLocation(), PrevTokLocation); + while (!SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; } else { DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); - ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, - NameInfo); + ExprResult Res = + Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo); if (Res.isUsable()) VarList.push_back(Res.take()); } // Consume ','. if (Tok.is(tok::comma)) { - ConsumeToken(); + ConsumeAnyToken(); } } @@ -246,15 +882,295 @@ } // Parse ')'. - IsCorrect = !T.consumeClose() && IsCorrect; + IsCorrect = + ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) && IsCorrect; return !IsCorrect && VarList.empty(); } +/// \brief Parsing of OpenMP declare reduction. +/// +/// declare_reduction: +/// '(' ':' {',' } ':' ')' +/// ['initializer' '(' 'omp_priv' [ '=' ] ')'] +/// +Decl *Parser::ParseOpenMPDeclareReduction( + SmallVectorImpl &Types, SmallVectorImpl &TyRanges, + SmallVectorImpl &Combiners, SmallVectorImpl &Inits, + AccessSpecifier AS) { + SourceLocation Loc = Tok.getLocation(); + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId UI; + DeclarationName Name; + Decl *D = 0; + + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + bool LParen = + !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction)); + bool IsCorrect = LParen; + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + switch (Tok.getKind()) { + case tok::plus: // '+' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("+")); + ConsumeAnyToken(); + break; + case tok::minus: // '-' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("-")); + ConsumeAnyToken(); + break; + case tok::star: // '*' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("*")); + ConsumeAnyToken(); + break; + case tok::amp: // '&' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("&")); + ConsumeAnyToken(); + break; + case tok::pipe: // '|' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("|")); + ConsumeAnyToken(); + break; + case tok::caret: // '^' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("^")); + ConsumeAnyToken(); + break; + case tok::ampamp: // '&&' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("&&")); + ConsumeAnyToken(); + break; + case tok::pipepipe: // '||' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("||")); + ConsumeAnyToken(); + break; + case tok::identifier: // identifier + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + Tok.getIdentifierInfo()); + ConsumeAnyToken(); + break; + default: + IsCorrect = false; + Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier); + while (!SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + break; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + // Consume ':'. + if (Tok.is(tok::colon)) { + ConsumeAnyToken(); + } else { + Diag(Tok.getLocation(), diag::err_expected_colon); + IsCorrect = false; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + IsCorrect = false; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + bool IsCommaFound = false; + bool FunctionsCorrect = true; + while (Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end)) { + ColonProtectionRAIIObject ColonRAII(*this); + IsCommaFound = false; + SourceRange Range; + TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext); + if (TR.isUsable()) { + QualType QTy = Sema::GetTypeFromParser(TR.take()); + if (!QTy.isNull() && Actions.IsOMPDeclareReductionTypeAllowed( + Range, QTy, Types, TyRanges)) { + Types.push_back(QTy); + TyRanges.push_back(Range); + } else { + FunctionsCorrect = false; + } + } else { + while (!SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + FunctionsCorrect = false; + } + + // Consume ','. + if (Tok.is(tok::comma)) { + ConsumeAnyToken(); + IsCommaFound = true; + } else if (Tok.isNot(tok::colon) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_comma); + IsCorrect = false; + } + } + + if (IsCommaFound) { + Diag(Tok.getLocation(), diag::err_expected_type); + IsCorrect = false; + if (Tok.is(tok::annot_pragma_openmp_end)) + return 0; + } + + if (Types.empty()) { + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + return 0; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + // Consume ':'. + if (Tok.is(tok::colon)) { + ConsumeAnyToken(); + } else { + Diag(Tok.getLocation(), diag::err_expected_colon); + IsCorrect = false; + } + + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_expression); + return 0; + } + + Sema::OMPDeclareReductionRAII RAII(Actions, Actions.CurScope, + Actions.CurContext, Loc, Name, + Types.size(), AS); + + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope); + + // Parse expression and make pseudo functions. + for (SmallVectorImpl::iterator I = Types.begin(), E = Types.end(); + I != E; ++I) { + TentativeParsingAction TPA(*this); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope); + Sema::OMPDeclareReductionFunctionScope Scope(Actions, Loc, Name, *I); + ExprResult ER = ParseAssignmentExpression(); + if (ER.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = IsCorrect && !ER.isInvalid(); + Scope.setBody(ER.take()); + Combiners.push_back(Scope.getCombiner()); + if (I + 1 != E) { + TPA.Revert(); + } else { + TPA.Commit(); + } + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return 0; + + D = RAII.getDecl(); + + // Parse ')'. + IsCorrect = + ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) && IsCorrect; + + if (Tok.isAnyIdentifier() && Tok.getIdentifierInfo()->isStr("initializer")) { + ConsumeAnyToken(); + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + LParen = + !T.expectAndConsume(diag::err_expected_lparen_after, "initializer"); + IsCorrect = IsCorrect && LParen; + + bool IsInit = false; + SourceLocation OmpPrivLoc; + if (Tok.isAnyIdentifier() && Tok.getIdentifierInfo()->isStr("omp_priv")) { + IsInit = true; + OmpPrivLoc = ConsumeAnyToken(); + if (!getLangOpts().CPlusPlus) { + // Expect '=' + if (Tok.isNot(tok::equal)) { + Diag(Tok, diag::err_expected_equal_after) << "'omp_priv'"; + IsCorrect = false; + } else + ConsumeAnyToken(); + } + } + + // Parse expression and make pseudo functions. + for (SmallVectorImpl::iterator I = Types.begin(), E = Types.end(); + I != E; ++I) { + TentativeParsingAction TPA(*this); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope); + Sema::OMPDeclareReductionInitFunctionScope Scope(Actions, Loc, Name, *I, + OmpPrivLoc, IsInit); + ExprResult ER = ParseAssignmentExpression(); + if (ER.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = IsCorrect && !ER.isInvalid(); + Scope.setInit(ER.take()); + Inits.push_back(Scope.getInitializer()); + if (I + 1 != E) { + TPA.Revert(); + } else { + TPA.Commit(); + } + } + + IsCorrect = + ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) && IsCorrect; + } else if (IsCorrect && FunctionsCorrect) { + // Parse expression and make pseudo functions. + for (SmallVectorImpl::iterator I = Types.begin(), E = Types.end(); + I != E; ++I) { + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope); + Sema::OMPDeclareReductionInitFunctionScope Scope(Actions, Loc, Name, *I, + SourceLocation(), true); + Scope.setInit(); + Inits.push_back(Scope.getInitializer()); + } + } + + if (!IsCorrect || !FunctionsCorrect) + D->setInvalidDecl(); + return (IsCorrect && FunctionsCorrect) ? D : 0; +} + /// \brief Parsing of OpenMP clauses. /// /// clause: -/// default-clause|private-clause|firstprivate-clause|shared-clause +/// if-clause | num_threads-clause | default-clause | proc_bind-clause | +/// private-clause | firstprivate-clause | shared-clause | +/// copyin-clause | reduction-clause | lastprivate-clause | +/// schedule-clause | collapse-clause | ordered-clause | nowait-clause | +/// copyprivate-clause | flush-clause | safelen-clause | linear-clause | +/// aligned-clause | simdlen-clause | num_teams-clause | +/// thread_limit-clause | uniform-clause | inbranch-clause | +/// notinbranch-clause | dist_schedule-clause | depend-clause | +/// device-clause | map-clause | to-clause | from-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -262,120 +1178,621 @@ bool ErrorFound = false; // Check if clause is allowed for the given directive. if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { - Diag(Tok, diag::err_omp_unexpected_clause) - << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) + << getOpenMPDirectiveName(DKind); ErrorFound = true; } switch (CKind) { + case OMPC_if: + case OMPC_num_threads: + case OMPC_collapse: + case OMPC_final: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_device: + // OpenMP [2.5, Restrictions, p.3] + // At most one if clause can appear on the directive. + // OpenMP [2.5, Restrictions, p.5] + // At most one num_threads clause can appear on the directive. + // OpenMP [2.7.1, Restrictions, p. 4] + // Only one collapse clause can appear on a loop directive. + // OpenMP [2.11.1, Restrictions, p. 4] + // At most one final clause can appear on the directive. + // OpenMP [2.8.1, Restrictions, p. 6] + // Only one safelen clause can appear on a simd directive. + // OpenMP [2.8.2, Restrictions, p. 2] + // At most one simdlen clause can appear in a declare simd directive. + // OpenMP [2.9.5, Restrictions, p. 4] + // At most one num_teams clause can appear on the directive. + // OpenMP [2.9.5, Restrictions, p. 3] + // At most one thread_limit clause can appear on the directive. + // OpenMP [2.9.1, Restrictions, p. 2] + // At most one device clause can appear on the directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSingleExprClause(CKind); + break; case OMPC_default: - // OpenMP [2.9.3.1, Restrictions] - // Only a single default clause may be specified on a parallel or task - // directive. + case OMPC_proc_bind: + // OpenMP [2.14.3.1, Restrictions] + // Only a single default clause may be specified on a parallel, task + // or teams directive. + // OpenMP [2.5, Restrictions, p. 4] + // At most one proc_bind clause can appear on the directive. if (!FirstClause) { - Diag(Tok, diag::err_omp_more_one_clause) - << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); } Clause = ParseOpenMPSimpleClause(CKind); break; + case OMPC_ordered: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + // OpenMP [2.7.1, Restrictions, p. 9] + // Only one ordered clause can appear on a loop directive. + // OpenMP [2.7.1, Restrictions, C/C++, p. 4] + // Only one nowait clause can appear on a loop directive. + // OpenMP [2.7.2, Restrictions, p. 3] + // Only one nowait clause can appear on a sections directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + // Fall-through... + // There is no restriction to have only one inbranch/only one + // notinbranch, only a restriction to not have them both on the + // same clause. + case OMPC_inbranch: + case OMPC_notinbranch: + Clause = ParseOpenMPClause(CKind); + break; + case OMPC_schedule: + case OMPC_dist_schedule: + // OpenMP [2.7.1, Restrictions, p. 3] + // Only one schedule clause can appear on a loop directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSingleExprWithTypeClause(CKind); + break; case OMPC_private: + case OMPC_lastprivate: case OMPC_firstprivate: case OMPC_shared: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_reduction: + case OMPC_depend: + case OMPC_linear: + case OMPC_aligned: + case OMPC_uniform: + case OMPC_map: + case OMPC_to: + case OMPC_from: Clause = ParseOpenMPVarListClause(CKind); break; + case OMPC_flush: case OMPC_unknown: Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + << getOpenMPDirectiveName(DKind); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; break; - case OMPC_threadprivate: - case NUM_OPENMP_CLAUSES: - Diag(Tok, diag::err_omp_unexpected_clause) - << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); - SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch); + default: + Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) + << getOpenMPDirectiveName(DKind); + while ( + !SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; break; } return ErrorFound ? 0 : Clause; } -/// \brief Parsing of simple OpenMP clauses like 'default'. +/// \brief Parsing of OpenMP clauses with single expressions like 'if', +/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or +/// 'thread_limit' or 'device'. +/// +/// if-clause: +/// 'if' '(' expression ')' +/// +/// num_threads-clause: +/// 'num_threads' '(' expression ')' +/// +/// collapse-clause: +/// 'collapse' '(' expression ')' +/// +/// safelen-clause: +/// 'safelen' '(' expression ')' +/// +/// simdlen-clause: +/// 'simdlen' '(' expression ')' +/// +/// num_teams-clause: +/// 'num_teams' '(' expression ')' +/// +/// thread_limit-clause: +/// 'thread_limit' '(' expression ')' +/// +/// device-clause: +/// 'device' '(' expression ')' +/// +OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeAnyToken(); + bool LParen = true; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << getOpenMPClauseName(Kind); + LParen = false; + } else + ConsumeAnyToken(); + + ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + + if (LParen && Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Diag(LOpen, diag::note_matching) << "("; + while (!SkipUntil(tok::r_paren, tok::comma, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + } + if (Tok.is(tok::r_paren)) + ConsumeAnyToken(); + + if (Val.isInvalid()) + return 0; + + return Actions.ActOnOpenMPSingleExprClause(Kind, Val.take(), Loc, + Tok.getLocation()); +} + +/// \brief Parsing of OpenMP clauses with single expressions and some additional +/// argument like 'schedule' or 'dist_schedule'. +/// +/// schedule-clause: +/// 'schedule' '(' kind [',' expression ] ')' +/// +/// dist_schedule-clause: +/// 'dist_schedule' '(' kind [',' expression] ')' +/// +OMPClause *Parser::ParseOpenMPSingleExprWithTypeClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeAnyToken(); + bool LParen = true; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << getOpenMPClauseName(Kind); + LParen = false; + } else + ConsumeAnyToken(); + + unsigned Type = Tok.isAnnotation() + ? 0 + : getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + SourceLocation TypeLoc = Tok.getLocation(); + ExprResult Val = ExprError(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + if (Tok.is(tok::comma)) { + ConsumeAnyToken(); + ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); + } + if (LParen && Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Diag(LOpen, diag::note_matching) << "("; + while (!SkipUntil(tok::r_paren, tok::comma, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + } + if (Tok.is(tok::r_paren)) + ConsumeAnyToken(); + + return Actions.ActOnOpenMPSingleExprWithTypeClause( + Kind, Type, TypeLoc, Val.take(), Loc, Tok.getLocation()); +} + +/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: -/// 'default' '(' 'none' | 'shared' ') +/// 'default' '(' 'none' | 'shared' ')' +/// +/// proc_bind-clause: +/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')' /// OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { SourceLocation Loc = Tok.getLocation(); - SourceLocation LOpen = ConsumeToken(); - // Parse '('. - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) - return 0; + SourceLocation LOpen = ConsumeAnyToken(); + bool LParen = true; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << getOpenMPClauseName(Kind); + LParen = false; + } else + ConsumeAnyToken(); - unsigned Type = Tok.isAnnotation() ? - unsigned(OMPC_DEFAULT_unknown) : - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + unsigned Type = + Tok.isAnnotation() + ? ((Kind == OMPC_default) ? (unsigned)OMPC_DEFAULT_unknown + : (unsigned)OMPC_PROC_BIND_unknown) + : getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); SourceLocation TypeLoc = Tok.getLocation(); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); - // Parse ')'. - T.consumeClose(); + if (LParen && Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Diag(LOpen, diag::note_matching) << "("; + while (!SkipUntil(tok::r_paren, tok::comma, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + } + if (Tok.is(tok::r_paren)) + ConsumeAnyToken(); - return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc, + return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, Loc, Tok.getLocation()); } +/// \brief Parsing of OpenMP clauses like 'ordered' or 'nowait'. +/// +/// ordered-clause: +/// 'ordered' +/// +/// nowait-clause: +/// 'nowait' +/// +OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + ConsumeAnyToken(); + + return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation()); +} + /// \brief Parsing of OpenMP clause 'private', 'firstprivate', -/// 'shared', 'copyin', or 'reduction'. +/// 'lastprivate', 'shared', 'copyin', 'reduction', 'flush', +/// 'linear', 'aligned' or 'depend'. /// /// private-clause: /// 'private' '(' list ')' +/// +/// lastprivate-clause: +/// 'lastprivate' '(' list ')' +/// /// firstprivate-clause: /// 'firstprivate' '(' list ')' +/// /// shared-clause: /// 'shared' '(' list ')' /// +/// copyin-clause: +/// 'copyin' '(' list ')' +/// +/// copyprivate-clause: +/// 'copyprivate' '(' list ')' +/// +/// reduction-clause: +/// 'reduction' '(' reduction-identifier ':' list ')' +/// +/// depend-clause: +/// 'depend' '(' dependence-type ':' list ')' +/// +/// flush-clause: +/// '(' list ')' +/// +/// linear-clause: +/// 'linear' '(' list [ ':' linear-step ] ')' +/// +/// aligned-clause: +/// 'aligned' '(' list [ ':' alignment ] ')' +/// +/// map-clause: +/// 'map' '(' map-kind ':' list ')' +/// +/// to-clause: +/// 'to' '(' list ')' +/// +/// from-clause: +/// 'from' '(' list ')' +/// OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { + assert(Kind != OMPC_uniform); SourceLocation Loc = Tok.getLocation(); - SourceLocation LOpen = ConsumeToken(); - // Parse '('. - BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(Kind))) - return 0; + SourceLocation LOpen = ConsumeAnyToken(); + bool LParen = true; + CXXScopeSpec SS; + UnqualifiedId OpName; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << getOpenMPClauseName(Kind); + LParen = false; + } else + ConsumeAnyToken(); - SmallVector Vars; - bool IsComma = true; - while (IsComma || (Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end))) { + unsigned Op = OMPC_REDUCTION_unknown; + // Parsing "reduction-identifier ':'" for reduction clause. + if (Kind == OMPC_reduction) { + Op = Tok.isAnnotation() + ? (unsigned)OMPC_REDUCTION_unknown + : getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + switch (Op) { + case OMPC_REDUCTION_add: + case OMPC_REDUCTION_mult: + case OMPC_REDUCTION_sub: + case OMPC_REDUCTION_bitand: + case OMPC_REDUCTION_bitor: + case OMPC_REDUCTION_bitxor: + case OMPC_REDUCTION_and: + case OMPC_REDUCTION_or: + case OMPC_REDUCTION_min: + case OMPC_REDUCTION_max: + OpName.setIdentifier( + &Actions.Context.Idents.get(getOpenMPSimpleClauseTypeName(Kind, Op)), + Tok.getLocation()); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { + ConsumeAnyToken(); + } + break; + case OMPC_REDUCTION_unknown: { + if (getLangOpts().CPlusPlus) { + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + } + SourceLocation TemplateKWLoc; + if (!ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, OpName)) { + Op = OMPC_REDUCTION_custom; + } + break; + } + case OMPC_REDUCTION_custom: + llvm_unreachable("'custom' reduction kind cannot be generated directly."); + case NUM_OPENMP_REDUCTION_OPERATORS: + llvm_unreachable("unexpected reduction kind."); + } + + if (Tok.isNot(tok::colon)) + Diag(Tok, diag::err_omp_expected_colon) << getOpenMPClauseName(Kind); + else + ConsumeAnyToken(); + } else if (Kind == OMPC_depend) { + // Parsing "dependence-type ':'" for depend clause. + Op = Tok.isAnnotation() + ? (unsigned)OMPC_DEPEND_unknown + : getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + switch (Op) { + case OMPC_DEPEND_in: + case OMPC_DEPEND_out: + case OMPC_DEPEND_inout: + break; + case OMPC_DEPEND_unknown: + Diag(Tok, diag::err_omp_unknown_dependence_type); + break; + case NUM_OPENMP_DEPENDENCE_TYPE: + llvm_unreachable("unexpected dependence type."); + } + + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { + ConsumeAnyToken(); + if (Tok.isNot(tok::colon)) + Diag(Tok, diag::err_omp_expected_colon) << getOpenMPClauseName(Kind); + else + ConsumeAnyToken(); + } + } else if (Kind == OMPC_map) { + // Parsing "map-kind ':'" for map clause. + Op = Tok.isAnnotation() + ? (unsigned)OMPC_MAP_unknown + : getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + switch (Op) { + case OMPC_MAP_alloc: + case OMPC_MAP_to: + case OMPC_MAP_from: + case OMPC_MAP_tofrom: + case OMPC_MAP_unknown: + break; + case NUM_OPENMP_MAP_KIND: + llvm_unreachable("unexpected mapping_kind."); + } + + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end) && + Op != OMPC_MAP_unknown) { + ConsumeAnyToken(); + if (Tok.isNot(tok::colon)) + Diag(Tok, diag::err_omp_expected_colon) << getOpenMPClauseName(Kind); + else + ConsumeAnyToken(); + } else { + Op = OMPC_MAP_tofrom; + } + } + + SmallVector Vars; + bool IsComma = (Kind != OMPC_reduction || Op != OMPC_REDUCTION_unknown) && + (Kind != OMPC_depend || Op != OMPC_DEPEND_unknown) && + (Kind != OMPC_map || Op != OMPC_MAP_unknown); + bool MayHaveTail = (Kind == OMPC_linear) || (Kind == OMPC_aligned); + while (IsComma || + (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end) && + Tok.isNot(tok::colon))) { // Parse variable + AllowCEANExpressions CEANRAII(*this, + Kind == OMPC_depend || Kind == OMPC_map || + Kind == OMPC_from || Kind == OMPC_to); ExprResult VarExpr = ParseAssignmentExpression(); if (VarExpr.isUsable()) { Vars.push_back(VarExpr.take()); } else { - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); + while (!SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; } // Skip ',' if any IsComma = Tok.is(tok::comma); if (IsComma) { - ConsumeToken(); + ConsumeAnyToken(); } else if (Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::err_omp_expected_punc) - << 1 << getOpenMPClauseName(Kind); + Tok.isNot(tok::annot_pragma_openmp_end) && + (!MayHaveTail || Tok.isNot(tok::colon))) { + Diag(Tok, diag::err_omp_expected_punc) << 1 << getOpenMPClauseName(Kind); } } - // Parse ')'. - T.consumeClose(); - if (Vars.empty()) + bool MustHaveTail = false; + Expr *TailExpr = 0; + SourceLocation TailLoc; + if (MayHaveTail) { + // Parse "':' linear-step" or "':' alignment" + if (Tok.is(tok::colon)) { + MustHaveTail = true; + ConsumeAnyToken(); + ColonProtectionRAIIObject ColonRAII(*this); + TailLoc = Tok.getLocation(); + ExprResult Tail = ParseAssignmentExpression(); + if (Tail.isUsable()) { + TailExpr = Tail.take(); + } else { + while (!SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + } + } + } + + if (LParen && Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + Diag(LOpen, diag::note_matching) << "("; + while (!SkipUntil(tok::r_paren, tok::comma, tok::annot_pragma_openmp_end, + StopBeforeMatch)) + ; + } + if (Tok.is(tok::r_paren)) + ConsumeAnyToken(); + + if (Vars.empty() || + (Kind == OMPC_reduction && Op == OMPC_REDUCTION_unknown) || + (Kind == OMPC_depend && Op == OMPC_DEPEND_unknown) || + (Kind == OMPC_map && Op == OMPC_MAP_unknown)) return 0; - return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen, - Tok.getLocation()); + if (MustHaveTail && !TailExpr) { + // The error ('expected expression') was already emitted. + return 0; + } + + return Actions.ActOnOpenMPVarListClause( + Kind, Vars, Loc, Tok.getLocation(), Op, TailExpr, SS, OpName, + (TailExpr ? TailLoc : SourceLocation())); } +/// \brief Parsing of OpenMP clause 'linear', 'aligned' or 'uniform' for +/// the '#pragma omp declare simd'. +/// +/// linear-clause: +/// 'linear' '(' list [ ':' linear-step ] ')' +/// +/// aligned-clause: +/// 'aligned' '(' list [ ':' alignment ] ')' +/// +/// uniform-clause: +/// 'uniform' '(' list ')' +/// +bool Parser::ParseOpenMPDeclarativeVarListClause( + OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, + DeclarationNameInfoList &NameInfos, SourceLocation &StartLoc, + SourceLocation &EndLoc, Expr *&TailExpr, SourceLocation &TailLoc) { + bool IsCorrect = true; + // Check if clause is allowed for the given directive. + if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { + Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) + << getOpenMPDirectiveName(DKind); + IsCorrect = false; + } + + // The following constraint should be enforced by directive-clause + // checks before calling this routine. + assert(CKind == OMPC_linear || CKind == OMPC_aligned || + CKind == OMPC_uniform); + + NameInfos.clear(); + + // Read the source location of the clause. + StartLoc = Tok.getLocation(); + ConsumeToken(); + + // Eat '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(CKind)); + IsCorrect &= LParen; + bool NoIdentIsFound = true; + + // Parse the comma-separated identifiers list. + bool IsComma = true; + while (IsComma || + (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end) && + Tok.isNot(tok::colon))) { + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), TemplateKWLoc, + Name)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); + NameInfos.push_back(NameInfo); + NoIdentIsFound = false; + } + // Consume ','. + IsComma = Tok.is(tok::comma); + if (IsComma) { + ConsumeToken(); + } + } + bool MayHaveTail = (CKind == OMPC_linear) || (CKind == OMPC_aligned); + bool MustHaveTail = false; + TailExpr = 0; + if (MayHaveTail) { + // Parse "':' linear-step" or "':' alignment" + if (Tok.is(tok::colon)) { + MustHaveTail = true; + ConsumeAnyToken(); + ColonProtectionRAIIObject ColonRAII(*this); + TailLoc = Tok.getLocation(); + ExprResult Tail = ParseAssignmentExpression(); + if (Tail.isUsable()) { + TailExpr = Tail.take(); + } else { + SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); + } + } + } + if (NoIdentIsFound) { + Diag(Tok, diag::err_expected_ident); + IsCorrect = false; + } + + EndLoc = Tok.getLocation(); + + // Eat ')'. + IsCorrect = + ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) && IsCorrect; + + return !IsCorrect; +} diff -uNr clang-3.4/lib/Parse/ParseStmt.cpp clang/lib/Parse/ParseStmt.cpp --- clang-3.4/lib/Parse/ParseStmt.cpp 2013-11-18 03:17:37.000000000 -0500 +++ clang/lib/Parse/ParseStmt.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -343,7 +343,7 @@ case tok::annot_pragma_openmp: ProhibitAttributes(Attrs); - return ParseOpenMPDeclarativeOrExecutableDirective(); + return ParseOpenMPDeclarativeOrExecutableDirective(!OnlyStatement); } diff -uNr clang-3.4/lib/Parse/Parser.cpp clang/lib/Parse/Parser.cpp --- clang-3.4/lib/Parse/Parser.cpp 2013-12-15 21:32:55.000000000 -0500 +++ clang/lib/Parse/Parser.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -52,7 +52,7 @@ : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0), - ParsingInObjCContainer(false) { + ParsingInObjCContainer(false), IsCEANAllowed(false) { SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; Tok.startToken(); Tok.setKind(tok::eof); @@ -294,6 +294,9 @@ } switch (Tok.getKind()) { + case tok::annot_pragma_openmp_end: + // Stop before an OpenMP pragma boundary. + return false; case tok::eof: // Ran out of tokens. return false; @@ -677,8 +680,7 @@ HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); case tok::annot_pragma_openmp: - ParseOpenMPDeclarativeDirective(); - return DeclGroupPtrTy(); + return ParseOpenMPDeclarativeDirective(AS_none); case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(), diff -uNr clang-3.4/lib/Parse/RAIIObjectsForParser.h clang/lib/Parse/RAIIObjectsForParser.h --- clang-3.4/lib/Parse/RAIIObjectsForParser.h 2013-05-13 00:18:18.000000000 -0400 +++ clang/lib/Parse/RAIIObjectsForParser.h 2014-05-19 19:58:57.000000000 -0400 @@ -430,6 +430,22 @@ void skipToEnd(); }; + /// \brief A RAII object used to temporarily allow using of CEAN expressions. + class AllowCEANExpressions { + Parser &P; + bool IsCEANAllowed; + + public: + AllowCEANExpressions(Parser &P, bool IsAllowed) + : P(P), IsCEANAllowed(P.IsCEANAllowed) { + P.IsCEANAllowed = IsAllowed; + } + + ~AllowCEANExpressions() { + P.IsCEANAllowed = IsCEANAllowed; + } + }; + } // end namespace clang #endif diff -uNr clang-3.4/lib/Sema/Sema.cpp clang/lib/Sema/Sema.cpp --- clang-3.4/lib/Sema/Sema.cpp 2013-11-11 20:46:33.000000000 -0500 +++ clang/lib/Sema/Sema.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -184,6 +184,7 @@ delete I->second; if (PackContext) FreePackedContext(); if (VisContext) FreeVisContext(); + delete TheTargetAttributesSema; MSStructPragmaOn = false; // Kill all the active scopes. diff -uNr clang-3.4/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaChecking.cpp --- clang-3.4/lib/Sema/SemaChecking.cpp 2013-11-13 22:29:16.000000000 -0500 +++ clang/lib/Sema/SemaChecking.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -115,6 +115,24 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); + // Check that setjmp/longjmp are not allowed in omp simd. + switch (BuiltinID) { + case Builtin::BI_setjmp: + case Builtin::BIsetjmp: + case Builtin::BIsetjmp_syscall: + case Builtin::BIqsetjmp: + case Builtin::BIgetcontext: + case Builtin::BI__builtin_setjmp: + case Builtin::BI_longjmp: + case Builtin::BIlongjmp: + case Builtin::BI__builtin_longjmp: + if (HasOpenMPSimdRegion()) { + Diag(TheCall->getExprLoc(), diag::err_setjmp_longjmp_in_omp_simd) + << TheCall->getSourceRange(); + return ExprError(); + } + break; + } // Find out if any arguments are required to be integer constant expressions. unsigned ICEArguments = 0; ASTContext::GetBuiltinTypeError Error; diff -uNr clang-3.4/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDecl.cpp --- clang-3.4/lib/Sema/SemaDecl.cpp 2013-12-05 00:24:30.000000000 -0500 +++ clang/lib/Sema/SemaDecl.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -4409,6 +4409,10 @@ CurContext->addHiddenDecl(New); } + if (IsDeclContextInOpenMPTarget(CurContext)) { + CheckDeclIsAllowedInOpenMPTarget(0, New); + } + return New; } diff -uNr clang-3.4/lib/Sema/SemaExceptionSpec.cpp clang/lib/Sema/SemaExceptionSpec.cpp --- clang-3.4/lib/Sema/SemaExceptionSpec.cpp 2013-09-17 23:29:45.000000000 -0400 +++ clang/lib/Sema/SemaExceptionSpec.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1090,6 +1090,10 @@ // These expressions can never throw. return CT_Cannot; + case Expr::CEANIndexExprClass: { + CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; + return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + } case Expr::MSPropertyRefExprClass: llvm_unreachable("Invalid class for expression"); diff -uNr clang-3.4/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExpr.cpp --- clang-3.4/lib/Sema/SemaExpr.cpp 2013-12-05 00:25:04.000000000 -0500 +++ clang/lib/Sema/SemaExpr.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1604,6 +1604,31 @@ return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS); } +static bool CheckOMPDeclareReductionVar(Sema &S, ValueDecl *D, + SourceLocation Loc) { + if (S.CurrentInstantiationScope) return true; + if (!D || !isa(D)) return true; + if (!S.getCurScope() || !S.getCurScope()->getEntity()) return true; + if (S.getCurScope()->getEntity() != S.CurContext) return true; + DeclContext *Parent = + static_cast(S.getCurScope()->getEntity()); + if (FunctionDecl *FD = dyn_cast_or_null(Parent)) { + Parent = FD->getDeclContext(); + if (OMPDeclareReductionDecl *OMPDR = + dyn_cast_or_null(Parent)) { + if (D->getDeclContext() != FD) { + S.Diag(Loc, + (FD->getDeclName() == OMPDR->getDeclName()) ? + diag::err_omp_wrong_var_in_combiner : + diag::err_omp_wrong_var_in_initializer) + << cast(D); + return false; + } + } + } + return true; +} + /// BuildDeclRefExpr - Build an expression that references a /// declaration that does not require a closure capture. ExprResult @@ -1611,6 +1636,13 @@ const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { + // Check that only 'omp_in' and 'omp_out' can be used in + // 'omp declare reduction' combiner. + // Check that only 'omp_priv' and 'omp_orig' can be used in + // 'omp declare reduction' initializer. + if (!CheckOMPDeclareReductionVar(*this, D, NameInfo.getLoc())) + return ExprError(); + if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast(CurContext)) if (const FunctionDecl *Callee = dyn_cast(D)) { @@ -11401,6 +11433,8 @@ bool IsBlock = isa(CSI); bool IsLambda = isa(CSI); + if (Var->hasAttr()) return false; + // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). // FIXME: The C++11 rule don't actually state this explicitly, but I'm @@ -11414,7 +11448,7 @@ } // Prohibit variably-modified types; they're difficult to deal with. - if (Var->getType()->isVariablyModifiedType()) { + if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) { if (Diagnose) { if (IsBlock) S.Diag(Loc, diag::err_ref_vm_type); @@ -11889,12 +11923,122 @@ } return true; } + // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this)) return true; + if (Var->getType()->isVariablyModifiedType()) { + // We're going to walk down into the type and look for VLA + // expressions. + QualType type = Var->getType(); + if (ParmVarDecl *PVD = dyn_cast_or_null(Var)) + type = PVD->getOriginalType(); + do { + const Type *ty = type.getTypePtr(); + switch (ty->getTypeClass()) { + +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + type = QualType(); + break; + + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::Record: + case Type::Enum: + case Type::Elaborated: + case Type::TemplateSpecialization: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + llvm_unreachable("type class is never variably-modified!"); + + case Type::Decayed: + type = cast(ty)->getPointeeType(); + break; + + case Type::Pointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::BlockPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::LValueReference: + case Type::RValueReference: + type = cast(ty)->getPointeeType(); + break; + + case Type::MemberPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + type = cast(ty)->getElementType(); + break; + + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *vat = cast(ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (Expr *size = vat->getSizeExpr()) { + MarkDeclarationsReferencedInExpr(size); + } + type = vat->getElementType(); + break; + } + + case Type::FunctionProto: + case Type::FunctionNoProto: + type = cast(ty)->getResultType(); + break; + + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::SubstTemplateTypeParm: + case Type::PackExpansion: + // Keep walking after single level desugaring. + type = type.getSingleStepDesugaredType(getASTContext()); + break; + + case Type::Typedef: + type = cast(ty)->desugar(); + break; + case Type::Decltype: + type = cast(ty)->desugar(); + break; + case Type::Auto: + type = cast(ty)->getDeducedType(); + break; + + case Type::TypeOfExpr: + type = cast(ty)->getUnderlyingExpr()->getType(); + break; + + case Type::Atomic: + type = cast(ty)->getValueType(); + break; + } + } while (!type.isNull() && type->isVariablyModifiedType()); + } + if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { // No capture-default, and this is not an explicit capture // so cannot capture this variable. @@ -12184,6 +12328,11 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, bool OdrUse) { + + if (SemaRef.IsDeclContextInOpenMPTarget(SemaRef.CurContext)) { + SemaRef.CheckDeclIsAllowedInOpenMPTarget(E, D); + } + if (VarDecl *Var = dyn_cast(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; diff -uNr clang-3.4/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaExprCXX.cpp --- clang-3.4/lib/Sema/SemaExprCXX.cpp 2013-12-07 18:53:50.000000000 -0500 +++ clang/lib/Sema/SemaExprCXX.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1637,7 +1637,7 @@ NewName = Context.DeclarationNames.getCXXOperatorName(OO_New); DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, - /*AllowMissing=*/false, OperatorNew)) + /*AllowMissing=*/false, OperatorNew)) return true; } } diff -uNr clang-3.4/lib/Sema/SemaLookup.cpp clang/lib/Sema/SemaLookup.cpp --- clang-3.4/lib/Sema/SemaLookup.cpp 2013-11-01 07:50:55.000000000 -0400 +++ clang/lib/Sema/SemaLookup.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -275,6 +275,10 @@ IDNS = Decl::IDNS_ObjCProtocol; break; + case Sema::LookupOMPDeclareReduction: + IDNS = Decl::IDNS_OMPDeclareReduction; + break; + case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol @@ -1685,6 +1689,9 @@ BaseCallback = &LookupAnyMember; break; + case LookupOMPDeclareReduction: + BaseCallback = &CXXRecordDecl::FindOMPDeclareReductionMember; + break; case LookupUsingDeclName: // This lookup is for redeclarations only. diff -uNr clang-3.4/lib/Sema/SemaOpenMP.cpp clang/lib/Sema/SemaOpenMP.cpp --- clang-3.4/lib/Sema/SemaOpenMP.cpp 2013-10-08 13:08:03.000000000 -0400 +++ clang/lib/Sema/SemaOpenMP.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -1,4 +1,3 @@ -//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===// // // The LLVM Compiler Infrastructure // @@ -13,16 +12,17 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/OpenMPKinds.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" -#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" -#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" using namespace clang; @@ -34,56 +34,68 @@ namespace { /// \brief Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { - DSA_unspecified = 0, /// \brief Data sharing attribute not specified. - DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'. - DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. + DSA_unspecified = 0, /// \brief Data sharing attribute not specified. + DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'. + DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. }; /// \brief Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. class DSAStackTy { public: - struct DSAVarData { - OpenMPDirectiveKind DKind; - OpenMPClauseKind CKind; - DeclRefExpr *RefExpr; - DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(0) { } + struct MapInfo { + Expr *RefExpr; + bool IsCEAN; }; + private: struct DSAInfo { OpenMPClauseKind Attributes; DeclRefExpr *RefExpr; }; typedef llvm::SmallDenseMap DeclSAMapTy; + typedef llvm::SmallDenseMap MappedDeclsTy; struct SharingMapTy { DeclSAMapTy SharingMap; + DeclSAMapTy AlignedMap; + MappedDeclsTy MappedDecls; DefaultDataSharingAttributes DefaultAttr; OpenMPDirectiveKind Directive; DeclarationNameInfo DirectiveName; + bool IsOrdered; + bool IsNowait; Scope *CurScope; - SharingMapTy(OpenMPDirectiveKind DKind, - const DeclarationNameInfo &Name, + SharingMapTy(OpenMPDirectiveKind DKind, const DeclarationNameInfo &Name, Scope *CurScope) - : SharingMap(), DefaultAttr(DSA_unspecified), Directive(DKind), - DirectiveName(Name), CurScope(CurScope) { } + : SharingMap(), AlignedMap(), MappedDecls(), + DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(Name), + IsOrdered(false), IsNowait(false), CurScope(CurScope) {} SharingMapTy() - : SharingMap(), DefaultAttr(DSA_unspecified), - Directive(OMPD_unknown), DirectiveName(), - CurScope(0) { } + : SharingMap(), AlignedMap(), MappedDecls(), + DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), + DirectiveName(), IsOrdered(false), IsNowait(false), CurScope(0) {} }; - typedef SmallVector StackTy; + typedef SmallVector StackTy; /// \brief Stack of used declaration and their data-sharing attributes. StackTy Stack; Sema &Actions; - typedef SmallVector::reverse_iterator reverse_iterator; + typedef SmallVector::reverse_iterator reverse_iterator; + + typedef llvm::DenseSet DeclaredTargetDeclsTy; + + DeclaredTargetDeclsTy DeclaredTargetDecls; + + OpenMPClauseKind getDSA(StackTy::reverse_iterator Iter, VarDecl *D, + OpenMPDirectiveKind &Kind, DeclRefExpr *&E); + /// \brief Checks if the variable is a local for OpenMP region. + bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); - DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D); public: - explicit DSAStackTy(Sema &S) : Stack(1), Actions(S) { } + DSAStackTy(Sema &S) : Stack(1), Actions(S) {} void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope) { @@ -91,74 +103,169 @@ } void pop() { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!"); + assert(Stack.size() > 1 && "Stack is empty!"); Stack.pop_back(); } + /// \brief Adds unique 'aligned' declaration of a given VarDecl, or, + /// if it already exists, returns false. + bool addUniqueAligned(VarDecl *D, DeclRefExpr *&E); + /// \brief Adds explicit data sharing attribute to the specified declaration. void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); - /// \brief Checks if the variable is a local for OpenMP region. - bool isOpenMPLocal(VarDecl *D); + /// \brief Adds explicit data sharing attribute to the specified declaration + /// to parent scope. + void addParentDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); + + bool IsThreadprivate(VarDecl *D, DeclRefExpr *&E); /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. - DSAVarData getTopDSA(VarDecl *D); + OpenMPClauseKind getTopDSA(VarDecl *D, DeclRefExpr *&E); /// \brief Returns data-sharing attributes for the specified declaration. - DSAVarData getImplicitDSA(VarDecl *D); + OpenMPClauseKind getImplicitDSA(VarDecl *D, OpenMPDirectiveKind &Kind, + DeclRefExpr *&E); + /// \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); + bool hasDSA(VarDecl *D, OpenMPClauseKind CKind, OpenMPDirectiveKind DKind, + DeclRefExpr *&E); + /// \brief Checks if the specified variables has \a CKind data-sharing + /// attribute in an innermost \a DKind directive. + bool hasInnermostDSA(VarDecl *D, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind, DeclRefExpr *&E); - /// \brief Returns currently analyzed directive. + /// \brief Returns currently analized directive. OpenMPDirectiveKind getCurrentDirective() const { return Stack.back().Directive; } + /// \brief Returns parent directive. + OpenMPDirectiveKind getParentDirective() const { + if (Stack.size() > 2) + return Stack[Stack.size() - 2].Directive; + return OMPD_unknown; + } + + /// \brief Returns true if region is an ordered parallel or + /// worksharing region. + bool isRegionOrdered() const { + if (Stack.size() > 1) + return Stack[Stack.size() - 1].IsOrdered; + return false; + } + + /// \brief Returns true if parent region is an ordered parallel or + /// worksharing region. + bool isParentRegionOrdered() const { + if (Stack.size() > 2) + return Stack[Stack.size() - 2].IsOrdered; + return false; + } + + /// \brief Marks current regions as ordered. + void setRegionOrdered() { Stack.back().IsOrdered = true; } + + /// \brief Returns true if region has nowait clause. + bool isRegionNowait() const { + if (Stack.size() > 1) + return Stack[Stack.size() - 1].IsNowait; + return false; + } + + /// \brief Marks current regions as nowait. + void setRegionNowait() { Stack.back().IsNowait = true; } + + /// \brief Checks if the specified kind of directive with the given name + /// already exists. + bool hasDirectiveWithName(OpenMPDirectiveKind Kind, + DeclarationNameInfo DirName); + + /// \brief Checks if the specified kind of directive exists. + bool hasDirective(OpenMPDirectiveKind Kind); + /// \brief Set default data sharing attribute to none. void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; } /// \brief Set default data sharing attribute to shared. void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; } - - DefaultDataSharingAttributes getDefaultDSA() const { + DefaultDataSharingAttributes getDefaultDSA() { return Stack.back().DefaultAttr; } Scope *getCurScope() { return Stack.back().CurScope; } + + DeclContext *GetOpenMPFunctionRegion(); + + void addDeclareTargetDecl(Decl *D) { DeclaredTargetDecls.insert(D); } + + bool isDeclareTargetDecl(Decl *D) { return DeclaredTargetDecls.count(D); } + + MapInfo getMapInfoForVar(VarDecl *VD) { + MapInfo Tmp = {0, false}; + for (unsigned Cnt = Stack.size() - 1; Cnt > 0; --Cnt) { + if (Stack[Cnt].MappedDecls.count(VD)) { + Tmp = Stack[Cnt].MappedDecls[VD]; + break; + } + } + return Tmp; + } + + void addMapInfoForVar(VarDecl *VD, MapInfo MI) { + if (Stack.size() > 1) { + Stack.back().MappedDecls[VD] = MI; + } + } + + MapInfo IsMappedInCurrentRegion(VarDecl *VD) { + assert(Stack.size() > 1 && "Target level is 0"); + MapInfo Tmp = {0, false}; + if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) { + Tmp = Stack.back().MappedDecls[VD]; + } + return Tmp; + } }; } // end anonymous namespace. -DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, - VarDecl *D) { - DSAVarData DVar; +OpenMPClauseKind DSAStackTy::getDSA(StackTy::reverse_iterator Iter, VarDecl *D, + OpenMPDirectiveKind &Kind, + DeclRefExpr *&E) { + E = 0; if (Iter == Stack.rend() - 1) { + Kind = OMPD_unknown; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // File-scope or namespace-scope variables referenced in called routines // in the region are shared unless they appear in a threadprivate // directive. - // TODO if (!D->isFunctionOrMethodVarDecl()) - DVar.CKind = OMPC_shared; + return 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 OMPC_shared; - return DVar; + return OMPC_unknown; } - DVar.DKind = Iter->Directive; + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++, predetermined, p.1] + // Variables with automatic storage duration that are declared in a scope + // inside the construct are private. + Kind = Iter->Directive; + if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() && + (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) + return OMPC_private; // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { - DVar.RefExpr = Iter->SharingMap[D].RefExpr; - DVar.CKind = Iter->SharingMap[D].Attributes; - return DVar; + E = Iter->SharingMap[D].RefExpr; + return Iter->SharingMap[D].Attributes; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -167,49 +274,53 @@ // variables are determined by the default clause, if present. switch (Iter->DefaultAttr) { case DSA_shared: - DVar.CKind = OMPC_shared; - return DVar; + return OMPC_shared; case DSA_none: - return DVar; + return OMPC_unknown; case DSA_unspecified: // 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. - if (DVar.DKind == OMPD_parallel) { - DVar.CKind = OMPC_shared; - return DVar; - } + if (Kind == OMPD_parallel || Kind == OMPD_teams || + Kind == OMPD_parallel_for || Kind == OMPD_parallel_for_simd || + Kind == OMPD_parallel_sections || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || + Kind == OMPD_target_teams) + return OMPC_shared; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.4] // In a task construct, if no default clause is present, a variable that in // the enclosing context is determined to be shared by all implicit tasks // bound to the current team is shared. - // TODO - if (DVar.DKind == OMPD_task) { - DSAVarData DVarTemp; - for (StackTy::reverse_iterator I = Iter + 1, - EE = Stack.rend() - 1; + if (Kind == OMPD_task) { + OpenMPClauseKind CKind = OMPC_unknown; + for (StackTy::reverse_iterator I = Iter + 1, EE = Stack.rend() - 1; I != EE; ++I) { - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables + // Referenced // in a Construct, implicitly determined, p.6] // In a task construct, if no default clause is present, a variable // whose data-sharing attribute is not determined by the rules above is // firstprivate. - DVarTemp = getDSA(I, D); - if (DVarTemp.CKind != OMPC_shared) { - DVar.RefExpr = 0; - DVar.DKind = OMPD_task; - DVar.CKind = OMPC_firstprivate; - return DVar; - } - if (I->Directive == OMPD_parallel) break; - } - DVar.DKind = OMPD_task; - DVar.CKind = - (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; - return DVar; + CKind = getDSA(I, D, Kind, E); + if (CKind != OMPC_shared) { + E = 0; + Kind = OMPD_task; + return OMPC_firstprivate; + } + if (I->Directive == OMPD_parallel || + I->Directive == OMPD_parallel_for || + I->Directive == OMPD_parallel_for_simd || + I->Directive == OMPD_parallel_sections || + I->Directive == OMPD_distribute_parallel_for || + I->Directive == OMPD_distribute_parallel_for_simd) + break; + } + Kind = OMPD_task; + return (CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; } } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -217,7 +328,21 @@ // For constructs other than task, if no default clause is present, these // variables inherit their data-sharing attributes from the enclosing // context. - return getDSA(Iter + 1, D); + return getDSA(Iter + 1, D, Kind, E); +} + +bool DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *&E) { + assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); + DeclSAMapTy::iterator It = Stack.back().AlignedMap.find(D); + if (It == Stack.back().AlignedMap.end()) { + Stack.back().AlignedMap[D].Attributes = OMPC_aligned; + Stack.back().AlignedMap[D].RefExpr = E; + return true; + } else { + assert(Stack.back().AlignedMap[D].Attributes == OMPC_aligned); + E = Stack.back().AlignedMap[D].RefExpr; + return false; + } } void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { @@ -225,70 +350,91 @@ Stack[0].SharingMap[D].Attributes = A; Stack[0].SharingMap[D].RefExpr = E; } else { - assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); Stack.back().SharingMap[D].Attributes = A; Stack.back().SharingMap[D].RefExpr = E; } } -bool DSAStackTy::isOpenMPLocal(VarDecl *D) { - Scope *CurScope = getCurScope(); - while (CurScope && !CurScope->isDeclScope(D)) - CurScope = CurScope->getParent(); - while (CurScope && !CurScope->isOpenMPDirectiveScope()) - CurScope = CurScope->getParent(); - bool isOpenMPLocal = !!CurScope; - if (!isOpenMPLocal) { - CurScope = getCurScope(); - while (CurScope && !CurScope->isOpenMPDirectiveScope()) +void DSAStackTy::addParentDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { + assert(Stack.size() > 2 && + "Data sharing attributes stack does not have parent"); + Stack[Stack.size() - 2].SharingMap[D].Attributes = A; + Stack[Stack.size() - 2].SharingMap[D].RefExpr = E; +} + +bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { + if (Stack.size() > 2) { + reverse_iterator I = Iter, E = Stack.rend() - 1; + Scope *TopScope = 0; + while (I != E && I->Directive != OMPD_parallel && + I->Directive != OMPD_parallel_for && + I->Directive != OMPD_parallel_for_simd && + I->Directive != OMPD_parallel_sections && + I->Directive != OMPD_distribute_parallel_for && + I->Directive != OMPD_distribute_parallel_for_simd && + I->Directive != OMPD_task && I->Directive != OMPD_teams && + I->Directive != OMPD_target_teams) { + ++I; + } + if (I == E) + return false; + TopScope = I->CurScope ? I->CurScope->getParent() : 0; + Scope *CurScope = getCurScope(); + while (CurScope != TopScope && !CurScope->isDeclScope(D)) { CurScope = CurScope->getParent(); - isOpenMPLocal = - CurScope && - isa(D->getDeclContext()) && - CurScope->getFnParent()->getEntity()->Encloses(D->getDeclContext()); + } + return CurScope != TopScope; + } + return false; +} + +bool DSAStackTy::IsThreadprivate(VarDecl *D, DeclRefExpr *&E) { + E = 0; + if (D->getTLSKind() != VarDecl::TLS_None) + return true; + if (Stack[0].SharingMap.count(D)) { + E = Stack[0].SharingMap[D].RefExpr; + return true; } - return isOpenMPLocal; + return false; } -DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) { - DSAVarData DVar; +OpenMPClauseKind DSAStackTy::getTopDSA(VarDecl *D, DeclRefExpr *&E) { + E = 0; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if (D->getTLSKind() != VarDecl::TLS_None) { - DVar.CKind = OMPC_threadprivate; - return DVar; - } - if (Stack[0].SharingMap.count(D)) { - DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; - DVar.CKind = OMPC_threadprivate; - return DVar; - } + if (IsThreadprivate(D, E)) + return OMPC_threadprivate; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope // inside the construct are private. - if (isOpenMPLocal(D) && D->isLocalVarDecl() && - (D->getStorageClass() == SC_Auto || - D->getStorageClass() == SC_None)) { - DVar.CKind = OMPC_private; - return DVar; + OpenMPDirectiveKind Kind = getCurrentDirective(); + if (Kind != OMPD_parallel && Kind != OMPD_parallel_for && + Kind != OMPD_parallel_for_simd && Kind != OMPD_distribute_parallel_for && + Kind != OMPD_distribute_parallel_for_simd && Kind != OMPD_task && + Kind != OMPD_teams && Kind != OMPD_parallel_sections && + Kind != OMPD_target_teams) { + if (isOpenMPLocal(D, Stack.rbegin() + 1) && D->isLocalVarDecl() && + (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) + return OMPC_private; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // 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 + DeclRefExpr *E; + // 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; + if (hasDSA(D, OMPC_firstprivate, OMPD_unknown, E) && E) + return OMPC_unknown; + return OMPC_shared; } QualType Type = D->getType().getNonReferenceType().getCanonicalType(); @@ -301,54 +447,102 @@ // in a Construct, C/C++, predetermined, p.6] // Variables with const qualified type having no mutable member are // shared. - CXXRecordDecl *RD = Actions.getLangOpts().CPlusPlus ? - Type->getAsCXXRecordDecl() : 0; + CXXRecordDecl *RD = + Actions.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; if (IsConstant && !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { + DeclRefExpr *E; // 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; + // listed + // in a firstprivate clause, even if they are static data members. + if (hasDSA(D, OMPC_firstprivate, OMPD_unknown, E) && E) + return OMPC_unknown; + return OMPC_shared; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. - if (isOpenMPLocal(D) && D->isStaticLocal()) { - DVar.CKind = OMPC_shared; - return DVar; - } + if (D->isStaticLocal()) + return OMPC_shared; // Explicitly specified attributes and local variables with predetermined // attributes. if (Stack.back().SharingMap.count(D)) { - DVar.RefExpr = Stack.back().SharingMap[D].RefExpr; - DVar.CKind = Stack.back().SharingMap[D].Attributes; + E = Stack.back().SharingMap[D].RefExpr; + return Stack.back().SharingMap[D].Attributes; } - return DVar; + return OMPC_unknown; } -DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) { - return getDSA(Stack.rbegin() + 1, D); +OpenMPClauseKind DSAStackTy::getImplicitDSA(VarDecl *D, + OpenMPDirectiveKind &Kind, + DeclRefExpr *&E) { + return getDSA(Stack.rbegin() + 1, D, Kind, E); } -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; +bool DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind, DeclRefExpr *&E) { + for (StackTy::reverse_iterator I = Stack.rbegin() + 1, EE = Stack.rend() - 1; + I != EE; ++I) { + if (DKind != OMPD_unknown && DKind != I->Directive) + continue; + OpenMPDirectiveKind K; + if (getDSA(I, D, K, E) == CKind) + return true; + } + E = 0; + return false; +} + +bool DSAStackTy::hasInnermostDSA(VarDecl *D, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind, DeclRefExpr *&E) { + assert(DKind != OMPD_unknown && "Directive must be specified explicitly"); + for (StackTy::reverse_iterator I = Stack.rbegin(), EE = Stack.rend() - 1; + I != EE; ++I) { + if (DKind != I->Directive) + continue; + if (getDSA(I, D, DKind, E) == CKind) + return true; + return false; + } + return false; +} + +bool DSAStackTy::hasDirectiveWithName(OpenMPDirectiveKind Kind, + DeclarationNameInfo DirName) { + for (reverse_iterator I = Stack.rbegin() + 1, E = Stack.rend() - 1; I != E; + ++I) { + if (I->Directive == Kind && + !DeclarationName::compare(I->DirectiveName.getName(), + DirName.getName())) + return true; + } + return false; +} + +bool DSAStackTy::hasDirective(OpenMPDirectiveKind Kind) { + for (reverse_iterator I = Stack.rbegin(), E = Stack.rend() - 1; I != E; ++I) { + if (I->Directive == Kind) + return true; + } + return false; +} + +DeclContext *DSAStackTy::GetOpenMPFunctionRegion() { + for (reverse_iterator I = Stack.rbegin(), E = Stack.rend() - 1; I != E; ++I) { + if (I->Directive == OMPD_parallel || I->Directive == OMPD_parallel_for || + I->Directive == OMPD_parallel_for_simd || + I->Directive == OMPD_distribute_parallel_for || + I->Directive == OMPD_distribute_parallel_for_simd || + I->Directive == OMPD_teams || I->Directive == OMPD_task || + I->Directive == OMPD_parallel_sections || + I->Directive == OMPD_target_teams) + return I->CurScope->getEntity(); } - return DSAVarData(); + return 0; } void Sema::InitDataSharingAttributesStack() { @@ -357,30 +551,133 @@ #define DSAStack static_cast(VarDataSharingAttributesStack) -void Sema::DestroyDataSharingAttributesStack() { - delete DSAStack; +void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } + +bool Sema::HasOpenMPRegion(OpenMPDirectiveKind Kind) { + return DSAStack->hasDirective(Kind); +} + +bool Sema::HasOpenMPSimdRegion() { + return HasOpenMPRegion(OMPD_simd) || HasOpenMPRegion(OMPD_for_simd) || + HasOpenMPRegion(OMPD_parallel_for_simd) || + HasOpenMPRegion(OMPD_distribute_simd) || + HasOpenMPRegion(OMPD_for_simd) || + HasOpenMPRegion(OMPD_distribute_parallel_for_simd); +} + +bool Sema::IsDeclContextInOpenMPTarget(DeclContext *DC) { + while (DC && !isa(DC)) { + DC = DC->getParent(); + } + return DC != 0; +} + +DeclContext *Sema::GetOpenMPFunctionRegion() { + return DSAStack->GetOpenMPFunctionRegion(); } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope) { DSAStack->push(DKind, DirName, CurScope); + PushExpressionEvaluationContext(PotentiallyEvaluated); } void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { + // if (!getCurScope()->isOpenMPDirectiveScope()) return; + // OpenMP [2.9.3.5, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a lastprivate + // clause requires an accessible, unambiguous default constructor for the + // class type, unless the list item is also specified in a firstprivate + // clause. + + if (OMPExecutableDirective *D = + dyn_cast_or_null(CurDirective)) { + for (ArrayRef::iterator I = D->clauses().begin(), + E = D->clauses().end(); + I != E; ++I) { + if (OMPLastPrivateClause *Clause = dyn_cast(*I)) { + SmallVector DefaultInits; + ArrayRef::iterator PVIter = Clause->getPseudoVars1().begin(); + for (OMPLastPrivateClause::varlist_iterator + VI = Clause->varlist_begin(), + VE = Clause->varlist_end(); + VI != VE; ++VI, ++PVIter) { + if ((*VI)->isValueDependent() || (*VI)->isTypeDependent() || + (*VI)->isInstantiationDependent() || + (*VI)->containsUnexpandedParameterPack()) { + DefaultInits.push_back(0); + continue; + } + DeclRefExpr *DE; + VarDecl *VD = cast(cast(*VI)->getDecl()); + QualType Type = (*VI)->getType().getCanonicalType(); + if (DSAStack->getTopDSA(VD, DE) == OMPC_lastprivate) { + SourceLocation ELoc = (*VI)->getExprLoc(); + while (Type->isArrayType()) { + QualType ElemType = + cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXConstructorDecl *CD = LookupDefaultConstructor(RD); + 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_lastprivate) << 0; + 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); + } + VD = cast(cast(*PVIter)->getDecl()); + InitializedEntity Entity = + InitializedEntity::InitializeVariable(VD); + InitializationKind InitKind = + InitializationKind::CreateDefault(ELoc); + InitializationSequence InitSeq(*this, Entity, InitKind, + MultiExprArg()); + ExprResult Res = + InitSeq.Perform(*this, Entity, InitKind, MultiExprArg()); + if (Res.isInvalid()) + continue; + DefaultInits.push_back(ActOnFinishFullExpr(Res.take()).take()); + } else { + DefaultInits.push_back(0); + } + } + if (DefaultInits.size() == Clause->numberOfVariables()) + Clause->setDefaultInits(DefaultInits); + } + } + } + DSAStack->pop(); DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); } namespace { - class VarDeclFilterCCC : public CorrectionCandidateCallback { private: Sema &Actions; + public: - VarDeclFilterCCC(Sema &S) : Actions(S) { } + VarDeclFilterCCC(Sema &S) : Actions(S) {} virtual bool ValidateCandidate(const TypoCorrection &Candidate) { NamedDecl *ND = Candidate.getCorrectionDecl(); if (VarDecl *VD = dyn_cast_or_null(ND)) { @@ -405,12 +702,13 @@ VarDecl *VD; if (!Lookup.isSingleResult()) { VarDeclFilterCCC Validator(*this); - if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope, - 0, Validator)) { + if (TypoCorrection Corrected = + CorrectTypo(Id, LookupOrdinaryName, CurScope, 0, Validator)) { diagnoseTypo(Corrected, - PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest - : diag::err_omp_expected_var_arg_suggest) - << Id.getName()); + PDiag(Lookup.empty() + ? diag::err_undeclared_var_use_suggest + : diag::err_omp_expected_var_arg_suggest) + << Id.getName()); VD = Corrected.getCorrectionDeclAs(); } else { Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use @@ -420,8 +718,7 @@ } } else { if (!(VD = Lookup.getAsSingle())) { - Diag(Id.getLoc(), diag::err_omp_expected_var_arg) - << Id.getName(); + Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName(); Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); return ExprError(); } @@ -432,70 +729,40 @@ // Variables must be file-scope, namespace-scope, or static block-scope. if (!VD->hasGlobalStorage()) { Diag(Id.getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) - << !VD->isStaticLocal(); - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; + << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal(); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; return ExprError(); } - VarDecl *CanonicalVD = VD->getCanonicalDecl(); - NamedDecl *ND = cast(CanonicalVD); // OpenMP [2.9.2, Restrictions, C/C++, p.2] // A threadprivate directive for file-scope variables must appear outside // any definition or declaration. - if (CanonicalVD->getDeclContext()->isTranslationUnit() && - !getCurLexicalContext()->isTranslationUnit()) { - Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; - return ExprError(); - } // OpenMP [2.9.2, Restrictions, C/C++, p.3] // A threadprivate directive for static class member variables must appear // in the class definition, in the same scope in which the member // variables are declared. - if (CanonicalVD->isStaticDataMember() && - !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) { - Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; - return ExprError(); - } // OpenMP [2.9.2, Restrictions, C/C++, p.4] // A threadprivate directive for namespace-scope variables must appear // outside any definition or declaration other than the namespace // definition itself. - if (CanonicalVD->getDeclContext()->isNamespace() && - (!getCurLexicalContext()->isFileContext() || - !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) { - Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; - return ExprError(); - } // OpenMP [2.9.2, Restrictions, C/C++, p.6] // A threadprivate directive for static block-scope variables must appear // in the scope of the variable and not in a nested scope. - if (CanonicalVD->isStaticLocal() && CurScope && - !isDeclInScope(ND, getCurLexicalContext(), CurScope)) { + NamedDecl *ND = cast(VD); + if ((!getCurLexicalContext()->isFileContext() || + !VD->getDeclContext()->isFileContext()) && + !isDeclInScope(ND, getCurLexicalContext(), getCurScope())) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; return ExprError(); } @@ -504,32 +771,30 @@ // of the variables in its list. if (VD->isUsed()) { Diag(Id.getLoc(), diag::err_omp_var_used) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; return ExprError(); } QualType ExprType = VD->getType().getNonReferenceType(); - ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc()); - DSAStack->addDSA(VD, cast(DE.get()), OMPC_threadprivate); + ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_LValue, Id.getLoc()); return DE; } -Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - ArrayRef VarList) { +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, + ArrayRef VarList) { if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) { + D->setAccess(AS_public); CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } return DeclGroupPtrTy(); } -OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( - SourceLocation Loc, - ArrayRef VarList) { - SmallVector Vars; - for (ArrayRef::iterator I = VarList.begin(), - E = VarList.end(); +OMPThreadPrivateDecl * +Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef VarList) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { DeclRefExpr *DE = cast(*I); VarDecl *VD = cast(DE->getDecl()); @@ -546,617 +811,7211 @@ // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) - << VD->getType(); - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; continue; } // Check if this is a TLS variable. if (VD->getTLSKind()) { Diag(ILoc, diag::err_omp_var_thread_local) << VD; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; continue; } + QualType Type = VD->getType().getNonReferenceType().getCanonicalType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + SourceLocation ELoc = (*I)->getExprLoc(); + CXXDestructorDecl *DD = RD->getDestructor(); + PartialDiagnostic PD = + PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); + if (DD && (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || + DD->isDeleted())) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_threadprivate) << 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; + } else if (DD) { + MarkFunctionReferenced(ELoc, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + + DSAStack->addDSA(VD, DE, OMPC_threadprivate); Vars.push_back(*I); } - return Vars.empty() ? - 0 : OMPThreadPrivateDecl::Create(Context, - getCurLexicalContext(), - Loc, Vars); + return Vars.empty() ? 0 : OMPThreadPrivateDecl::Create( + Context, getCurLexicalContext(), Loc, Vars); } -namespace { -class DSAAttrChecker : public StmtVisitor { - DSAStackTy *Stack; - Sema &Actions; - bool ErrorFound; - CapturedStmt *CS; - llvm::SmallVector ImplicitFirstprivate; -public: - void VisitDeclRefExpr(DeclRefExpr *E) { - if(VarDecl *VD = dyn_cast(E->getDecl())) { - // Skip internally declared variables. - if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return; - - SourceLocation ELoc = E->getExprLoc(); +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( + SourceLocation Loc, Decl *FuncDecl, ArrayRef SrcRanges, + ArrayRef BeginIdx, ArrayRef EndIdx, + ArrayRef CL) { + DeclContext *CurDC = getCurLexicalContext(); + if (OMPDeclareSimdDecl *D = CheckOMPDeclareSimdDecl( + Loc, FuncDecl, SrcRanges, BeginIdx, EndIdx, CL, CurDC)) { + D->setAccess(AS_public); + CurContext->addDecl(D); + if (FunctionTemplateDecl *FTDecl = + dyn_cast(FuncDecl)) { + OMPDSimdMap[FTDecl] = D; + } + return DeclGroupPtrTy::make(DeclGroupRef(D)); + } + return DeclGroupPtrTy(); +} - OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); - 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) - ImplicitFirstprivate.push_back(DVar.RefExpr); - return; +OMPDeclareSimdDecl *Sema::CheckOMPDeclareSimdDecl( + SourceLocation Loc, Decl *FuncDecl, ArrayRef SrcRanges, + ArrayRef BeginIdx, ArrayRef EndIdx, + ArrayRef CL, DeclContext *CurDC) { + // Checks the clauses and their arguments. + // + typedef llvm::SmallDenseMap SeenVarMap; + SeenVarMap SeenVarsLinear, SeenVarsAligned; + // Build NewBeginIdx/NewEndIdx to remove the dead (NULL) clauses. + // + SmallVector NewBeginIdx; + SmallVector NewEndIdx; + SmallVector NewCL; + unsigned NumDeadClauses = 0; + for (unsigned J = 0; J < BeginIdx.size(); ++J) { + unsigned BeginI = BeginIdx[J]; + unsigned EndI = EndIdx[J]; + SeenVarsLinear.clear(); + SeenVarsAligned.clear(); + bool hasInBranch = false; + bool hasNotInBranch = false; + SourceLocation PrevLocInBranch; + NewBeginIdx.push_back(BeginI - NumDeadClauses); + // Walk the current variant's clauses. + for (unsigned Idx = BeginI; Idx < EndI; ++Idx) { + OMPClause *Clause = CL[Idx]; + if (OMPUniformClause *C = dyn_cast_or_null(Clause)) { + for (OMPUniformClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + DeclRefExpr *DE = cast(*I); + VarDecl *VD = cast(DE->getDecl()); + SeenVarMap::iterator SVI = SeenVarsLinear.find(VD); + if (SVI != SeenVarsLinear.end()) { + Diag(DE->getLocation(), + diag::err_omp_at_most_one_uniform_or_linear); + Diag(SVI->second, diag::note_omp_referenced); + } else { + SeenVarsLinear.insert(std::make_pair(VD, DE->getLocation())); + } + } + } else if (OMPLinearClause *C = + dyn_cast_or_null(Clause)) { + for (OMPLinearClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + DeclRefExpr *DE = cast(*I); + VarDecl *VD = cast(DE->getDecl()); + SeenVarMap::iterator SVI = SeenVarsLinear.find(VD); + if (SVI != SeenVarsLinear.end()) { + Diag(DE->getLocation(), + diag::err_omp_at_most_one_uniform_or_linear); + Diag(SVI->second, diag::note_omp_referenced); + } else { + SeenVarsLinear.insert(std::make_pair(VD, DE->getLocation())); + } + } + } else if (OMPAlignedClause *C = + dyn_cast_or_null(Clause)) { + for (OMPAlignedClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + DeclRefExpr *DE = cast(*I); + VarDecl *VD = cast(DE->getDecl()); + SeenVarMap::iterator SVI = SeenVarsAligned.find(VD); + if (SVI != SeenVarsAligned.end()) { + Diag(DE->getLocation(), diag::err_omp_at_most_one_aligned); + Diag(SVI->second, diag::note_omp_referenced); + } else { + SeenVarsAligned.insert(std::make_pair(VD, DE->getLocation())); + } + } + } else if (OMPInBranchClause *C = + dyn_cast_or_null(Clause)) { + if (hasNotInBranch) { + Diag(C->getLocStart(), diag::err_omp_inbranch); + Diag(PrevLocInBranch, diag::note_omp_specified); + Clause = 0; + } + hasInBranch = true; + PrevLocInBranch = C->getLocStart(); + } else if (OMPNotInBranchClause *C = + dyn_cast_or_null(Clause)) { + if (hasInBranch) { + Diag(C->getLocStart(), diag::err_omp_inbranch); + Diag(PrevLocInBranch, diag::note_omp_specified); + Clause = 0; + } + hasNotInBranch = true; + PrevLocInBranch = C->getLocStart(); } - // The default(none) clause requires that each variable that is referenced - // in the construct, and does not have a predetermined data-sharing - // attribute, must have its data-sharing attribute explicitly determined - // by being listed in a data-sharing attribute clause. - if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none && - (DKind == OMPD_parallel || DKind == OMPD_task)) { - ErrorFound = true; - Actions.Diag(ELoc, diag::err_omp_no_dsa_for_variable) << VD; - return; + if (Clause == 0) { + ++NumDeadClauses; + } else { + NewCL.push_back(Clause); } + } + NewEndIdx.push_back(EndI - NumDeadClauses); + } - // OpenMP [2.9.3.6, Restrictions, p.2] - // A list item that appears in a reduction clause of the innermost - // enclosing worksharing or parallel construct may not be accessed in an - // explicit task. - // TODO: + OMPDeclareSimdDecl *D = OMPDeclareSimdDecl::Create( + Context, CurDC, Loc, FuncDecl, SrcRanges.size(), NewCL); + CompleteOMPDeclareSimdDecl(D, SrcRanges, NewBeginIdx, NewEndIdx); + return D; +} - // Define implicit data-sharing attributes for task. - DVar = Stack->getImplicitDSA(VD); - if (DKind == OMPD_task && DVar.CKind != OMPC_shared) - ImplicitFirstprivate.push_back(DVar.RefExpr); +void Sema::CompleteOMPDeclareSimdDecl(OMPDeclareSimdDecl *D, + ArrayRef SrcRanges, + ArrayRef BeginIdx, + ArrayRef EndIdx) { + SmallVector Data; + ArrayRef::iterator IS = SrcRanges.begin(); + ArrayRef::iterator IB = BeginIdx.begin(); + ArrayRef::iterator IE = EndIdx.begin(); + for (ArrayRef::iterator ES = SrcRanges.end(); IS != ES; + ++IS, ++IB, ++IE) { + Data.push_back(OMPDeclareSimdDecl::SimdVariant(*IS, *IB, *IE)); + } + D->setVariants(Data); +} + +OMPDeclareReductionDecl *Sema::OMPDeclareReductionRAII::InitDeclareReduction( + Scope *CS, DeclContext *DC, SourceLocation Loc, DeclarationName Name, + unsigned NumTypes, AccessSpecifier AS) { + OMPDeclareReductionDecl *D = + OMPDeclareReductionDecl::Create(S.Context, DC, Loc, Name, NumTypes); + if (CS) + S.PushOnScopeChains(D, CS); + else + DC->addDecl(D); + D->setAccess(AS); + return D; +} + +Decl *Sema::OMPDeclareReductionRAII::getDecl() { return D; } + +Sema::OMPDeclareReductionRAII::OMPDeclareReductionRAII( + Sema &S, Scope *CS, DeclContext *DC, SourceLocation Loc, DeclarationName DN, + unsigned NumTypes, AccessSpecifier AS) + : S(S), D(InitDeclareReduction(CS, DC, Loc, DN, NumTypes, AS)), + SavedContext(S, D) {} + +FunctionDecl * +Sema::OMPDeclareReductionFunctionScope::ActOnOMPDeclareReductionFunction( + Sema &S, SourceLocation Loc, DeclarationName Name, QualType QTy) { + QualType PtrQTy = S.Context.getPointerType(QTy); + QualType Args[] = {PtrQTy, PtrQTy}; + FunctionProtoType::ExtProtoInfo EPI; + QualType FuncType = S.Context.getFunctionType(S.Context.VoidTy, Args, EPI); + TypeSourceInfo *TI = S.Context.getTrivialTypeSourceInfo(FuncType); + FunctionTypeLoc FTL = TI->getTypeLoc().getAs(); + FunctionDecl *FD = + FunctionDecl::Create(S.Context, S.CurContext, Loc, Loc, Name, FuncType, + TI, SC_PrivateExtern, false, false); + FD->setImplicit(); + S.CurContext->addDecl(FD); + if (S.CurContext->isDependentContext()) { + DeclContext *DC = S.CurContext->getParent(); + TemplateParameterList *TPL = 0; + if (ClassTemplatePartialSpecializationDecl *CTPSD = + dyn_cast(DC)) { + TPL = CTPSD->getTemplateParameters(); + } else if (CXXRecordDecl *RD = dyn_cast(DC)) { + TPL = RD->getDescribedClassTemplate() + ->getCanonicalDecl() + ->getTemplateParameters(); + } else if (FunctionDecl *RD = dyn_cast(DC)) { + TPL = RD->getDescribedFunctionTemplate() + ->getCanonicalDecl() + ->getTemplateParameters(); } + FunctionTemplateDecl *FTD = FunctionTemplateDecl::Create( + S.Context, S.CurContext, Loc, Name, TPL, FD); + FD->setDescribedFunctionTemplate(FTD); } - void VisitOMPExecutableDirective(OMPExecutableDirective *S) { - for (ArrayRef::iterator I = S->clauses().begin(), - E = S->clauses().end(); - I != E; ++I) - if (OMPClause *C = *I) - for (StmtRange R = C->children(); R; ++R) - if (Stmt *Child = *R) - Visit(Child); + ParLHS = ParmVarDecl::Create(S.Context, FD, Loc, Loc, 0, PtrQTy, + S.Context.getTrivialTypeSourceInfo(PtrQTy), + SC_None, 0); + ParLHS->setScopeInfo(0, 0); + ParRHS = ParmVarDecl::Create(S.Context, FD, Loc, Loc, 0, PtrQTy, + S.Context.getTrivialTypeSourceInfo(PtrQTy), + SC_None, 0); + ParRHS->setScopeInfo(0, 1); + ParmVarDecl *Params[] = {ParLHS, ParRHS}; + FD->setParams(Params); + FTL.setArg(0, ParLHS); + FTL.setArg(1, ParRHS); + OmpIn = + VarDecl::Create(S.Context, FD, Loc, Loc, &S.Context.Idents.get("omp_in"), + QTy, S.Context.getTrivialTypeSourceInfo(QTy), SC_Auto); + OmpOut = + VarDecl::Create(S.Context, FD, Loc, Loc, &S.Context.Idents.get("omp_out"), + QTy, S.Context.getTrivialTypeSourceInfo(QTy), SC_Auto); + S.AddKnownFunctionAttributes(FD); + if (S.CurScope) { + S.PushFunctionScope(); + S.PushDeclContext(S.CurScope, FD); + S.PushOnScopeChains(OmpOut, S.CurScope); + S.PushOnScopeChains(OmpIn, S.CurScope); + S.PushExpressionEvaluationContext(PotentiallyEvaluated); + } else { + S.CurContext = FD; + FD->addDecl(OmpIn); + FD->addDecl(OmpOut); } - void VisitStmt(Stmt *S) { - for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); - I != E; ++I) - if (Stmt *Child = *I) - if (!isa(Child)) - Visit(Child); + ExprResult LHS = + S.BuildDeclRefExpr(ParLHS, ParLHS->getType(), VK_LValue, Loc); + ExprResult RHS = + S.BuildDeclRefExpr(ParRHS, ParRHS->getType(), VK_LValue, Loc); + LHS = S.DefaultLvalueConversion(LHS.take()); + RHS = S.DefaultLvalueConversion(RHS.take()); + LHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.take()); + RHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, RHS.take()); + LHS = S.ActOnFinishFullExpr(LHS.take()); + RHS = S.ActOnFinishFullExpr(RHS.take()); + S.AddInitializerToDecl(OmpOut, LHS.take(), true, false); + S.AddInitializerToDecl(OmpIn, RHS.take(), true, false); + return FD; +} + +void Sema::OMPDeclareReductionFunctionScope::setBody(Expr *E) { + if (!E) { + FD->setBody(S.ActOnNullStmt(SourceLocation()).take()); + FD->setInvalidDecl(); + return; + } + StmtResult S1 = S.ActOnDeclStmt(DeclGroupPtrTy::make(DeclGroupRef(OmpIn)), + E->getExprLoc(), E->getExprLoc()); + StmtResult S2 = S.ActOnDeclStmt(DeclGroupPtrTy::make(DeclGroupRef(OmpOut)), + E->getExprLoc(), E->getExprLoc()); + ExprResult S3 = S.IgnoredValueConversions(E); + ExprResult LHS = + S.BuildDeclRefExpr(ParLHS, ParLHS->getType(), VK_LValue, E->getExprLoc()); + LHS = S.DefaultLvalueConversion(LHS.take()); + LHS = S.CreateBuiltinUnaryOp(E->getExprLoc(), UO_Deref, LHS.take()); + ExprResult RHS = + S.BuildDeclRefExpr(OmpOut, OmpOut->getType(), VK_LValue, E->getExprLoc()); + ExprResult Res = + S.BuildBinOp(0, E->getExprLoc(), BO_Assign, LHS.take(), RHS.take()); + ExprResult S4 = S.IgnoredValueConversions(Res.take()); + if (S1.isInvalid() || S2.isInvalid() || S3.isInvalid() || S4.isInvalid()) { + FD->setBody(S.ActOnNullStmt(SourceLocation()).take()); + FD->setInvalidDecl(); + } else { + CompoundScopeRAII CompoundScope(S); + Stmt *Stmts[] = {S1.take(), S2.take(), S3.take(), S4.take()}; + StmtResult Body = + S.ActOnCompoundStmt(E->getExprLoc(), E->getExprLoc(), Stmts, false); + FD->setBody(Body.take()); + } +} + +Expr *Sema::OMPDeclareReductionFunctionScope::getCombiner() { + ExprResult Res = + S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, FD->getLocation()); + return Res.take(); +} + +FunctionDecl *Sema::OMPDeclareReductionInitFunctionScope:: + ActOnOMPDeclareReductionInitFunction(Sema &S, SourceLocation Loc, + DeclarationName Name, QualType QTy) { + QualType PtrQTy = S.Context.getPointerType(QTy); + QualType Args[] = {PtrQTy, PtrQTy}; + FunctionProtoType::ExtProtoInfo EPI; + QualType FuncType = S.Context.getFunctionType(S.Context.VoidTy, Args, EPI); + TypeSourceInfo *TI = S.Context.getTrivialTypeSourceInfo(FuncType); + FunctionTypeLoc FTL = TI->getTypeLoc().getAs(); + FunctionDecl *FD = + FunctionDecl::Create(S.Context, S.CurContext, Loc, Loc, + DeclarationName(&S.Context.Idents.get("init")), + FuncType, TI, SC_PrivateExtern, false, false); + FD->setImplicit(); + S.CurContext->addDecl(FD); + if (S.CurContext->isDependentContext()) { + DeclContext *DC = S.CurContext->getParent(); + TemplateParameterList *TPL = 0; + if (ClassTemplatePartialSpecializationDecl *CTPSD = + dyn_cast(DC)) { + TPL = CTPSD->getTemplateParameters(); + } else if (CXXRecordDecl *RD = dyn_cast(DC)) { + TPL = RD->getDescribedClassTemplate() + ->getCanonicalDecl() + ->getTemplateParameters(); + } else if (FunctionDecl *RD = dyn_cast(DC)) { + TPL = RD->getDescribedFunctionTemplate() + ->getCanonicalDecl() + ->getTemplateParameters(); } + FunctionTemplateDecl *FTD = FunctionTemplateDecl::Create( + S.Context, S.CurContext, Loc, Name, TPL, FD); + FD->setDescribedFunctionTemplate(FTD); + } + ParLHS = ParmVarDecl::Create(S.Context, FD, Loc, Loc, 0, PtrQTy, + S.Context.getTrivialTypeSourceInfo(PtrQTy), + SC_None, 0); + ParLHS->setScopeInfo(0, 0); + ParRHS = ParmVarDecl::Create(S.Context, FD, Loc, Loc, 0, PtrQTy, + S.Context.getTrivialTypeSourceInfo(PtrQTy), + SC_None, 0); + ParRHS->setScopeInfo(0, 1); + ParmVarDecl *Params[] = {ParLHS, ParRHS}; + FD->setParams(Params); + FTL.setArg(0, ParLHS); + FTL.setArg(1, ParRHS); + OmpOrig = VarDecl::Create(S.Context, FD, Loc, Loc, + &S.Context.Idents.get("omp_orig"), QTy, + S.Context.getTrivialTypeSourceInfo(QTy), SC_Auto); + OmpPriv = VarDecl::Create(S.Context, FD, OmpPrivLoc, OmpPrivLoc, + &S.Context.Idents.get("omp_priv"), QTy, + S.Context.getTrivialTypeSourceInfo(QTy), SC_Auto); + S.AddKnownFunctionAttributes(FD); + if (S.CurScope) { + S.PushFunctionScope(); + S.PushDeclContext(S.CurScope, FD); + S.PushOnScopeChains(OmpPriv, S.CurScope); + S.PushOnScopeChains(OmpOrig, S.CurScope); + S.PushExpressionEvaluationContext(PotentiallyEvaluated); + } else { + S.CurContext = FD; + FD->addDecl(OmpOrig); + FD->addDecl(OmpPriv); + } + ExprResult RHS = + S.BuildDeclRefExpr(ParRHS, ParRHS->getType(), VK_LValue, Loc); + RHS = S.DefaultLvalueConversion(RHS.take()); + RHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, RHS.take()); + RHS = S.ActOnFinishFullExpr(RHS.take()); + S.AddInitializerToDecl(OmpOrig, RHS.take(), true, false); + return FD; +} - bool isErrorFound() { return ErrorFound; } - ArrayRef getImplicitFirstprivate() { return ImplicitFirstprivate; } +void Sema::CreateDefaultDeclareReductionInitFunctionBody(FunctionDecl *FD, + VarDecl *OmpPriv, + ParmVarDecl *ParLHS) { + ExprResult MemCall; + SourceLocation Loc = OmpPriv->getLocation(); + if (!getLangOpts().CPlusPlus || OmpPriv->getType().isPODType(Context)) { + // Perform explicit initialization of POD types. + ExprResult OmpPrivDRE = + BuildDeclRefExpr(OmpPriv, OmpPriv->getType(), VK_LValue, Loc); + Expr *OmpPrivDREExpr = OmpPrivDRE.take(); + ExprResult OmpPrivAddr = + CreateBuiltinUnaryOp(Loc, UO_AddrOf, OmpPrivDREExpr); + OmpPrivAddr = PerformImplicitConversion(OmpPrivAddr.take(), + Context.VoidPtrTy, AA_Casting); + ExprResult OmpPrivSizeOf; + { + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::Unevaluated, Sema::ReuseLambdaContextDecl); - DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS) - : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { } -}; + OmpPrivSizeOf = + CreateUnaryExprOrTypeTraitExpr(OmpPrivDREExpr, Loc, UETT_SizeOf); + } + UnqualifiedId Name; + CXXScopeSpec SS; + SourceLocation TemplateKwLoc; + Name.setIdentifier(PP.getIdentifierInfo("__builtin_memset"), Loc); + ExprResult MemSetFn = + ActOnIdExpression(TUScope, SS, TemplateKwLoc, Name, true, false); + Expr *Args[] = {OmpPrivAddr.take(), ActOnIntegerConstant(Loc, 0).take(), + OmpPrivSizeOf.take()}; + MemCall = ActOnCallExpr(0, MemSetFn.take(), Loc, Args, Loc); + MemCall = IgnoredValueConversions(MemCall.take()); + } else { + ActOnUninitializedDecl(OmpPriv, false); + } + StmtResult S1 = + ActOnDeclStmt(DeclGroupPtrTy::make(DeclGroupRef(OmpPriv)), Loc, Loc); + ExprResult LHS = BuildDeclRefExpr(ParLHS, ParLHS->getType(), VK_LValue, Loc); + LHS = DefaultLvalueConversion(LHS.take()); + LHS = CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.take()); + ExprResult RHS = + BuildDeclRefExpr(OmpPriv, OmpPriv->getType(), VK_LValue, Loc); + ExprResult Res = BuildBinOp(0, Loc, BO_Assign, LHS.take(), RHS.take()); + ExprResult S2 = + IgnoredValueConversions(ActOnFinishFullExpr(Res.take()).take()); + if (S1.isInvalid() || S2.isInvalid()) { + FD->setBody(ActOnNullStmt(Loc).take()); + FD->setInvalidDecl(); + } else { + CompoundScopeRAII CompoundScope(*this); + SmallVector Stmts; + Stmts.push_back(S1.take()); + if (MemCall.isUsable()) + Stmts.push_back(MemCall.take()); + Stmts.push_back(S2.take()); + StmtResult Body = ActOnCompoundStmt(Loc, Loc, Stmts, false); + FD->setBody(Body.take()); + } } -StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, - ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, - SourceLocation EndLoc) { - assert(AStmt && isa(AStmt) && "Captured statement expected"); +void Sema::OMPDeclareReductionInitFunctionScope::setInit(Expr *E) { + ExprResult MemCall; + if (!E) { + if (OmpPriv->getType()->isDependentType() || + OmpPriv->getType()->isInstantiationDependentType()) + // It will be handled later on instantiation. + return; + S.CreateDefaultDeclareReductionInitFunctionBody(FD, OmpPriv, ParLHS); + return; + } else { + if (IsInit) + S.AddInitializerToDecl(OmpPriv, E, true, false); + else { + if (!isa(E->IgnoreParenImpCasts())) { + FD->setInvalidDecl(); + S.Diag(E->getExprLoc(), diag::err_omp_reduction_non_function_init) + << E->getSourceRange(); + return; + } + MemCall = S.IgnoredValueConversions(E); + } + } + SourceLocation Loc = E->getExprLoc(); + StmtResult S1 = + S.ActOnDeclStmt(DeclGroupPtrTy::make(DeclGroupRef(OmpOrig)), Loc, Loc); + StmtResult S2 = + S.ActOnDeclStmt(DeclGroupPtrTy::make(DeclGroupRef(OmpPriv)), Loc, Loc); + ExprResult LHS = + S.BuildDeclRefExpr(ParLHS, ParLHS->getType(), VK_LValue, Loc); + LHS = S.DefaultLvalueConversion(LHS.take()); + LHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.take()); + ExprResult RHS = + S.BuildDeclRefExpr(OmpPriv, OmpPriv->getType(), VK_LValue, Loc); + ExprResult Res = S.BuildBinOp(0, Loc, BO_Assign, LHS.take(), RHS.take()); + Res = S.ActOnFinishFullExpr(Res.take()); + ExprResult S3 = S.IgnoredValueConversions(Res.take()); + if (S1.isInvalid() || S2.isInvalid() || S3.isInvalid()) { + FD->setBody(S.ActOnNullStmt(Loc).take()); + FD->setInvalidDecl(); + } else { + CompoundScopeRAII CompoundScope(S); + SmallVector Stmts; + Stmts.push_back(S1.take()); + Stmts.push_back(S2.take()); + if (MemCall.isUsable()) + Stmts.push_back(MemCall.take()); + Stmts.push_back(S3.take()); + StmtResult Body = S.ActOnCompoundStmt(Loc, Loc, Stmts, false); + FD->setBody(Body.take()); + } +} - StmtResult Res = StmtError(); +Expr *Sema::OMPDeclareReductionInitFunctionScope::getInitializer() { + ExprResult Res = + S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, FD->getLocation()); + return Res.take(); +} - // Check default data sharing attributes for referenced variables. - DSAAttrChecker DSAChecker(DSAStack, *this, cast(AStmt)); - DSAChecker.Visit(cast(AStmt)->getCapturedStmt()); - if (DSAChecker.isErrorFound()) - return StmtError(); - // Generate list of implicitly defined firstprivate variables. - llvm::SmallVector ClausesWithImplicit; - ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); +bool Sema::IsOMPDeclareReductionTypeAllowed(SourceRange Range, QualType QTy, + ArrayRef Types, + ArrayRef TyRanges) { + if (QTy.isNull()) + return false; - bool ErrorFound = false; - if (!DSAChecker.getImplicitFirstprivate().empty()) { - if (OMPClause *Implicit = - ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(), - SourceLocation(), SourceLocation(), - SourceLocation())) { - ClausesWithImplicit.push_back(Implicit); - ErrorFound = cast(Implicit)->varlist_size() != - DSAChecker.getImplicitFirstprivate().size(); - } else - ErrorFound = true; + if (QTy.getCanonicalType().hasQualifiers()) { + Diag(Range.getBegin(), diag::err_omp_reduction_qualified_type) << Range; + return false; } - switch (Kind) { - case OMPD_parallel: - Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, - StartLoc, EndLoc); - break; - case OMPD_threadprivate: - case OMPD_task: - llvm_unreachable("OpenMP Directive is not allowed"); - case OMPD_unknown: - case NUM_OPENMP_DIRECTIVES: - llvm_unreachable("Unknown OpenMP directive"); + QTy = QTy.getCanonicalType(); + if (QTy->isFunctionType() || QTy->isFunctionNoProtoType() || + QTy->isFunctionProtoType() || QTy->isFunctionPointerType() || + QTy->isMemberFunctionPointerType()) { + Diag(Range.getBegin(), diag::err_omp_reduction_function_type) << Range; + return false; + } + if (QTy->isReferenceType()) { + Diag(Range.getBegin(), diag::err_omp_reduction_reference_type) << Range; + return false; + } + if (QTy->isArrayType()) { + Diag(Range.getBegin(), diag::err_omp_reduction_array_type) << Range; + return false; } - if (ErrorFound) return StmtError(); - return Res; + bool IsValid = true; + ArrayRef::iterator IR = TyRanges.begin(); + for (ArrayRef::iterator I = Types.begin(), E = Types.end(); I != E; + ++I, ++IR) { + if (Context.hasSameType(QTy, *I)) { + Diag(Range.getBegin(), diag::err_omp_reduction_redeclared) << *I << Range; + Diag(IR->getBegin(), diag::note_previous_declaration) << *IR; + IsValid = false; + } + } + return IsValid; } -StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, - SourceLocation EndLoc) { - getCurFunction()->setHasBranchProtectedScope(); +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirective( + Decl *D, ArrayRef Types, ArrayRef TyRanges, + ArrayRef Combiners, ArrayRef Inits) { + OMPDeclareReductionDecl *DR = cast(D); + + LookupResult Found(*this, DR->getDeclName(), DR->getLocation(), + LookupOMPDeclareReduction); + Found.suppressDiagnostics(); + LookupName(Found, CurScope); + for (LookupResult::iterator I = Found.begin(), E = Found.end(); I != E; ++I) { + OMPDeclareReductionDecl *DRI = cast(*I); + if (DRI == D) + continue; + for (OMPDeclareReductionDecl::datalist_iterator II = DRI->datalist_begin(), + EE = DRI->datalist_end(); + II != EE; ++II) { + ArrayRef::iterator IR = TyRanges.begin(); + for (ArrayRef::iterator IT = Types.begin(), IE = Types.end(); + IT != IE; ++IT, ++IR) { + if (!II->QTy.isNull() && !IT->isNull() && + Context.hasSameType(II->QTy, *IT)) { + Diag(IR->getBegin(), diag::err_omp_reduction_redeclared) << II->QTy + << *IR; + Diag(II->TyRange.getBegin(), diag::note_previous_declaration) + << II->TyRange; + D->setInvalidDecl(); + } + } + } + } - return Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc, - Clauses, AStmt)); + if (!D->isInvalidDecl()) { + CompleteOMPDeclareReductionDecl(DR, Types, TyRanges, Combiners, Inits); + PushOnScopeChains(DR, CurScope, false); + return DeclGroupPtrTy::make(DeclGroupRef(DR)); + } + return DeclGroupPtrTy(); } -OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, - unsigned Argument, - SourceLocation ArgumentLoc, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - OMPClause *Res = 0; +void Sema::CompleteOMPDeclareReductionDecl(OMPDeclareReductionDecl *D, + ArrayRef Types, + ArrayRef TyRanges, + ArrayRef Combiners, + ArrayRef Inits) { + SmallVector Data; + ArrayRef::iterator IC = Combiners.begin(); + ArrayRef::iterator II = Inits.begin(); + ArrayRef::iterator IR = TyRanges.begin(); + for (ArrayRef::iterator IT = Types.begin(), ET = Types.end(); + IT != ET; ++IT, ++IC, ++II, ++IR) { + Data.push_back(OMPDeclareReductionDecl::ReductionData(*IT, *IR, *IC, *II)); + } + D->setData(Data); +} + +bool Sema::ActOnStartOpenMPDeclareTargetDirective(Scope *S, + SourceLocation Loc) { + if (CurContext && !CurContext->isFileContext()) { + Diag(Loc, diag::err_omp_region_not_file_context); + return false; + } + OMPDeclareTargetDecl *DT = + OMPDeclareTargetDecl::Create(Context, CurContext, Loc); + DT->setAccess(AS_public); + CurContext->addDecl(DT); + if (CurScope) + PushDeclContext(S, DT); + else + CurContext = DT; + return true; +} + +void Sema::ActOnOpenMPDeclareTargetDecls(Sema::DeclGroupPtrTy Decls) { + if (!Decls) + return; + DeclGroupRef DGR = Decls.get(); + if (DGR.isNull()) + return; + for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end(); I != E; ++I) { + if (*I) + DSAStack->addDeclareTargetDecl(*I); + } +} + +Sema::DeclGroupPtrTy Sema::ActOnFinishOpenMPDeclareTargetDirective() { + if (CurContext && isa(CurContext)) { + OMPDeclareTargetDecl *DT = cast(CurContext); + PopDeclContext(); + return DeclGroupPtrTy::make(DeclGroupRef(DT)); + } + return DeclGroupPtrTy(); +} + +void Sema::ActOnOpenMPDeclareTargetDirectiveError() { + if (CurContext && isa(CurContext)) { + PopDeclContext(); + } +} + +static void CheckDeclInTargetContext(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + Decl *D) { + if (!D) + return; + Decl *LD = 0; + if (isa(D)) { + LD = cast(D)->getDefinition(); + } else if (isa(D)) { + LD = cast(D)->getDefinition(); + } else if (isa(D)) { + const FunctionDecl *FD = 0; + if (cast(D)->hasBody(FD)) + LD = const_cast(FD); + } + if (!LD) + LD = D; + if (LD) { + if (!Stack->isDeclareTargetDecl(LD)) { + // Outlined declaration is not declared target. + if (LD->isOutOfLine()) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } else { + DeclContext *DC = LD->getDeclContext(); + while (DC) { + if (isa(DC)) + break; + DC = DC->getParent(); + } + // Is not declared in target context. + if (!DC) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + } + } + // Mark decl as declared to prevent further diagnostic. + if (isa(LD) || isa(LD)) + Stack->addDeclareTargetDecl(LD); + } +} + +static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, + DSAStackTy *Stack, CXXRecordDecl *RD); + +static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, + DSAStackTy *Stack, QualType QTy) { + NamedDecl *ND; + if (QTy->isIncompleteType(&ND)) { + SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; + return false; + } else if (CXXRecordDecl *RD = dyn_cast_or_null(ND)) { + if (!RD->isInvalidDecl() && + !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) { + return false; + } + } + return true; +} + +static bool CheckValueDeclInTarget(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + ValueDecl *VD) { + if (Stack->isDeclareTargetDecl(VD)) + return true; + if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType())) { + return false; + } + return true; +} + +static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, + DSAStackTy *Stack, CXXRecordDecl *RD) { + if (!RD || RD->isInvalidDecl()) + return true; + + QualType QTy = SemaRef.Context.getRecordType(RD); + if (RD->isDynamicClass()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); + return false; + } + DeclContext *DC = RD; + bool IsCorrect = true; + for (DeclContext::decl_iterator I = DC->noload_decls_begin(), + E = DC->noload_decls_end(); + I != E; ++I) { + if (*I) { + if (CXXMethodDecl *MD = dyn_cast(*I)) { + if (MD->isStatic()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(MD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } else if (VarDecl *VD = dyn_cast(*I)) { + if (VD->isStaticDataMember()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(VD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } + } + } + for (CXXRecordDecl::base_class_iterator I = RD->bases_begin(), + E = RD->bases_end(); + I != E; ++I) { + if (!IsCXXRecordForMappable(SemaRef, I->getLocStart(), Stack, + I->getType()->getAsCXXRecordDecl())) { + IsCorrect = false; + } + } + return IsCorrect; +} + +void Sema::CheckDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { + if (!D || D->isInvalidDecl()) + return; + SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); + SourceLocation SL = E ? E->getLocStart() : D->getLocation(); + if (VarDecl *VD = dyn_cast(D)) { + DeclRefExpr *DRE; + if (DSAStack->IsThreadprivate(VD, DRE)) { + SourceLocation Loc = DRE ? DRE->getLocation() : VD->getLocation(); + Diag(Loc, diag::err_omp_threadprivate_in_target); + Diag(SL, diag::note_used_here) << SR; + D->setInvalidDecl(); + return; + } + } + if (ValueDecl *VD = dyn_cast(D)) { + if (!CheckValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { + VD->setInvalidDecl(); + return; + } + } + if (!E) { + // Checking declaration. + if (isa(D) || isa(D)) + DSAStack->addDeclareTargetDecl(D); + return; + } + CheckDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, + DSAStack, D); +} + +void Sema::MarkOpenMPClauses(ArrayRef Clauses) { + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + for (Stmt::child_range S = (*I)->children(); S; ++S) { + if (*S && isa(*S)) + MarkDeclarationsReferencedInExpr(cast(*S)); + } +} + +namespace { +class DSAAttrChecker : public StmtVisitor { + DSAStackTy *Stack; + Sema &Actions; + llvm::SmallVector ImplicitFirstprivate; + bool ErrorFound; + CapturedStmt *CS; + +public: + void VisitDeclRefExpr(DeclRefExpr *E) { + if (VarDecl *VD = dyn_cast(E->getDecl())) { + if (VD->isImplicit() && VD->hasAttr()) + return; + // Skip internally declared variables. + if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) + return; + // NamedDecl *ND = VD; + // if ( + // Actions.isDeclInScope(ND, Actions.CurContext, + // Stack->getCurScope())) return; + SourceLocation ELoc = E->getExprLoc(); + DeclRefExpr *PrevRef; + + OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); + OpenMPClauseKind Kind = Stack->getTopDSA(VD, PrevRef); + + // The default(none) clause requires that each variable that is referenced + // in the construct, and does not have a predetermined data-sharing + // attribute, must have its data-sharing attribute explicitly determined + // by being listed in a data-sharing attribute clause. + if (Kind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none && + (DKind == OMPD_parallel || DKind == OMPD_parallel_for || + DKind == OMPD_parallel_for_simd || + DKind == OMPD_distribute_parallel_for || + DKind == OMPD_distribute_parallel_for_simd || DKind == OMPD_task || + DKind == OMPD_teams || DKind == OMPD_parallel_sections || + DKind == OMPD_target_teams)) { + ErrorFound = true; + Actions.Diag(ELoc, diag::err_omp_no_dsa_for_variable) << VD; + return; + } + + // OpenMP [2.9.3.6, Restrictions, p.2] + // A list item that appears in a reduction clause of the innermost + // enclosing worksharing or parallel construct may not be accessed in an + // explicit task. + if (DKind == OMPD_task && + (Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_for, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_for_simd, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_sections, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel_for, + PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel_for_simd, + PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, + OMPD_distribute_parallel_for, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, + OMPD_distribute_parallel_for_simd, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel_sections, + PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_teams, PrevRef) || + Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_target_teams, + PrevRef))) { + ErrorFound = true; + Actions.Diag(ELoc, diag::err_omp_reduction_in_task); + if (PrevRef) { + Actions.Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_reduction); + } + return; + } + // Define implicit data-sharing attributes for task. + if (DKind == OMPD_task && Kind == OMPC_unknown) { + Kind = Stack->getImplicitDSA(VD, DKind, PrevRef); + if (Kind != OMPC_shared) + ImplicitFirstprivate.push_back(E); + } + } + } + void VisitOMPExecutableDirective(OMPExecutableDirective *S) { + for (ArrayRef::iterator I = S->clauses().begin(), + E = S->clauses().end(); + I != E; ++I) { + if (OMPClause *C = *I) + for (StmtRange R = C->children(); R; ++R) { + if (Stmt *Child = *R) + Visit(Child); + } + } + } + void VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; + ++I) { + if (Stmt *Child = *I) { + if (!isa(Child)) + Visit(Child); + } + } + } + + ArrayRef getImplicitFirstprivate() { return ImplicitFirstprivate; } + bool isErrorFound() { return ErrorFound; } + + DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS) + : Stack(S), Actions(Actions), ImplicitFirstprivate(), ErrorFound(false), + CS(CS) {} +}; +} + +StmtResult Sema::ActOnOpenMPExecutableDirective( + OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, + ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, OpenMPDirectiveKind ConstructType) { + // OpenMP [2.16, Nesting of Regions] + llvm::SmallVector ClausesWithImplicit; + bool ErrorFound = false; + if (DSAStack->getCurScope()) { + OpenMPDirectiveKind ParentKind = DSAStack->getParentDirective(); + bool NestingProhibited = false; + bool CloseNesting = true; + bool HasNamedDirective = false; + StringRef Region; + bool ConstructTypeMatches = false; + if (Kind == OMPD_cancel || Kind == OMPD_cancellation_point) { + switch (ConstructType) { + case OMPD_parallel: + ConstructTypeMatches = ParentKind == OMPD_parallel; + break; + case OMPD_for: + ConstructTypeMatches = ParentKind == OMPD_for || + ParentKind == OMPD_parallel_for || + ParentKind == OMPD_distribute_parallel_for; + break; + case OMPD_sections: + ConstructTypeMatches = + ParentKind == OMPD_sections || ParentKind == OMPD_parallel_sections; + break; + case OMPD_taskgroup: + ConstructTypeMatches = ParentKind == OMPD_task; + break; + default: + break; + } + } + switch (ParentKind) { + case OMPD_parallel: + NestingProhibited = + (Kind == OMPD_cancel && !ConstructTypeMatches) || + (Kind == OMPD_cancellation_point && !ConstructTypeMatches); + Region = "a parallel"; + break; + case OMPD_for: + case OMPD_sections: + case OMPD_distribute_parallel_for: + case OMPD_parallel_for: + case OMPD_parallel_sections: + case OMPD_single: + // Worksharing region + // OpenMP [2.16, Nesting of Regions, p. 1] + // A worksharing region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 2] + // A barrier region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 3] + // A master region may not be closely nested inside a worksharing, + // atomic, + // or explicit task region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + Kind == OMPD_master || Kind == OMPD_barrier || + (Kind == OMPD_cancel && !ConstructTypeMatches) || + (Kind == OMPD_cancellation_point && !ConstructTypeMatches); + Region = "a worksharing"; + break; + case OMPD_task: + // Task region + // OpenMP [2.16, Nesting of Regions, p. 1] + // A worksharing region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 2] + // A barrier region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 3] + // A master region may not be closely nested inside a worksharing, + // atomic, + // or explicit task region. + // OpenMP [2.16, Nesting of Regions, p. 4] + // An ordered region may not be closely nested inside a critical, atomic, + // or explicit task region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + Kind == OMPD_master || Kind == OMPD_barrier || Kind == OMPD_ordered || + (Kind == OMPD_cancel && !ConstructTypeMatches) || + (Kind == OMPD_cancellation_point && !ConstructTypeMatches); + Region = "explicit task"; + break; + case OMPD_master: + // OpenMP [2.16, Nesting of Regions, p. 1] + // A worksharing region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 2] + // A barrier region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + Kind == OMPD_barrier || Kind == OMPD_cancel || + Kind == OMPD_cancellation_point; + Region = "a master"; + break; + case OMPD_critical: + // OpenMP [2.16, Nesting of Regions, p. 1] + // A worksharing region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 2] + // A barrier region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 4] + // An ordered region may not be closely nested inside a critical, atomic, + // or explicit task region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + HasNamedDirective || Kind == OMPD_barrier || Kind == OMPD_ordered || + Kind == OMPD_cancel || Kind == OMPD_cancellation_point; + Region = "a critical"; + break; + case OMPD_atomic: + // OpenMP [2.16, Nesting of Regions, p. 7] + // OpenMP constructs may not be nested inside an atomic region. + NestingProhibited = true; + Region = "an atomic"; + break; + case OMPD_simd: + // OpenMP [2.16, Nesting of Regions, p. 8] + // OpenMP constructs may not be nested inside a simd region. + NestingProhibited = true; + Region = "a simd"; + break; + case OMPD_for_simd: + // OpenMP [2.16, Nesting of Regions, p. 8] + // OpenMP constructs may not be nested inside a simd region. + NestingProhibited = true; + Region = "a for simd"; + break; + case OMPD_distribute_simd: + // OpenMP [2.16, Nesting of Regions, p. 8] + // OpenMP constructs may not be nested inside a simd region. + NestingProhibited = true; + Region = "a distribute simd"; + break; + case OMPD_parallel_for_simd: + // OpenMP [2.16, Nesting of Regions, p. 8] + // OpenMP constructs may not be nested inside a simd region. + NestingProhibited = true; + Region = "a parallel for simd"; + break; + case OMPD_distribute_parallel_for_simd: + // OpenMP [2.16, Nesting of Regions, p. 8] + // OpenMP constructs may not be nested inside a simd region. + NestingProhibited = true; + Region = "a distribute parallel for simd"; + break; + case OMPD_ordered: + // OpenMP [2.16, Nesting of Regions, p. 1] + // A worksharing region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 2] + // A barrier region may not be closely nested inside a worksharing, + // explicit task, critical, ordered, atomic, or master region. + // OpenMP [2.16, Nesting of Regions, p. 3] + // A master region may not be closely nested inside a worksharing, + // atomic, + // or explicit task region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + Kind == OMPD_master || Kind == OMPD_barrier || Kind == OMPD_cancel || + Kind == OMPD_cancellation_point; + Region = "an ordered"; + break; + case OMPD_teams: + // OpenMP [2.16, Nesting of Regions, p. 11] + // distribute, parallel, parallel sections, parallel workshare, and + // the parallel loop and parallel loop SIMD constructs are the only + // OpenMP constructs that can be closely nested in the teams region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_single || + Kind == OMPD_for_simd || Kind == OMPD_simd || Kind == OMPD_master || + Kind == OMPD_barrier || Kind == OMPD_task || Kind == OMPD_ordered || + Kind == OMPD_teams || Kind == OMPD_atomic || Kind == OMPD_critical || + Kind == OMPD_taskgroup || Kind == OMPD_cancel || + Kind == OMPD_cancellation_point || Kind == OMPD_target_teams; + Region = "a teams"; + break; + case OMPD_target_teams: + // OpenMP [2.16, Nesting of Regions, p. 11] + // distribute, parallel, parallel sections, parallel workshare, and + // the parallel loop and parallel loop SIMD constructs are the only + // OpenMP constructs that can be closely nested in the teams region. + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_single || + Kind == OMPD_for_simd || Kind == OMPD_simd || Kind == OMPD_master || + Kind == OMPD_barrier || Kind == OMPD_task || Kind == OMPD_ordered || + Kind == OMPD_teams || Kind == OMPD_atomic || Kind == OMPD_critical || + Kind == OMPD_taskgroup || Kind == OMPD_cancel || + Kind == OMPD_cancellation_point || Kind == OMPD_target_teams; + Region = "a target teams"; + break; + case OMPD_distribute: + NestingProhibited = + Kind == OMPD_for || Kind == OMPD_sections || Kind == OMPD_for_simd || + Kind == OMPD_distribute_simd || Kind == OMPD_distribute || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || Kind == OMPD_single || + Kind == OMPD_master || Kind == OMPD_barrier || + (Kind == OMPD_cancel && !ConstructTypeMatches) || + (Kind == OMPD_cancellation_point && !ConstructTypeMatches); + Region = "a distribute"; + break; + case OMPD_taskgroup: + NestingProhibited = + (Kind == OMPD_cancel) || (Kind == OMPD_cancellation_point); + Region = "a taskgroup"; + break; + default: + break; + } + // OpenMP [2.16, Nesting of Regions, p. 6] + // A critical region may not be nested (closely or otherwise) inside a + // critical region with the same name. Note that this restriction is not + // sufficient to prevent deadlock. + if (DirName.getName() && Kind == OMPD_critical) { + HasNamedDirective = DSAStack->hasDirectiveWithName(Kind, DirName); + CloseNesting = false; + NestingProhibited = HasNamedDirective; + Region = "a critical"; + } + if (NestingProhibited) { + Diag(StartLoc, diag::err_omp_prohibited_region) + << CloseNesting << Region << HasNamedDirective << DirName.getName(); + return StmtError(); + } + // OpenMP [2.16, Nesting of Regions, p. 5] + // An ordered region must be closely nested inside a loop region (or + // parallel loop region) with an ordered clause. + if (Kind == OMPD_ordered && + (ParentKind != OMPD_unknown && !DSAStack->isParentRegionOrdered())) { + Diag(StartLoc, diag::err_omp_prohibited_ordered_region); + return StmtError(); + } + if (Kind == OMPD_cancel && ParentKind != OMPD_unknown) { + // OpenMP [2.16, Nesting of Regions, p. 13] + // the cancel construct must be nested inside a taskgroup region. + if (ConstructType == OMPD_taskgroup && + !DSAStack->hasDirective(OMPD_taskgroup)) { + Diag(StartLoc, diag::err_omp_prohibited_cancel_region); + return StmtError(); + } + // OpenMP [2.13.1, cancel Construct, Restriction] + // A worksharing construct that is cancelled must not have a nowait + // clause. + if ((ConstructType == OMPD_for || ConstructType == OMPD_sections) && + DSAStack->isRegionNowait()) { + Diag(StartLoc, diag::err_omp_prohibited_cancel_region_nowait); + return StmtError(); + } + // OpenMP [2.13.1, cancel Construct, Restriction] + // A loop construct that is cancelled must not have an ordered clause. + if (ConstructType == OMPD_for && DSAStack->isRegionOrdered()) { + Diag(StartLoc, diag::err_omp_prohibited_cancel_region_ordered); + return StmtError(); + } + } + // OpenMP [2.16, Nesting of Regions, p. 5] + // A distribute construct must be closely nested in a teams region. + if ((Kind == OMPD_distribute || Kind == OMPD_distribute_simd || + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd) && + (ParentKind != OMPD_unknown && ParentKind != OMPD_teams && + ParentKind != OMPD_target_teams)) { + Diag(StartLoc, diag::err_omp_prohibited_distribute_region); + return StmtError(); + } + // OpenMP [2.16, Nesting of Regions, p. 10] + // If specified, a teams construct must be contained within a target + // construct. + if (Kind == OMPD_teams && ParentKind != OMPD_target) { + Diag(StartLoc, diag::err_omp_prohibited_teams_region); + return StmtError(); + } + } + if (Kind == OMPD_task) { + assert(AStmt && isa(AStmt) && "Captured statement expected"); + // Check default data sharing attributes for captured variables. + DSAAttrChecker DSAChecker(DSAStack, *this, cast(AStmt)); + DSAChecker.Visit(cast(AStmt)->getCapturedStmt()); + if (DSAChecker.isErrorFound()) + return StmtError(); + if (DSAChecker.getImplicitFirstprivate().size() > 0) { + if (OMPClause *Implicit = ActOnOpenMPFirstPrivateClause( + DSAChecker.getImplicitFirstprivate(), SourceLocation(), + SourceLocation())) { + ClausesWithImplicit.push_back(Implicit); + if (Implicit && + cast(Implicit)->varlist_size() != + DSAChecker.getImplicitFirstprivate().size()) + ErrorFound = true; + } else + ErrorFound = true; + } + } + ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); + + StmtResult Res = StmtError(); switch (Kind) { - case OMPC_default: + case OMPD_parallel: + Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_parallel_for: + Res = ActOnOpenMPParallelForDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_for: + Res = ActOnOpenMPForDirective(Kind, ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_parallel_sections: + Res = ActOnOpenMPParallelSectionsDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_sections: + Res = ActOnOpenMPSectionsDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_section: + assert(Clauses.empty() && "Clauses are not allowed for section"); + Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc); + break; + case OMPD_single: + Res = ActOnOpenMPSingleDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_task: Res = - ActOnOpenMPDefaultClause(static_cast(Argument), - ArgumentLoc, StartLoc, LParenLoc, EndLoc); + ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; - case OMPC_private: - case OMPC_firstprivate: - case OMPC_shared: - case OMPC_threadprivate: - case OMPC_unknown: - case NUM_OPENMP_CLAUSES: - llvm_unreachable("Clause is not allowed."); + case OMPD_taskyield: + assert(Clauses.empty() && !AStmt && + "Clauses and statement are not allowed for taskyield"); + Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc); + break; + case OMPD_master: + assert(Clauses.empty() && "Clauses are not allowed for master"); + Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc); + break; + case OMPD_critical: + assert(Clauses.empty() && "Clauses are not allowed for critical"); + Res = ActOnOpenMPCriticalDirective(DirName, AStmt, StartLoc, EndLoc); + break; + case OMPD_barrier: + assert(Clauses.empty() && !AStmt && + "Clauses and statement are not allowed for barrier"); + Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc); + break; + case OMPD_taskwait: + assert(Clauses.empty() && !AStmt && + "Clauses and statement are not allowed for taskwait"); + Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); + break; + case OMPD_taskgroup: + assert(Clauses.empty() && "Clauses are not allowed for taskgroup"); + Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc); + break; + case OMPD_atomic: + Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_flush: + assert(!AStmt && "Statement is not allowed for flush"); + Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; + case OMPD_ordered: + assert(Clauses.empty() && "Clauses are not allowed for ordered"); + Res = ActOnOpenMPOrderedDirective(AStmt, StartLoc, EndLoc); + break; + case OMPD_simd: + Res = ActOnOpenMPSimdDirective(Kind, ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_for_simd: + Res = ActOnOpenMPForSimdDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_parallel_for_simd: + Res = ActOnOpenMPParallelForSimdDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_distribute_simd: + Res = ActOnOpenMPDistributeSimdDirective(Kind, ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; + case OMPD_distribute_parallel_for: + Res = ActOnOpenMPDistributeParallelForDirective(Kind, ClausesWithImplicit, + AStmt, StartLoc, EndLoc); + break; + case OMPD_distribute_parallel_for_simd: + Res = ActOnOpenMPDistributeParallelForSimdDirective( + Kind, ClausesWithImplicit, AStmt, StartLoc, EndLoc); + break; + case OMPD_teams: + Res = + ActOnOpenMPTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + break; + case OMPD_target_teams: + Res = ActOnOpenMPTargetTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_distribute: + Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_target: + Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_target_data: + Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_target_update: + assert(!AStmt && "Statement is not allowed for target update"); + Res = + ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; + case OMPD_cancel: + assert(!AStmt && "Statement is not allowed for cancel"); + if (ConstructType == OMPD_unknown) + return StmtError(); + Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc, + ConstructType); + break; + case OMPD_cancellation_point: + assert(!AStmt && "Statement is not allowed for cancellation point"); + assert(Clauses.empty() && "Clauses are not allowed for cancellation point"); + if (ConstructType == OMPD_unknown) + return StmtError(); + Res = + ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, ConstructType); + break; + default: + break; + } + // Additional analysis for all directives except for task + switch (Kind) { + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_flush: + case OMPD_cancel: + case OMPD_cancellation_point: + case OMPD_target_update: + case OMPD_task: + break; + default: { + assert(AStmt && isa(AStmt) && "Captured statement expected"); + // Check default data sharing attributes for captured variables. + DSAAttrChecker DSAChecker(DSAStack, *this, cast(AStmt)); + DSAChecker.Visit(cast(AStmt)->getCapturedStmt()); + if (DSAChecker.isErrorFound()) + return StmtError(); + if (DSAChecker.getImplicitFirstprivate().size() > 0) { + if (OMPClause *Implicit = ActOnOpenMPFirstPrivateClause( + DSAChecker.getImplicitFirstprivate(), SourceLocation(), + SourceLocation())) { + ClausesWithImplicit.push_back(Implicit); + if (Implicit && + cast(Implicit)->varlist_size() != + DSAChecker.getImplicitFirstprivate().size()) + ErrorFound = true; + } else + ErrorFound = true; + } + break; + } + } + + if (ErrorFound) + return StmtError(); + + return Res; +} + +StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + + getCurFunction()->setHasBranchProtectedScope(); + return Owned( + OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +namespace { +class ForBreakStmtChecker : public StmtVisitor { + Stmt *Break; + +public: + bool VisitBreakStmt(BreakStmt *S) { + Break = S; + return true; + } + bool VisitSwitchStmt(SwitchStmt *S) { return false; } + bool VisitWhileStmt(WhileStmt *S) { return false; } + bool VisitDoStmt(DoStmt *S) { return false; } + bool VisitForStmt(ForStmt *S) { return false; } + bool VisitCXXForRangeStmt(CXXForRangeStmt *S) { return false; } + bool VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; + ++I) { + if (*I && Visit(*I)) + return true; + } + return false; + } + ForBreakStmtChecker() {} + Stmt *getBreak() { return Break; } +}; +} + +namespace { +class EhChecker : public StmtVisitor { + Stmt *BadStmt; + +public: + bool VisitCXXCatchStmt(CXXCatchStmt *S) { + BadStmt = S; + return true; + } + bool VisitCXXThrowExpr(CXXThrowExpr *S) { + BadStmt = S; + return true; + } + bool VisitCXXTryStmt(CXXTryStmt *S) { + BadStmt = S; + return true; + } + bool VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; + ++I) { + if (*I && Visit(*I)) + return true; + } + return false; + } + EhChecker() {} + Stmt *getBadStmt() { return BadStmt; } +}; +} + +bool Sema::CollapseOpenMPLoop(OpenMPDirectiveKind Kind, + ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + Expr *&NewVar, Expr *&NewEnd, + Expr *&NewVarCntExpr, Expr *&NewFinal, + SmallVector &VarCnts) { + // This is helper routine to process collapse clause that + // can be met in directives 'for', 'simd', 'for simd' and others. + // + // OpenMP [2.7.1, Loop construct, Description] + // The collapse clause may be used to specify how many loops are + // associated with the loop construct. + // + NewVar = 0; + NewEnd = 0; + NewVarCntExpr = 0; + NewFinal = 0; + VarCnts.clear(); + FunctionDecl *FD = getCurFunctionDecl(); + if (FD && FD->isDependentContext()) + return true; + SmallVector Ends; + SmallVector Incrs; + SmallVector Inits; + SmallVector OpKinds; + unsigned StmtCount = 1; + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) { + if (OMPCollapseClause *Clause = dyn_cast_or_null(*I)) { + IntegerLiteral *IL = cast(Clause->getNumForLoops()); + StmtCount = IL->getValue().getLimitedValue(); + break; + } + } + Stmt *CStmt = AStmt; + while (CapturedStmt *CS = dyn_cast_or_null(CStmt)) + CStmt = CS->getCapturedStmt(); + while (AttributedStmt *AS = dyn_cast_or_null(CStmt)) + CStmt = AS->getSubStmt(); + bool SkipExprCount = false; + for (unsigned Cnt = 0; Cnt < StmtCount; ++Cnt) { + Expr *NewEnd; + Expr *NewIncr; + Expr *Init; + Expr *VarCnt; + BinaryOperatorKind OpKind; + if (isNotOpenMPCanonicalLoopForm(CStmt, Kind, NewEnd, NewIncr, Init, VarCnt, + OpKind)) + return false; + if (NewEnd->getType()->isDependentType() || + NewIncr->getType()->isDependentType() || + Init->getType()->isDependentType() || + VarCnt->getType()->isDependentType()) + SkipExprCount = true; + Ends.push_back(NewEnd); + Incrs.push_back(NewIncr); + Inits.push_back(Init); + VarCnts.push_back(VarCnt); + OpKinds.push_back(OpKind); + CStmt = cast(CStmt)->getBody(); + bool SkippedContainers = false; + while (!SkippedContainers) { + if (AttributedStmt *AS = dyn_cast_or_null(CStmt)) + CStmt = AS->getSubStmt(); + else if (CompoundStmt *CS = dyn_cast_or_null(CStmt)) { + if (CS->size() != 1) { + SkippedContainers = true; + } else { + CStmt = CS->body_back(); + } + } else + SkippedContainers = true; + } + } + + ForBreakStmtChecker Check; + if (CStmt && Check.Visit(CStmt)) { + Diag(Check.getBreak()->getLocStart(), diag::err_omp_for_cannot_break) + << getOpenMPDirectiveName(Kind); + return false; + } + + if (Kind == OMPD_simd || Kind == OMPD_for_simd || + Kind == OMPD_parallel_for_simd || Kind == OMPD_distribute_simd || + Kind == OMPD_distribute_parallel_for_simd) { + // OpenMP [2.8.1] No exception can be raised in the simd region. + EhChecker Check; + if (CStmt && Check.Visit(CStmt)) { + Diag(Check.getBadStmt()->getLocStart(), diag::err_omp_for_cannot_have_eh) + << getOpenMPDirectiveName(Kind); + return false; + } + } + + // Build ending for Idx var; + NewEnd = 0; + NewVar = 0; + NewVarCntExpr = 0; + NewFinal = 0; + + if (!SkipExprCount) { + NewEnd = Ends[0]; + for (unsigned I = 1; I < StmtCount; ++I) { + ExprResult Res = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, + Ends[I], NewEnd); + if (!Res.isUsable()) + return false; + NewEnd = Res.take(); + } + QualType IdxTy = NewEnd->getType(); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(IdxTy, StartLoc); + VarDecl *Idx = VarDecl::Create(Context, Context.getTranslationUnitDecl(), + StartLoc, StartLoc, 0, IdxTy, TI, SC_Static); + Idx->setImplicit(); + Idx->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(Idx); + ExprResult IdxExprRes = BuildDeclRefExpr(Idx, IdxTy, VK_LValue, StartLoc); + NewVar = IdxExprRes.take(); + + // Build new values for actual indexes. + + // We can go either from outer loop to inner [0, StmtCount, 1] or reverse + // [StmtCount-1, -1, -1] in the case of 'omp for', but in an 'omp simd' + // directive the reverse order is required because we may have loop-carried + // dependencies (as specified by 'safelen' clause). + // For cache locality reasons this may be also preffered for 'omp for', as + // usually programs walk inner array dimensions first. + int LoopIdBegin = StmtCount - 1; + int LoopIdEnd = -1; + int LoopIdStep = -1; + + Expr *NewDiv = Ends[LoopIdBegin]; + Expr *IdxRVal = DefaultLvalueConversion(NewVar).take(); + if (!IdxRVal) + return false; + ExprResult Res = + BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Sub, NewEnd, + ActOnIntegerConstant(SourceLocation(), 1).take()); + if (!Res.isUsable()) + return false; + NewEnd = Res.take(); + + Expr *NewIncr = IdxRVal; + if (StmtCount != 1) { + NewIncr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Rem, IdxRVal, + Ends[LoopIdBegin]).take(); + if (!NewIncr) + return false; + } + + NewIncr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, NewIncr, + Incrs[LoopIdBegin]).take(); + if (!NewIncr) + return false; + NewFinal = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Assign, + VarCnts[LoopIdBegin], Inits[LoopIdBegin]).take(); + if (!NewFinal) + return false; + NewFinal = IgnoredValueConversions(NewFinal).take(); + if (!NewFinal) + return false; + Expr *NewFinal1 = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, + Ends[LoopIdBegin], Incrs[LoopIdBegin]).take(); + if (!NewFinal1) + return false; + NewFinal1 = BuildBinOp(DSAStack->getCurScope(), StartLoc, + (OpKinds[LoopIdBegin] == BO_Add) ? BO_AddAssign + : BO_SubAssign, + VarCnts[LoopIdBegin], NewFinal1).take(); + if (!NewFinal1) + return false; + NewFinal1 = IgnoredValueConversions(NewFinal1).take(); + if (!NewFinal1) + return false; + NewFinal = + CreateBuiltinBinOp(StartLoc, BO_Comma, NewFinal, NewFinal1).take(); + if (!NewFinal) + return false; + // Expr *NewStep = BuildBinOp(DSAStack->getCurScope(), StartLoc, + // OpKinds[LoopIdBegin], Inits[LoopIdBegin], + // NewIncr).take(); + // if (!NewStep) return false; + // NewVarCntExpr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Assign, + // VarCnts[LoopIdBegin], NewStep).take(); + NewVarCntExpr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Assign, + VarCnts[LoopIdBegin], Inits[LoopIdBegin]).take(); + if (!NewVarCntExpr) + return false; + NewVarCntExpr = IgnoredValueConversions(NewVarCntExpr).take(); + if (!NewVarCntExpr) + return false; + Expr *NewVarCntExpr1 = + BuildBinOp(DSAStack->getCurScope(), StartLoc, + (OpKinds[LoopIdBegin] == BO_Add) ? BO_AddAssign + : BO_SubAssign, + VarCnts[LoopIdBegin], NewIncr).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr1 = IgnoredValueConversions(NewVarCntExpr1).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr = CreateBuiltinBinOp(StartLoc, BO_Comma, NewVarCntExpr, + NewVarCntExpr1).take(); + if (!NewVarCntExpr) + return false; + + for (int I = LoopIdBegin + LoopIdStep; I != LoopIdEnd; I += LoopIdStep) { + NewIncr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Div, IdxRVal, + NewDiv).take(); + if (!NewIncr) + return false; + + if (I + LoopIdStep != LoopIdEnd) { + NewIncr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Rem, NewIncr, + Ends[I]).take(); + if (!NewIncr) + return false; + } + + NewIncr = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, NewIncr, + Incrs[I]).take(); + if (!NewIncr) + return false; + NewFinal1 = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Assign, + VarCnts[I], Inits[I]).take(); + if (!NewFinal1) + return false; + NewFinal = + CreateBuiltinBinOp(StartLoc, BO_Comma, NewFinal, NewFinal1).take(); + if (!NewFinal) + return false; + NewFinal1 = IgnoredValueConversions(NewFinal1).take(); + if (!NewFinal1) + return false; + NewFinal1 = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, Ends[I], + Incrs[I]).take(); + if (!NewFinal1) + return false; + NewFinal1 = + BuildBinOp(DSAStack->getCurScope(), StartLoc, + (OpKinds[I] == BO_Add) ? BO_AddAssign : BO_SubAssign, + VarCnts[I], NewFinal1).take(); + if (!NewFinal1) + return false; + NewFinal1 = IgnoredValueConversions(NewFinal1).take(); + if (!NewFinal1) + return false; + NewFinal = + CreateBuiltinBinOp(StartLoc, BO_Comma, NewFinal, NewFinal1).take(); + if (!NewFinal) + return false; + // NewStep = BuildBinOp(DSAStack->getCurScope(), StartLoc, + // OpKinds[I], + // Inits[I], NewIncr).take(); + // if (!NewStep) return false; + // Expr *NewVarCntExpr1 = BuildBinOp(DSAStack->getCurScope(), + // StartLoc, BO_Assign, + // VarCnts[I], NewStep).take(); + NewVarCntExpr1 = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Assign, + VarCnts[I], Inits[I]).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr1 = IgnoredValueConversions(NewVarCntExpr1).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr = CreateBuiltinBinOp(StartLoc, BO_Comma, NewVarCntExpr, + NewVarCntExpr1).take(); + if (!NewVarCntExpr) + return false; + NewVarCntExpr1 = + BuildBinOp(DSAStack->getCurScope(), StartLoc, + (OpKinds[I] == BO_Add) ? BO_AddAssign : BO_SubAssign, + VarCnts[I], NewIncr).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr1 = IgnoredValueConversions(NewVarCntExpr1).take(); + if (!NewVarCntExpr1) + return false; + NewVarCntExpr = CreateBuiltinBinOp(StartLoc, BO_Comma, NewVarCntExpr, + NewVarCntExpr1).take(); + if (!NewVarCntExpr) + return false; + NewDiv = BuildBinOp(DSAStack->getCurScope(), StartLoc, BO_Mul, NewDiv, + Ends[I]).take(); + if (!NewDiv) + return false; + } + NewVarCntExpr = IgnoredValueConversions(NewVarCntExpr).take(); + NewFinal = IgnoredValueConversions(NewFinal).take(); + NewFinal = ActOnFinishFullExpr(NewFinal).take(); + NewVarCntExpr = ActOnFinishFullExpr(NewVarCntExpr).take(); + NewEnd = ActOnFinishFullExpr(NewEnd).take(); + } + return true; +} + +StmtResult Sema::ActOnOpenMPForDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPForDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt, NewVar, NewEnd, NewVarCntExpr, + NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPParallelForDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPParallelForDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, NewVar, NewEnd, NewVarCntExpr, + NewFinal, VarCnts)); +} + +CapturedStmt *Sema::AddSimdArgsIntoCapturedStmt(CapturedStmt *Cap, + Expr *NewVar) { + CapturedDecl *CD = Cap->getCapturedDecl(); + DeclContext *DC = CapturedDecl::castToDeclContext(CD); + assert(CD->getNumParams() == 3); + if (!DC->isDependentContext()) { + assert(NewVar); + QualType IndexType = NewVar->getType(); + ImplicitParamDecl *Index = 0, *LastIter = 0; + Index = ImplicitParamDecl::Create(getASTContext(), DC, SourceLocation(), 0, + IndexType); + DC->addDecl(Index); + CD->setParam(1, Index); + LastIter = ImplicitParamDecl::Create(getASTContext(), DC, SourceLocation(), + 0, Context.BoolTy); + DC->addDecl(LastIter); + CD->setParam(2, LastIter); + } + RecordDecl *RD = const_cast(Cap->getCapturedRecordDecl()); + + // Extract the captures from AStmt and insert them into CapturedBody. + SmallVector Captures; + SmallVector CaptureInits; + CapturedStmt::capture_iterator I; + CapturedStmt::capture_init_iterator J; + for (I = Cap->capture_begin(), J = Cap->capture_init_begin(); + (I != Cap->capture_end()) && (J != Cap->capture_init_end()); ++I, ++J) { + // Assuming that copy constructors are OK here. + Captures.push_back(*I); + CaptureInits.push_back(*J); + } + CapturedRegionKind CapKind = Cap->getCapturedRegionKind(); + Stmt *Body = Cap->getCapturedStmt(); + // Rebuild the captured stmt. + CapturedStmt *CapturedBody = CapturedStmt::Create( + getASTContext(), Body, CapKind, Captures, CaptureInits, CD, RD); + CD->setBody(Body); + + return CapturedBody; +} + +Stmt *Sema::AddDistributedParallelArgsIntoCapturedStmt(CapturedStmt *Cap, + Expr *NewVar, + Expr *&LowerBound, + Expr *&UpperBound) { + CapturedDecl *CD = Cap->getCapturedDecl(); + DeclContext *DC = CapturedDecl::castToDeclContext(CD); + VarDecl *LowerBoundVar = 0; + VarDecl *UpperBoundVar = 0; + if (!DC->isDependentContext()) { + assert(NewVar); + QualType VDTy = NewVar->getType(); + uint64_t TypeSize = 32; + if (Context.getTypeSize(VDTy) > TypeSize) + TypeSize = 64; + VDTy = Context.getIntTypeForBitwidth(TypeSize, true); + TypeSourceInfo *TI = + Context.getTrivialTypeSourceInfo(VDTy, SourceLocation()); + LowerBoundVar = VarDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), 0, VDTy, TI, SC_Auto); + UpperBoundVar = VarDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), 0, VDTy, TI, SC_Auto); + LowerBound = DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), LowerBoundVar, false, + SourceLocation(), VDTy, VK_LValue); + UpperBound = DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), UpperBoundVar, false, + SourceLocation(), VDTy, VK_LValue); + } + + Stmt *Body = Cap->getCapturedStmt(); + + ActOnCapturedRegionStart(Cap->getLocStart(), 0, Cap->getCapturedRegionKind(), + Cap->getCapturedDecl()->getNumParams()); + MarkVariableReferenced(Cap->getLocStart(), LowerBoundVar); + MarkVariableReferenced(Cap->getLocStart(), UpperBoundVar); + for (CapturedStmt::capture_iterator I = Cap->capture_begin(), + E = Cap->capture_end(); + I != E; ++I) { + if (I->capturesVariable()) + MarkVariableReferenced(I->getLocation(), I->getCapturedVar()); + else + CheckCXXThisCapture(I->getLocation(), /*explicit*/ false); + } + StmtResult CapturedBody = ActOnCapturedRegionEnd(Body); + + return CapturedBody.take(); +} + +StmtResult Sema::ActOnOpenMPSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + // Add two arguments into captured stmt for index and last_iter. + CapturedStmt *CapturedBody = + AddSimdArgsIntoCapturedStmt(cast(AStmt), NewVar); + + getCurFunction()->setHasBranchProtectedScope(); + + // Rebuild the directive. + return Owned(OMPSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, + CapturedBody, NewVar, NewEnd, + NewVarCntExpr, NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPForSimdDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + // Add two arguments into captured stmt for index and last_iter. + CapturedStmt *CapturedBody = + AddSimdArgsIntoCapturedStmt(cast(AStmt), NewVar); + + getCurFunction()->setHasBranchProtectedScope(); + + // Rebuild the directive. + return Owned(OMPForSimdDirective::Create(Context, StartLoc, EndLoc, Clauses, + CapturedBody, NewVar, NewEnd, + NewVarCntExpr, NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPParallelForSimdDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + // Add two arguments into captured stmt for index and last_iter. + CapturedStmt *CapturedBody = + AddSimdArgsIntoCapturedStmt(cast(AStmt), NewVar); + + getCurFunction()->setHasBranchProtectedScope(); + + // Rebuild the directive. + return Owned(OMPParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, Clauses, CapturedBody, NewVar, NewEnd, + NewVarCntExpr, NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPDistributeSimdDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + // Add two arguments into captured stmt for index and last_iter. + CapturedStmt *CapturedBody = + AddSimdArgsIntoCapturedStmt(cast(AStmt), NewVar); + + getCurFunction()->setHasBranchProtectedScope(); + + // Rebuild the directive. + return Owned(OMPDistributeSimdDirective::Create( + Context, StartLoc, EndLoc, Clauses, CapturedBody, NewVar, NewEnd, + NewVarCntExpr, NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + getCurFunction()->setHasBranchProtectedScope(); + + // Create variables for lower/upper bound + Expr *LowerBound = 0; + Expr *UpperBound = 0; + if (NewVar && AStmt) { + AStmt = AddDistributedParallelArgsIntoCapturedStmt( + cast(AStmt), NewVar, LowerBound, UpperBound); + } + // Rebuild the directive. + return Owned(OMPDistributeParallelForDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, NewVar, NewEnd, NewVarCntExpr, + NewFinal, LowerBound, UpperBound, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(Kind, Clauses, AStmt, StartLoc, EndLoc, NewVar, + NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + getCurFunction()->setHasBranchProtectedScope(); + + // Create variables for lower/upper bound + Expr *LowerBound = 0; + Expr *UpperBound = 0; + if (NewVar && AStmt) { + AStmt = AddDistributedParallelArgsIntoCapturedStmt( + cast(AStmt), NewVar, LowerBound, UpperBound); + } + + // Add two arguments into captured stmt for index and last_iter. + CapturedStmt *CapturedBody = + AddSimdArgsIntoCapturedStmt(cast(AStmt), NewVar); + + // Rebuild the directive. + return Owned(OMPDistributeParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, Clauses, CapturedBody, NewVar, NewEnd, + NewVarCntExpr, NewFinal, LowerBound, UpperBound, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPSectionsDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + Stmt *BaseStmt = AStmt; + while (CapturedStmt *CS = dyn_cast_or_null(BaseStmt)) + BaseStmt = CS->getCapturedStmt(); + CompoundStmt *C = dyn_cast_or_null(BaseStmt); + if (!C) { + Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt) + << getOpenMPDirectiveName(Kind); + return StmtError(); + } + // All associated statements must be '#pragma omp section' except for + // the first one. + Stmt::child_range S = C->children(); + if (!S) + return StmtError(); + for (++S; S; ++S) { + Stmt *SectionStmt = *S; + if (!SectionStmt || !isa(SectionStmt)) { + if (SectionStmt) + Diag(SectionStmt->getLocStart(), diag::err_omp_sections_not_section) + << getOpenMPDirectiveName(Kind); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + + return Owned( + OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPParallelSectionsDirective( + OpenMPDirectiveKind Kind, ArrayRef Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc) { + Stmt *BaseStmt = AStmt; + while (CapturedStmt *CS = dyn_cast_or_null(BaseStmt)) + BaseStmt = CS->getCapturedStmt(); + CompoundStmt *C = dyn_cast_or_null(BaseStmt); + if (!C) { + Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt) + << getOpenMPDirectiveName(Kind); + return StmtError(); + } + // All associated statements must be '#pragma omp section' except for + // the first one. + Stmt::child_range S = C->children(); + if (!S) + return StmtError(); + for (++S; S; ++S) { + Stmt *SectionStmt = *S; + if (!SectionStmt || !isa(SectionStmt)) { + if (SectionStmt) + Diag(SectionStmt->getLocStart(), diag::err_omp_sections_not_section) + << getOpenMPDirectiveName(Kind); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPParallelSectionsDirective::Create(Context, StartLoc, EndLoc, + Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.6.2, Sections Construct, Restrictions, p.1] + // Orphaned section directives are prohibited. That is, the section + // directives must appear within the sections construct and must not + // be encountered elsewhere in the sections region. + // OpenMP scope for current directive. + if (DSAStack->getCurScope()) { + Scope *ParentScope = DSAStack->getCurScope()->getParent(); + // CompoundStmt scope for sections scope. + ParentScope = ParentScope ? getCurScope()->getParent() : 0; + // Sections scope. + ParentScope = ParentScope ? ParentScope->getParent() : 0; + if (!ParentScope || !ParentScope->isOpenMPDirectiveScope() || + (DSAStack->getParentDirective() != OMPD_sections && + DSAStack->getParentDirective() != OMPD_parallel_sections)) { + Diag(StartLoc, diag::err_omp_section_orphaned); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt)); +} + +StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned( + OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned( + OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPTaskyieldDirective::Create(Context, StartLoc, EndLoc)); +} + +StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt)); +} + +StmtResult +Sema::ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned( + OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, AStmt)); +} + +StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPBarrierDirective::Create(Context, StartLoc, EndLoc)); +} + +StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc)); +} + +StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt)); +} + +namespace { +class ExprUseChecker : public StmtVisitor { + const llvm::FoldingSetNodeID &ExprID; + const ASTContext &Context; + +public: + bool VisitStmt(Stmt *S) { + if (!S) + return false; + for (Stmt::child_range R = S->children(); R; ++R) { + if (Visit(*R)) + return true; + } + llvm::FoldingSetNodeID ID; + S->Profile(ID, Context, true); + return ID == ExprID; + } + ExprUseChecker(const llvm::FoldingSetNodeID &ExprID, + const ASTContext &Context) + : ExprID(ExprID), Context(Context) {} +}; +} + +StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.10.6, atomic Construct, Syntax] + // There should not be no more than 1 clause 'read', 'write', 'update' + // or 'capture'. + OpenMPClauseKind Kind = OMPC_update; + if (!Clauses.empty()) { + bool FoundClauses = false; + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) { + if ((*I)->getClauseKind() != OMPC_seq_cst) { + Kind = (*I)->getClauseKind(); + bool CurFoundClauses = Kind == OMPC_read || Kind == OMPC_write || + Kind == OMPC_update || Kind == OMPC_capture; + if (FoundClauses && CurFoundClauses) { + Diag(StartLoc, diag::err_omp_atomic_more_one_clause); + Kind = OMPC_unknown; + return StmtError(); + } + FoundClauses = FoundClauses || CurFoundClauses; + } + } + } + + // OpenMP [2.10.6, atomic Construct, Syntax] + // For 'read', 'write', 'update' clauses only expression statements are + // allowed. + Stmt *BaseStmt = AStmt; + while (CapturedStmt *CS = dyn_cast_or_null(BaseStmt)) + BaseStmt = CS->getCapturedStmt(); + while (ExprWithCleanups *EWC = dyn_cast_or_null(BaseStmt)) + BaseStmt = EWC->getSubExpr(); + while (AttributedStmt *AS = dyn_cast_or_null(BaseStmt)) + BaseStmt = AS->getSubStmt(); + bool ExprStmt = isa(BaseStmt); + if (Kind != OMPC_capture && !ExprStmt) { + Diag(BaseStmt->getLocStart(), diag::err_omp_atomic_not_expression) + << getOpenMPClauseName(Kind); + return StmtError(); + } + bool WrongStmt = false; + Expr *V = 0; + Expr *X = 0; + Expr *OpExpr = 0; + BinaryOperatorKind Op = BO_Assign; + bool CaptureAfter = false; + bool Reversed = false; + switch (Kind) { + case OMPC_read: { + // expr : v = x, where x and v are both l-value with scalar type. + BinaryOperator *BinOp = dyn_cast_or_null(BaseStmt); + ImplicitCastExpr *ImpCast; + WrongStmt = + !BinOp || BinOp->getOpcode() != BO_Assign || !BinOp->getLHS() || + !BinOp->getRHS() || + (!BinOp->getLHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getLHS()->getType().getCanonicalType()->isDependentType()) || + (!BinOp->getRHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getRHS()->getType().getCanonicalType()->isDependentType()) || + !(ImpCast = dyn_cast_or_null(BinOp->getRHS())) || + ImpCast->getCastKind() != CK_LValueToRValue; + if (!WrongStmt) { + llvm::FoldingSetNodeID ID; + BinOp->getLHS()->IgnoreParenCasts()->Profile(ID, Context, true); + ExprUseChecker UseCheck(ID, Context); + WrongStmt = UseCheck.Visit(BinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + V = BinOp->getLHS(); + X = BinOp->getRHS(); + } + } + break; + } + case OMPC_write: { + // expr : x = expr, where x is an l-value with scalar type and expr has + // scalar type. + BinaryOperator *BinOp = dyn_cast_or_null(BaseStmt); + WrongStmt = + !BinOp || BinOp->getOpcode() != BO_Assign || !BinOp->getLHS() || + !BinOp->getRHS() || + (!BinOp->getLHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getLHS()->getType().getCanonicalType()->isDependentType()) || + (!BinOp->getRHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getRHS()->getType().getCanonicalType()->isDependentType()); + if (!WrongStmt) { + llvm::FoldingSetNodeID ID; + BinOp->getLHS()->IgnoreParenCasts()->Profile(ID, Context, true); + ExprUseChecker UseCheck(ID, Context); + WrongStmt = UseCheck.Visit(BinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + X = BinOp->getLHS(); + OpExpr = BinOp->getRHS(); + } + } + break; + } + case OMPC_update: { + // expr : x++, where x is an l-value with scalar type. + // expr : x--, where x is an l-value with scalar type. + // expr : ++x, where x is an l-value with scalar type. + // expr : --x, where x is an l-value with scalar type. + // expr : x binop= expr, where x is an l-value with scalar type and expr is + // scalar. + // expr : x = x binop expr, where x is an l-value with scalar type and expr + // is scalar. + // expr : x = expr binop x, where x is an l-value with scalar type and expr + // is scalar. + // binop : +, *, -, /, &, ^, |, << or >>. + UnaryOperator *UnOp = dyn_cast_or_null(BaseStmt); + BinaryOperator *BinOp = dyn_cast_or_null(BaseStmt); + BinaryOperator *RHSBinOp = BinOp ? dyn_cast_or_null( + BinOp->getRHS()->IgnoreParenCasts()) + : 0; + WrongStmt = + (!UnOp && !BinOp) || + (UnOp && ((!UnOp->getType().getCanonicalType()->isScalarType() && + !UnOp->getType().getCanonicalType()->isDependentType()) || + !UnOp->isIncrementDecrementOp())) || + (BinOp && + ((!BinOp->getLHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getLHS()->getType().getCanonicalType()->isDependentType()) || + (!BinOp->getRHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getRHS() + ->getType() + .getCanonicalType() + ->isDependentType()))) || + (BinOp && + (!BinOp->isCompoundAssignmentOp() && !BinOp->isShiftAssignOp()) && + RHSBinOp && + (BinOp->getOpcode() != BO_Assign || + (!RHSBinOp->isAdditiveOp() && RHSBinOp->getOpcode() != BO_Mul && + RHSBinOp->getOpcode() != BO_Div && !RHSBinOp->isBitwiseOp() && + !RHSBinOp->isShiftOp()))) || + (BinOp && !RHSBinOp && + ((!BinOp->isCompoundAssignmentOp() && !BinOp->isShiftAssignOp()) || + BinOp->getOpcode() == BO_RemAssign)); + if (!WrongStmt && UnOp) { + X = UnOp->getSubExpr(); + OpExpr = ActOnIntegerConstant(BaseStmt->getLocStart(), 1).take(); + if (UnOp->isIncrementOp()) + Op = BO_Add; + else + Op = BO_Sub; + } else if (!WrongStmt && BinOp && + (BinOp->isCompoundAssignmentOp() || BinOp->isShiftAssignOp())) { + llvm::FoldingSetNodeID ID; + BinOp->getLHS()->IgnoreParenCasts()->Profile(ID, Context, true); + ExprUseChecker UseCheck(ID, Context); + WrongStmt = UseCheck.Visit(BinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + X = BinOp->getLHS(); + OpExpr = BinOp->getRHS(); + switch (BinOp->getOpcode()) { + case BO_AddAssign: + Op = BO_Add; + break; + case BO_MulAssign: + Op = BO_Mul; + break; + case BO_SubAssign: + Op = BO_Sub; + break; + case BO_DivAssign: + Op = BO_Div; + break; + case BO_AndAssign: + Op = BO_And; + break; + case BO_XorAssign: + Op = BO_Xor; + break; + case BO_OrAssign: + Op = BO_Or; + break; + case BO_ShlAssign: + Op = BO_Shl; + break; + case BO_ShrAssign: + Op = BO_Shr; + break; + default: + WrongStmt = true; + break; + } + } + } else if (!WrongStmt && RHSBinOp) { + llvm::FoldingSetNodeID ID1, ID2; + BinOp->getLHS()->IgnoreParenCasts()->Profile(ID1, Context, true); + RHSBinOp->getLHS()->IgnoreParenCasts()->Profile(ID2, Context, true); + if (ID1 == ID2) { + ExprUseChecker UseCheck(ID1, Context); + WrongStmt = UseCheck.Visit(RHSBinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + X = BinOp->getLHS(); + OpExpr = RHSBinOp->getRHS(); + Op = RHSBinOp->getOpcode(); + } + } else { + ID2.clear(); + RHSBinOp->getRHS()->IgnoreParenCasts()->Profile(ID2, Context, true); + if (ID1 == ID2) { + ExprUseChecker UseCheck(ID2, Context); + WrongStmt = UseCheck.Visit(RHSBinOp->getLHS()->IgnoreParenCasts()); + if (!WrongStmt) { + X = BinOp->getLHS(); + OpExpr = RHSBinOp->getLHS(); + Op = RHSBinOp->getOpcode(); + Reversed = true; + } + } else + WrongStmt = true; + } + } + break; + } + case OMPC_capture: { + // expr : v = x++, where v and x are l-values with scalar types. + // expr : v = x--, where v and x are l-values with scalar types. + // expr : v = ++x, where v and x are l-values with scalar types. + // expr : v = --x, where v and x are l-values with scalar types. + // expr : v = x binop= expr, where v and x are l-values with scalar types + // and expr is scalar. + // expr : v = x = x binop expr, where v and x are l-values with scalar type + // and expr is scalar. + // expr : v = x = expr binop x, where v and x are l-values with scalar type + // and expr is scalar. + // stmt : {v = x; x binop= expr;} + // stmt : {x binop= expr; v = x;} + // stmt : {v = x; x = x binop expr;} + // stmt : {v = x; x = expr binop x;} + // stmt : {x = x binop expr; v = x;} + // stmt : {x = expr binop x; v = x;} + // stmt : {v = x; x = expr;} + // stmt : {v = x; x++;} + // stmt : {v = x; ++x;} + // stmt : {x++; v = x;} + // stmt : {++x; v = x;} + // stmt : {v = x; x--;} + // stmt : {v = x; --x;} + // stmt : {x--; v = x;} + // stmt : {--x; v = x;} + // binop : +, *, -, /, &, ^, |, << or >>. + + // Expr *V = 0; + // Expr *X = 0; + llvm::FoldingSetNodeID VID, XID; + BinaryOperator *BinOp = dyn_cast_or_null(BaseStmt); + if (ExprStmt && (!BinOp || BinOp->getOpcode() != BO_Assign)) { + WrongStmt = true; + break; + } + if (ExprStmt) { + V = BinOp->getLHS(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + ExprUseChecker UseCheck(VID, Context); + WrongStmt = + (!V->getType().getCanonicalType()->isScalarType() && + !V->getType().getCanonicalType()->isDependentType()) || + (!BinOp->getRHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getRHS()->getType().getCanonicalType()->isDependentType()); + Expr *RHS = BinOp->getRHS()->IgnoreParenLValueCasts(); + if (UnaryOperator *XOp = dyn_cast_or_null(RHS)) { + X = XOp->getSubExpr(); + X->IgnoreParenCasts()->Profile(XID, Context, true); + OpExpr = ActOnIntegerConstant(X->getLocStart(), 1).take(); + if (XOp->isIncrementOp()) + Op = BO_Add; + else + Op = BO_Sub; + CaptureAfter = XOp->isPrefix(); + } else if (BinaryOperator *XOp = dyn_cast_or_null(RHS)) { + X = XOp->getLHS(); + X->IgnoreParenCasts()->Profile(XID, Context, true); + CaptureAfter = true; + } else + WrongStmt = true; + if (WrongStmt) + break; + BaseStmt = RHS; + } else if (CompoundStmt *CStmt = dyn_cast_or_null(BaseStmt)) { + WrongStmt = CStmt->size() != 2; + if (WrongStmt) + break; + Stmt *S1 = *(CStmt->body_begin()); + Stmt *S2 = CStmt->body_back(); + BinaryOperator *VXOp1 = dyn_cast_or_null(S1); + BinaryOperator *VXOp2 = dyn_cast_or_null(S2); + UnaryOperator *XOp1 = dyn_cast_or_null(S1); + UnaryOperator *XOp2 = dyn_cast_or_null(S2); + if (VXOp1 && VXOp2 && VXOp1->getOpcode() == BO_Assign && + VXOp2->getOpcode() == BO_Assign) { + V = VXOp1->getLHS(); + X = VXOp1->getRHS()->IgnoreParenLValueCasts(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + X->IgnoreParenCasts()->Profile(XID, Context, true); + llvm::FoldingSetNodeID X2ID; + VXOp2->getLHS()->IgnoreParenCasts()->Profile(X2ID, Context, true); + if (!(XID == X2ID)) { + llvm::FoldingSetNodeID ExprID; + VXOp2->getRHS()->IgnoreParenCasts()->Profile(ExprID, Context, true); + if (ExprID == VID) { + X = VXOp1->getLHS(); + XID = VID; + V = VXOp2->getLHS(); + VID = X2ID; + BaseStmt = S1; + CaptureAfter = true; + } else { + WrongStmt = true; + break; + } + } else { + BaseStmt = S2; + } + } else if (VXOp1 && VXOp2 && VXOp1->getOpcode() == BO_Assign && + VXOp2->isCompoundAssignmentOp()) { + V = VXOp1->getLHS(); + X = VXOp1->getRHS()->IgnoreParenLValueCasts(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + X->IgnoreParenCasts()->Profile(XID, Context, true); + llvm::FoldingSetNodeID X2ID; + VXOp2->getLHS()->IgnoreParenCasts()->Profile(X2ID, Context, true); + if (!(XID == X2ID)) { + WrongStmt = true; + break; + } + BaseStmt = S2; + } else if (VXOp1 && VXOp2 && VXOp2->getOpcode() == BO_Assign && + VXOp1->isCompoundAssignmentOp()) { + V = VXOp2->getLHS(); + X = VXOp2->getRHS()->IgnoreParenLValueCasts(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + X->IgnoreParenCasts()->Profile(XID, Context, true); + llvm::FoldingSetNodeID X2ID; + VXOp1->getLHS()->IgnoreParenCasts()->Profile(X2ID, Context, true); + if (!(XID == X2ID)) { + WrongStmt = true; + break; + } + BaseStmt = S1; + CaptureAfter = true; + } else if (VXOp1 && XOp2 && VXOp1->getOpcode() == BO_Assign) { + V = VXOp1->getLHS(); + X = VXOp1->getRHS()->IgnoreParenLValueCasts(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + X->IgnoreParenCasts()->Profile(XID, Context, true); + llvm::FoldingSetNodeID X2ID; + XOp2->getSubExpr()->IgnoreParenCasts()->Profile(X2ID, Context, true); + if (!(XID == X2ID)) { + WrongStmt = true; + break; + } + BaseStmt = S2; + } else if (VXOp2 && XOp1 && VXOp2->getOpcode() == BO_Assign) { + V = VXOp2->getLHS(); + X = VXOp2->getRHS()->IgnoreParenLValueCasts(); + V->IgnoreParenCasts()->Profile(VID, Context, true); + X->IgnoreParenCasts()->Profile(XID, Context, true); + llvm::FoldingSetNodeID X2ID; + XOp1->getSubExpr()->IgnoreParenCasts()->Profile(X2ID, Context, true); + if (!(XID == X2ID)) { + WrongStmt = true; + break; + } + BaseStmt = S1; + CaptureAfter = true; + } else { + WrongStmt = true; + break; + } + if ((!V->getType().getCanonicalType()->isScalarType() && + !V->getType().getCanonicalType()->isDependentType()) || + (!X->getType().getCanonicalType()->isScalarType() && + !X->getType().getCanonicalType()->isDependentType())) { + WrongStmt = true; + break; + } + } else { + WrongStmt = true; + break; + } + ExprUseChecker UseCheckV(VID, Context); + ExprUseChecker UseCheckX(XID, Context); + WrongStmt = UseCheckV.Visit(X->IgnoreParenCasts()) || + UseCheckX.Visit(V->IgnoreParenCasts()); + if (WrongStmt) + break; + UnaryOperator *UnOp = dyn_cast_or_null(BaseStmt); + BinOp = dyn_cast_or_null(BaseStmt); + BinaryOperator *RHSBinOp = BinOp ? dyn_cast_or_null( + BinOp->getRHS()->IgnoreParenCasts()) + : 0; + WrongStmt = + (!UnOp && !BinOp) || + (UnOp && ((!UnOp->getType().getCanonicalType()->isScalarType() && + !UnOp->getType().getCanonicalType()->isDependentType()) || + !UnOp->isIncrementDecrementOp())) || + (BinOp && + ((!BinOp->getLHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getLHS()->getType().getCanonicalType()->isDependentType()) || + (!BinOp->getRHS()->getType().getCanonicalType()->isScalarType() && + !BinOp->getRHS() + ->getType() + .getCanonicalType() + ->isDependentType()))) || + (BinOp && + (!BinOp->isCompoundAssignmentOp() && !BinOp->isShiftAssignOp()) && + RHSBinOp && + (BinOp->getOpcode() != BO_Assign || + (!RHSBinOp->isAdditiveOp() && RHSBinOp->getOpcode() != BO_Mul && + RHSBinOp->getOpcode() != BO_Div && !RHSBinOp->isBitwiseOp() && + !RHSBinOp->isShiftOp()))) || + (BinOp && !RHSBinOp && + ((!BinOp->isCompoundAssignmentOp() && !BinOp->isShiftAssignOp() && + BinOp->getOpcode() != BO_Assign) || + BinOp->getOpcode() == BO_RemAssign)); + if (!WrongStmt && UnOp) { + OpExpr = ActOnIntegerConstant(BaseStmt->getLocStart(), 1).take(); + if (UnOp->isIncrementOp()) + Op = BO_Add; + else + Op = BO_Sub; + } else if (!WrongStmt && BinOp && !RHSBinOp && + BinOp->getOpcode() == BO_Assign) { + Op = BO_Assign; + OpExpr = BinOp->getRHS(); + } else if (!WrongStmt && BinOp && + (BinOp->isCompoundAssignmentOp() || BinOp->isShiftAssignOp())) { + ExprUseChecker UseCheckX(XID, Context); + ExprUseChecker UseCheckV(VID, Context); + WrongStmt = UseCheckX.Visit(BinOp->getRHS()->IgnoreParenCasts()) || + UseCheckV.Visit(BinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + OpExpr = BinOp->getRHS(); + switch (BinOp->getOpcode()) { + case BO_AddAssign: + Op = BO_Add; + break; + case BO_MulAssign: + Op = BO_Mul; + break; + case BO_SubAssign: + Op = BO_Sub; + break; + case BO_DivAssign: + Op = BO_Div; + break; + case BO_AndAssign: + Op = BO_And; + break; + case BO_XorAssign: + Op = BO_Xor; + break; + case BO_OrAssign: + Op = BO_Or; + break; + case BO_ShlAssign: + Op = BO_Shl; + break; + case BO_ShrAssign: + Op = BO_Shr; + break; + default: + WrongStmt = true; + break; + } + } + } else if (!WrongStmt && RHSBinOp) { + llvm::FoldingSetNodeID ID; + RHSBinOp->getLHS()->IgnoreParenCasts()->Profile(ID, Context, true); + if (XID == ID) { + ExprUseChecker UseCheckX(XID, Context); + ExprUseChecker UseCheckV(VID, Context); + WrongStmt = UseCheckX.Visit(RHSBinOp->getRHS()->IgnoreParenCasts()) || + UseCheckV.Visit(RHSBinOp->getRHS()->IgnoreParenCasts()); + if (!WrongStmt) { + OpExpr = RHSBinOp->getRHS(); + Op = RHSBinOp->getOpcode(); + } + } else { + ID.clear(); + RHSBinOp->getRHS()->IgnoreParenCasts()->Profile(ID, Context, true); + if (XID == ID) { + ExprUseChecker UseCheckX(XID, Context); + ExprUseChecker UseCheckV(VID, Context); + WrongStmt = UseCheckX.Visit(RHSBinOp->getLHS()->IgnoreParenCasts()) || + UseCheckV.Visit(RHSBinOp->getLHS()->IgnoreParenCasts()); + if (!WrongStmt) { + OpExpr = RHSBinOp->getLHS(); + Op = RHSBinOp->getOpcode(); + Reversed = true; + } + } else + WrongStmt = true; + } + } + break; + } + default: + break; + } + if (WrongStmt) { + Diag(BaseStmt->getLocStart(), diag::err_omp_atomic_wrong_statement) + << getOpenMPClauseName(Kind); + return StmtError(); + } + // if (OpExpr && !X->getType()->isDependentType() && + // !OpExpr->getType()->isDependentType()) { + // ExprResult Res = Owned(OpExpr); + // CastKind CK = PrepareScalarCast(Res, X->getType()); + // if (CK != CK_NoOp) + // OpExpr = ImpCastExprToType(Res.take(), X->getType(), CK).take(); + // } + // if (V && !V->getType()->isDependentType()) { + // ExprResult Res = Owned(X); + // CastKind CK = PrepareScalarCast(Res, V->getType()); + // if (CK != CK_NoOp) + // X = ImpCastExprToType(Res.take(), V->getType(), CK).take(); + // } + + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt, V, X, OpExpr, Op, CaptureAfter, + Reversed)); +} + +StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses)); +} + +StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + + getCurFunction()->setHasBranchProtectedScope(); + return Owned( + OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, + Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPDistributeDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // Prepare the output arguments for routine CollapseOpenMPLoop + Expr *NewEnd = 0; + Expr *NewVar = 0; + Expr *NewVarCntExpr = 0; + Expr *NewFinal = 0; + SmallVector VarCnts; + + // Do the collapse. + if (!CollapseOpenMPLoop(OMPD_distribute, Clauses, AStmt, StartLoc, EndLoc, + NewVar, NewEnd, NewVarCntExpr, NewFinal, VarCnts)) { + return StmtError(); + } + + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPDistributeDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, NewVar, NewEnd, NewVarCntExpr, + NewFinal, VarCnts)); +} + +StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType) { + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses, + ConstructType)); +} + +StmtResult +Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType) { + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPCancellationPointDirective::Create(Context, StartLoc, EndLoc, + ConstructType)); +} + +namespace { +class TeamsChecker : public StmtVisitor { + Stmt *FoundTeams; + +public: + bool VisitOMPTeamsDirective(OMPTeamsDirective *D) { + FoundTeams = D; + return false; + } + bool VisitCompoundStmt(CompoundStmt *S) { + bool Flag = false; + for (Stmt::child_range R = S->children(); R; ++R) { + Flag |= Visit(*R); + if (Flag && FoundTeams) + return true; + } + return Flag; + } + bool VisitNullStmt(NullStmt *) { return false; } + bool VisitStmt(Stmt *) { return true; } + TeamsChecker() : FoundTeams(0) {} + Stmt *getFoundTeams() { return FoundTeams; } +}; +} + +StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + TeamsChecker Checker; + // If specified, a teams construct must be contained within a target + // construct. That target construct must contain no statements or directives + // outside of the teams construct. + if (Checker.Visit(cast(AStmt)->getCapturedStmt())) { + if (Stmt *S = Checker.getFoundTeams()) { + Diag(S->getLocStart(), diag::err_omp_teams_not_single_in_target); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + return Owned( + OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, + Clauses, AStmt)); +} + +StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + //FIXME Add checking that at least one 'from' or 'to' clause is specified + + getCurFunction()->setHasBranchProtectedScope(); + return Owned( + OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses)); +} + +OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, + SourceLocation StartLoc, + SourceLocation EndLoc) { + OMPClause *Res = 0; + switch (Kind) { + case OMPC_if: + Res = ActOnOpenMPIfClause(Expr, StartLoc, EndLoc); + break; + case OMPC_num_threads: + Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, EndLoc); + break; + case OMPC_collapse: + Res = ActOnOpenMPCollapseClause(Expr, StartLoc, EndLoc); + break; + case OMPC_final: + Res = ActOnOpenMPFinalClause(Expr, StartLoc, EndLoc); + break; + case OMPC_safelen: + Res = ActOnOpenMPSafelenClause(Expr, StartLoc, EndLoc); + break; + case OMPC_simdlen: + Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, EndLoc); + break; + case OMPC_num_teams: + Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, EndLoc); + break; + case OMPC_thread_limit: + Res = ActOnOpenMPThreadLimitClause(Expr, StartLoc, EndLoc); + break; + case OMPC_device: + Res = ActOnOpenMPDeviceClause(Expr, StartLoc, EndLoc); + break; + default: + break; + } + return Res; +} + +OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc, + SourceLocation EndLoc) { + QualType Type = Condition->getType(); + Expr *ValExpr = Condition; + if (!Type->isDependentType() && !Type->isInstantiationDependentType()) { + ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), + Condition->getExprLoc(), Condition); + if (Val.isInvalid()) + return 0; + + ValExpr = Val.take(); + } + + return new (Context) OMPIfClause(ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, + SourceLocation StartLoc, + SourceLocation EndLoc) { + QualType Type = Condition->getType(); + Expr *ValExpr = Condition; + if (!Type->isDependentType() && !Type->isInstantiationDependentType()) { + ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), + Condition->getExprLoc(), Condition); + if (Val.isInvalid()) + return 0; + + ValExpr = Val.take(); + } + + return new (Context) OMPFinalClause(ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (!NumThreads) + return 0; + + Expr *ValExpr = NumThreads; + if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && + !ValExpr->isInstantiationDependent()) { + SourceLocation Loc = NumThreads->getExprLoc(); + ExprResult Value = + PerformContextualImplicitConversion(Loc, NumThreads, ConvertDiagnoser); + if (Value.isInvalid() || + !Value.get()->getType()->isIntegralOrUnscopedEnumerationType()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + !Result.isStrictlyPositive()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << NumThreads->getSourceRange(); + return 0; + } + Value = DefaultLvalueConversion(Value.take()); + if (Value.isInvalid()) + return 0; + Value = PerformImplicitConversion( + Value.take(), Context.getIntTypeForBitwidth(32, true), AA_Converting); + ValExpr = Value.take(); + } + + return new (Context) OMPNumThreadsClause(ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, + SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (!Device) + return 0; + + Expr *ValExpr = Device; + if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && + !ValExpr->isInstantiationDependent()) { + SourceLocation Loc = ValExpr->getExprLoc(); + ExprResult Value = + PerformContextualImplicitConversion(Loc, ValExpr, ConvertDiagnoser); + if (Value.isInvalid() || + !Value.get()->getType()->isIntegralOrUnscopedEnumerationType()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + Result.isNegative()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << ValExpr->getSourceRange(); + return 0; + } + Value = DefaultLvalueConversion(Value.take()); + if (Value.isInvalid()) + return 0; + Value = PerformImplicitConversion( + Value.take(), Context.getIntTypeForBitwidth(32, true), AA_Converting); + ValExpr = Value.take(); + } + + return new (Context) OMPDeviceClause(ValExpr, StartLoc, EndLoc); +} + +Expr *Sema::ActOnConstantPositiveSubExpressionInClause(Expr *E) { + if (!E) + return 0; + if (E->isInstantiationDependent()) + return E; + llvm::APSInt Result; + ExprResult ICE = VerifyIntegerConstantExpression(E, &Result); + if (ICE.isInvalid()) + return 0; + if (!Result.isStrictlyPositive()) { + Diag(E->getExprLoc(), diag::err_negative_expression_in_clause) + << E->getSourceRange(); + return 0; + } + return IntegerLiteral::Create(Context, Result, + ICE.get()->getType().getNonReferenceType(), + E->getExprLoc()); +} + +Expr *Sema::ActOnConstantLinearStep(Expr *E) { + if (!E) + return 0; + if (E->isInstantiationDependent()) + return E; + llvm::APSInt Result; + ExprResult ICE = VerifyIntegerConstantExpression(E, &Result); + if (ICE.isInvalid()) + return 0; + if (!Result.isStrictlyPositive() && !Result.isNegative()) { + Diag(E->getExprLoc(), diag::err_zero_step_in_linear_clause) + << E->getSourceRange(); + return 0; + } + return IntegerLiteral::Create(Context, Result, + ICE.get()->getType().getNonReferenceType(), + E->getExprLoc()); +} + +OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumLoops, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.7.1, Loop construct, Description] + // The parameter of the collapse clause must be a constant + // positive integer expression. + Expr *Val = ActOnConstantPositiveSubExpressionInClause(NumLoops); + if (!Val) + return 0; + + return new (Context) OMPCollapseClause(Val, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.8.1, simd construct, Description] + // The parameter of the safelen clause must be a constant + // positive integer expression. + Expr *Val = ActOnConstantPositiveSubExpressionInClause(Len); + if (!Val) + return 0; + + return new (Context) OMPSafelenClause(Val, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.8.2, declare simd construct, Description] + // The parameter of the simdlen clause must be a constant + // positive integer expression. + Expr *Val = ActOnConstantPositiveSubExpressionInClause(Len); + if (!Val) + return 0; + + return new (Context) OMPSimdlenClause(Val, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *E, SourceLocation StartLoc, + SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (!E) + return 0; + + Expr *ValExpr = E; + if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && + !ValExpr->isInstantiationDependent()) { + SourceLocation Loc = ValExpr->getExprLoc(); + ExprResult Value = + PerformContextualImplicitConversion(Loc, ValExpr, ConvertDiagnoser); + if (Value.isInvalid() || + !Value.get()->getType()->isIntegralOrUnscopedEnumerationType()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + !Result.isStrictlyPositive()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << ValExpr->getSourceRange(); + return 0; + } + Value = DefaultLvalueConversion(Value.take()); + if (Value.isInvalid()) + return 0; + Value = PerformImplicitConversion( + Value.take(), Context.getIntTypeForBitwidth(32, true), AA_Converting); + if (Value.isInvalid()) + return 0; + ValExpr = Value.take(); + } + + return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *E, SourceLocation StartLoc, + SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (!E) + return 0; + + Expr *ValExpr = E; + if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && + !ValExpr->isInstantiationDependent()) { + SourceLocation Loc = ValExpr->getExprLoc(); + ExprResult Value = + PerformContextualImplicitConversion(Loc, ValExpr, ConvertDiagnoser); + if (Value.isInvalid() || + !Value.get()->getType()->isIntegralOrUnscopedEnumerationType()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + !Result.isStrictlyPositive()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << ValExpr->getSourceRange(); + return 0; + } + Value = DefaultLvalueConversion(Value.take()); + if (Value.isInvalid()) + return 0; + Value = PerformImplicitConversion( + Value.take(), Context.getIntTypeForBitwidth(32, true), AA_Converting); + if (Value.isInvalid()) + return 0; + ValExpr = Value.take(); + } + + return new (Context) OMPThreadLimitClause(ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, + unsigned Argument, + SourceLocation ArgumentLoc, + SourceLocation StartLoc, + SourceLocation EndLoc) { + OMPClause *Res = 0; + switch (Kind) { + case OMPC_default: + Res = + ActOnOpenMPDefaultClause(static_cast(Argument), + ArgumentLoc, StartLoc, EndLoc); + break; + case OMPC_proc_bind: + Res = ActOnOpenMPProcBindClause( + static_cast(Argument), ArgumentLoc, StartLoc, + EndLoc); + break; + default: + break; + } + return Res; +} + +OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DEFAULT_unknown) { + std::string Values; + std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : ""); + for (unsigned i = OMPC_DEFAULT_unknown + 1; i < NUM_OPENMP_DEFAULT_KINDS; + ++i) { + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_default, i); + Values += "'"; + switch (i) { + case NUM_OPENMP_DEFAULT_KINDS - 2: + Values += " or "; + break; + case NUM_OPENMP_DEFAULT_KINDS - 1: + break; + default: + Values += Sep; + break; + } + } + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_default); + return 0; + } + switch (Kind) { + case OMPC_DEFAULT_none: + DSAStack->setDefaultDSANone(); + break; + case OMPC_DEFAULT_shared: + DSAStack->setDefaultDSAShared(); + break; + default: + break; + } + return new (Context) OMPDefaultClause(Kind, KindLoc, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_PROC_BIND_unknown) { + std::string Values; + std::string Sep(NUM_OPENMP_PROC_BIND_KINDS > 1 ? ", " : ""); + for (unsigned i = OMPC_PROC_BIND_unknown + 1; + i < NUM_OPENMP_PROC_BIND_KINDS; ++i) { + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i); + Values += "'"; + switch (i) { + case NUM_OPENMP_PROC_BIND_KINDS - 2: + Values += " or "; + break; + case NUM_OPENMP_PROC_BIND_KINDS - 1: + break; + default: + Values += Sep; + break; + } + } + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_proc_bind); + return 0; + } + return new (Context) OMPProcBindClause(Kind, KindLoc, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, + SourceLocation StartLoc, + SourceLocation EndLoc) { + OMPClause *Res = 0; + switch (Kind) { + case OMPC_ordered: + Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc); + break; + case OMPC_nowait: + Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc); + break; + case OMPC_untied: + Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc); + break; + case OMPC_mergeable: + Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc); + break; + case OMPC_read: + Res = ActOnOpenMPReadClause(StartLoc, EndLoc); + break; + case OMPC_write: + Res = ActOnOpenMPWriteClause(StartLoc, EndLoc); + break; + case OMPC_update: + Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc); + break; + case OMPC_capture: + Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc); + break; + case OMPC_seq_cst: + Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); + break; + case OMPC_inbranch: + Res = ActOnOpenMPInBranchClause(StartLoc, EndLoc); + break; + case OMPC_notinbranch: + Res = ActOnOpenMPNotInBranchClause(StartLoc, EndLoc); + break; + default: + break; + } + return Res; +} + +OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + DSAStack->setRegionOrdered(); + return new (Context) OMPOrderedClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + DSAStack->setRegionNowait(); + return new (Context) OMPNowaitClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPUntiedClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPMergeableClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSingleExprWithTypeClause( + OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, + Expr *Expr, SourceLocation StartLoc, SourceLocation EndLoc) { + OMPClause *Res = 0; + switch (Kind) { + case OMPC_schedule: + Res = ActOnOpenMPScheduleClause( + static_cast(Argument), ArgumentLoc, Expr, + StartLoc, EndLoc); + break; + case OMPC_dist_schedule: + Res = ActOnOpenMPDistScheduleClause( + static_cast(Argument), ArgumentLoc, Expr, + StartLoc, EndLoc); + break; + default: + break; + } + return Res; +} + +OMPClause *Sema::ActOnOpenMPScheduleClause(OpenMPScheduleClauseKind Kind, + SourceLocation KindLoc, + Expr *ChunkSize, + SourceLocation StartLoc, + SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (Kind == OMPC_SCHEDULE_unknown) { + std::string Values; + std::string Sep(NUM_OPENMP_SCHEDULE_KINDS > 1 ? ", " : ""); + for (int i = OMPC_SCHEDULE_unknown + 1; i < NUM_OPENMP_SCHEDULE_KINDS; + ++i) { + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i); + Values += "'"; + switch (i) { + case NUM_OPENMP_SCHEDULE_KINDS - 2: + Values += " or "; + break; + case NUM_OPENMP_SCHEDULE_KINDS - 1: + break; + default: + Values += Sep; + break; + } + } + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_schedule); + return 0; + } + ExprResult Value; + if (ChunkSize) { + if (!ChunkSize->isTypeDependent() && !ChunkSize->isValueDependent() && + !ChunkSize->isInstantiationDependent()) { + SourceLocation Loc = ChunkSize->getExprLoc(); + Value = + PerformContextualImplicitConversion(Loc, ChunkSize, ConvertDiagnoser); + if (Value.isInvalid()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + !Result.isStrictlyPositive()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << ChunkSize->getSourceRange(); + return 0; + } + } + } else { + // OpenMP [2.5.1, Loop Construct, Description, Table 2-1] + // dynamic When no chunk_size is specified, it defaults to 1. + // guided When no chunk_size is specified, it defaults to 1. + switch (Kind) { + case OMPC_SCHEDULE_dynamic: + case OMPC_SCHEDULE_guided: + Value = ActOnIntegerConstant(StartLoc, 1); + break; + default: + break; + } + } + Expr *ValExpr = Value.take(); + + return new (Context) + OMPScheduleClause(Kind, KindLoc, ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, SourceLocation KindLoc, Expr *ChunkSize, + SourceLocation StartLoc, SourceLocation EndLoc) { + class CConvertDiagnoser : public ICEConvertDiagnoser { + public: + CConvertDiagnoser() : ICEConvertDiagnoser(true, false, true) {} + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_incomplete_class_type) << T; + } + virtual SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder + noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_multiple_conversions) << T; + } + + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion(Sema &S, + SourceLocation Loc, + QualType T, + QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser; + + if (Kind != OMPC_DIST_SCHEDULE_static) { + std::string Values = "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, + OMPC_DIST_SCHEDULE_static); + Values += "'"; + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dist_schedule); + return 0; + } + ExprResult Value; + if (ChunkSize) { + if (!ChunkSize->isTypeDependent() && !ChunkSize->isValueDependent() && + !ChunkSize->isInstantiationDependent()) { + SourceLocation Loc = ChunkSize->getExprLoc(); + Value = + PerformContextualImplicitConversion(Loc, ChunkSize, ConvertDiagnoser); + if (Value.isInvalid()) + return 0; + + llvm::APSInt Result; + if (Value.get()->isIntegerConstantExpr(Result, Context) && + !Result.isStrictlyPositive()) { + Diag(Loc, diag::err_negative_expression_in_clause) + << ChunkSize->getSourceRange(); + return 0; + } + } + } else { + Value = ExprEmpty(); + } + Expr *ValExpr = Value.take(); + + return new (Context) + OMPDistScheduleClause(Kind, KindLoc, ValExpr, StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPVarListClause( + OpenMPClauseKind Kind, ArrayRef VarList, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned Op, Expr *TailExpr, CXXScopeSpec &SS, + const UnqualifiedId &OpName, SourceLocation OpLoc) { + OMPClause *Res = 0; + switch (Kind) { + case OMPC_private: + Res = ActOnOpenMPPrivateClause(VarList, StartLoc, EndLoc); + break; + case OMPC_lastprivate: + Res = ActOnOpenMPLastPrivateClause(VarList, StartLoc, EndLoc); + break; + case OMPC_firstprivate: + Res = ActOnOpenMPFirstPrivateClause(VarList, StartLoc, EndLoc); + break; + case OMPC_shared: + Res = ActOnOpenMPSharedClause(VarList, StartLoc, EndLoc); + break; + case OMPC_copyin: + Res = ActOnOpenMPCopyinClause(VarList, StartLoc, EndLoc); + break; + case OMPC_copyprivate: + Res = ActOnOpenMPCopyPrivateClause(VarList, StartLoc, EndLoc); + break; + case OMPC_reduction: + Res = ActOnOpenMPReductionClause( + VarList, StartLoc, EndLoc, + static_cast(Op), SS, + GetNameFromUnqualifiedId(OpName)); + break; + case OMPC_flush: + Res = ActOnOpenMPFlushClause(VarList, StartLoc, EndLoc); + break; + case OMPC_depend: + Res = + ActOnOpenMPDependClause(VarList, StartLoc, EndLoc, + static_cast(Op), OpLoc); + break; + case OMPC_uniform: + Res = ActOnOpenMPUniformClause(VarList, StartLoc, EndLoc); + break; + case OMPC_linear: + Res = ActOnOpenMPLinearClause(VarList, StartLoc, EndLoc, TailExpr, OpLoc); + break; + case OMPC_aligned: + Res = ActOnOpenMPAlignedClause(VarList, StartLoc, EndLoc, TailExpr, OpLoc); + break; + case OMPC_map: + Res = ActOnOpenMPMapClause(VarList, StartLoc, EndLoc, + static_cast(Op), OpLoc); + break; + case OMPC_to: + Res = ActOnOpenMPToClause(VarList, StartLoc, EndLoc); + break; + case OMPC_from: + Res = ActOnOpenMPFromClause(VarList, StartLoc, EndLoc); + break; + default: + break; + } + return Res; +} + +Expr *Sema::ActOnOpenMPParameterInDeclarativeVarListClause(SourceLocation Loc, + ParmVarDecl *Param) { + QualType ExprType = Param->getType().getNonReferenceType(); + DeclContext *SavedCurContext = CurContext; + CurContext = Param->getDeclContext(); + ExprResult DE = BuildDeclRefExpr(Param, ExprType, VK_RValue, Loc); + CurContext = SavedCurContext; + return DE.get(); +} + +Expr *Sema::FindOpenMPDeclarativeClauseParameter(StringRef Name, + SourceLocation Loc, + Decl *FuncDecl) { + FunctionDecl *FDecl = dyn_cast(FuncDecl); + FunctionTemplateDecl *FTDecl = dyn_cast(FuncDecl); + if (FTDecl) { + FDecl = FTDecl->getTemplatedDecl(); + } + if (!FDecl) + return 0; + for (FunctionDecl::param_iterator PI = FDecl->param_begin(), + PE = FDecl->param_end(); + PI != PE; ++PI) { + ParmVarDecl *Param = *PI; + if (Name == Param->getName()) { + Expr *E = ActOnOpenMPParameterInDeclarativeVarListClause(Loc, Param); + if (E) { + return E; + } + } + } + return 0; +} + +OMPClause *Sema::ActOnOpenMPDeclarativeVarListClause( + OpenMPClauseKind CKind, ArrayRef NameInfos, + SourceLocation StartLoc, SourceLocation EndLoc, Expr *TailExpr, + SourceLocation TailLoc, Decl *FuncDecl) { + // Vars for the clause. + SmallVector Vars; + if (FuncDecl) { + // Find each var among the function parameters. + for (unsigned J = 0; J < NameInfos.size(); ++J) { + Expr *Param = FindOpenMPDeclarativeClauseParameter( + NameInfos[J].getName().getAsString(), NameInfos[J].getLoc(), + FuncDecl); + if (!Param) { + Diag(NameInfos[J].getLoc(), diag::err_omp_arg_not_found); + } else { + Vars.push_back(Param); + } + } + } + + switch (CKind) { + case OMPC_linear: + return ActOnOpenMPDeclarativeLinearClause(Vars, StartLoc, EndLoc, TailExpr, + TailLoc); + case OMPC_aligned: + return ActOnOpenMPDeclarativeAlignedClause(Vars, StartLoc, EndLoc, TailExpr, + TailLoc); + case OMPC_uniform: + return ActOnOpenMPDeclarativeUniformClause(Vars, StartLoc, EndLoc); + default: + assert(0 && "bad clause kind for a declarative clause"); + } + return 0; +} + +OMPClause *Sema::ActOnOpenMPDeclarativeLinearClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Step, + SourceLocation StepLoc) { + if (VarList.empty()) + return 0; + // OpenMP [2.8.2 declare simd Construct, Restrictions] + // When a constant-linear-step expression is specified in a linear clause + // it must be a constant positive integer expression + if (Step) { + Step = ActOnConstantPositiveSubExpressionInClause(Step); + if (!Step) + return 0; + } + + // Check the vars. + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + + assert(*I && "Null expr in omp linear"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + continue; + } + SourceLocation ELoc = (*I)->getExprLoc(); + // A list-item that appears in a linear clause must be of integral + // or pointer type. + // + DeclRefExpr *DE = dyn_cast_or_null(*I); + QualType QTy = DE->getType().getUnqualifiedType().getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isIntegerType() && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_expected_int_or_ptr) << (*I)->getSourceRange(); + continue; + } + + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPLinearClause::Create(Context, StartLoc, EndLoc, VarList, Step, + StepLoc); +} + +OMPClause *Sema::ActOnOpenMPDeclarativeAlignedClause( + ArrayRef VarList, SourceLocation StartLoc, SourceLocation EndLoc, + Expr *Alignment, SourceLocation AlignmentLoc) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + + assert(*I && "Null expr in omp aligned"); + if (*I && isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + DeclRefExpr *DE = dyn_cast_or_null(*I); + + // OpenMP [2.8.2, declare simd construct, Restrictions] + // The type of list items appearing in the aligned clause must be + // array, pointer, reference to array, or reference to pointer. + QualType QTy = DE->getType() + .getNonReferenceType() + .getUnqualifiedType() + .getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_expected_array_or_ptr) << (*I)->getSourceRange(); + continue; + } + + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + // OpenMP [2.8.2 declare simd Construct] + // The optional parameter of the aligned clause, alignment, must be + // a constant positive integer expression. + if (Alignment) { + Alignment = ActOnConstantPositiveSubExpressionInClause(Alignment); + if (!Alignment) + return 0; + } + return OMPAlignedClause::Create(Context, StartLoc, EndLoc, VarList, Alignment, + AlignmentLoc); +} + +OMPClause *Sema::ActOnOpenMPDeclarativeUniformClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (VarList.empty()) + return 0; + return OMPUniformClause::Create(Context, StartLoc, EndLoc, VarList); +} + +OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector DefaultInits; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp private"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + DefaultInits.push_back(0); + 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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + DefaultInits.push_back(0); + 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_private_incomplete_type)) { + continue; + } + if (Type->isReferenceType()) { + Diag(ELoc, diag::err_omp_clause_ref_type_arg) + << getOpenMPClauseName(OMPC_private); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + 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. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (Kind != OMPC_unknown && Kind != OMPC_private) { + Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_private); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } else { + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + + // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a private + // clause requires an accesible, unambiguous default constructor for the + // class type. + Type = Type.getNonReferenceType().getCanonicalType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXConstructorDecl *CD = LookupDefaultConstructor(RD); + 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_private) << 0; + 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 && (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || + DD->isDeleted())) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_private) << 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; + } else if (DD) { + MarkFunctionReferenced(ELoc, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + Type = Type.getUnqualifiedType(); + IdentifierInfo *Id = &Context.Idents.get(".private."); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar->setImplicit(); + PseudoVar->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + InitializedEntity Entity = InitializedEntity::InitializeVariable(PseudoVar); + InitializationKind InitKind = InitializationKind::CreateDefault(ELoc); + InitializationSequence InitSeq(*this, Entity, InitKind, MultiExprArg()); + ExprResult Res = InitSeq.Perform(*this, Entity, InitKind, MultiExprArg()); + if (Res.isInvalid()) + continue; + DefaultInits.push_back(ActOnFinishFullExpr(Res.take()).take()); + DSAStack->addDSA(VD, DE, OMPC_private); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPPrivateClause::Create(Context, StartLoc, EndLoc, Vars, + DefaultInits); +} + +OMPClause *Sema::ActOnOpenMPFirstPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector PseudoVars; + SmallVector Inits; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp firstprivate"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars.push_back(0); + Inits.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + // OpenMP [2.9.3.4, 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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars.push_back(0); + Inits.push_back(0); + continue; + } + + // OpenMP [2.9.3.4, Restrictions, C/C++, p.2] + // A variable that appears in a firstprivate 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); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + 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. + // OpenMP [2.9.3.4, Description] + // If a list item appears in both firstprivate and lastprivate clauses, + // the update requires for lastprivate occurs after all the initializations + // for firstprivate. + DeclRefExpr *PrevRef; + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + Type = Type.getNonReferenceType().getCanonicalType(); + bool IsConstant = Type.isConstant(Context); + bool IsArray = Type->isArrayType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + if (Kind != OMPC_unknown && Kind != OMPC_firstprivate && + Kind != OMPC_lastprivate && + !(Kind == OMPC_shared && !PrevRef && + (IsConstant || VD->isStaticDataMember()))) { + if ((CurrDir != OMPD_task || PrevRef) && StartLoc.isValid() && + EndLoc.isValid()) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_firstprivate); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } else { + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(Kind); + } + 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. + OpenMPDirectiveKind DKind; + Kind = DSAStack->getImplicitDSA(VD, DKind, PrevRef); + if ((Kind != OMPC_shared && + (CurrDir == OMPD_for || CurrDir == OMPD_sections || + CurrDir == OMPD_for_simd || CurrDir == OMPD_distribute_simd || + CurrDir == OMPD_single || CurrDir == OMPD_distribute)) || + (CurrDir == OMPD_task && + DSAStack->hasDSA(VD, OMPC_reduction, OMPD_parallel, PrevRef))) { + if (Kind == OMPC_unknown) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_firstprivate) + << getOpenMPClauseName(OMPC_shared); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } else if (DKind == OMPD_unknown) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_firstprivate); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } else { + // Skip template instantiations for parallel for and parallel sections. + if (Kind != OMPC_firstprivate || DKind != OMPD_parallel || + (CurrDir != OMPD_for && CurrDir != OMPD_sections) || !PrevRef || + PrevRef->getExprLoc() != ELoc) { + Diag(ELoc, diag::err_omp_dsa_with_directives) + << getOpenMPClauseName(Kind) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(OMPC_firstprivate) + << getOpenMPDirectiveName(CurrDir); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + } + } + + // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a + // firstprivate clause requires an accesible, unambiguous copy constructor + // for the class type. + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->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 && (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; + } else if (DD) { + MarkFunctionReferenced(ELoc, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + + Type = Type.getUnqualifiedType(); + if ((RD && !RD->isTriviallyCopyable()) || IsArray) { + DeclRefExpr *PseudoDE = DE; + IdentifierInfo *Id = &Context.Idents.get(".firstprivate."); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar->setImplicit(); + PseudoVar->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar); + PseudoDE = cast( + BuildDeclRefExpr(PseudoVar, Type, VK_LValue, ELoc).take()); + InitializedEntity Entity = + InitializedEntity::InitializeVariable(PseudoVar); + InitializationKind InitKind = InitializationKind::CreateCopy(ELoc, ELoc); + Expr *Arg = DefaultLvalueConversion(PseudoDE).take(); + if (!Arg) + continue; + InitializationSequence InitSeq(*this, Entity, InitKind, + MultiExprArg(&Arg, 1)); + ExprResult Res = + InitSeq.Perform(*this, Entity, InitKind, MultiExprArg(&Arg, 1)); + if (Res.isInvalid()) + continue; + PseudoVars.push_back(PseudoDE); + Inits.push_back(ActOnFinishFullExpr(Res.take()).take()); + } else { + PseudoVars.push_back(0); + Inits.push_back(0); + } + DSAStack->addDSA(VD, DE, OMPC_firstprivate); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPFirstPrivateClause::Create(Context, StartLoc, EndLoc, Vars, + PseudoVars, Inits); +} + +OMPClause *Sema::ActOnOpenMPLastPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector PseudoVars1; + SmallVector PseudoVars2; + SmallVector Assignments; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp lastprivate"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + // OpenMP [2.11.3.5, 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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + // OpenMP [2.9.3.11, Restrictions, C/C++, p.4] + // A variable that appears in a firstprivate clause must not have an + // incomplete type or a reference type. + if (RequireCompleteType(ELoc, Type, + diag::err_omp_lastprivate_incomplete_type)) { + continue; + } + if (Type->isReferenceType()) { + Diag(ELoc, diag::err_omp_clause_ref_type_arg) + << getOpenMPClauseName(OMPC_lastprivate); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + 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.3.4, Description] + // If a list item appears in both firstprivate and lastprivate clauses, + // the update requires for lastprivate occurs after all the initializations + // for firstprivate. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + Type = Type.getNonReferenceType().getCanonicalType(); + bool IsArray = Type->isArrayType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + if (Kind != OMPC_unknown && Kind != OMPC_firstprivate && + Kind != OMPC_lastprivate) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) << getOpenMPClauseName(OMPC_lastprivate); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } else { + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + bool IsNotFirstprivate = Kind != OMPC_firstprivate; + + // OpenMP [2.9.3.5, Restrictions, p.2] + // A list item that is private within a parallel region, or that appears + // in the reduction clause of a parallel construct, must not appear in + // a lastprivate clause on a worksharing construct if any of the + // worksharing regions ever bind to any of the correspponding parallel + // regions. + OpenMPDirectiveKind DKind; + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); + Kind = DSAStack->getImplicitDSA(VD, DKind, PrevRef); + if ((Kind != OMPC_shared && Kind != OMPC_unknown && + DKind != OMPD_unknown) && + (CurrDir == OMPD_for || CurrDir == OMPD_sections || + CurrDir == OMPD_for_simd)) { + if (Kind == OMPC_unknown) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_lastprivate) + << getOpenMPClauseName(OMPC_shared); + } else if (DKind == OMPD_unknown) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_lastprivate); + } else { + Diag(ELoc, diag::err_omp_dsa_with_directives) + << getOpenMPClauseName(Kind) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(OMPC_lastprivate) + << getOpenMPDirectiveName(CurrDir); + } + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + + // OpenMP [2.9.3.5, Restrictions, C/C++, p.2] + // A variable of class type (or array thereof) that appears in a + // lastprivate clause requires an accesible, unambiguous copy assignment + // operator for the class type. + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); + if (!MD || + CheckMemberAccess(ELoc, RD, + DeclAccessPair::make(MD, MD->getAccess())) == + AR_inaccessible || + MD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_lastprivate) << 2; + 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, MD); + DiagnoseUseOfDecl(MD, ELoc); + PartialDiagnostic PD = + PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); + CXXDestructorDecl *DD = RD->getDestructor(); + if (DD && (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || + DD->isDeleted())) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_lastprivate) << 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; + } else if (DD) { + MarkFunctionReferenced(ELoc, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + + Type = Type.getUnqualifiedType(); + IdentifierInfo *Id = &Context.Idents.get(".lastprivate."); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar1 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar1->setImplicit(); + PseudoVar1->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar1); + DeclRefExpr *PseudoDE1 = cast( + BuildDeclRefExpr(PseudoVar1, Type, VK_LValue, ELoc).take()); + if ((RD && !RD->isTriviallyCopyable()) || IsArray) { + VarDecl *PseudoVar2 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar2->setImplicit(); + PseudoVar2->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar2); + DeclRefExpr *PseudoDE2 = cast( + BuildDeclRefExpr(PseudoVar2, Type, VK_LValue, ELoc).take()); + Expr *PseudoDE2RVal = DefaultLvalueConversion(PseudoDE2).take(); + if (!PseudoDE2RVal) + continue; + ExprResult Res = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + PseudoDE1, PseudoDE2RVal).take(); + if (Res.isInvalid()) + continue; + PseudoVars2.push_back(PseudoDE2); + Assignments.push_back(ActOnFinishFullExpr(IgnoredValueConversions( + Res.take()).take()).take()); + } else { + PseudoVars2.push_back(0); + Assignments.push_back(0); + } + PseudoVars1.push_back(PseudoDE1); + if (IsNotFirstprivate) + DSAStack->addDSA(VD, DE, OMPC_lastprivate); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPLastPrivateClause::Create(Context, StartLoc, EndLoc, Vars, + PseudoVars1, PseudoVars2, Assignments); +} + +OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp shared"); + if (isa(*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.4, 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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + 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. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (Kind != OMPC_unknown && Kind != OMPC_shared && PrevRef) { + Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_shared); + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + continue; + } + + DSAStack->addDSA(VD, DE, OMPC_shared); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPSharedClause::Create(Context, StartLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector PseudoVars1; + SmallVector PseudoVars2; + SmallVector Assignments; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp copyin"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + DeclRefExpr *DE = dyn_cast_or_null(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + // OpenMP [2.9.2, Restrictions, p.1] + // A threadprivate variable must not appear in any clause except the + // copyin, copyprivate, schedule, num_threads, and if clauses. + // OpenMP [2.9.4.1, Restrictions, C/C++, p.1] + // A list item that appears in a copyin clause must be threadprivate. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (Kind != OMPC_threadprivate && Kind != OMPC_copyin) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_copyin) + << getOpenMPDirectiveName(OMPD_threadprivate); + continue; + } + + // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a + // firstprivate clause requires an accesible, unambiguous copy assignment + // operator for the class type. + Type = Type.getNonReferenceType().getCanonicalType(); + bool IsArray = Type->isArrayType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); + if (!MD || + CheckMemberAccess(ELoc, RD, + DeclAccessPair::make(MD, MD->getAccess())) == + AR_inaccessible || + MD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_copyin) << 2; + 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, MD); + DiagnoseUseOfDecl(MD, ELoc); + } + + Type = Type.getUnqualifiedType(); + IdentifierInfo *Id = &Context.Idents.get(".copyin."); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar1 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar1->setImplicit(); + PseudoVar1->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar1); + DeclRefExpr *PseudoDE1 = cast( + BuildDeclRefExpr(PseudoVar1, Type, VK_LValue, ELoc).take()); + if ((RD && !RD->isTriviallyCopyable()) || IsArray) { + VarDecl *PseudoVar2 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar2->setImplicit(); + PseudoVar2->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar2); + DeclRefExpr *PseudoDE2 = cast( + BuildDeclRefExpr(PseudoVar2, Type, VK_LValue, ELoc).take()); + Expr *PseudoDE2RVal = DefaultLvalueConversion(PseudoDE2).take(); + if (!PseudoDE2RVal) + continue; + ExprResult Res = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + PseudoDE1, PseudoDE2RVal).take(); + if (Res.isInvalid()) + continue; + PseudoVars2.push_back(PseudoDE2); + Assignments.push_back(ActOnFinishFullExpr(IgnoredValueConversions( + Res.take()).take()).take()); + } else { + PseudoVars2.push_back(0); + Assignments.push_back(0); + } + PseudoVars1.push_back(PseudoDE1); + DSAStack->addDSA(VD, DE, OMPC_copyin); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPCopyinClause::Create(Context, StartLoc, EndLoc, Vars, PseudoVars1, + PseudoVars2, Assignments); +} + +OMPClause *Sema::ActOnOpenMPCopyPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector PseudoVars1; + SmallVector PseudoVars2; + SmallVector Assignments; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp copyprivate"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + DeclRefExpr *DE = dyn_cast_or_null(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + PseudoVars1.push_back(0); + PseudoVars2.push_back(0); + Assignments.push_back(0); + continue; + } + + // OpenMP [2.11.4.2, Restrictions, p.2] + // A list item that appears in a copyprivate clause may not appear in + // a private or firstprivate clause on the single construct. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (Kind != OMPC_threadprivate && Kind != OMPC_copyprivate && + Kind != OMPC_unknown && !(Kind == OMPC_private && !PrevRef)) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) << getOpenMPClauseName(OMPC_copyprivate); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } else { + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + + // OpenMP [2.11.4.2, Restrictions, p.1] + // All list items that appear in a copyprivate clause must be either + // threadprivate or private in the enclosing context. + if (Kind == OMPC_unknown) { + OpenMPDirectiveKind DKind; + Kind = DSAStack->getImplicitDSA(VD, DKind, PrevRef); + if (Kind == OMPC_shared) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_copyprivate) + << "threadprivate or private in the enclosing context"; + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + } + + // OpenMP [2.11.4.2, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a + // copytprivate clause requires an accesible, unambiguous copy assignment + // operator for the class type. + Type = Type.getNonReferenceType().getCanonicalType(); + while (Type->isArrayType()) { + QualType ElemType = cast(Type.getTypePtr())->getElementType(); + Type = ElemType.getNonReferenceType().getCanonicalType(); + } + CXXRecordDecl *RD = + getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; + if (RD) { + CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); + if (!MD || + CheckMemberAccess(ELoc, RD, + DeclAccessPair::make(MD, MD->getAccess())) == + AR_inaccessible || + MD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_copyprivate) << 2; + 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, MD); + DiagnoseUseOfDecl(MD, ELoc); + } + + Type = Type.getUnqualifiedType(); + IdentifierInfo *Id = &Context.Idents.get(".copyin."); + TypeSourceInfo *TI = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar1 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar1->setImplicit(); + PseudoVar1->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar1); + DeclRefExpr *PseudoDE1 = cast( + BuildDeclRefExpr(PseudoVar1, Type, VK_LValue, ELoc).take()); + VarDecl *PseudoVar2 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI, SC_Static); + PseudoVar2->setImplicit(); + PseudoVar2->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(PseudoVar2); + DeclRefExpr *PseudoDE2 = cast( + BuildDeclRefExpr(PseudoVar2, Type, VK_LValue, ELoc).take()); + Expr *PseudoDE2RVal = DefaultLvalueConversion(PseudoDE2).take(); + if (!PseudoDE2RVal) + continue; + ExprResult Res = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + PseudoDE1, PseudoDE2RVal).take(); + if (Res.isInvalid()) + continue; + PseudoVars1.push_back(PseudoDE1); + PseudoVars2.push_back(PseudoDE2); + Assignments.push_back( + ActOnFinishFullExpr(IgnoredValueConversions(Res.take()).take()).take()); + DSAStack->addDSA(VD, DE, OMPC_copyprivate); + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPCopyPrivateClause::Create(Context, StartLoc, EndLoc, Vars, + PseudoVars1, PseudoVars2, Assignments); +} + +namespace { +class DSARefChecker : public StmtVisitor { + DSAStackTy *Stack; + +public: + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (VarDecl *VD = dyn_cast(E->getDecl())) { + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = Stack->getTopDSA(VD, PrevRef); + if (Kind == OMPC_shared && !PrevRef) + return false; + if (Kind != OMPC_unknown) + return true; + // OpenMPDirectiveKind DKind; + // Kind = Stack->getImplicitDSA(VD, DKind, PrevRef); + if (Stack->hasDSA(VD, OMPC_private, OMPD_unknown, PrevRef) || + Stack->hasDSA(VD, OMPC_firstprivate, OMPD_unknown, PrevRef) || + Stack->hasDSA(VD, OMPC_lastprivate, OMPD_unknown, PrevRef) || + Stack->hasDSA(VD, OMPC_reduction, OMPD_unknown, PrevRef) || + Stack->hasDSA(VD, OMPC_linear, OMPD_unknown, PrevRef)) + return true; + return false; + // return Kind != OMPC_shared && Kind != OMPC_unknown; + } + return false; + } + bool VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; + ++I) { + if (Stmt *Child = *I) + if (Visit(Child)) + return true; + } + return false; + } + DSARefChecker(DSAStackTy *S) : Stack(S) {} +}; +} + +namespace { +class RedDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &Actions; + QualType QTy; + OMPDeclareReductionDecl::ReductionData *FoundData; + +public: + RedDeclFilterCCC(Sema &S, QualType QTy) + : Actions(S), QTy(QTy), FoundData(0) {} + virtual bool ValidateCandidate(const TypoCorrection &Candidate) { + if (OMPDeclareReductionDecl *D = dyn_cast_or_null( + Candidate.getCorrectionDecl())) { + if (D->isInvalidDecl()) + return false; + bool Found = false; + for (OMPDeclareReductionDecl::datalist_iterator IT = D->datalist_begin(), + ET = D->datalist_end(); + IT != ET; ++IT) { + if (!IT->QTy.isNull() && + (Actions.Context.hasSameUnqualifiedType(IT->QTy, QTy) || + Actions.IsDerivedFrom(QTy, IT->QTy))) { + Found = true; + FoundData = IT; + } + } + return Found; + } + return false; + } + OMPDeclareReductionDecl::ReductionData *getFoundData() { return FoundData; } +}; +} + +static OMPDeclareReductionDecl::ReductionData * +TryToFindDeclareReductionDecl(Sema &SemaRef, CXXScopeSpec &SS, + DeclarationNameInfo OpName, QualType QTy, + OpenMPReductionClauseOperator Op) { + LookupResult Lookup(SemaRef, OpName, Sema::LookupOMPDeclareReduction); + if (Op != OMPC_REDUCTION_custom) { + Lookup.suppressDiagnostics(); + } + if (SemaRef.LookupParsedName(Lookup, SemaRef.getCurScope(), &SS)) { + LookupResult::Filter Filter = Lookup.makeFilter(); + SmallVector Found; + SmallVector FoundDecl; + while (Filter.hasNext()) { + OMPDeclareReductionDecl *D = cast(Filter.next()); + bool Remove = true; + if (!D->isInvalidDecl()) { + for (OMPDeclareReductionDecl::datalist_iterator + IT = D->datalist_begin(), + ET = D->datalist_end(); + IT != ET; ++IT) { + if (!IT->QTy.isNull() && + SemaRef.Context.hasSameUnqualifiedType(IT->QTy, QTy)) { + Found.push_back(IT); + FoundDecl.push_back(D); + Remove = false; + } + } + if (Found.empty()) { + for (OMPDeclareReductionDecl::datalist_iterator + IT = D->datalist_begin(), + ET = D->datalist_end(); + IT != ET; ++IT) { + if (!IT->QTy.isNull() && SemaRef.IsDerivedFrom(QTy, IT->QTy)) { + Found.push_back(IT); + FoundDecl.push_back(D); + Remove = false; + } + } + } + } + if (Remove) + Filter.erase(); + } + Filter.done(); + if (Found.size() > 1) { + // Ambiguous declaration found. + SemaRef.Diag(OpName.getLoc(), diag::err_ambiguous_reference) + << OpName.getName(); + SmallVectorImpl::iterator IT = + Found.begin(); + for (SmallVectorImpl::iterator + IR = FoundDecl.begin(), + ER = FoundDecl.end(); + IR != ER; ++IR, ++IT) { + SemaRef.Diag((*IR)->getLocation(), diag::note_ambiguous_candidate) + << *IR << (*IT)->TyRange; + } + } + if (!Found.empty()) + return Found.back(); + } + assert(Lookup.empty() && "Lookup is not empty."); + return 0; +} + +OMPClause *Sema::ActOnOpenMPReductionClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPReductionClauseOperator Op, + CXXScopeSpec &SS, + DeclarationNameInfo OpName) { + BinaryOperatorKind NewOp = BO_Assign; + switch (Op) { + case OMPC_REDUCTION_add: + NewOp = BO_AddAssign; + break; + case OMPC_REDUCTION_mult: + NewOp = BO_MulAssign; + break; + case OMPC_REDUCTION_sub: + NewOp = BO_SubAssign; + break; + case OMPC_REDUCTION_bitand: + NewOp = BO_AndAssign; + break; + case OMPC_REDUCTION_bitor: + NewOp = BO_OrAssign; + break; + case OMPC_REDUCTION_bitxor: + NewOp = BO_XorAssign; + break; + case OMPC_REDUCTION_and: + NewOp = BO_LAnd; + break; + case OMPC_REDUCTION_or: + NewOp = BO_LOr; + break; + case OMPC_REDUCTION_min: + NewOp = BO_LT; + break; + case OMPC_REDUCTION_max: + NewOp = BO_GT; + break; + default: + break; + } + SmallVector Vars; + SmallVector DefaultInits; + SmallVector OpExprs; + SmallVector HelperParams1; + SmallVector HelperParams2; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp reduction"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + DefaultInits.push_back(0); + OpExprs.push_back(0); + HelperParams1.push_back(0); + HelperParams2.push_back(0); + 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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(*I); + DefaultInits.push_back(0); + OpExprs.push_back(0); + HelperParams1.push_back(0); + HelperParams2.push_back(0); + continue; + } + + // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] + // If a list-item is a reference type then it must bind to the same object + // for all threads of the team. + if (Type.getCanonicalType()->isReferenceType() && VD->hasInit()) { + DSARefChecker Check(DSAStack); + if (Check.Visit(VD->getInit())) { + Diag(ELoc, diag::err_omp_reduction_ref_type_arg) + << getOpenMPClauseName(OMPC_reduction); + 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.6, Restrictions, C/C++, p.2] + // Aggregate types (including arrays), pointer types and reference types + // may not appear in a reduction clause. + if (RequireCompleteType(ELoc, Type, + diag::err_omp_reduction_incomplete_type)) + continue; + Type = Type.getNonReferenceType().getCanonicalType(); + if (Type->isArrayType()) { + Diag(ELoc, diag::err_omp_clause_array_type_arg) + << getOpenMPClauseName(OMPC_reduction); + 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.6, Restrictions, C/C++, p.3] + // A list item that appears in a reduction clause must not be + // const-qualified. + if (Type.isConstant(Context)) { + Diag(ELoc, diag::err_omp_const_variable) + << getOpenMPClauseName(OMPC_reduction); + 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.6, Restrictions, C/C++, p.1] + // The type of a list item that appears in a reduction clause must be valid + // for the reduction operator. For max or min reduction in C/C++ must be an + // arithmetic type. + if (((Op == OMPC_REDUCTION_min || Op == OMPC_REDUCTION_max) && + !Type->isArithmeticType() && !Type->isDependentType()) || + (!getLangOpts().CPlusPlus && !Type->isScalarType() && + !Type->isDependentType())) { + Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) + << getOpenMPClauseName(OMPC_reduction) << getLangOpts().CPlusPlus; + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + 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.3.6, Restrictions, p.3] + // Any number of reduction clauses can be specified on the directive, + // but a list item can appear only once in the reduction clauses for that + // directive. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (Kind == OMPC_reduction) { + Diag(ELoc, diag::err_omp_once_referenced) + << getOpenMPClauseName(OMPC_reduction); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_referenced); + } + } else if (Kind != OMPC_unknown) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) << getOpenMPClauseName(OMPC_reduction); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } else { + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + + // OpenMP [2.9.3.6, Restrictions, p.1] + // A list item that appears in a reduction clause of a worksharing + // construct must be shared in the parallel regions to which any of the + // worksharing regions arising from the worksharing construct bind. + OpenMPDirectiveKind DKind; + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); + Kind = DSAStack->getImplicitDSA(VD, DKind, PrevRef); + if ((Kind != OMPC_shared && Kind != OMPC_unknown && + DKind != OMPD_unknown) && + (CurrDir == OMPD_for || CurrDir == OMPD_sections || + CurrDir == OMPD_for_simd)) { + if (Kind == OMPC_unknown) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseName(OMPC_reduction) + << getOpenMPClauseName(OMPC_shared); + } else if (DKind == OMPD_unknown) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(Kind) << getOpenMPClauseName(OMPC_reduction); + } else { + Diag(ELoc, diag::err_omp_dsa_with_directives) + << getOpenMPClauseName(Kind) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(OMPC_reduction) + << getOpenMPDirectiveName(CurrDir); + } + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); + } + continue; + } + + QualType RedTy = DE->getType().getUnqualifiedType(); + OMPDeclareReductionDecl::ReductionData *DRRD = + TryToFindDeclareReductionDecl(*this, SS, OpName, RedTy, Op); + if (Op == OMPC_REDUCTION_custom && !DRRD) { + RedDeclFilterCCC CCC(*this, RedTy); + LookupResult Lookup(*this, OpName, LookupOMPDeclareReduction); + if (DiagnoseEmptyLookup(getCurScope(), SS, Lookup, CCC)) + continue; + DRRD = CCC.getFoundData(); + if (!DRRD) + continue; + } + if (DRRD) { + Op = OMPC_REDUCTION_custom; + QualType PtrQTy = Context.getPointerType(DE->getType()); + TypeSourceInfo *TI = + Context.getTrivialTypeSourceInfo(PtrQTy, SourceLocation()); + IdentifierInfo *Id1 = &Context.Idents.get(".ptr1."); + VarDecl *Parameter1 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id1, PtrQTy, TI, SC_Static); + Parameter1->setImplicit(); + Parameter1->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + IdentifierInfo *Id2 = &Context.Idents.get(".ptr2."); + VarDecl *Parameter2 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id2, PtrQTy, TI, SC_Static); + Parameter2->setImplicit(); + Parameter2->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(Parameter1); + Context.getTranslationUnitDecl()->addHiddenDecl(Parameter2); + ExprResult PtrDE1 = + BuildDeclRefExpr(Parameter1, PtrQTy, VK_LValue, SourceLocation()); + ExprResult PtrDE2 = + BuildDeclRefExpr(Parameter2, PtrQTy, VK_LValue, SourceLocation()); + Expr *PtrDE1Expr = PtrDE1.take(); + Expr *PtrDE2Expr = PtrDE2.take(); + ExprResult DE1 = DefaultLvalueConversion(PtrDE1Expr); + ExprResult DE2 = DefaultLvalueConversion(PtrDE2Expr); + Expr *Args[] = {DE1.take(), DE2.take()}; + ExprResult Res = + ActOnCallExpr(DSAStack->getCurScope(), DRRD->CombinerFunction, ELoc, + Args, SourceLocation()); + if (Res.isInvalid()) + continue; + + DefaultInits.push_back(DRRD->InitFunction); + Vars.push_back(DE); + OpExprs.push_back(Res.take()); + HelperParams1.push_back(PtrDE1Expr); + HelperParams2.push_back(PtrDE2Expr); + } else { + if ((Op == OMPC_REDUCTION_bitor || Op == OMPC_REDUCTION_bitand || + Op == OMPC_REDUCTION_bitxor) && + Type->isFloatingType()) { + Diag(ELoc, diag::err_omp_clause_floating_type_arg); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + QualType PtrQTy = Context.getPointerType(DE->getType()); + TypeSourceInfo *TI = + Context.getTrivialTypeSourceInfo(PtrQTy, SourceLocation()); + IdentifierInfo *Id1 = &Context.Idents.get(".ptr1."); + VarDecl *Parameter1 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id1, PtrQTy, TI, SC_Static); + Parameter1->setImplicit(); + Parameter1->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + IdentifierInfo *Id2 = &Context.Idents.get(".ptr2."); + VarDecl *Parameter2 = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id2, PtrQTy, TI, SC_Static); + Parameter2->setImplicit(); + Parameter2->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + Context.getTranslationUnitDecl()->addHiddenDecl(Parameter1); + Context.getTranslationUnitDecl()->addHiddenDecl(Parameter2); + ExprResult PtrDE1 = + BuildDeclRefExpr(Parameter1, PtrQTy, VK_LValue, SourceLocation()); + ExprResult PtrDE2 = + BuildDeclRefExpr(Parameter2, PtrQTy, VK_LValue, SourceLocation()); + Expr *PtrDE1Expr = PtrDE1.take(); + Expr *PtrDE2Expr = PtrDE2.take(); + ExprResult DE1 = DefaultLvalueConversion(PtrDE1Expr); + ExprResult DE2 = DefaultLvalueConversion(PtrDE2Expr); + DE1 = CreateBuiltinUnaryOp(ELoc, UO_Deref, DE1.take()); + DE2 = CreateBuiltinUnaryOp(ELoc, UO_Deref, DE2.take()); + if (NewOp == BO_SubAssign) { + NewOp = BO_AddAssign; + } + ExprResult Res = BuildBinOp(DSAStack->getCurScope(), ELoc, NewOp, + DE1.take(), DE2.take()); + if (Res.isInvalid()) + continue; + CXXRecordDecl *RD = Type->getAsCXXRecordDecl(); + if (RD) { + CXXConstructorDecl *CD = LookupDefaultConstructor(RD); + 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_reduction) << 0; + 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 && (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || + DD->isDeleted())) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_reduction) << 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; + } else if (DD) { + MarkFunctionReferenced(ELoc, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + if (NewOp == BO_LAnd || NewOp == BO_LOr) { + Res = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, DE1.take(), + Res.take()); + } else if (NewOp == BO_LT || NewOp == BO_GT) { + Res = + ActOnConditionalOp(ELoc, ELoc, Res.take(), DE1.take(), DE2.take()); + if (Res.isInvalid()) + continue; + Res = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, DE1.take(), + Res.take()); + } + if (Res.isInvalid()) + continue; + Res = IgnoredValueConversions(Res.take()); + + Type = Type.getUnqualifiedType(); + if (RD) { + IdentifierInfo *Id = &Context.Idents.get(".firstprivate."); + TypeSourceInfo *TI1 = Context.getTrivialTypeSourceInfo(Type, ELoc); + VarDecl *PseudoVar = VarDecl::Create( + Context, Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), Id, Type, TI1, SC_Static); + PseudoVar->setImplicit(); + PseudoVar->addAttr(new (Context) UnusedAttr(SourceLocation(), Context)); + InitializedEntity Entity = + InitializedEntity::InitializeVariable(PseudoVar); + InitializationKind InitKind = InitializationKind::CreateDefault(ELoc); + InitializationSequence InitSeq(*this, Entity, InitKind, MultiExprArg()); + ExprResult CPRes = + InitSeq.Perform(*this, Entity, InitKind, MultiExprArg()); + if (CPRes.isInvalid()) + continue; + DefaultInits.push_back(ActOnFinishFullExpr(CPRes.take()).take()); + } else { + DefaultInits.push_back(0); + } + Vars.push_back(DE); + OpExprs.push_back(ActOnFinishFullExpr(Res.take()).take()); + HelperParams1.push_back(PtrDE1Expr); + HelperParams2.push_back(PtrDE2Expr); + } + DSAStack->addDSA(VD, DE, OMPC_reduction); + } + + if (Vars.empty()) + return 0; + + return OMPReductionClause::Create( + Context, StartLoc, EndLoc, Vars, OpExprs, HelperParams1, HelperParams2, + DefaultInits, Op, SS.getWithLocInContext(Context), OpName); +} + +namespace { +class ArrayItemChecker : public StmtVisitor { +private: + Sema &SemaRef; + Expr *End; + +public: + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (isa(E->getDecl())) { + End = E; + return false; + } + return true; + } + bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + Expr *Base = E->getBase()->IgnoreImplicit(); + bool Result = Visit(Base); + if (!End) + return Result; + if (CEANIndexExpr *CIE = dyn_cast_or_null(E->getIdx())) { + llvm::APSInt Value; + // OpenMP [2.11.1.1, Restrictions] + // List items used in dependent clauses cannot be zero-length array + // sections. + if (CIE->getLength()->EvaluateAsInt(Value, SemaRef.getASTContext()) && + ((Value.isSigned() && Value.isNegative()) || !Value)) { + SemaRef.Diag(CIE->getExprLoc(), + diag::err_omp_array_section_length_not_greater_zero) + << CIE->getSourceRange(); + End = 0; + return Result; + } + ExprResult Idx = SemaRef.CreateBuiltinBinOp( + E->getExprLoc(), BO_Add, CIE->getLowerBound(), CIE->getLength()); + if (Idx.isInvalid()) { + End = 0; + return Result; + } + Idx = SemaRef.CreateBuiltinBinOp( + E->getExprLoc(), BO_Sub, Idx.take(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).take()); + if (Idx.isInvalid()) { + End = 0; + return Result; + } + End = SemaRef.CreateBuiltinArraySubscriptExpr(End, E->getExprLoc(), + Idx.take(), + E->getExprLoc()).take(); + CIE->setIndexExpr(CIE->getLowerBound()); + } else if (End != Base) { + End = SemaRef.CreateBuiltinArraySubscriptExpr(End, E->getExprLoc(), + E->getIdx(), + E->getExprLoc()).take(); + } else { + End = E; + } + return Result; + } + bool VisitStmt(Stmt *S) { return true; } + + ArrayItemChecker(Sema &SemaRef) : SemaRef(SemaRef), End(0) {} + + std::pair CalculateSize(Expr *Begin) { + if (!Begin) + return std::make_pair(0, 0); + QualType CharPtrTy = + SemaRef.getASTContext().getPointerType(SemaRef.getASTContext().CharTy); + if (!End || Begin == End) { + Expr *Size; + { + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::Unevaluated, Sema::ReuseLambdaContextDecl); + + Size = SemaRef.CreateUnaryExprOrTypeTraitExpr(Begin, SourceLocation(), + UETT_SizeOf).take(); + } + ExprResult AddrBegin = + SemaRef.CreateBuiltinUnaryOp(Begin->getExprLoc(), UO_AddrOf, Begin); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + AddrBegin = + SemaRef.ImpCastExprToType(AddrBegin.take(), CharPtrTy, CK_BitCast); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + Expr *AB = SemaRef.DefaultLvalueConversion(AddrBegin.take()).take(); + return std::make_pair(AB, Size); + } + + ExprResult AddrEnd = + SemaRef.CreateBuiltinUnaryOp(End->getExprLoc(), UO_AddrOf, End); + if (AddrEnd.isInvalid()) + return std::make_pair(0, 0); + AddrEnd = SemaRef.CreateBuiltinBinOp( + End->getExprLoc(), BO_Add, AddrEnd.take(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).take()); + if (AddrEnd.isInvalid()) + return std::make_pair(0, 0); + ExprResult AddrBegin = + SemaRef.CreateBuiltinUnaryOp(Begin->getExprLoc(), UO_AddrOf, Begin); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + Expr *AE = SemaRef.DefaultLvalueConversion(AddrEnd.take()).take(); + Expr *AB = SemaRef.DefaultLvalueConversion(AddrBegin.take()).take(); + return std::make_pair(AB, AE); + } +}; +} + +OMPClause *Sema::ActOnOpenMPDependClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDependClauseType Ty, + SourceLocation TyLoc) { + SmallVector Vars; + SmallVector Begins; + SmallVector SizeInBytes; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp depend"); + if ((*I)->isValueDependent() || (*I)->isTypeDependent() || + (*I)->isInstantiationDependent()) { + // It will be analyzed later. + Vars.push_back(*I); + Begins.push_back(0); + SizeInBytes.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + + // OpenMP [2.11.1.1, Restrictions] + // A variable that is part of another variable (such as field of a + // structure) but is not an array element or an array section cannot appear + // in a depend clause. + // 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. + Expr *VE = (*I)->IgnoreParenLValueCasts(); + + if (VE->isRValue()) { + Diag(ELoc, diag::err_omp_depend_arg_not_lvalue) << (*I)->getSourceRange(); + continue; + } + + DeclRefExpr *DE = dyn_cast_or_null(VE); + ArraySubscriptExpr *ASE = dyn_cast_or_null(VE); + ArrayItemChecker Checker(*this); + if ((!DE || !isa(DE->getDecl())) && (!ASE || Checker.Visit(ASE))) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << (*I)->getSourceRange(); + continue; + } + + std::pair BeginSize = Checker.CalculateSize(VE); + if (!BeginSize.first || !BeginSize.second) + continue; + + Vars.push_back(VE); + Begins.push_back(BeginSize.first); + SizeInBytes.push_back(BeginSize.second); } - return Res; + + if (Vars.empty() || Vars.size() != Begins.size()) + return 0; + return OMPDependClause::Create(Context, StartLoc, EndLoc, Vars, Begins, + SizeInBytes, Ty, TyLoc); } -OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, - SourceLocation KindKwLoc, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - if (Kind == OMPC_DEFAULT_unknown) { - std::string Values; - std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : ""); - for (unsigned i = OMPC_DEFAULT_unknown + 1; - i < NUM_OPENMP_DEFAULT_KINDS; ++i) { - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(OMPC_default, i); - Values += "'"; - switch (i) { - case NUM_OPENMP_DEFAULT_KINDS - 2: - Values += " or "; - break; - case NUM_OPENMP_DEFAULT_KINDS - 1: - break; - default: - Values += Sep; - break; +namespace { +class MapArrayItemChecker : public StmtVisitor { +private: + Sema &SemaRef; + Expr *CopyBegin; + Expr *CopyEnd; + Expr *WholeBegin; + Expr *WholeEnd; + VarDecl *VD; + DeclRefExpr *DRE; + bool IsCEAN; + + std::pair CalculateSize(Expr *Begin, Expr *End) { + if (!Begin || !End) + return std::make_pair(0, 0); + QualType CharPtrTy = + SemaRef.getASTContext().getPointerType(SemaRef.getASTContext().CharTy); + if (Begin == End) { + Expr *Size; + { + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::Unevaluated, Sema::ReuseLambdaContextDecl); + + Size = SemaRef.CreateUnaryExprOrTypeTraitExpr(Begin, SourceLocation(), + UETT_SizeOf).take(); } + ExprResult AddrBegin = + SemaRef.CreateBuiltinUnaryOp(Begin->getExprLoc(), UO_AddrOf, Begin); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + AddrBegin = + SemaRef.ImpCastExprToType(AddrBegin.take(), CharPtrTy, CK_BitCast); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + Expr *AB = SemaRef.DefaultLvalueConversion(AddrBegin.take()).take(); + return std::make_pair(AB, Size); } - Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) - << Values << getOpenMPClauseName(OMPC_default); - return 0; + + ExprResult AddrEnd = + SemaRef.CreateBuiltinUnaryOp(End->getExprLoc(), UO_AddrOf, End); + if (AddrEnd.isInvalid()) + return std::make_pair(0, 0); + AddrEnd = SemaRef.CreateBuiltinBinOp( + End->getExprLoc(), BO_Add, AddrEnd.take(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).take()); + if (AddrEnd.isInvalid()) + return std::make_pair(0, 0); + ExprResult AddrBegin = + SemaRef.CreateBuiltinUnaryOp(Begin->getExprLoc(), UO_AddrOf, Begin); + if (AddrBegin.isInvalid()) + return std::make_pair(0, 0); + Expr *AE = SemaRef.DefaultLvalueConversion(AddrEnd.take()).take(); + Expr *AB = SemaRef.DefaultLvalueConversion(AddrBegin.take()).take(); + return std::make_pair(AB, AE); } - switch (Kind) { - case OMPC_DEFAULT_none: - DSAStack->setDefaultDSANone(); - break; - case OMPC_DEFAULT_shared: - DSAStack->setDefaultDSAShared(); - break; - default: - break; + +public: + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (isa(E->getDecl())) { + CopyBegin = CopyEnd = E; + WholeBegin = WholeEnd = E; + VD = cast(E->getDecl()); + DRE = E; + return false; + } + return true; + } + bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + Expr *Base = E->getBase()->IgnoreImplicit(); + bool Result = Visit(Base); + if (!CopyEnd || !CopyBegin) + return Result; + if (!WholeEnd || !WholeBegin) + return Result; + WholeBegin = + SemaRef.CreateBuiltinArraySubscriptExpr( + WholeBegin, E->getExprLoc(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 0).take(), + E->getExprLoc()).take(); + QualType QTy = Base->getType(); + Expr *Idx = 0; + if (const ArrayType *AT = QTy->getAsArrayTypeUnsafe()) { + if (const ConstantArrayType *CAT = dyn_cast(AT)) { + Idx = SemaRef.ActOnIntegerConstant( + SourceLocation(), + (CAT->getSize() - 1).getLimitedValue()).take(); + } else if (const VariableArrayType *VAT = + dyn_cast(AT)) { + Idx = VAT->getSizeExpr(); + Idx = SemaRef.CreateBuiltinBinOp( + E->getExprLoc(), BO_Sub, Idx, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1) + .take()).take(); + } else if (const DependentSizedArrayType *DSAT = + dyn_cast(AT)) { + Idx = DSAT->getSizeExpr(); + Idx = SemaRef.CreateBuiltinBinOp( + E->getExprLoc(), BO_Sub, Idx, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1) + .take()).take(); + } + } + Expr *LastIdx = 0; + if (CEANIndexExpr *CIE = dyn_cast_or_null(E->getIdx())) { + IsCEAN = true; + LastIdx = SemaRef.CreateBuiltinBinOp(E->getExprLoc(), BO_Add, + CIE->getLowerBound(), + CIE->getLength()).take(); + if (LastIdx == 0) { + CopyBegin = CopyEnd = 0; + WholeBegin = WholeEnd = 0; + return Result; + } + LastIdx = SemaRef.CreateBuiltinBinOp( + E->getExprLoc(), BO_Sub, LastIdx, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1) + .take()).take(); + CopyBegin = SemaRef.CreateBuiltinArraySubscriptExpr( + CopyBegin, E->getExprLoc(), CIE->getLowerBound(), + E->getExprLoc()).take(); + } else { + LastIdx = E->getIdx(); + CopyBegin = SemaRef.CreateBuiltinArraySubscriptExpr( + CopyBegin, E->getExprLoc(), LastIdx, + E->getExprLoc()).take(); + } + CopyEnd = SemaRef.CreateBuiltinArraySubscriptExpr(CopyEnd, E->getExprLoc(), + LastIdx, + E->getExprLoc()).take(); + if (Idx == 0) { + Idx = LastIdx; + } + if (Idx == 0) { + CopyBegin = CopyEnd = 0; + WholeBegin = WholeEnd = 0; + return Result; + } + WholeEnd = + SemaRef.CreateBuiltinArraySubscriptExpr(WholeEnd, E->getExprLoc(), Idx, + E->getExprLoc()).take(); + return Result; + } + bool VisitStmt(Stmt *S) { return true; } + + MapArrayItemChecker(Sema &SemaRef) + : SemaRef(SemaRef), CopyBegin(0), CopyEnd(0), WholeBegin(0), WholeEnd(0), + VD(0), DRE(0), IsCEAN(false) {} + + VarDecl *getBaseDecl() { return VD; } + DeclRefExpr *getDeclRefExprForBaseDecl() { return DRE; } + bool IsCEANExpr() const { return IsCEAN; } + + std::pair CalculateCopySize() { + return CalculateSize(CopyBegin, CopyEnd); } - return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, - EndLoc); + std::pair CalculateWholeSize() { + return CalculateSize(WholeBegin, WholeEnd); + } +}; } -OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, - ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - OMPClause *Res = 0; - switch (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; - case OMPC_default: - case OMPC_threadprivate: - case OMPC_unknown: - case NUM_OPENMP_CLAUSES: - llvm_unreachable("Clause is not allowed."); +OMPClause *Sema::ActOnOpenMPMapClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPMapClauseKind Kind, + SourceLocation KindLoc) { + SmallVector Vars; + SmallVector WholeBegins; + SmallVector WholeEnds; + SmallVector CopyBegins; + SmallVector CopyEnds; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp map"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + + // OpenMP [2.14.5, Restrictions] + // A variable that is part of another variable (such as field of a + // structure) but is not an array element or an array section cannot appear + // in a map clause. + Expr *VE = (*I)->IgnoreParenLValueCasts(); + + if (VE->isValueDependent() || VE->isTypeDependent() || + VE->isInstantiationDependent() || + VE->containsUnexpandedParameterPack()) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + MapArrayItemChecker Checker(*this); + VarDecl *VD = 0; + DeclRefExpr *DE = 0; + if (Checker.Visit(VE) || !(VD = Checker.getBaseDecl()) || + !(DE = Checker.getDeclRefExprForBaseDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << (*I)->getSourceRange(); + continue; + } + + // OpenMP [2.14.5, Restrictions, p.8] + // threadprivate variables cannot appear in a map clause. + DeclRefExpr *DRE = 0; + if (DSAStack->IsThreadprivate(VD, DRE)) { + SourceLocation Loc = DRE ? DRE->getLocation() : VD->getLocation(); + Diag(Loc, diag::err_omp_threadprivate_in_target); + Diag(DE->getLocStart(), diag::note_used_here) << DE->getSourceRange(); + continue; + } + + // OpenMP [2.14.5, map Clause] + // If a corresponding list item of the original list item is in the + // enclosing device data environment, the new device data environment uses + // the corresponding list item from the enclosing device data environment. + // No additional storage is allocated in the new device data environment + // and neither initialization nor assignment is performed, regardless of + // the map-type that is specified. + if (DSAStack->isDeclareTargetDecl(VD)) { + // Use original variable. + continue; + } + // OpenMP [2.14.5, Restrictions, p.2] + // At most one list item can be an array item derived from a given variable + // in map clauses of the same construct. + // OpenMP [2.14.5, Restrictions, p.3] + // List items of map clauses in the same construct must not share original + // storage. + // OpenMP [2.14.5, Restrictions, C/C++, p.2] + // A variable for which the type is pointer, reference to array, or + // reference to pointer and an array section derived from that variable + // must not appear as list items of map clauses of the same construct. + DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); + if (MI.RefExpr) { + Diag(DE->getExprLoc(), diag::err_omp_map_shared_storage) + << DE->getSourceRange(); + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + + // OpenMP [2.14.5, Restrictions, C/C++, p.3,4] + // A variable for which the type is pointer, reference to array, or + // reference to pointer must not appear as a list item if the enclosing + // device data environment already contains an array section derived from + // that variable. + // An array section derived from a variable for which the type is pointer, + // reference to array, or reference to pointer must not appear as a list + // item if the enclosing device data environment already contains that + // variable. + QualType Type = VD->getType(); + MI = DSAStack->getMapInfoForVar(VD); + if (MI.RefExpr && (isa(MI.RefExpr->IgnoreParenLValueCasts()) != + isa(VE)) && + (MI.IsCEAN || Checker.IsCEANExpr()) && + (Type->isPointerType() || Type->isReferenceType())) { + Diag(DE->getExprLoc(), diag::err_omp_map_shared_storage) + << DE->getSourceRange(); + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + + // OpenMP [2.14.5, Restrictions, C/C++, p.7] + // A list item must have a mappable type. + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, + DSAStack, Type)) { + continue; + } + + std::pair WholeSize = Checker.CalculateWholeSize(); + if (!WholeSize.first || !WholeSize.second) { + continue; + } + std::pair CopySize = Checker.CalculateCopySize(); + if (!CopySize.first || !CopySize.second) { + continue; + } + + Vars.push_back(*I); + WholeBegins.push_back(WholeSize.first); + WholeEnds.push_back(WholeSize.second); + CopyBegins.push_back(CopySize.first); + CopyEnds.push_back(CopySize.second); + MI.RefExpr = *I; + MI.IsCEAN = Checker.IsCEANExpr(); + DSAStack->addMapInfoForVar(VD, MI); } - return Res; + + if (Vars.empty()) + return 0; + + return OMPMapClause::Create(Context, StartLoc, EndLoc, Vars, WholeBegins, + WholeEnds, CopyBegins, CopyEnds, Kind, KindLoc); } -OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - SmallVector Vars; +OMPClause *Sema::ActOnOpenMPToClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector WholeBegins; + SmallVector WholeEnds; + SmallVector CopyBegins; + SmallVector CopyEnds; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp to"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + + // OpenMP [2.9.3, Restrictions] + // A variable that is part of another variable (such as field of a + // structure) but is not an array element or an array section cannot appear + // as a list item in a clause of a target update construct. + Expr *VE = (*I)->IgnoreParenLValueCasts(); + + if (VE->isValueDependent() || VE->isTypeDependent() || + VE->isInstantiationDependent() || + VE->containsUnexpandedParameterPack()) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + MapArrayItemChecker Checker(*this); + VarDecl *VD = 0; + DeclRefExpr *DE = 0; + if (Checker.Visit(VE) || !(VD = Checker.getBaseDecl()) || + !(DE = Checker.getDeclRefExprForBaseDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << (*I)->getSourceRange(); + continue; + } + + // threadprivate variables cannot appear in a map clause. + DeclRefExpr *DRE = 0; + if (DSAStack->IsThreadprivate(VD, DRE)) { + SourceLocation Loc = DRE ? DRE->getLocation() : VD->getLocation(); + Diag(Loc, diag::err_omp_threadprivate_in_target); + Diag(DE->getLocStart(), diag::note_used_here) << DE->getSourceRange(); + continue; + } + + // OpenMP [2.9.3, Restrictions, p.6] + // A list item in a to or from clause must have a mappable type. + QualType Type = VD->getType(); + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, + DSAStack, Type)) { + continue; + } + + // OpenMP [2.9.3, Restrictions, p.6] + // A list item can only appear in a to or from clause, but not both. + DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); + if (MI.RefExpr) { + Diag(DE->getExprLoc(), diag::err_omp_once_referenced_in_target_update) + << DE->getSourceRange(); + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + + std::pair WholeSize = Checker.CalculateWholeSize(); + if (!WholeSize.first || !WholeSize.second) { + continue; + } + std::pair CopySize = Checker.CalculateCopySize(); + if (!CopySize.first || !CopySize.second) { + continue; + } + + Vars.push_back(*I); + WholeBegins.push_back(WholeSize.first); + WholeEnds.push_back(WholeSize.second); + CopyBegins.push_back(CopySize.first); + CopyEnds.push_back(CopySize.second); + MI.RefExpr = *I; + MI.IsCEAN = Checker.IsCEANExpr(); + DSAStack->addMapInfoForVar(VD, MI); + } + + if (Vars.empty()) + return 0; + + return OMPToClause::Create(Context, StartLoc, EndLoc, Vars, WholeBegins, + WholeEnds, CopyBegins, CopyEnds); +} + +OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + SmallVector WholeBegins; + SmallVector WholeEnds; + SmallVector CopyBegins; + SmallVector CopyEnds; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp from"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + + // OpenMP [2.9.3, Restrictions] + // A variable that is part of another variable (such as field of a + // structure) but is not an array element or an array section cannot appear + // as a list item in a clause of a target update construct. + Expr *VE = (*I)->IgnoreParenLValueCasts(); + + if (VE->isValueDependent() || VE->isTypeDependent() || + VE->isInstantiationDependent() || + VE->containsUnexpandedParameterPack()) { + // It will be analyzed later. + Vars.push_back(*I); + WholeBegins.push_back(0); + WholeEnds.push_back(0); + CopyBegins.push_back(0); + CopyEnds.push_back(0); + continue; + } + + MapArrayItemChecker Checker(*this); + VarDecl *VD = 0; + DeclRefExpr *DE = 0; + if (Checker.Visit(VE) || !(VD = Checker.getBaseDecl()) || + !(DE = Checker.getDeclRefExprForBaseDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) + << (*I)->getSourceRange(); + continue; + } + + // threadprivate variables cannot appear in a map clause. + DeclRefExpr *DRE = 0; + if (DSAStack->IsThreadprivate(VD, DRE)) { + SourceLocation Loc = DRE ? DRE->getLocation() : VD->getLocation(); + Diag(Loc, diag::err_omp_threadprivate_in_target); + Diag(DE->getLocStart(), diag::note_used_here) << DE->getSourceRange(); + continue; + } + + // OpenMP [2.9.3, Restrictions, p.6] + // A list item in a to or from clause must have a mappable type. + QualType Type = VD->getType(); + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, + DSAStack, Type)) { + continue; + } + + // OpenMP [2.9.3, Restrictions, p.6] + // A list item can only appear in a to or from clause, but not both. + DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); + if (MI.RefExpr) { + Diag(DE->getExprLoc(), diag::err_omp_once_referenced_in_target_update) + << DE->getSourceRange(); + Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) + << MI.RefExpr->getSourceRange(); + continue; + } + + std::pair WholeSize = Checker.CalculateWholeSize(); + if (!WholeSize.first || !WholeSize.second) { + continue; + } + std::pair CopySize = Checker.CalculateCopySize(); + if (!CopySize.first || !CopySize.second) { + continue; + } + + Vars.push_back(*I); + WholeBegins.push_back(WholeSize.first); + WholeEnds.push_back(WholeSize.second); + CopyBegins.push_back(CopySize.first); + CopyEnds.push_back(CopySize.second); + MI.RefExpr = *I; + MI.IsCEAN = Checker.IsCEANExpr(); + DSAStack->addMapInfoForVar(VD, MI); + } + + if (Vars.empty()) + return 0; + + return OMPFromClause::Create(Context, StartLoc, EndLoc, Vars, WholeBegins, + WholeEnds, CopyBegins, CopyEnds); +} + +OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, Expr *Step, + SourceLocation StepLoc) { + // Checks that apply to both private and linear variables. + SmallVector Vars; for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - assert(*I && "NULL expr in OpenMP private clause."); + + assert(*I && "Null expr in omp linear"); if (isa(*I)) { // It will be analyzed later. Vars.push_back(*I); 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 = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. - // OpenMP [2.9.3.3, Restrictions, p.1] + // 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_or_null(*I); if (!DE || !isa(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) - << (*I)->getSourceRange(); + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } - Decl *D = DE->getDecl(); - VarDecl *VD = cast(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); + VarDecl *VD = cast(DE->getDecl()); + // 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. + DeclRefExpr *PrevRef; + OpenMPClauseKind Kind = DSAStack->getTopDSA(VD, PrevRef); + if (PrevRef && (Kind == OMPC_linear || Kind == OMPC_private || + Kind == OMPC_lastprivate || Kind == OMPC_reduction)) { + Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(Kind) + << getOpenMPClauseName(OMPC_linear); + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(Kind); 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_private_incomplete_type)) { + QualType QTy = VD->getType().getCanonicalType(); + if (RequireCompleteType(ELoc, QTy, diag::err_omp_linear_incomplete_type)) { continue; } - if (Type->isReferenceType()) { + if (QTy->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) - << getOpenMPClauseName(OMPC_private) << Type; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : - diag::note_defined_here) << VD; + << getOpenMPClauseName(OMPC_linear); + 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.3, Restrictions, C/C++, p.1] - // A variable of class type (or array thereof) that appears in a private - // clause requires an accesible, unambiguous default constructor for the - // class type. - while (Type.getNonReferenceType()->isArrayType()) { - Type = cast( - Type.getNonReferenceType().getTypePtr())->getElementType(); - } - CXXRecordDecl *RD = getLangOpts().CPlusPlus ? - Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - 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_private) << 0; - 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_private) << 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); - } + // A list item that appears in a private clause must not be + // const-qualified. + if (QTy.isConstant(Context)) { + Diag(ELoc, diag::err_omp_const_variable) + << getOpenMPClauseName(OMPC_linear); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + 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. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); - if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { - Diag(ELoc, diag::err_omp_wrong_dsa) - << getOpenMPClauseName(DVar.CKind) - << getOpenMPClauseName(OMPC_private); - if (DVar.RefExpr) { - Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) - << getOpenMPClauseName(DVar.CKind); - } else { - Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) - << getOpenMPClauseName(DVar.CKind); - } + // - A list-item that appears in a linear clause must be of integral + // or pointer type. + QTy = QTy.getUnqualifiedType().getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_expected_int_or_ptr) << (*I)->getSourceRange(); continue; } - DSAStack->addDSA(VD, DE, OMPC_private); + DSAStack->addDSA(VD, DE, OMPC_linear); + Vars.push_back(DE); } - if (Vars.empty()) return 0; + if (Vars.empty()) + return 0; + + if (Step && Step->isIntegerConstantExpr(Context)) { + Step = ActOnConstantLinearStep(Step); + if (!Step) + return 0; + } - return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPLinearClause::Create(Context, StartLoc, EndLoc, Vars, Step, + StepLoc); } -OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - SmallVector Vars; +OMPClause *Sema::ActOnOpenMPAlignedClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Alignment, + SourceLocation AlignmentLoc) { + SmallVector Vars; for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - assert(*I && "NULL expr in OpenMP firstprivate clause."); - if (isa(*I)) { + + assert(*I && "Null expr in omp aligned"); + if (*I && isa(*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(*I); if (!DE || !isa(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) - << (*I)->getSourceRange(); - continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast(D); - - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); 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)) { + // OpenMP [2.8.1, simd construct, Restrictions] + // The type of list items appearing in the aligned clause must be + // array, pointer, reference to array, or reference to pointer. + QualType QTy = DE->getType() + .getNonReferenceType() + .getUnqualifiedType() + .getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_expected_array_or_ptr) << (*I)->getSourceRange(); 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; + // OpenMP [2.8.1, simd construct, Restrictions] + // A list-item cannot appear in more than one aligned clause. + DeclRefExpr *PrevRef = DE; + if (!DSAStack->addUniqueAligned(cast(DE->getDecl()), PrevRef)) { + Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(OMPC_aligned) + << getOpenMPClauseName(OMPC_aligned); + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_aligned); 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); + Vars.push_back(DE); + } - 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 (Vars.empty()) + return 0; - // 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.8.1, simd construct, Description] + // The optional parameter of the aligned clause, alignment, must be + // a constant positive integer expression. + if (Alignment) { + Alignment = ActOnConstantPositiveSubExpressionInClause(Alignment); + if (!Alignment) + return 0; + } - // 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; - } + return OMPAlignedClause::Create(Context, StartLoc, EndLoc, Vars, Alignment, + AlignmentLoc); +} - // 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: - } +OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPReadClause(StartLoc, EndLoc); +} - DSAStack->addDSA(VD, DE, OMPC_firstprivate); - Vars.push_back(DE); - } +OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPWriteClause(StartLoc, EndLoc); +} - if (Vars.empty()) return 0; +OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPUpdateClause(StartLoc, EndLoc); +} - return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); +OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPCaptureClause(StartLoc, EndLoc); } -OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, +OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc) { - SmallVector Vars; + return new (Context) OMPSeqCstClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPInBranchClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPNotInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPNotInBranchClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - assert(*I && "NULL expr in OpenMP shared clause."); + assert(*I && "Null expr in omp flush"); if (isa(*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.4, 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(*I); - if (!DE || !isa(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) - << (*I)->getSourceRange(); + if (DeclRefExpr *DE = dyn_cast_or_null(*I)) + Vars.push_back(DE); + } + + if (Vars.empty()) + return 0; + + return OMPFlushClause::Create(Context, StartLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPUniformClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "Null expr in omp uniform"); + if (isa(*I)) { + // It will be analyzed later. + Vars.push_back(*I); continue; } - Decl *D = DE->getDecl(); - VarDecl *VD = cast(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. + if (DeclRefExpr *DE = dyn_cast_or_null(*I)) Vars.push_back(DE); - continue; + } + + if (Vars.empty()) + return 0; + + return OMPUniformClause::Create(Context, StartLoc, EndLoc, Vars); +} + +namespace { +class ForInitChecker : public StmtVisitor { + class ForInitVarChecker : public StmtVisitor { + public: + VarDecl *VisitDeclRefExpr(DeclRefExpr *E) { + return dyn_cast_or_null(E->getDecl()); } + Decl *VisitStmt(Stmt *S) { return 0; } + ForInitVarChecker() {} + } VarChecker; + Expr *InitValue; - // 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. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); - if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { - Diag(ELoc, diag::err_omp_wrong_dsa) - << getOpenMPClauseName(DVar.CKind) - << getOpenMPClauseName(OMPC_shared); - Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) - << getOpenMPClauseName(DVar.CKind); - continue; +public: + Decl *VisitBinaryOperator(BinaryOperator *BO) { + if (BO->getOpcode() != BO_Assign) + return 0; + + InitValue = BO->getRHS(); + return VarChecker.Visit(BO->getLHS()); + } + Decl *VisitDeclStmt(DeclStmt *S) { + if (S->isSingleDecl()) { + VarDecl *Var = dyn_cast_or_null(S->getSingleDecl()); + if (Var && Var->hasInit()) { + if (CXXConstructExpr *Init = + dyn_cast(Var->getInit())) { + if (Init->getNumArgs() != 1) + return 0; + InitValue = Init->getArg(0); + } else { + InitValue = Var->getInit(); + } + return Var; + } } + return 0; + } + Decl *VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_Equal: + InitValue = E->getArg(1); + return VarChecker.Visit(E->getArg(0)); + default: + break; + } + return 0; + } + Decl *VisitStmt(Stmt *S) { return 0; } + ForInitChecker() : VarChecker(), InitValue(0) {} + Expr *getInitValue() { return InitValue; } +}; - DSAStack->addDSA(VD, DE, OMPC_shared); - Vars.push_back(DE); +class ForVarChecker : public StmtVisitor { + Decl *InitVar; + +public: + bool VisitDeclRefExpr(DeclRefExpr *E) { return E->getDecl() == InitVar; } + bool VisitImplicitCastExpr(ImplicitCastExpr *E) { + return Visit(E->getSubExpr()); + } + bool VisitStmt(Stmt *S) { return false; } + ForVarChecker(Decl *D) : InitVar(D) {} +}; + +class ForTestChecker : public StmtVisitor { + ForVarChecker VarChecker; + Expr *CheckValue; + bool IsLessOp; + bool IsStrictOp; + +public: + bool VisitBinaryOperator(BinaryOperator *BO) { + if (!BO->isRelationalOp()) + return false; + if (VarChecker.Visit(BO->getLHS())) { + CheckValue = BO->getRHS(); + IsLessOp = BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE; + IsStrictOp = BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT; + } else if (VarChecker.Visit(BO->getRHS())) { + CheckValue = BO->getLHS(); + IsLessOp = BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE; + IsStrictOp = BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT; + } + return CheckValue != 0; + } + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_Greater: + case OO_GreaterEqual: + case OO_Less: + case OO_LessEqual: + break; + default: + return false; + } + if (E->getNumArgs() != 2) + return false; + + if (VarChecker.Visit(E->getArg(0))) { + CheckValue = E->getArg(1); + IsLessOp = + E->getOperator() == OO_Less || E->getOperator() == OO_LessEqual; + IsStrictOp = E->getOperator() == OO_Less; + } else if (VarChecker.Visit(E->getArg(1))) { + CheckValue = E->getArg(0); + IsLessOp = + E->getOperator() == OO_Greater || E->getOperator() == OO_GreaterEqual; + IsStrictOp = E->getOperator() == OO_Greater; + } + + return CheckValue != 0; + } + bool VisitStmt(Stmt *S) { return false; } + ForTestChecker(Decl *D) + : VarChecker(D), CheckValue(0), IsLessOp(false), IsStrictOp(false) {} + Expr *getCheckValue() { return CheckValue; } + bool isLessOp() const { return IsLessOp; } + bool isStrictOp() const { return IsStrictOp; } +}; + +class ForIncrChecker : public StmtVisitor { + ForVarChecker VarChecker; + class ForIncrExprChecker : public StmtVisitor { + ForVarChecker VarChecker; + Expr *StepValue; + bool IsIncrement; + + public: + bool VisitBinaryOperator(BinaryOperator *BO) { + if (!BO->isAdditiveOp()) + return false; + if (BO->getOpcode() == BO_Add) { + IsIncrement = true; + if (VarChecker.Visit(BO->getLHS())) + StepValue = BO->getRHS(); + else if (VarChecker.Visit(BO->getRHS())) + StepValue = BO->getLHS(); + return StepValue != 0; + } + // BO_Sub + if (VarChecker.Visit(BO->getLHS())) + StepValue = BO->getRHS(); + return StepValue != 0; + } + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_Plus: + IsIncrement = true; + if (VarChecker.Visit(E->getArg(0))) + StepValue = E->getArg(1); + else if (VarChecker.Visit(E->getArg(1))) + StepValue = E->getArg(0); + return StepValue != 0; + case OO_Minus: + if (VarChecker.Visit(E->getArg(0))) + StepValue = E->getArg(1); + return StepValue != 0; + default: + return false; + } + } + bool VisitStmt(Stmt *S) { return false; } + ForIncrExprChecker(ForVarChecker &C) + : VarChecker(C), StepValue(0), IsIncrement(false) {} + Expr *getStepValue() { return StepValue; } + bool isIncrement() const { return IsIncrement; } + } ExprChecker; + Expr *StepValue; + Sema &Actions; + bool IsLessOp, IsCompatibleWithTest; + +public: + bool VisitUnaryOperator(UnaryOperator *UO) { + if (!UO->isIncrementDecrementOp()) + return false; + if (VarChecker.Visit(UO->getSubExpr())) { + IsCompatibleWithTest = (IsLessOp && UO->isIncrementOp()) || + (!IsLessOp && UO->isDecrementOp()); + if (!IsCompatibleWithTest && IsLessOp) + StepValue = Actions.ActOnIntegerConstant(SourceLocation(), -1).take(); + else + StepValue = Actions.ActOnIntegerConstant(SourceLocation(), 1).take(); + } + return StepValue != 0; + } + bool VisitBinaryOperator(BinaryOperator *BO) { + IsCompatibleWithTest = (IsLessOp && BO->getOpcode() == BO_AddAssign) || + (!IsLessOp && BO->getOpcode() == BO_SubAssign); + switch (BO->getOpcode()) { + case BO_AddAssign: + case BO_SubAssign: + if (VarChecker.Visit(BO->getLHS())) { + StepValue = BO->getRHS(); + IsCompatibleWithTest = (IsLessOp && BO->getOpcode() == BO_AddAssign) || + (!IsLessOp && BO->getOpcode() == BO_SubAssign); + } + return StepValue != 0; + case BO_Assign: + if (VarChecker.Visit(BO->getLHS()) && ExprChecker.Visit(BO->getRHS())) { + StepValue = ExprChecker.getStepValue(); + IsCompatibleWithTest = IsLessOp == ExprChecker.isIncrement(); + } + return StepValue != 0; + default: + break; + } + return false; + } + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_PlusPlus: + case OO_MinusMinus: + if (VarChecker.Visit(E->getArg(0))) { + IsCompatibleWithTest = (IsLessOp && E->getOperator() == OO_PlusPlus) || + (!IsLessOp && E->getOperator() == OO_MinusMinus); + if (!IsCompatibleWithTest && IsLessOp) + StepValue = Actions.ActOnIntegerConstant(SourceLocation(), -1).take(); + else + StepValue = Actions.ActOnIntegerConstant(SourceLocation(), 1).take(); + } + return StepValue != 0; + case OO_PlusEqual: + case OO_MinusEqual: + if (VarChecker.Visit(E->getArg(0))) { + StepValue = E->getArg(1); + IsCompatibleWithTest = (IsLessOp && E->getOperator() == OO_PlusEqual) || + (!IsLessOp && E->getOperator() == OO_MinusEqual); + } + return StepValue != 0; + case OO_Equal: + if (VarChecker.Visit(E->getArg(0)) && ExprChecker.Visit(E->getArg(1))) { + StepValue = ExprChecker.getStepValue(); + IsCompatibleWithTest = IsLessOp == ExprChecker.isIncrement(); + } + return StepValue != 0; + default: + break; + } + return false; + } + bool VisitStmt(Stmt *S) { return false; } + ForIncrChecker(Decl *D, Sema &S, bool LessOp) + : VarChecker(D), ExprChecker(VarChecker), StepValue(0), Actions(S), + IsLessOp(LessOp), IsCompatibleWithTest(false) {} + Expr *getStepValue() { return StepValue; } + bool isCompatibleWithTest() const { return IsCompatibleWithTest; } +}; +} + +bool Sema::isNotOpenMPCanonicalLoopForm(Stmt *S, OpenMPDirectiveKind Kind, + Expr *&NewEnd, Expr *&NewIncr, + Expr *&InitVal, Expr *&VarCnt, + BinaryOperatorKind &OpKind) { + // assert(S && "non-null statement must be specified"); + // OpenMP [2.9.5, Canonical Loop Form] + // for (init-expr; test-expr; incr-expr) structured-block + OpKind = BO_Assign; + ForStmt *For = dyn_cast_or_null(S); + if (!For) { + Diag(S->getLocStart(), diag::err_omp_not_for) + << getOpenMPDirectiveName(Kind); + return true; + } + Stmt *Body = For->getBody(); + if (!Body) { + Diag(S->getLocStart(), diag::err_omp_directive_nonblock) + << getOpenMPDirectiveName(Kind) << Body; + return true; + } + + // OpenMP [2.9.5, Canonical Loop Form] + // init-expr One of the following: + // var = lb + // integer-type var = lb + // random-access-iterator-type var = lb + // pointer-type var = lb + ForInitChecker InitChecker; + Stmt *Init = For->getInit(); + VarDecl *Var; + if (!Init || !(Var = dyn_cast_or_null(InitChecker.Visit(Init)))) { + Diag(Init ? Init->getLocStart() : For->getForLoc(), + diag::err_omp_not_canonical_for) + << 0; + return true; + } + SourceLocation InitLoc = Init->getLocStart(); + + // OpenMP [2.11.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++] + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct may be listed in a private or lastprivate clause. + bool HasErrors = false; + DeclRefExpr *PrevRef; + OpenMPDirectiveKind CurrentDir = DSAStack->getCurrentDirective(); + OpenMPClauseKind CKind = DSAStack->getTopDSA(Var, PrevRef); + if (CKind == OMPC_threadprivate) { + // Diag(InitLoc, diag::err_omp_for_loop_var_dsa) + // << getOpenMPClauseName(CKind); + // if (PrevRef) + // Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + // << getOpenMPClauseName(CKind); + // HasErrors = true; + } else if (CKind != OMPC_unknown && CKind != OMPC_private && + CKind != OMPC_lastprivate && + (CurrentDir == OMPD_for || CurrentDir == OMPD_parallel_for || + CurrentDir == OMPD_distribute || + CurrentDir == OMPD_distribute_parallel_for)) { + Diag(InitLoc, diag::err_omp_for_loop_var_dsa) << getOpenMPClauseName(CKind); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(CKind); + } else { + Diag(Var->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(CKind); + } + HasErrors = true; + } else if (CKind != OMPC_unknown && CKind != OMPC_linear && + CKind != OMPC_lastprivate && + (CurrentDir == OMPD_simd || CurrentDir == OMPD_for_simd || + CurrentDir == OMPD_parallel_for_simd || + CurrentDir == OMPD_distribute_parallel_for_simd || + CurrentDir == OMPD_distribute_simd)) { + // OpenMP [2.11.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++] + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop may be listed in a linear + // clause with a constant-linear-step that is the increment of the + // associated for-loop. + Diag(InitLoc, diag::err_omp_for_loop_var_dsa) << getOpenMPClauseName(CKind); + if (PrevRef) { + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(CKind); + } else { + Diag(Var->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(CKind); + } + HasErrors = true; + } else { + // OpenMP [2.11.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++] + // The loop iteration variable(s) in the associated for-loop(s)of a for or + // parallel for construct is (are) private. + DSAStack->addDSA(Var, 0, OMPC_private); + } + + // OpenMP [2.9.5, Canonical Loop Form] + // Var One of the following + // A variable of signed or unsigned integer type + // For C++, a variable of a random access iterator type. + // For C, a variable of a pointer type. + QualType Type = Var->getType() + .getNonReferenceType() + .getCanonicalType() + .getUnqualifiedType(); + if (!Type->isIntegerType() && !Type->isPointerType() && + (!getLangOpts().CPlusPlus || !Type->isOverloadableType())) { + Diag(Init->getLocStart(), diag::err_omp_for_variable) + << getLangOpts().CPlusPlus; + HasErrors = true; + } + + // OpenMP [2.9.5, Canonical Loop Form] + // test-expr One of the following: + // var relational-op b + // b relational-op var + ForTestChecker TestChecker(Var); + Stmt *Cond = For->getCond(); + bool TestCheckCorrect = false; + if (!Cond || !(TestCheckCorrect = TestChecker.Visit(Cond))) { + Diag(Cond ? Cond->getLocStart() : For->getForLoc(), + diag::err_omp_not_canonical_for) + << 1; + HasErrors = true; + } + + // OpenMP [2.9.5, Canonical Loop Form] + // incr-expr One of the following: + // ++var + // var++ + // --var + // var-- + // var += incr + // var -= incr + // var = var + incr + // var = incr + var + // var = var - incr + ForIncrChecker IncrChecker(Var, *this, TestChecker.isLessOp()); + Stmt *Incr = For->getInc(); + bool IncrCheckCorrect = false; + if (!Incr || !(IncrCheckCorrect = IncrChecker.Visit(Incr))) { + Diag(Incr ? Incr->getLocStart() : For->getForLoc(), + diag::err_omp_not_canonical_for) + << 2; + HasErrors = true; + } + + // OpenMP [2.9.5, Canonical Loop Form] + // lb and b Loop invariant expressions of a type compatible with the type + // of var. + Expr *InitValue = InitChecker.getInitValue(); + // QualType InitTy = + // InitValue ? InitValue->getType().getNonReferenceType(). + // getCanonicalType().getUnqualifiedType() : + // QualType(); + // if (InitValue && + // Context.mergeTypes(Type, InitTy, false, true).isNull()) { + // Diag(InitValue->getExprLoc(), diag::err_omp_for_type_not_compatible) + // << InitValue->getType() + // << Var << Var->getType(); + // HasErrors = true; + // } + Expr *CheckValue = TestChecker.getCheckValue(); + // QualType CheckTy = + // CheckValue ? CheckValue->getType().getNonReferenceType(). + // getCanonicalType().getUnqualifiedType() : + // QualType(); + // if (CheckValue && + // Context.mergeTypes(Type, CheckTy, false, true).isNull()) { + // Diag(CheckValue->getExprLoc(), diag::err_omp_for_type_not_compatible) + // << CheckValue->getType() + // << Var << Var->getType(); + // HasErrors = true; + // } + + // OpenMP [2.9.5, Canonical Loop Form] + // incr A loop invariant integer expression. + Expr *Step = IncrChecker.getStepValue(); + if (Step && !Step->getType()->isIntegralOrEnumerationType()) { + Diag(Step->getExprLoc(), diag::err_omp_for_incr_not_integer); + HasErrors = true; + } + // llvm::APSInt Result; + // if (Step && Step->isIntegerConstantExpr(Result, Context) && + // !Result.isStrictlyPositive()) { + // Diag(Step->getExprLoc(), diag::err_negative_expression_in_clause); + // HasErrors = true; + //} + + // OpenMP [2.9.5, Canonical Loop Form, Restrictions] + // If test-expr is of form var relational-op b and relational-op is < or + // <= then incr-expr must cause var to increase on each iteration of the + // loop. If test-expr is of form var relational-op b and relational-op is + // > or >= then incr-expr must cause var to decrease on each iteration of the + // loop. + // If test-expr is of form b relational-op var and relational-op is < or + // <= then incr-expr must cause var to decrease on each iteration of the + // loop. If test-expr is of form b relational-op var and relational-op is + // > or >= then incr-expr must cause var to increase on each iteration of the + // loop. + if (Incr && TestCheckCorrect && IncrCheckCorrect && + !IncrChecker.isCompatibleWithTest()) { + // Additional type checking. + llvm::APSInt Result; + bool IsConst = Step->isIntegerConstantExpr(Result, getASTContext()); + bool IsConstNeg = IsConst && Result.isSigned() && Result.isNegative(); + bool IsSigned = Step->getType()->hasSignedIntegerRepresentation(); + if ((TestChecker.isLessOp() && IsConst && IsConstNeg) || + (!TestChecker.isLessOp() && + ((IsConst && !IsConstNeg) || (!IsConst && !IsSigned)))) { + Diag(Incr->getLocStart(), diag::err_omp_for_incr_not_compatible) + << Var << TestChecker.isLessOp(); + HasErrors = true; + } else { + Step = CreateBuiltinUnaryOp(Step->getExprLoc(), UO_Minus, Step).take(); + } + } + if (HasErrors) + return true; + + // Build expression for number of iterations. + // if (getLangOpts().CPlusPlus && !StdNamespace && !Type->isIntegerType()) { + // Diag(Var->getLocation(), diag::err_omp_type_not_rai); + // return true; + //} + + ExprResult Diff; + assert(Step && "Null expr in Step in OMP FOR"); + Step = Step->IgnoreParenImpCasts(); + CheckValue = CheckValue->IgnoreParenImpCasts(); + InitValue = InitValue->IgnoreParenImpCasts(); + if (Step->getType()->isDependentType() || + CheckValue->getType()->isDependentType() || + InitValue->getType()->isDependentType()) { + NewEnd = CheckValue; + NewIncr = Step; + InitVal = InitValue; + VarCnt = CheckValue; + return false; } + if (getLangOpts().CPlusPlus && !Type->isIntegerType() && + !Type->isPointerType()) { + // Check that var type is a random access iterator, i.e. + // we can apply 'std::distance' to the init and test arguments + // of the for-loop. + CXXScopeSpec SS; + SS.Extend(Context, getOrCreateStdNamespace(), SourceLocation(), + SourceLocation()); + IdentifierInfo *IIT = &Context.Idents.get("iterator_traits"); + DeclarationNameInfo DNIIT(IIT, SourceLocation()); + LookupResult RIT(*this, DNIIT, LookupNestedNameSpecifierName); + TemplateDecl *D; + if (!LookupParsedName(RIT, DSAStack->getCurScope(), &SS) || + !RIT.isSingleResult() || !(D = RIT.getAsSingle())) { + Diag(Var->getLocation(), diag::err_omp_type_not_rai); + return true; + } + + TemplateArgumentListInfo Args; + TemplateArgument Arg(Type); + TemplateArgumentLoc ArgLoc(Arg, Context.CreateTypeSourceInfo(Type)); + Args.addArgument(ArgLoc); + QualType T = CheckTemplateIdType(TemplateName(D), SourceLocation(), Args); + CXXRecordDecl *TRDType; + if (T.isNull() || RequireCompleteType(Var->getLocation(), T, 0) || + !(TRDType = T->getAsCXXRecordDecl())) { + Diag(Var->getLocation(), diag::err_omp_type_not_rai); + return true; + } + + IdentifierInfo *IIRAI = &Context.Idents.get("random_access_iterator_tag"); + DeclarationNameInfo DNIRAI(IIRAI, SourceLocation()); + LookupResult RRAI(*this, DNIRAI, LookupOrdinaryName); + TypeDecl *TDRAI; + CXXRecordDecl *RDType = Type->getAsCXXRecordDecl(); + if (!LookupParsedName(RRAI, DSAStack->getCurScope(), &SS) || + !RRAI.isSingleResult() || !(TDRAI = RRAI.getAsSingle()) || + !RDType) { + Diag(Var->getLocation(), diag::err_omp_type_not_rai); + return true; + } + + IdentifierInfo *IIC = &Context.Idents.get("iterator_category"); + DeclarationNameInfo DNIIC(IIC, SourceLocation()); + LookupResult RIC(*this, DNIIC, LookupOrdinaryName); + TypeDecl *TDIC; + if (!LookupQualifiedName(RIC, TRDType) || !RIC.isSingleResult() || + !(TDIC = RIC.getAsSingle()) || + !Context.hasSameType(Context.getTypeDeclType(TDRAI), + Context.getTypeDeclType(TDIC))) { + Diag(Var->getLocation(), diag::err_omp_type_not_rai); + return true; + } - if (Vars.empty()) return 0; + IdentifierInfo *IID = &Context.Idents.get("distance"); + DeclarationNameInfo DNID(IID, SourceLocation()); + ExprResult ER = BuildQualifiedTemplateIdExpr(SS, InitLoc, DNID, &Args); + Expr *CallArgs[2] = {TestChecker.isLessOp() ? InitValue : CheckValue, + TestChecker.isLessOp() ? CheckValue : InitValue}; + Diff = ActOnCallExpr(DSAStack->getCurScope(), ER.take(), InitLoc, CallArgs, + InitLoc); + if (Diff.isInvalid()) { + Diag(Var->getLocation(), diag::err_omp_type_not_rai); + return true; + } + } else { + Diff = BuildBinOp(DSAStack->getCurScope(), InitLoc, BO_Sub, + TestChecker.isLessOp() ? CheckValue : InitValue, + TestChecker.isLessOp() ? InitValue : CheckValue); + } + if (Diff.isUsable() && TestChecker.isStrictOp()) { + Diff = BuildBinOp(DSAStack->getCurScope(), InitLoc, BO_Sub, Diff.take(), + ActOnIntegerConstant(SourceLocation(), 1).take()); + } + if (Diff.isUsable()) { + Diff = + BuildBinOp(DSAStack->getCurScope(), InitLoc, BO_Add, Diff.take(), Step); + } + if (Diff.isUsable()) { + Diff = + BuildBinOp(DSAStack->getCurScope(), InitLoc, BO_Div, Diff.take(), Step); + } + bool Signed = Type->hasSignedIntegerRepresentation(); + uint64_t TypeSize = Context.getTypeSize(Type); + if (TypeSize < 32) + TypeSize = 32; + else if (TypeSize > 64) + TypeSize = 64; + QualType DiffType = Context.getIntTypeForBitwidth(TypeSize, Signed); + TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(DiffType); + NewEnd = BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), + Diff.take()).take(); + NewIncr = + BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), Step).take(); + InitVal = + PerformImplicitConversion(InitValue, Type, AA_Initializing, true).take(); + // NamedDecl *ND = Var; + VarCnt = + DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), SourceLocation(), + Var, false, SourceLocation(), Type, VK_LValue); + // if (!isDeclInScope(ND, CurContext, DSAStack->getCurScope())) { + // DeclContext *SavedCurContext = CurContext; + // CurContext = Var->getDeclContext(); + // VarCnt = BuildDeclRefExpr(Var, Type, VK_LValue, InitLoc).take(); + // CurContext = SavedCurContext; + //} + OpKind = TestChecker.isLessOp() ? BO_Add : BO_Sub; + return false; +} - return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +namespace { +class CEANExprChecker : public StmtVisitor { +public: + bool VisitCEANIndexExpr(CEANIndexExpr *E) { return true; } + bool VisitOpaqueValueExpr(OpaqueValueExpr *E) { + return E->getSourceExpr() && Visit(E->getSourceExpr()); + } + bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + return E->getExpr() && Visit(E->getExpr()); + } + bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + return E->getExpr() && Visit(E->getExpr()); + } + bool VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + return E->getQueriedExpression() && Visit(E->getQueriedExpression()); + } + unsigned VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { + if (!E->isArgumentType()) + return (E->getKind() == UETT_SizeOf) ? false + : Visit(E->getArgumentExpr()); + return VisitStmt(E); + } + unsigned VisitLambdaExpr(LambdaExpr *E) { return false; } + bool VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; + ++I) { + if (*I && Visit(*I)) + return true; + } + return false; + } + CEANExprChecker() {} +}; } -#undef DSAStack +ExprResult Sema::ActOnCEANIndexExpr(Scope *S, Expr *Base, Expr *LowerBound, + SourceLocation ColonLoc, Expr *Length) { + bool ArgsDep = + (Base && (Base->isTypeDependent() || Base->isValueDependent() || + Base->isInstantiationDependent() || + Base->containsUnexpandedParameterPack())) || + (LowerBound && + (LowerBound->isTypeDependent() || LowerBound->isValueDependent() || + LowerBound->isInstantiationDependent() || + LowerBound->containsUnexpandedParameterPack())) || + (Length && (Length->isTypeDependent() || Length->isValueDependent() || + Length->isInstantiationDependent() || + Length->containsUnexpandedParameterPack())); + + if (ArgsDep) + return Owned(new (Context) CEANIndexExpr(Base, LowerBound, ColonLoc, Length, + Context.IntTy)); + + SourceLocation SLoc; + if (LowerBound) + SLoc = LowerBound->getExprLoc(); + else + SLoc = ColonLoc; + SourceLocation ELoc; + if (Length) + ELoc = Length->getLocEnd(); + else + ELoc = ColonLoc; + + QualType BaseType = + Base ? Base->getType().getNonReferenceType().getCanonicalType() + : QualType(); + if (Base && ((Base->isGLValue() && Base->getObjectKind() != OK_Ordinary) || + !BaseType->isCompoundType())) { + Diag(SLoc, diag::err_cean_not_in_statement) << SourceRange(SLoc, ELoc); + return ExprError(); + } + + if (!LowerBound) + LowerBound = ActOnIntegerConstant(ColonLoc, 0).take(); + else { + CEANExprChecker Checker; + if (Checker.Visit(LowerBound)) { + Diag(LowerBound->getExprLoc(), diag::err_cean_not_in_statement) + << LowerBound->getSourceRange(); + return ExprError(); + } + } + if (!Length) { + if (!Base) + return ExprError(); + QualType Type = Base->getType().getCanonicalType(); + if (DeclRefExpr *DRE = + dyn_cast_or_null(Base->IgnoreParenLValueCasts())) { + if (ParmVarDecl *PVD = dyn_cast_or_null(DRE->getDecl())) { + Type = PVD->getOriginalType().getNonReferenceType().getCanonicalType(); + } + } + if (!Type->isConstantArrayType() && !Type->isVariableArrayType()) { + Diag(ColonLoc, diag::err_cean_no_length_for_non_array) << Base->getType(); + return ExprError(); + } + const ArrayType *ArrType = Type->castAsArrayTypeUnsafe(); + if (const ConstantArrayType *ConstArrType = + dyn_cast(ArrType)) + Length = ActOnIntegerConstant( + ColonLoc, ConstArrType->getSize().getZExtValue()).take(); + else if (const VariableArrayType *VarArrType = + dyn_cast(ArrType)) + Length = VarArrType->getSizeExpr(); + Length = CreateBuiltinBinOp(ColonLoc, BO_Sub, Length, LowerBound).take(); + if (!Length) + return ExprError(); + } else { + CEANExprChecker Checker; + if (Checker.Visit(Length)) { + Diag(Length->getExprLoc(), diag::err_cean_not_in_statement) + << Length->getSourceRange(); + return ExprError(); + } + } + + if (!LowerBound->getType()->isIntegerType()) { + Diag(LowerBound->getExprLoc(), diag::err_cean_lower_bound_not_integer) + << LowerBound->getType(); + return ExprError(); + } + if (!Length->getType()->isIntegerType()) { + Diag(Length->getExprLoc(), diag::err_cean_length_not_integer) + << Length->getType(); + return ExprError(); + } + + ExprResult LowerBoundRes(LowerBound); + ExprResult LengthRes(Length); + QualType ResType = UsualArithmeticConversions(LowerBoundRes, LengthRes); + LowerBoundRes = PerformImplicitConversion(LowerBound, ResType, AA_Converting); + LengthRes = PerformImplicitConversion(Length, ResType, AA_Converting); + return Owned(new (Context) CEANIndexExpr(Base, LowerBoundRes.take(), ColonLoc, + LengthRes.take(), ResType)); +} diff -uNr clang-3.4/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaOverload.cpp --- clang-3.4/lib/Sema/SemaOverload.cpp 2013-11-14 21:58:23.000000000 -0500 +++ clang/lib/Sema/SemaOverload.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -3734,6 +3734,26 @@ return Result; } +/// MarkAsImplicitConversion - Create an ImplicitCastExpr as the parent of +/// Arg if Arg is a CXXConstructExpr. This function is called when +/// constructors are called as part of an implicit conversion. This serves +/// as a marker to be able to distinguish between implicitly generated +/// constructor calls and explicit constructor calls. +static Expr *MarkAsImplicitConversion(ASTContext &Context, ExprResult &Arg) { + Expr *ArgExpr = Arg.takeAs(); + Expr *E = ArgExpr; + + if (CXXBindTemporaryExpr *BE = dyn_cast(E)) + E = BE->getSubExpr(); + + if (isa(E)) + return ImplicitCastExpr::Create(Context, ArgExpr->getType(), + CK_ConstructorConversion, ArgExpr, + 0, ArgExpr->getValueKind()); + else + return ArgExpr; +} + /// CompareDerivedToBaseConversions - Compares two standard conversion /// sequences to determine whether they can be ranked based on their /// various kinds of derived-to-base conversions (C++ @@ -10753,8 +10773,11 @@ SourceLocation(), Owned(Args[1])); if (Arg1.isInvalid()) return ExprError(); - Args[0] = LHS = Arg0.takeAs(); - Args[1] = RHS = Arg1.takeAs(); + + // Mark the arguments as having an implicit conversion if a + // CXXConstructExpr was implicitly created. + Args[0] = LHS = MarkAsImplicitConversion(Context, Arg0); + Args[1] = RHS = MarkAsImplicitConversion(Context, Arg1); } // Build the actual expression node. diff -uNr clang-3.4/lib/Sema/SemaStmt.cpp clang/lib/Sema/SemaStmt.cpp --- clang-3.4/lib/Sema/SemaStmt.cpp 2013-10-11 18:16:04.000000000 -0400 +++ clang/lib/Sema/SemaStmt.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -458,7 +458,8 @@ DiagnoseUnusedExprResult(elseStmt); - return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, + return Owned(new (Context) IfStmt(Context, IfLoc, + ConditionVar, ConditionExpr, thenStmt, ElseLoc, elseStmt)); } @@ -1357,63 +1358,7 @@ }; // end class DeclMatcher - void CheckForLoopConditionalStatement(Sema &S, Expr *Second, - Expr *Third, Stmt *Body) { - // Condition is empty - if (!Second) return; - - if (S.Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body, - Second->getLocStart()) - == DiagnosticsEngine::Ignored) - return; - - PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body); - llvm::SmallPtrSet Decls; - SmallVector Ranges; - DeclExtractor DE(S, Decls, Ranges); - DE.Visit(Second); - - // Don't analyze complex conditionals. - if (!DE.isSimple()) return; - - // No decls found. - if (Decls.size() == 0) return; - - // Don't warn on volatile, static, or global variables. - for (llvm::SmallPtrSet::iterator I = Decls.begin(), - E = Decls.end(); - I != E; ++I) - if ((*I)->getType().isVolatileQualified() || - (*I)->hasGlobalStorage()) return; - - if (DeclMatcher(S, Decls, Second).FoundDeclInUse() || - DeclMatcher(S, Decls, Third).FoundDeclInUse() || - DeclMatcher(S, Decls, Body).FoundDeclInUse()) - return; - - // Load decl names into diagnostic. - if (Decls.size() > 4) - PDiag << 0; - else { - PDiag << Decls.size(); - for (llvm::SmallPtrSet::iterator I = Decls.begin(), - E = Decls.end(); - I != E; ++I) - PDiag << (*I)->getDeclName(); - } - - // Load SourceRanges into diagnostic if there is room. - // Otherwise, load the SourceRange of the conditional expression. - if (Ranges.size() <= PartialDiagnostic::MaxArguments) - for (SmallVectorImpl::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - PDiag << *I; - else - PDiag << Second->getSourceRange(); - - S.Diag(Ranges.begin()->getBegin(), PDiag); - } + // If Statement is an incemement or decrement, return true and sets the // variables Increment and DRE. @@ -1515,6 +1460,64 @@ } // end namespace +void Sema::CheckForLoopConditionalStatement(Expr *Second, Expr *Third, + Stmt *Body) { + // Condition is empty + if (!Second) return; + + if (Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body, + Second->getLocStart()) + == DiagnosticsEngine::Ignored) + return; + + PartialDiagnostic PDiag = this->PDiag(diag::warn_variables_not_in_loop_body); + llvm::SmallPtrSet Decls; + SmallVector Ranges; + DeclExtractor DE(*this, Decls, Ranges); + DE.Visit(Second); + + // Don't analyze complex conditionals. + if (!DE.isSimple()) return; + + // No decls found. + if (Decls.size() == 0) return; + + // Don't warn on volatile, static, or global variables. + for (llvm::SmallPtrSet::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) + if ((*I)->getType().isVolatileQualified() || + (*I)->hasGlobalStorage()) return; + + if (DeclMatcher(*this, Decls, Second).FoundDeclInUse() || + DeclMatcher(*this, Decls, Third).FoundDeclInUse() || + DeclMatcher(*this, Decls, Body).FoundDeclInUse()) + return; + + // Load decl names into diagnostic. + if (Decls.size() > 4) + PDiag << 0; + else { + PDiag << Decls.size(); + for (llvm::SmallPtrSet::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) + PDiag << (*I)->getDeclName(); + } + + // Load SourceRanges into diagnostic if there is room. + // Otherwise, load the SourceRange of the conditional expression. + if (Ranges.size() <= PartialDiagnostic::MaxArguments) + for (SmallVectorImpl::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + PDiag << *I; + else + PDiag << Second->getSourceRange(); + + Diag(Ranges.begin()->getBegin(), PDiag); +} + StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, FullExprArg second, Decl *secondVar, @@ -1538,7 +1541,7 @@ } } - CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); + CheckForLoopConditionalStatement(second.get(), third.get(), Body); CheckForRedundantIteration(*this, third.get(), Body); ExprResult SecondResult(second.release()); @@ -3253,6 +3256,8 @@ // Enter the capturing scope for this captured region. PushCapturedRegionScope(CurScope, CD, RD, Kind); + PushCompoundScope(); + if (CurScope) PushDeclContext(CurScope, CD); else @@ -3277,6 +3282,8 @@ SourceLocation(), SourceLocation(), /*AttributeList=*/0); PopDeclContext(); + // Pop the compound scope we inserted implicitly. + PopCompoundScope(); PopFunctionScopeInfo(); } @@ -3301,6 +3308,8 @@ PopExpressionEvaluationContext(); PopDeclContext(); + // Pop the compound scope we inserted implicitly. + PopCompoundScope(); PopFunctionScopeInfo(); return Owned(Res); diff -uNr clang-3.4/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- clang-3.4/lib/Sema/SemaTemplateInstantiateDecl.cpp 2013-12-14 02:59:40.000000000 -0500 +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -1468,6 +1468,14 @@ PrincipalDecl->setNonMemberOperator(); assert(!D->isDefaulted() && "only methods should be defaulted"); + if (FunctionTemplate) { + OMPDeclareSimdDecl *DSimd = SemaRef.OMPDSimdMap[FunctionTemplate]; + if (DSimd) { + OMPDeclareSimdDecl *TD = cast( + TouchOMPDeclareSimdDecl(DSimd, Function, DC)); + SemaRef.PendingOMP[Function] = TD; + } + } return Function; } @@ -1738,7 +1746,20 @@ } else if (!IsClassScopeSpecialization) { Owner->addDecl(Method); } - + // Check for #omp declare simd in old record and add it into new record + // with our new method. + CXXRecordDecl *Parent = D->getParent(); + for (DeclContext::decl_iterator DI = Parent->decls_begin(), + DE = Parent->decls_end(); + DI != DE; ++DI) { + if (OMPDeclareSimdDecl *DSimd = + dyn_cast_or_null(*DI)) { + if (dyn_cast_or_null(DSimd->getFunction()) == D) { + TouchOMPDeclareSimdDecl(DSimd, Method, + SemaRef.CurContext); + } + } + } return Method; } @@ -2299,9 +2320,224 @@ OMPThreadPrivateDecl *TD = SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars); + TD->setAccess(AS_public); + Owner->addDecl(TD); + return TD; } +Decl *TemplateDeclInstantiator::VisitOMPDeclareSimdDecl( + OMPDeclareSimdDecl *D) { + return TouchOMPDeclareSimdDecl(D, D->getFunction(), Owner); +} + +void TemplateDeclInstantiator::TouchOMPVarlist( + llvm::MutableArrayRef VL, + SmallVector &NewVL, + Decl *FuncDecl) { + for (llvm::MutableArrayRef::iterator I = VL.begin(), + E = VL.end(); + I != E; ++I) { + const DeclRefExpr *DRE = dyn_cast_or_null(*I); + assert(DRE); + DeclarationNameInfo DNI = DRE->getNameInfo(); + Expr *NewV = SemaRef.FindOpenMPDeclarativeClauseParameter( + DNI.getAsString(), + DNI.getLoc(), + FuncDecl); + assert(NewV); + NewVL.push_back(NewV); + } +} + +Decl *TemplateDeclInstantiator::TouchOMPDeclareSimdDecl( + OMPDeclareSimdDecl *D, + Decl *NewFunc, + DeclContext *DC) { + SmallVector SrcRanges; + SmallVector BeginIdx; + SmallVector EndIdx; + // Perform AOS->SOA (will be done backward in CheckOMPDeclareSimdDecl). + for (ArrayRef::iterator + I = D->simd_variants_begin(), + E = D->simd_variants_end(); + I != E; ++I) { + SrcRanges.push_back(I->SrcRange); + BeginIdx.push_back(I->BeginIdx); + EndIdx.push_back(I->EndIdx); + } + // Substitute the necessary stuff into the clauses. + SmallVector CL; + for (OMPDeclareSimdDecl::clauses_iterator + J = D->clauses_begin(), + F = D->clauses_end(); + J != F; ++J) { + if (OMPLinearClause *C = dyn_cast_or_null(*J)) { + Expr *Step = C->getStep(); + Step = SemaRef.SubstExpr(Step, TemplateArgs).take(); + SmallVector NewVars; + TouchOMPVarlist(C->getVars(), NewVars, NewFunc); + OMPClause *NC = SemaRef.ActOnOpenMPDeclarativeLinearClause( + NewVars, + C->getLocStart(), + C->getLocEnd(), + Step, + C->getStepLoc()); + CL.push_back(NC); + } + else if (OMPAlignedClause *C = dyn_cast_or_null(*J)) { + Expr *Alignment = C->getAlignment(); + Alignment = SemaRef.SubstExpr(Alignment, TemplateArgs).take(); + SmallVector NewVars; + TouchOMPVarlist(C->getVars(), NewVars, NewFunc); + OMPClause *NC = SemaRef.ActOnOpenMPDeclarativeAlignedClause( + NewVars, + C->getLocStart(), + C->getLocEnd(), + Alignment, + C->getAlignmentLoc()); + CL.push_back(NC); + } + else if (OMPUniformClause *C = dyn_cast_or_null(*J)) { + SmallVector NewVars; + TouchOMPVarlist(C->getVars(), NewVars, NewFunc); + OMPClause *NC = SemaRef.ActOnOpenMPDeclarativeUniformClause( + NewVars, + C->getLocStart(), + C->getLocEnd()); + CL.push_back(NC); + } + else if (OMPSimdlenClause *C = dyn_cast_or_null(*J)) { + Expr *Length = C->getSimdlen(); + Length = SemaRef.SubstExpr(Length, TemplateArgs).take(); + OMPClause *NC = SemaRef.ActOnOpenMPSimdlenClause( + Length, + C->getLocStart(), + C->getLocEnd()); + CL.push_back(NC); + } + else { + // May push NULL here -- CheckOMPDeclareSimdDecl will clean up. + CL.push_back(*J); + } + } + + OMPDeclareSimdDecl *TD = + SemaRef.CheckOMPDeclareSimdDecl(D->getLocation(), NewFunc, + SrcRanges, BeginIdx, EndIdx, CL, DC); + TD->setAccess(AS_public); + DC->addDecl(TD); + return TD; +} + + +Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( + OMPDeclareReductionDecl *D) { + if (D->isInvalidDecl()) return D; + SmallVector Types; + SmallVector TyRanges; + bool IsValid = true; + for (ArrayRef::iterator + I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + if (I->QTy.isNull()) { + Types.push_back(QualType()); + TyRanges.push_back(SourceRange()); + IsValid = false; + continue; + } + QualType ResQTy = SemaRef.SubstType(I->QTy, TemplateArgs, + D->getLocation(), DeclarationName()); + if (!ResQTy.isNull() && + SemaRef.IsOMPDeclareReductionTypeAllowed(I->TyRange, ResQTy, + Types, TyRanges)) { + Types.push_back(ResQTy); + TyRanges.push_back(I->TyRange); + } else { + Types.push_back(QualType()); + TyRanges.push_back(SourceRange()); + IsValid = false; + } + } + if (!IsValid) return 0; + + SmallVector Combiners; + SmallVector Inits; + Decl *NewDR; + { + Sema::OMPDeclareReductionRAII RAII(SemaRef, 0, Owner, + D->getLocation(), D->getDeclName(), + D->datalist_size(), D->getAccess()); + NewDR = RAII.getDecl(); + DeclContext *NewOwner = cast(NewDR); + SemaRef.OMPInstantiatedDecls.clear(); + + LocalInstantiationScope Scope(SemaRef); + Scope.InstantiatedLocal(D, NewDR); + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I != E; ++I) { + if ((*I)->getDeclContext() != D) continue; + if ((*I)->isInvalidDecl()) { + RAII.getDecl()->setInvalidDecl(); + continue; + } + Decl *NewD = SemaRef.SubstDecl(*I, NewOwner, TemplateArgs); + if (!NewD || NewD->isInvalidDecl()) { + NewDR->setInvalidDecl(); + return NewDR; + } + if (FunctionDecl *FD = cast(NewD)) { + if ((*I)->hasBody()) { + SemaRef.InstantiateFunctionDefinition(SourceLocation(), + FD, false, true); + } else { + Sema::ContextRAII S(SemaRef, FD); + // Only init function may have just a declaration. + ParmVarDecl *ParLHS = FD->getParamDecl(0); + // The first parameter is a pointer. + QualType QTy = (ParLHS->getType())->getPointeeType(); + VarDecl *OmpPriv = + VarDecl::Create(SemaRef.Context, FD, SourceLocation(), + SourceLocation(), + &SemaRef.Context.Idents.get("omp_priv_inst"), + QTy, SemaRef.Context.getTrivialTypeSourceInfo(QTy), + SC_Auto); + FD->addDecl(OmpPriv); + SemaRef.CreateDefaultDeclareReductionInitFunctionBody(FD, OmpPriv, + ParLHS); + } + } + NewOwner->addDecl(NewD); + SemaRef.OMPInstantiatedDecls[*I] = NewD; + } + + SmallVectorImpl::iterator IT = Types.begin(); + for (ArrayRef::iterator + I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I, ++IT) { + if (!IT->isNull()) { + Combiners.push_back(SemaRef.SubstExpr(I->CombinerFunction, + TemplateArgs).take()); + Inits.push_back(SemaRef.SubstExpr(I->InitFunction, TemplateArgs).take()); + } + } + + SemaRef.OMPInstantiatedDecls.clear(); + } + + SemaRef.CompleteOMPDeclareReductionDecl( + cast(NewDR), + Types, TyRanges, Combiners, Inits); + return NewDR; +} + +Decl * +TemplateDeclInstantiator::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + llvm_unreachable("OpenMP declare target cannot be instantiated"); +} + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return VisitFunctionDecl(D, 0); } @@ -3419,6 +3655,12 @@ DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); + PendingOMPInstMap::iterator IOMP = PendingOMP.find(Function); + if (IOMP != PendingOMP.end()) { + DeclGroupRef DGOMP(IOMP->second); + Consumer.HandleTopLevelDecl(DGOMP); + } + // This class may have local implicit instantiations that need to be // instantiation within this scope. PerformPendingInstantiations(/*LocalOnly=*/true); @@ -4339,7 +4581,7 @@ // find an instantiated decl for (T y) when the ParentDC for y is // the translation unit. // e.g. template void Foo(auto (*p)(T y) -> decltype(y())) {} - // float baz(float(*)()) { return 0.0; } + // float baz(float(*)()) { return 0.0; } // Foo(baz); // The better fix here is perhaps to ensure that a ParmVarDecl, by the time // it gets here, always has a FunctionOrMethod as its ParentDC?? @@ -4487,7 +4729,9 @@ } NamedDecl *Result = 0; - if (D->getDeclName()) { + if (isa(ParentDC) && isa(D)) { + Result = cast(OMPInstantiatedDecls[D]); + } else if (D->getDeclName()) { DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName()); Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); } else { diff -uNr clang-3.4/lib/Sema/TreeTransform.h clang/lib/Sema/TreeTransform.h --- clang-3.4/lib/Sema/TreeTransform.h 2013-12-06 04:07:48.000000000 -0500 +++ clang/lib/Sema/TreeTransform.h 2014-06-09 10:05:34.000000000 -0400 @@ -619,6 +619,8 @@ #define ABSTRACT_STMT(Stmt) #include "clang/AST/StmtNodes.inc" + StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S); + #define OPENMP_CLAUSE(Name, Class) \ LLVM_ATTRIBUTE_NOINLINE \ OMPClause *Transform ## Class(Class *S); @@ -1286,16 +1288,70 @@ return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } - /// \brief Build a new OpenMP parallel directive. + /// \brief Build a new OpenMP executable directive. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildOMPParallelDirective(ArrayRef Clauses, - Stmt *AStmt, - SourceLocation StartLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPParallelDirective(Clauses, AStmt, - StartLoc, EndLoc); + StmtResult RebuildOMPExecutableDirective(OpenMPDirectiveKind Kind, + DeclarationNameInfo DirName, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDirectiveKind ConstructType) { + return getSema().ActOnOpenMPExecutableDirective(Kind, DirName, Clauses, + AStmt, StartLoc, EndLoc, + ConstructType); + } + + /// \brief Build a new OpenMP 'if' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPIfClause(Expr *Condition, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPIfClause(Condition, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'final' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFinalClause(Expr *Condition, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFinalClause(Condition, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'num_threads' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNumThreadsClause(Expr *NumThreads, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNumThreadsClause(NumThreads, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'collapse' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCollapseClause(Expr *NumForLoops, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCollapseClause(NumForLoops, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'device' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDeviceClause(Expr *Device, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, EndLoc); } /// \brief Build a new OpenMP 'default' clause. @@ -1303,12 +1359,49 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind, - SourceLocation KindKwLoc, + SourceLocation KindLoc, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPDefaultClause(Kind, KindKwLoc, - StartLoc, LParenLoc, EndLoc); + return getSema().ActOnOpenMPDefaultClause(Kind, KindLoc, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'proc_bind' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPProcBindClause(Kind, KindLoc, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'schedule' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPScheduleClause(OpenMPScheduleClauseKind Kind, + SourceLocation KindLoc, + Expr *ChunkSize, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPScheduleClause(Kind, KindLoc, ChunkSize, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'dist_schedule' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind, + SourceLocation KindLoc, + Expr *ChunkSize, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDistScheduleClause(Kind, KindLoc, ChunkSize, + StartLoc, EndLoc); } /// \brief Build a new OpenMP 'private' clause. @@ -1317,30 +1410,311 @@ /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPPrivateClause(VarList, + StartLoc, 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 VarList, + OMPClause *RebuildOMPFirstPrivateClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPFirstPrivateClause(VarList, + StartLoc, EndLoc); } + /// \brief Build a new OpenMP 'shared' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPSharedClause(VarList, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'copyin' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCopyinClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCopyinClause(VarList, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'copyprivate' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCopyPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCopyPrivateClause(VarList, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'lastprivate' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPLastPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPLastPrivateClause(VarList, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'reduction' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPReductionClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPReductionClauseOperator Op, + CXXScopeSpec &SS, + DeclarationNameInfo OpName) { + return getSema().ActOnOpenMPReductionClause(VarList, + StartLoc, EndLoc, Op, + SS, OpName); + } + + /// \brief Build a new OpenMP 'depend' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDependClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPDependClauseType Ty, + SourceLocation TyLoc) { + return getSema().ActOnOpenMPDependClause(VarList, StartLoc, EndLoc, Ty, + TyLoc); + } + + /// \brief Build a new OpenMP 'map' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPMapClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + OpenMPMapClauseKind Kind, + SourceLocation KindLoc) { + return getSema().ActOnOpenMPMapClause(VarList, StartLoc, EndLoc, Kind, + KindLoc); + } + + /// \brief Build a new OpenMP 'to' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPToClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPToClause(VarList, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'from' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFromClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFromClause(VarList, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'ordered' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPOrderedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPOrderedClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'nowait' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNowaitClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNowaitClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'untied' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUntiedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPUntiedClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'mergeable' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPMergeableClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPMergeableClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'read' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPReadClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'write' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPWriteClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'update' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPUpdateClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'capture' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPCaptureClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'seq_cst' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPSeqCstClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPSeqCstClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'inbranch' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPInBranchClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'notinbranch' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNotInBranchClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNotInBranchClause(StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP list of vars for 'flush' directive. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFlushClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFlushClause(VarList, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP list of vars for 'uniform' directive. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUniformClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPUniformClause(VarList, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'safelen' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPSafelenClause(Expr *Len, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPSafelenClause(Len, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'simdlen' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPSimdlenClause(Expr *Len, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPSimdlenClause(Len, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'num_teams' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNumTeamsClause(Expr *NumTeams, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNumTeamsClause(NumTeams, StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'thread_limit' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPThreadLimitClause(Expr *ThreadLimit, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPThreadLimitClause(ThreadLimit, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'linear' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPLinearClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Step, + SourceLocation StepLoc) { + return getSema().ActOnOpenMPLinearClause(VarList, StartLoc, EndLoc, + Step, StepLoc); + } + + /// \brief Build a new OpenMP 'aligned' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAlignedClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation EndLoc, + Expr *Alignment, + SourceLocation AlignmentLoc) { + return getSema().ActOnOpenMPAlignedClause(VarList, StartLoc, EndLoc, + Alignment, AlignmentLoc); } /// \brief Rebuild the operand to an Objective-C \@synchronized statement. @@ -1605,6 +1979,17 @@ RBracketLoc); } + /// \brief Build a new CEAN index expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCEANIndexExpr(Expr *Base, Expr *LowerBound, + SourceLocation ColonLoc, + Expr *Length) { + return getSema().ActOnCEANIndexExpr(0, Base, LowerBound, ColonLoc, + Length); + } + /// \brief Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -6130,7 +6515,7 @@ return FinishCXXForRangeStmt(NewStmt.get(), Body.get()); } -template +template StmtResult TreeTransform::TransformMSDependentExistsStmt( MSDependentExistsStmt *S) { @@ -6274,63 +6659,495 @@ return getDerived().TransformSEHExceptStmt(cast(Handler)); } -template -StmtResult -TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { - DeclarationNameInfo DirName; - getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0); - +template +StmtResult TreeTransform::TransformOMPExecutableDirective( + OMPExecutableDirective *D) { // Transform the clauses - llvm::SmallVector TClauses; + llvm::SmallVector TClauses; ArrayRef Clauses = D->clauses(); TClauses.reserve(Clauses.size()); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) { if (*I) { OMPClause *Clause = getDerived().TransformOMPClause(*I); - if (!Clause) { - getSema().EndOpenMPDSABlock(0); + if (!Clause) return StmtError(); - } TClauses.push_back(Clause); - } - else { + } else { TClauses.push_back(0); } } - if (!D->getAssociatedStmt()) { - getSema().EndOpenMPDSABlock(0); - return StmtError(); - } - StmtResult AssociatedStmt = - getDerived().TransformStmt(D->getAssociatedStmt()); - if (AssociatedStmt.isInvalid()) { - getSema().EndOpenMPDSABlock(0); + StmtResult AssociatedStmt; + if (D->hasAssociatedStmt() && D->getAssociatedStmt()) { + CapturedStmt *S = cast(D->getAssociatedStmt()); + SourceLocation Loc = S->getLocStart(); + unsigned NumParams = S->getCapturedDecl()->getNumParams(); + getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/ 0, + S->getCapturedRegionKind(), NumParams); + StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt()); + + if (Body.isInvalid()) { + getSema().ActOnCapturedRegionError(); + return StmtError(); + } + + getSema().MarkOpenMPClauses(TClauses); + AssociatedStmt = getSema().ActOnCapturedRegionEnd(Body.take()); + if (!AssociatedStmt.isUsable()) + return StmtError(); + } else if (D->hasAssociatedStmt()) return StmtError(); + Stmt *AStmt = AssociatedStmt.take(); + DeclarationNameInfo DirName; + if (D->getDirectiveKind() == OMPD_critical) { + DirName = cast(D)->getDirectiveName(); + DirName = getDerived().TransformDeclarationNameInfo(DirName); + } + OpenMPDirectiveKind ConstructType = OMPD_unknown; + if (D->getDirectiveKind() == OMPD_cancel) { + ConstructType = cast(D)->getConstructType(); + } else if (D->getDirectiveKind() == OMPD_cancellation_point) { + ConstructType = cast(D)->getConstructType(); } - StmtResult Res = getDerived().RebuildOMPParallelDirective(TClauses, - AssociatedStmt.take(), - D->getLocStart(), - D->getLocEnd()); - getSema().EndOpenMPDSABlock(Res.get()); - return Res; + return getDerived().RebuildOMPExecutableDirective( + D->getDirectiveKind(), DirName, TClauses, AStmt, D->getLocStart(), + D->getLocEnd(), ConstructType); } -template -OMPClause * -TreeTransform::TransformOMPDefaultClause(OMPDefaultClause *C) { - return getDerived().RebuildOMPDefaultClause(C->getDefaultKind(), - C->getDefaultKindKwLoc(), - C->getLocStart(), - C->getLParenLoc(), - C->getLocEnd()); +template +StmtResult +TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; } -template -OMPClause * +template +StmtResult TreeTransform::TransformOMPParallelForDirective( + OMPParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPParallelForSimdDirective( + OMPParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for_simd, DirName, + 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPParallelSectionsDirective( + OMPParallelSectionsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_sections, DirName, + 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPForDirective(OMPForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPSimdDirective(OMPSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPForSimdDirective(OMPForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_for_simd, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPDistributeSimdDirective( + OMPDistributeSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_simd, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPDistributeParallelForDirective( + OMPDistributeParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_parallel_for, + DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPDistributeParallelForSimdDirective( + OMPDistributeParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_parallel_for_simd, + DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPSectionsDirective(OMPSectionsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPSectionDirective(OMPSectionDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPSingleDirective(OMPSingleDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPTaskDirective(OMPTaskDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_task, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPTaskyieldDirective( + OMPTaskyieldDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_taskyield, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPMasterDirective(OMPMasterDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_master, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPCriticalDirective(OMPCriticalDirective *D) { + getDerived().getSema().StartOpenMPDSABlock(OMPD_critical, + D->getDirectiveName(), 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPBarrierDirective(OMPBarrierDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_barrier, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_taskwait, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPTaskgroupDirective( + OMPTaskgroupDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_taskgroup, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPAtomicDirective(OMPAtomicDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPFlushDirective(OMPFlushDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_flush, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPOrderedDirective(OMPOrderedDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPTeamsDirective(OMPTeamsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_teams, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPDistributeDirective( + OMPDistributeDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPCancelDirective(OMPCancelDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_cancel, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPCancellationPointDirective( + OMPCancellationPointDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_cancellation_point, DirName, + 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPTargetDirective(OMPTargetDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPTargetDataDirective( + OMPTargetDataDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_data, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPTargetUpdateDirective( + OMPTargetUpdateDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_update, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult TreeTransform::TransformOMPTargetTeamsDirective( + OMPTargetTeamsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_teams, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +OMPClause *TreeTransform::TransformOMPIfClause(OMPIfClause *C) { + // Transform condition. + ExprResult E = getDerived().TransformExpr(C->getCondition()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPIfClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPFinalClause(OMPFinalClause *C) { + // Transform condition. + ExprResult E = getDerived().TransformExpr(C->getCondition()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPFinalClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) { + // Transform expression. + ExprResult E = getDerived().TransformExpr(C->getNumThreads()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPNumThreadsClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPDeviceClause(OMPDeviceClause *C) { + // Transform expression. + ExprResult E = getDerived().TransformExpr(C->getDevice()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPDeviceClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPCollapseClause(OMPCollapseClause *C) { + // Transform expression. + ExprResult E = getDerived().TransformExpr(C->getNumForLoops()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPCollapseClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPDefaultClause(OMPDefaultClause *C) { + return getDerived().RebuildOMPDefaultClause(C->getDefaultKind(), + C->getDefaultKindLoc(), + C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPProcBindClause(OMPProcBindClause *C) { + return getDerived().RebuildOMPProcBindClause( + C->getThreadAffinity(), C->getThreadAffinityLoc(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPScheduleClause(OMPScheduleClause *C) { + // Transform expression. + ExprResult E; + if (C->getChunkSize()) { + E = getDerived().TransformExpr(C->getChunkSize()); + + if (E.isInvalid()) + return 0; + } + + return getDerived().RebuildOMPScheduleClause( + C->getScheduleKind(), C->getScheduleKindLoc(), E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPDistScheduleClause( + OMPDistScheduleClause *C) { + // Transform expression. + ExprResult E; + if (C->getDistChunkSize()) { + E = getDerived().TransformExpr(C->getDistChunkSize()); + + if (E.isInvalid()) + return 0; + } + + return getDerived().RebuildOMPDistScheduleClause( + C->getDistScheduleKind(), C->getDistScheduleKindLoc(), E.take(), + C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { - llvm::SmallVector Vars; + llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); @@ -6340,19 +7157,16 @@ return 0; Vars.push_back(EVar.take()); } - return getDerived().RebuildOMPPrivateClause(Vars, - C->getLocStart(), - C->getLParenLoc(), + return getDerived().RebuildOMPPrivateClause(Vars, C->getLocStart(), C->getLocEnd()); } -template -OMPClause * -TreeTransform::TransformOMPFirstprivateClause( - OMPFirstprivateClause *C) { - llvm::SmallVector Vars; +template +OMPClause *TreeTransform::TransformOMPFirstPrivateClause( + OMPFirstPrivateClause *C) { + llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(), + for (OMPFirstPrivateClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); I != E; ++I) { ExprResult EVar = getDerived().TransformExpr(cast(*I)); @@ -6360,16 +7174,14 @@ return 0; Vars.push_back(EVar.take()); } - return getDerived().RebuildOMPFirstprivateClause(Vars, - C->getLocStart(), - C->getLParenLoc(), + return getDerived().RebuildOMPFirstPrivateClause(Vars, C->getLocStart(), C->getLocEnd()); } -template +template OMPClause * TreeTransform::TransformOMPSharedClause(OMPSharedClause *C) { - llvm::SmallVector Vars; + llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (OMPSharedClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); @@ -6379,12 +7191,343 @@ return 0; Vars.push_back(EVar.take()); } - return getDerived().RebuildOMPSharedClause(Vars, - C->getLocStart(), - C->getLParenLoc(), + return getDerived().RebuildOMPSharedClause(Vars, C->getLocStart(), C->getLocEnd()); } +template +OMPClause * +TreeTransform::TransformOMPCopyinClause(OMPCopyinClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPCopyinClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPCopyinClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPCopyPrivateClause(OMPCopyPrivateClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPCopyPrivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPCopyPrivateClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPLastPrivateClause(OMPLastPrivateClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPLastPrivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPLastPrivateClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPReductionClause(OMPReductionClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPReductionClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + CXXScopeSpec SS; + SS.Adopt(C->getSpec()); + DeclarationNameInfo DNI = + getDerived().TransformDeclarationNameInfo(C->getOpName()); + return getDerived().RebuildOMPReductionClause( + Vars, C->getLocStart(), C->getLocEnd(), C->getOperator(), SS, DNI); +} + +template +OMPClause * +TreeTransform::TransformOMPDependClause(OMPDependClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPDependClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPDependClause( + Vars, C->getLocStart(), C->getLocEnd(), C->getType(), C->getTypeLoc()); +} + +template +OMPClause *TreeTransform::TransformOMPMapClause(OMPMapClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPMapClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPMapClause( + Vars, C->getLocStart(), C->getLocEnd(), C->getKind(), C->getKindLoc()); +} + +template +OMPClause *TreeTransform::TransformOMPToClause(OMPToClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPToClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPToClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPFromClause(OMPFromClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPFromClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPFromClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPOrderedClause(OMPOrderedClause *C) { + return getDerived().RebuildOMPOrderedClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPNowaitClause(OMPNowaitClause *C) { + return getDerived().RebuildOMPNowaitClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPUntiedClause(OMPUntiedClause *C) { + return getDerived().RebuildOMPUntiedClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPMergeableClause(OMPMergeableClause *C) { + return getDerived().RebuildOMPMergeableClause(C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPReadClause(OMPReadClause *C) { + return getDerived().RebuildOMPReadClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPWriteClause(OMPWriteClause *C) { + return getDerived().RebuildOMPWriteClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPUpdateClause(OMPUpdateClause *C) { + return getDerived().RebuildOMPUpdateClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPCaptureClause(OMPCaptureClause *C) { + return getDerived().RebuildOMPCaptureClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPSeqCstClause(OMPSeqCstClause *C) { + return getDerived().RebuildOMPSeqCstClause(C->getLocStart(), C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPInBranchClause(OMPInBranchClause *C) { + return getDerived().RebuildOMPInBranchClause(C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPNotInBranchClause(OMPNotInBranchClause *C) { + return getDerived().RebuildOMPNotInBranchClause(C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause *TreeTransform::TransformOMPFlushClause(OMPFlushClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPFlushClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPFlushClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPUniformClause(OMPUniformClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPUniformClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPUniformClause(Vars, C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPSafelenClause(OMPSafelenClause *C) { + // Transform length expression. + ExprResult E = getDerived().TransformExpr(C->getSafelen()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPSafelenClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPSimdlenClause(OMPSimdlenClause *C) { + // Transform length expression. + ExprResult E = getDerived().TransformExpr(C->getSimdlen()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPSimdlenClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPNumTeamsClause(OMPNumTeamsClause *C) { + // Transform the number-of-teams expession. + ExprResult E = getDerived().TransformExpr(C->getNumTeams()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPNumTeamsClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPThreadLimitClause(OMPThreadLimitClause *C) { + // Transform the thread-limit expression. + ExprResult E = getDerived().TransformExpr(C->getThreadLimit()); + + if (E.isInvalid()) + return 0; + + return getDerived().RebuildOMPThreadLimitClause(E.take(), C->getLocStart(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPLinearClause(OMPLinearClause *C) { + // Transform step expression. + ExprResult E = getDerived().TransformExpr(C->getStep()); + if (E.isInvalid()) + return 0; + + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPLinearClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPLinearClause( + Vars, C->getLocStart(), C->getLocEnd(), E.take(), C->getStepLoc()); +} + +template +OMPClause * +TreeTransform::TransformOMPAlignedClause(OMPAlignedClause *C) { + // Transform alignment expression. + ExprResult E = getDerived().TransformExpr(C->getAlignment()); + if (E.isInvalid()) + return 0; + + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPAlignedClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPAlignedClause( + Vars, C->getLocStart(), C->getLocEnd(), E.take(), C->getAlignmentLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -6723,6 +7866,31 @@ template ExprResult +TreeTransform::TransformCEANIndexExpr(CEANIndexExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + ExprResult LowerBound = getDerived().TransformExpr(E->getLowerBound()); + if (LowerBound.isInvalid()) + return ExprError(); + ExprResult Length = getDerived().TransformExpr(E->getLength()); + if (Length.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase() && + LowerBound.get() == E->getLowerBound() && + Length.get() == E->getLength()) + return SemaRef.Owned(E); + + return getDerived().RebuildCEANIndexExpr(Base.get(), + LowerBound.get(), + E->getColonLoc(), + Length.get()); +} + +template +ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { // Transform the callee. ExprResult Callee = getDerived().TransformExpr(E->getCallee()); @@ -9831,7 +10999,7 @@ /*TemplateArgs*/ 0); } -template +template StmtResult TreeTransform::TransformCapturedStmt(CapturedStmt *S) { SourceLocation Loc = S->getLocStart(); diff -uNr clang-3.4/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTCommon.cpp --- clang-3.4/lib/Serialization/ASTCommon.cpp 2013-10-22 22:17:46.000000000 -0400 +++ clang/lib/Serialization/ASTCommon.cpp 2014-05-19 19:58:57.000000000 -0400 @@ -211,6 +211,9 @@ case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareSimd: + case Decl::OMPDeclareTarget: return false; } diff -uNr clang-3.4/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTReaderDecl.cpp --- clang-3.4/lib/Serialization/ASTReaderDecl.cpp 2013-11-03 20:48:18.000000000 -0500 +++ clang/lib/Serialization/ASTReaderDecl.cpp 2014-06-01 09:40:40.000000000 -0400 @@ -35,6 +35,7 @@ namespace clang { class ASTDeclReader : public DeclVisitor { + friend class OMPClauseReader; ASTReader &Reader; ModuleFile &F; const DeclID ThisDeclID; @@ -314,6 +315,9 @@ void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); }; } @@ -1934,6 +1938,52 @@ D->setVars(Vars); } +void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitDecl(D); + D->setDeclName(Reader.ReadDeclarationName(F, Record, Idx)); + unsigned NumTypes = D->datalist_size(); + SmallVector Data; + Data.reserve(NumTypes); + for (unsigned i = 0; i != NumTypes; ++i) { + QualType QTy = Reader.readType(F, Record, Idx); + SourceRange SR = Reader.ReadSourceRange(F, Record, Idx); + Expr *E1 = Reader.ReadExpr(F); + Expr *E2 = Reader.ReadExpr(F); + Data.push_back(OMPDeclareReductionDecl::ReductionData(QTy, SR, E1, E2)); + } + D->setData(Data); +} + +void ASTDeclReader::VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D) { + VisitDecl(D); + unsigned NumVariants = D->simd_variants_size(); + unsigned NumClauses = D->clauses_size(); + if (NumClauses > 0) { + SmallVector Clauses; + OMPClauseReader ClauseReader(Reader, Reader.getContext(), Record, Idx, F); + for (unsigned i = 0; i != NumClauses; ++i) { + Clauses.push_back(ClauseReader.readClause()); + } + D->setClauses(Clauses); + } + if (NumVariants > 0) { + SmallVector SimdVariants; + for (unsigned i = 0; i != NumVariants; ++i) { + SourceRange SR = Reader.ReadSourceRange(F, Record, Idx); + unsigned BeginIdx = Record[Idx++]; + unsigned EndIdx = Record[Idx++]; + SimdVariants.push_back(OMPDeclareSimdDecl::SimdVariant( + SR, BeginIdx, EndIdx)); + } + D->setVariants(SimdVariants); + } + D->setFunction(ReadDeclAs(Record, Idx)); +} + +void ASTDeclReader::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + VisitDecl(D); +} + //===----------------------------------------------------------------------===// // Attribute Reading //===----------------------------------------------------------------------===// @@ -1981,7 +2031,11 @@ if (isa(D) || isa(D) || - isa(D)) + isa(D) || + isa(D) || + isa(D) || + isa(D) || + isa(D)) return true; if (VarDecl *Var = dyn_cast(D)) return Var->isFileVarDecl() && @@ -2565,6 +2619,19 @@ case DECL_OMP_THREADPRIVATE: D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); break; + case DECL_OMP_DECLAREREDUCTION: + D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; + case DECL_OMP_DECLARESIMD: { + unsigned NumVariants = Record[Idx++]; + unsigned NumClauses = Record[Idx++]; + D = OMPDeclareSimdDecl::CreateDeserialized( + Context, ID, NumVariants, NumClauses); + } + break; + case DECL_OMP_DECLARETARGET: + D = OMPDeclareTargetDecl::CreateDeserialized(Context, ID); + break; case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; diff -uNr clang-3.4/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTReaderStmt.cpp --- clang-3.4/lib/Serialization/ASTReaderStmt.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/lib/Serialization/ASTReaderStmt.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -588,6 +588,16 @@ E->setLHS(Reader.ReadSubExpr()); E->setRHS(Reader.ReadSubExpr()); E->setRBracketLoc(ReadSourceLocation(Record, Idx)); + if (CEANIndexExpr *CIE = dyn_cast_or_null(E->getIdx())) + CIE->setBase(E->getBase()); +} + +void ASTStmtReader::VisitCEANIndexExpr(CEANIndexExpr *E) { + VisitExpr(E); + E->setBase(0); + E->setLowerBound(Reader.ReadSubExpr()); + E->setColonLoc(ReadSourceLocation(Record, Idx)); + E->setLength(Reader.ReadSubExpr()); } void ASTStmtReader::VisitCallExpr(CallExpr *E) { @@ -1670,101 +1680,867 @@ //===----------------------------------------------------------------------===// // OpenMP Clauses. //===----------------------------------------------------------------------===// - -namespace clang { -class OMPClauseReader : public OMPClauseVisitor { - ASTStmtReader *Reader; - ASTContext &Context; - const ASTReader::RecordData &Record; - unsigned &Idx; -public: - OMPClauseReader(ASTStmtReader *R, ASTContext &C, - const ASTReader::RecordData &Record, unsigned &Idx) - : Reader(R), Context(C), Record(Record), Idx(Idx) { } -#define OPENMP_CLAUSE(Name, Class) \ - void Visit##Class(Class *S); -#include "clang/Basic/OpenMPKinds.def" - OMPClause *readClause(); -}; -} - OMPClause *OMPClauseReader::readClause() { OMPClause *C; switch (Record[Idx++]) { + case OMPC_if: + C = new (Context) OMPIfClause(); + break; + case OMPC_final: + C = new (Context) OMPFinalClause(); + break; + case OMPC_num_threads: + C = new (Context) OMPNumThreadsClause(); + break; + case OMPC_num_teams: + C = new (Context) OMPNumTeamsClause(); + break; + case OMPC_thread_limit: + C = new (Context) OMPThreadLimitClause(); + break; + case OMPC_collapse: + C = new (Context) OMPCollapseClause(); + break; + case OMPC_device: + C = new (Context) OMPDeviceClause(); + break; case OMPC_default: C = new (Context) OMPDefaultClause(); break; + case OMPC_proc_bind: + C = new (Context) OMPProcBindClause(); + break; + case OMPC_schedule: + C = new (Context) OMPScheduleClause(); + break; + case OMPC_dist_schedule: + C = new (Context) OMPDistScheduleClause(); + break; case OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); break; case OMPC_firstprivate: - C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]); + C = OMPFirstPrivateClause::CreateEmpty(Context, Record[Idx++]); break; case OMPC_shared: C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_copyin: + C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_copyprivate: + C = OMPCopyPrivateClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_lastprivate: + C = OMPLastPrivateClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_reduction: + C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_ordered: + C = new (Context) OMPOrderedClause(); + break; + case OMPC_nowait: + C = new (Context) OMPNowaitClause(); + break; + case OMPC_untied: + C = new (Context) OMPUntiedClause(); + break; + case OMPC_mergeable: + C = new (Context) OMPMergeableClause(); + break; + case OMPC_read: + C = new (Context) OMPReadClause(); + break; + case OMPC_write: + C = new (Context) OMPWriteClause(); + break; + case OMPC_update: + C = new (Context) OMPUpdateClause(); + break; + case OMPC_capture: + C = new (Context) OMPCaptureClause(); + break; + case OMPC_seq_cst: + C = new (Context) OMPSeqCstClause(); + break; + case OMPC_inbranch: + C = new (Context) OMPInBranchClause(); + break; + case OMPC_notinbranch: + C = new (Context) OMPNotInBranchClause(); + break; + case OMPC_flush: + C = OMPFlushClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_depend: + C = OMPDependClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_map: + C = OMPMapClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_to: + C = OMPToClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_from: + C = OMPFromClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_safelen: + C = new (Context) OMPSafelenClause(); + break; + case OMPC_simdlen: + C = new (Context) OMPSimdlenClause(); + break; + case OMPC_linear: + C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_aligned: + C = OMPAlignedClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_uniform: + C = OMPUniformClause::CreateEmpty(Context, Record[Idx++]); + break; + default: + assert(0 && "Unknown clause!"); + return 0; } Visit(C); - C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); - C->setLocEnd(Reader->ReadSourceLocation(Record, Idx)); - + C->setLocStart(this->ReadSourceLocation(Record, Idx)); + C->setLocEnd(this->ReadSourceLocation(Record, Idx)); return C; } +void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { + C->setCondition(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) { + C->setCondition(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + C->setNumThreads(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) { + C->setNumForLoops(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { + C->setDevice(Reader.ReadSubExpr()); +} + void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { C->setDefaultKind( static_cast(Record[Idx++])); - C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); - C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setDefaultKindLoc(this->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { + C->setThreadAffinity( + static_cast(Record[Idx++])); + C->setThreadAffinityLoc(this->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) { + C->setScheduleKind( + static_cast(Record[Idx++])); + C->setScheduleKindLoc(this->ReadSourceLocation(Record, Idx)); + C->setChunkSize(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + C->setDistScheduleKind( + static_cast(Record[Idx++])); + C->setDistScheduleKindLoc(this->ReadSourceLocation(Record, Idx)); + C->setDistChunkSize(Reader.ReadSubExpr()); } void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { - C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) - Vars.push_back(Reader->Reader.ReadSubExpr()); - C->setVarRefs(Vars); + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); + SmallVector Inits; + Inits.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Inits.push_back(Reader.ReadSubExpr()); + } + C->setDefaultInits(Inits); } -void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { - C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +void OMPClauseReader::VisitOMPFirstPrivateClause(OMPFirstPrivateClause *C) { unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) - Vars.push_back(Reader->Reader.ReadSubExpr()); - C->setVarRefs(Vars); + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); + SmallVector Vars1; + Vars1.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars(Vars1); + SmallVector Inits; + Inits.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Inits.push_back(Reader.ReadSubExpr()); + } + C->setInits(Inits); +} + +void OMPClauseReader::VisitOMPLastPrivateClause(OMPLastPrivateClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars.push_back(cast(E)); + else + Vars.push_back(0); + } + C->setVars(Vars); + SmallVector Vars1; + Vars1.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars1(Vars1); + Vars1.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars2(Vars1); + SmallVector Inits; + Inits.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Inits.push_back(Reader.ReadSubExpr()); + } + C->setDefaultInits(Inits); + SmallVector Assignments; + Assignments.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Assignments.push_back(Reader.ReadSubExpr()); + } + C->setAssignments(Assignments); } void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { - C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) - Vars.push_back(Reader->Reader.ReadSubExpr()); - C->setVarRefs(Vars); + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); +} + +void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); + SmallVector Vars1; + Vars1.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars1(Vars1); + Vars1.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars2(Vars1); + SmallVector Assignments; + Assignments.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Assignments.push_back(Reader.ReadSubExpr()); + } + C->setAssignments(Assignments); +} + +void OMPClauseReader::VisitOMPCopyPrivateClause(OMPCopyPrivateClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); + SmallVector Vars1; + Vars1.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars1(Vars1); + Vars1.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + if (Expr *E = Reader.ReadSubExpr()) + Vars1.push_back(cast(E)); + else + Vars1.push_back(0); + } + C->setPseudoVars2(Vars1); + SmallVector Assignments; + Assignments.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Assignments.push_back(Reader.ReadSubExpr()); + } + C->setAssignments(Assignments); +} + +void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { + C->setOperator( + static_cast(Record[Idx++])); + NestedNameSpecifierLoc NNSL = + Reader.ReadNestedNameSpecifierLoc(this->MFile, Record, Idx); + DeclarationNameInfo DNI; + Reader.ReadDeclarationNameInfo(this->MFile, DNI, Record, Idx); + C->setOpName(NNSL, DNI); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setVars(Vars); + SmallVector OpExprs; + OpExprs.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + OpExprs.push_back(Reader.ReadSubExpr()); + } + C->setOpExprs(OpExprs); + OpExprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + OpExprs.push_back(Reader.ReadSubExpr()); + } + C->setHelperParameters1st(OpExprs); + OpExprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + OpExprs.push_back(Reader.ReadSubExpr()); + } + C->setHelperParameters2nd(OpExprs); + SmallVector Inits; + Inits.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Inits.push_back(Reader.ReadSubExpr()); + } + C->setDefaultInits(Inits); +} + +void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) { } + +void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *C) { } + +void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *C) { } + +void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *C) { } + +void OMPClauseReader::VisitOMPReadClause(OMPReadClause *C) { } + +void OMPClauseReader::VisitOMPWriteClause(OMPWriteClause *C) { } + +void OMPClauseReader::VisitOMPUpdateClause(OMPUpdateClause *C) { } + +void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *C) { } + +void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *C) { } + +void OMPClauseReader::VisitOMPInBranchClause(OMPInBranchClause *C) { } + +void OMPClauseReader::VisitOMPNotInBranchClause(OMPNotInBranchClause *C) { } + +void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + C->setVars(Vars); +} + +void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { + C->setType( + static_cast(Record[Idx++])); + C->setTypeLoc(this->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setVars(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setBegins(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setSizeInBytes(Vars); +} + +void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { + C->setKind( + static_cast(Record[Idx++])); + C->setKindLoc(this->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setVars(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeSizesEndAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingSizesEndAddresses(Vars); +} + +void OMPClauseReader::VisitOMPToClause(OMPToClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setVars(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeSizesEndAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingSizesEndAddresses(Vars); +} + +void OMPClauseReader::VisitOMPFromClause(OMPFromClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setVars(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setWholeSizesEndAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingStartAddresses(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader.ReadSubExpr()); + } + C->setCopyingSizesEndAddresses(Vars); +} + +void OMPClauseReader::VisitOMPUniformClause(OMPUniformClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadExpr(MFile)); + C->setVars(Vars); +} + +void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) { + C->setSafelen(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + C->setSimdlen(Reader.ReadExpr(MFile)); +} + +void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + C->setNumTeams(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + C->setThreadLimit(Reader.ReadSubExpr()); +} + +void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadExpr(MFile)); + C->setVars(Vars); + C->setStep(Reader.ReadExpr(MFile)); +} + +void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) { + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadExpr(MFile)); + C->setVars(Vars); + C->setAlignment(Reader.ReadExpr(MFile)); } //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { - VisitStmt(E); - ++Idx; E->setLocStart(ReadSourceLocation(Record, Idx)); E->setLocEnd(ReadSourceLocation(Record, Idx)); - OMPClauseReader ClauseReader(this, Reader.getContext(), Record, Idx); - SmallVector Clauses; - for (unsigned i = 0; i < E->getNumClauses(); ++i) + OMPClauseReader ClauseReader(Reader, Reader.getContext(), Record, Idx, F); + SmallVector Clauses; + for (unsigned i = 0, N = E->getNumClauses(); i < N; ++i) Clauses.push_back(ClauseReader.readClause()); - E->setClauses(Clauses); - E->setAssociatedStmt(Reader.ReadSubStmt()); + if (E->getNumClauses() > 0) + E->setClauses(Clauses); + if (E->hasAssociatedStmt()) + E->setAssociatedStmt(Reader.ReadSubStmt()); } void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPForSimdDirective(OMPForSimdDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPParallelForSimdDirective(OMPParallelForSimdDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPDistributeSimdDirective(OMPDistributeSimdDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPDistributeParallelForDirective(OMPDistributeParallelForDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + D->setLowerBound(Reader.ReadSubExpr()); + D->setUpperBound(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPDistributeParallelForSimdDirective(OMPDistributeParallelForSimdDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + D->setFinal(Reader.ReadSubExpr()); + D->setLowerBound(Reader.ReadSubExpr()); + D->setUpperBound(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPParallelSectionsDirective(OMPParallelSectionsDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPSectionDirective(OMPSectionDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPSingleDirective(OMPSingleDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPMasterDirective(OMPMasterDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); + ReadDeclarationNameInfo(D->DirName, Record, Idx); +} + +void ASTStmtReader::VisitOMPBarrierDirective(OMPBarrierDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); + D->setV(Reader.ReadSubExpr()); + D->setX(Reader.ReadSubExpr()); + D->setExpr(Reader.ReadSubExpr()); + D->setOperator(static_cast(Record[Idx++])); + D->setCaptureAfter(Record[Idx++] != 0); + D->setReversed(Record[Idx++] != 0); +} + +void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTeamsDirective(OMPTeamsDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); + D->setNewIterVar(Reader.ReadSubExpr()); + D->setNewIterEnd(Reader.ReadSubExpr()); + D->setInit(Reader.ReadSubExpr()); + unsigned NumVars = D->getCollapsedNumber(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader.ReadSubExpr()); + D->setCounters(Vars); +} + +void ASTStmtReader::VisitOMPCancelDirective(OMPCancelDirective *D) { + VisitStmt(D); + Idx += 2; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPCancellationPointDirective( + OMPCancellationPointDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { + VisitStmt(D); + ++Idx; VisitOMPExecutableDirective(D); } @@ -2000,6 +2776,10 @@ S = new (Context) ArraySubscriptExpr(Empty); break; + case EXPR_CEAN_INDEX: + S = new (Context) CEANIndexExpr(Empty); + break; + case EXPR_CALL: S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty); break; @@ -2241,12 +3021,136 @@ 0); break; case STMT_OMP_PARALLEL_DIRECTIVE: - S = - OMPParallelDirective::CreateEmpty(Context, - Record[ASTStmtReader::NumStmtFields], - Empty); + S = OMPParallelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; - + case STMT_OMP_FOR_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPForDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_PARALLEL_FOR_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPParallelForDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_SIMD_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPSimdDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_FOR_SIMD_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPForSimdDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPParallelForSimdDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPDistributeSimdDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPDistributeParallelForDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPDistributeParallelForSimdDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_SECTIONS_DIRECTIVE: + S = OMPSectionsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE: + S = OMPParallelSectionsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_SECTION_DIRECTIVE: + S = OMPSectionDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_SINGLE_DIRECTIVE: + S = OMPSingleDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TASK_DIRECTIVE: + S = OMPTaskDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TASKYIELD_DIRECTIVE: + S = OMPTaskyieldDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_MASTER_DIRECTIVE: + S = OMPMasterDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_CRITICAL_DIRECTIVE: + S = OMPCriticalDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_BARRIER_DIRECTIVE: + S = OMPBarrierDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_TASKWAIT_DIRECTIVE: + S = OMPTaskwaitDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_TASKGROUP_DIRECTIVE: + S = OMPTaskgroupDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_ATOMIC_DIRECTIVE: + S = OMPAtomicDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_FLUSH_DIRECTIVE: + S = OMPFlushDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_ORDERED_DIRECTIVE: + S = OMPOrderedDirective::CreateEmpty(Context, Empty); + break; + case STMT_OMP_TEAMS_DIRECTIVE: + S = OMPTeamsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TARGET_TEAMS_DIRECTIVE: + S = OMPTargetTeamsDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_DISTRIBUTE_DIRECTIVE: { + unsigned Val = Record[ASTStmtReader::NumStmtFields]; + S = OMPDistributeDirective::CreateEmpty( + Context, Val, Record[ASTStmtReader::NumStmtFields + 1], Empty); + } break; + case STMT_OMP_CANCEL_DIRECTIVE: + S = OMPCancelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], + static_cast( + Record[ASTStmtReader::NumStmtFields + 1]), + Empty); + break; + case STMT_OMP_CANCELLATION_POINT_DIRECTIVE: + S = OMPCancellationPointDirective::CreateEmpty( + Context, static_cast( + Record[ASTStmtReader::NumStmtFields]), + Empty); + break; + case STMT_OMP_TARGET_DIRECTIVE: + S = OMPTargetDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TARGET_DATA_DIRECTIVE: + S = OMPTargetDataDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TARGET_UPDATE_DIRECTIVE: + S = OMPTargetUpdateDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(Context, Empty); break; diff -uNr clang-3.4/lib/Serialization/ASTWriterDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp --- clang-3.4/lib/Serialization/ASTWriterDecl.cpp 2013-10-25 17:44:50.000000000 -0400 +++ clang/lib/Serialization/ASTWriterDecl.cpp 2014-06-01 09:40:40.000000000 -0400 @@ -32,7 +32,7 @@ namespace clang { class ASTDeclWriter : public DeclVisitor { - + friend class OMPClauseWriter; ASTWriter &Writer; ASTContext &Context; typedef ASTWriter::RecordData RecordData; @@ -130,6 +130,9 @@ void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); }; } @@ -1436,6 +1439,47 @@ Code = serialization::DECL_OMP_THREADPRIVATE; } +void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + Record.push_back(D->datalist_size()); + VisitDecl(D); + Writer.AddDeclarationName(D->getDeclName(), Record); + for (OMPDeclareReductionDecl::datalist_iterator I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + Writer.AddTypeRef(I->QTy, Record); + Writer.AddSourceRange(I->TyRange, Record); + Writer.AddStmt(I->CombinerFunction); + Writer.AddStmt(I->InitFunction); + } + Code = serialization::DECL_OMP_DECLAREREDUCTION; +} + +void ASTDeclWriter::VisitOMPDeclareSimdDecl(OMPDeclareSimdDecl *D) { + Record.push_back(D->simd_variants_size()); + Record.push_back(D->clauses_size()); + VisitDecl(D); + OMPClauseWriter ClauseWriter(Writer, Record); + for (OMPDeclareSimdDecl::clauses_iterator IC = D->clauses_begin(), + EC = D->clauses_end(); IC != EC; ++IC) { + // Save the clause. + ClauseWriter.writeClause(*IC); + } + for (OMPDeclareSimdDecl::simd_variants_iterator + IV = D->simd_variants_begin(), + EV = D->simd_variants_end(); IV != EV; ++IV) { + // Save the variant info. + Writer.AddSourceRange(IV->SrcRange, Record); + Record.push_back(IV->BeginIdx); + Record.push_back(IV->EndIdx); + } + Writer.AddDeclRef(D->getFunction(), Record); + Code = serialization::DECL_OMP_DECLARESIMD; +} + +void ASTDeclWriter::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + VisitDecl(D); + Code = serialization::DECL_OMP_DECLARETARGET; +} //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// @@ -1818,7 +1862,9 @@ // implementation container always is. // File scoped assembly or obj-c implementation must be seen. - if (isa(D) || isa(D)) + if (isa(D) || isa(D) || + isa(D) || isa(D) || + isa(D) || isa(D)) return true; return Context.DeclMustBeEmitted(D); diff -uNr clang-3.4/lib/Serialization/ASTWriterStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp --- clang-3.4/lib/Serialization/ASTWriterStmt.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/lib/Serialization/ASTWriterStmt.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -515,6 +515,14 @@ Code = serialization::EXPR_ARRAY_SUBSCRIPT; } +void ASTStmtWriter::VisitCEANIndexExpr(CEANIndexExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getLowerBound()); + Writer.AddSourceLocation(E->getColonLoc(), Record); + Writer.AddStmt(E->getLength()); + Code = serialization::EXPR_CEAN_INDEX; +} + void ASTStmtWriter::VisitCallExpr(CallExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); @@ -1676,80 +1684,657 @@ // OpenMP Clauses. //===----------------------------------------------------------------------===// -namespace clang { -class OMPClauseWriter : public OMPClauseVisitor { - ASTStmtWriter *Writer; - ASTWriter::RecordData &Record; -public: - OMPClauseWriter(ASTStmtWriter *W, ASTWriter::RecordData &Record) - : Writer(W), Record(Record) { } -#define OPENMP_CLAUSE(Name, Class) \ - void Visit##Class(Class *S); -#include "clang/Basic/OpenMPKinds.def" - void writeClause(OMPClause *C); -}; -} - void OMPClauseWriter::writeClause(OMPClause *C) { Record.push_back(C->getClauseKind()); Visit(C); - Writer->Writer.AddSourceLocation(C->getLocStart(), Record); - Writer->Writer.AddSourceLocation(C->getLocEnd(), Record); + Writer.AddSourceLocation(C->getLocStart(), Record); + Writer.AddSourceLocation(C->getLocEnd(), Record); +} + +void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { + Writer.AddStmt(C->getCondition()); +} + +void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) { + Writer.AddStmt(C->getCondition()); +} + +void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + Writer.AddStmt(C->getNumThreads()); +} + +void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) { + Writer.AddStmt(C->getNumForLoops()); +} + +void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) { + Writer.AddStmt(C->getDevice()); } void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { Record.push_back(C->getDefaultKind()); - Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); - Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record); + Writer.AddSourceLocation(C->getDefaultKindLoc(), Record); +} + +void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { + Record.push_back(C->getThreadAffinity()); + Writer.AddSourceLocation(C->getThreadAffinityLoc(), Record); +} + +void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) { + Record.push_back(C->getScheduleKind()); + Writer.AddSourceLocation(C->getScheduleKindLoc(), Record); + Writer.AddStmt(C->getChunkSize()); +} + +void OMPClauseWriter::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { + Record.push_back(C->getDistScheduleKind()); + Writer.AddSourceLocation(C->getDistScheduleKindLoc(), Record); + Writer.AddStmt(C->getDistChunkSize()); } void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); - Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); I != E; ++I) - Writer->Writer.AddStmt(*I); + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getDefaultInits().begin(), + E = C->getDefaultInits().end(); + I != E; ++I) + Writer.AddStmt(*I); } -void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { +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(), + for (OMPFirstPrivateClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); I != E; ++I) - Writer->Writer.AddStmt(*I); + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars().begin(), + E = C->getPseudoVars().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getInits().begin(), + E = C->getInits().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPLastPrivateClause(OMPLastPrivateClause *C) { + Record.push_back(C->varlist_size()); + for (OMPLastPrivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars1().begin(), + E = C->getPseudoVars1().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars2().begin(), + E = C->getPseudoVars2().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getDefaultInits().begin(), + E = C->getDefaultInits().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getAssignments().begin(), + E = C->getAssignments().end(); + I != E; ++I) + Writer.AddStmt(*I); } void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { Record.push_back(C->varlist_size()); - Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); for (OMPSharedClause::varlist_iterator I = C->varlist_begin(), E = C->varlist_end(); I != E; ++I) - Writer->Writer.AddStmt(*I); + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { + Record.push_back(C->varlist_size()); + for (OMPCopyinClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars1().begin(), + E = C->getPseudoVars1().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars2().begin(), + E = C->getPseudoVars2().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getAssignments().begin(), + E = C->getAssignments().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPCopyPrivateClause(OMPCopyPrivateClause *C) { + Record.push_back(C->varlist_size()); + for (OMPCopyPrivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars1().begin(), + E = C->getPseudoVars1().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getPseudoVars2().begin(), + E = C->getPseudoVars2().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getAssignments().begin(), + E = C->getAssignments().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getOperator()); + Writer.AddNestedNameSpecifierLoc(C->getSpec(), Record); + Writer.AddDeclarationNameInfo(C->getOpName(), Record); + for (OMPReductionClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getOpExprs().begin(), + E = C->getOpExprs().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getHelperParameters1st().begin(), + E = C->getHelperParameters1st().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getHelperParameters2nd().begin(), + E = C->getHelperParameters2nd().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getDefaultInits().begin(), + E = C->getDefaultInits().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) { } + +void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *C) { } + +void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *C) { } + +void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *C) { } + +void OMPClauseWriter::VisitOMPReadClause(OMPReadClause *C) { } + +void OMPClauseWriter::VisitOMPWriteClause(OMPWriteClause *C) { } + +void OMPClauseWriter::VisitOMPUpdateClause(OMPUpdateClause *C) { } + +void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *C) { } + +void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *C) { } + +void OMPClauseWriter::VisitOMPInBranchClause(OMPInBranchClause *C) { } + +void OMPClauseWriter::VisitOMPNotInBranchClause(OMPNotInBranchClause *C) { } + +void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) { + Record.push_back(C->varlist_size()); + for (OMPFlushClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getType()); + Writer.AddSourceLocation(C->getTypeLoc(), Record); + for (OMPDependClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (unsigned i = 0, e = C->varlist_size(); i != e; ++i) + Writer.AddStmt(C->getBegins(i)); + for (unsigned i = 0, e = C->varlist_size(); i != e; ++i) + Writer.AddStmt(C->getSizeInBytes(i)); +} + +void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getKind()); + Writer.AddSourceLocation(C->getKindLoc(), Record); + for (OMPMapClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeStartAddresses().begin(), + E = C->getWholeStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeSizesEndAddresses().begin(), + E = C->getWholeSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingStartAddresses().begin(), + E = C->getCopyingStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingSizesEndAddresses().begin(), + E = C->getCopyingSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPToClause(OMPToClause *C) { + Record.push_back(C->varlist_size()); + for (OMPToClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeStartAddresses().begin(), + E = C->getWholeStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeSizesEndAddresses().begin(), + E = C->getWholeSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingStartAddresses().begin(), + E = C->getCopyingStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingSizesEndAddresses().begin(), + E = C->getCopyingSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPFromClause(OMPFromClause *C) { + Record.push_back(C->varlist_size()); + for (OMPFromClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeStartAddresses().begin(), + E = C->getWholeStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getWholeSizesEndAddresses().begin(), + E = C->getWholeSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingStartAddresses().begin(), + E = C->getCopyingStartAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); + for (ArrayRef::iterator I = C->getCopyingSizesEndAddresses().begin(), + E = C->getCopyingSizesEndAddresses().end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPUniformClause(OMPUniformClause *C) { + Record.push_back(C->varlist_size()); + for (OMPUniformClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); +} + +void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) { + Writer.AddStmt(C->getSafelen()); +} + +void OMPClauseWriter::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + Writer.AddStmt(C->getSimdlen()); +} + +void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + Writer.AddStmt(C->getNumTeams()); +} + +void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + Writer.AddStmt(C->getThreadLimit()); +} + +void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { + Record.push_back(C->varlist_size()); + for (OMPLinearClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + Writer.AddStmt(C->getStep()); +} + +void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) { + Record.push_back(C->varlist_size()); + for (OMPAlignedClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + Writer.AddStmt(C->getAlignment()); } //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { - VisitStmt(E); - Record.push_back(E->getNumClauses()); Writer.AddSourceLocation(E->getLocStart(), Record); Writer.AddSourceLocation(E->getLocEnd(), Record); - OMPClauseWriter ClauseWriter(this, Record); - for (unsigned i = 0; i < E->getNumClauses(); ++i) { + OMPClauseWriter ClauseWriter(Writer, Record); + for (unsigned i = 0, N = E->getNumClauses(); i < N; ++i) { ClauseWriter.writeClause(E->getClause(i)); } - Writer.AddStmt(E->getAssociatedStmt()); + if (E->hasAssociatedStmt()) + Writer.AddStmt(E->getAssociatedStmt()); } void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE; } +void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_PARALLEL_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPForSimdDirective(OMPForSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPParallelForSimdDirective(OMPParallelForSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeSimdDirective(OMPDistributeSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_DISTRIBUTE_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeParallelForDirective(OMPDistributeParallelForDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + Writer.AddStmt(D->getLowerBound()); + Writer.AddStmt(D->getUpperBound()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeParallelForSimdDirective(OMPDistributeParallelForSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + Writer.AddStmt(D->getFinal()); + Writer.AddStmt(D->getLowerBound()); + Writer.AddStmt(D->getUpperBound()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPSectionsDirective(OMPSectionsDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_SECTIONS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPParallelSectionsDirective(OMPParallelSectionsDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPSectionDirective(OMPSectionDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_SECTION_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPSingleDirective(OMPSingleDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_SINGLE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TASK_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TASKYIELD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPMasterDirective(OMPMasterDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_MASTER_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Writer.AddDeclarationNameInfo(D->getDirectiveName(), Record); + Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPBarrierDirective(OMPBarrierDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_BARRIER_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TASKGROUP_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPAtomicDirective(OMPAtomicDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getV()); + Writer.AddStmt(D->getX()); + Writer.AddStmt(D->getExpr()); + Record.push_back(D->getOperator()); + Record.push_back(D->isCaptureAfter() ? 1 : 0); + Record.push_back(D->isReversed() ? 1 : 0); + Code = serialization::STMT_OMP_ATOMIC_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPFlushDirective(OMPFlushDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_FLUSH_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPOrderedDirective(OMPOrderedDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_ORDERED_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTeamsDirective(OMPTeamsDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TEAMS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_TEAMS_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Writer.AddStmt(D->getNewIterVar()); + Writer.AddStmt(D->getNewIterEnd()); + Writer.AddStmt(D->getInit()); + for (unsigned i = 0, N = D->getCollapsedNumber(); i < N; ++i) { + Writer.AddStmt(D->getCounters()[i]); + } + Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getConstructType()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_CANCEL_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPCancellationPointDirective( + OMPCancellationPointDirective *D) { + VisitStmt(D); + Record.push_back(D->getConstructType()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_CANCELLATION_POINT_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetDirective(OMPTargetDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_DATA_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTargetUpdateDirective(OMPTargetUpdateDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_UPDATE_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff -uNr clang-3.4/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- clang-3.4/lib/StaticAnalyzer/Core/ExprEngine.cpp 2013-12-09 13:37:00.000000000 -0500 +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -707,8 +707,38 @@ case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: - case Stmt::CapturedStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPForDirectiveClass: + case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelForSimdDirectiveClass: + case Stmt::OMPSimdDirectiveClass: + case Stmt::OMPForSimdDirectiveClass: + case Stmt::OMPDistributeSimdDirectiveClass: + case Stmt::OMPDistributeParallelForDirectiveClass: + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + case Stmt::OMPSectionsDirectiveClass: + case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPSectionDirectiveClass: + case Stmt::OMPSingleDirectiveClass: + case Stmt::OMPTaskDirectiveClass: + case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPMasterDirectiveClass: + case Stmt::OMPCriticalDirectiveClass: + case Stmt::OMPBarrierDirectiveClass: + case Stmt::OMPTaskwaitDirectiveClass: + case Stmt::OMPTaskgroupDirectiveClass: + case Stmt::OMPAtomicDirectiveClass: + case Stmt::OMPFlushDirectiveClass: + case Stmt::OMPOrderedDirectiveClass: + case Stmt::OMPTeamsDirectiveClass: + case Stmt::OMPTargetTeamsDirectiveClass: + case Stmt::OMPDistributeDirectiveClass: + case Stmt::OMPCancelDirectiveClass: + case Stmt::OMPCancellationPointDirectiveClass: + case Stmt::OMPTargetDirectiveClass: + case Stmt::OMPTargetDataDirectiveClass: + case Stmt::OMPTargetUpdateDirectiveClass: + case Stmt::CapturedStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -755,7 +785,8 @@ case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: case Stmt::AtomicExprClass: - // Fall through. + case Stmt::CEANIndexExprClass: + // Fall through. // Cases we intentionally don't evaluate, since they don't need // to be explicitly evaluated. diff -uNr clang-3.4/runtime/compiler-rt/Makefile clang/runtime/compiler-rt/Makefile --- clang-3.4/runtime/compiler-rt/Makefile 2013-11-15 18:12:44.000000000 -0500 +++ clang/runtime/compiler-rt/Makefile 2014-05-19 19:58:57.000000000 -0400 @@ -78,7 +78,7 @@ # support. RuntimeDirs := ifeq ($(OS),Darwin) -RuntimeDirs += darwin darwin_embedded +RuntimeDirs += darwin RuntimeLibrary.darwin.Configs := \ eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \ asan_osx_dynamic.dylib \ diff -uNr clang-3.4/test/Driver/Inputs/montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0/libgcc.a000644 clang/test/Driver/Inputs/montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0/libgcc.a000644 --- clang-3.4/test/Driver/Inputs/montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0/libgcc.a000644 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/Driver/Inputs/montavista_i686_tree/usr/lib/gcc/i686-montavista-linux/4.2.0/libgcc.a000644 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1 @@ +dummy file for gcc toolchain detection (libgcc.a) diff -uNr clang-3.4/test/OpenMP/array.c clang/test/OpenMP/array.c --- clang-3.4/test/OpenMP/array.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/array.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -verify -fopenmp -S -emit-llvm -o - -Wno-sizeof-array-argument %s +// expected-no-diagnostics + +int A[2][2] = {1, 2, 3, 4}; +void assert(int arg) { } +void f(int n, int B[n][n], int C[]) +{ + int D[2][2] = {1, 2, 3, 4}; + int E[n][n]; + assert(n >= 2); + E[1][1] = 4; +#pragma omp parallel firstprivate(B, C, D, E) + { + assert(sizeof(B) == sizeof(int (*)[n])); + assert(sizeof(C) == sizeof(int*)); + assert(sizeof(D) == 4 * sizeof(int)); + assert(sizeof(E) == n * n * sizeof(int)); + /* Private B and C have values of original B and C. */ + assert(&B[1][1] == &A[1][1]); + assert(&C[3] == &A[1][1]); + assert(D[1][1] == 4); + assert(E[1][1] == 4); + } +} +int main() { + f(2, A, A[0]); + return 0; +} + diff -uNr clang-3.4/test/OpenMP/atomic_ast_print.cpp clang/test/OpenMP/atomic_ast_print.cpp --- clang-3.4/test/OpenMP/atomic_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/atomic_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int a; +// CHECK: int a; +#pragma omp atomic +a++; +// CHECK-NEXT: #pragma omp atomic +// CHECK-NEXT: a++; +#pragma omp atomic update +a--; +// CHECK-NEXT: #pragma omp atomic update +// CHECK-NEXT: a--; +#pragma omp atomic seq_cst +++a; +// CHECK-NEXT: #pragma omp atomic seq_cst +// CHECK-NEXT: ++a; +#pragma omp atomic update seq_cst +--a; +// CHECK-NEXT: #pragma omp atomic update seq_cst +// CHECK-NEXT: --a; +#pragma omp atomic read +a = argc; +// CHECK-NEXT: #pragma omp atomic read +// CHECK-NEXT: a = argc; +#pragma omp atomic read seq_cst +argc = a; +// CHECK-NEXT: #pragma omp atomic read seq_cst +// CHECK-NEXT: argc = a; +#pragma omp atomic write +a = argc * 2; +// CHECK-NEXT: #pragma omp atomic write +// CHECK-NEXT: a = argc * 2; +#pragma omp atomic write seq_cst +argc = a - 3; +// CHECK-NEXT: #pragma omp atomic write seq_cst +// CHECK-NEXT: argc = a - 3; +#pragma omp atomic capture +a = argc++; +// CHECK-NEXT: #pragma omp atomic capture +// CHECK-NEXT: a = argc++; +#pragma omp atomic capture seq_cst +{argc = a; ++a;} +// CHECK-NEXT: #pragma omp atomic capture seq_cst +// CHECK-NEXT: { +// CHECK-NEXT: argc = a; +// CHECK-NEXT: ++a; +// CHECK-NEXT: } + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/atomic_messages.cpp clang/test/OpenMP/atomic_messages.cpp --- clang-3.4/test/OpenMP/atomic_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/atomic_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +struct S { + int s; + S operator+=(const S &s) { return *this; } +} s1, s2, s3; + +int main() { + int a, b, c; + int arr[5]; + + #pragma omp atomic + ; // expected-error {{expected expression statement for '#pragma omp atomic update'}} + #pragma omp atomic untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp atomic'}} + ++a; + #pragma omp atomic unknown // expected-warning {{extra tokens at the end of '#pragma omp atomic' are ignored}} + ++a; + #pragma omp atomic read write update capture // expected-error {{directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause}} + ++a; + #pragma omp atomic (name) // expected-warning {{extra tokens at the end of '#pragma omp atomic' are ignored}} + ++a; + #pragma omp atomic read + a = b; + #pragma omp atomic read seq_cst + a = b; + #pragma omp atomic read + s1 = s2; //expected-error {{statement form is not allowed for '#pragma omp atomic read'}} + #pragma omp atomic read + a = b + 5; //expected-error {{statement form is not allowed for '#pragma omp atomic read'}} + #pragma omp atomic read seq_cst + a = a; //expected-error {{statement form is not allowed for '#pragma omp atomic read'}} + #pragma omp atomic read + ++a; //expected-error {{statement form is not allowed for '#pragma omp atomic read'}} + + #pragma omp atomic write + a = b + 5; + #pragma omp atomic write seq_cst + a = b; + #pragma omp atomic write + s1 = s2; //expected-error {{statement form is not allowed for '#pragma omp atomic write'}} + #pragma omp atomic write seq_cst + a = a; //expected-error {{statement form is not allowed for '#pragma omp atomic write'}} + #pragma omp atomic write + ++a; //expected-error {{statement form is not allowed for '#pragma omp atomic write'}} + + #pragma omp atomic + ++a; + #pragma omp atomic update + b++; + #pragma omp atomic seq_cst + a -= b; + #pragma omp atomic update seq_cst + a = b & a; + #pragma omp atomic update seq_cst + a += b & b; + #pragma omp atomic + s1 += s2; //expected-error {{statement form is not allowed for '#pragma omp atomic update'}} + #pragma omp atomic + a %= b; //expected-error {{statement form is not allowed for '#pragma omp atomic update'}} + #pragma omp atomic update + a = a & int(a); //expected-error {{statement form is not allowed for '#pragma omp atomic update'}} + #pragma omp atomic seq_cst + a = b && a; //expected-error {{statement form is not allowed for '#pragma omp atomic update'}} + #pragma omp atomic update seq_cst + {a--;} //expected-error {{expected expression statement for '#pragma omp atomic update'}} + + #pragma omp atomic capture + b = ++a; + #pragma omp atomic capture + a = b++; + #pragma omp atomic capture seq_cst + c = a -= b; + #pragma omp atomic capture seq_cst + arr[1] = a = b & a; + #pragma omp atomic capture seq_cst + arr[1] = arr[1] &= b; //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture seq_cst + arr[1] = b &= arr[1]; //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + s3 = s1 += s2; //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + c = a %= b; //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + c = a = a & int(a); //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture seq_cst + c = a = b && a; //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + {c = b; ++b;} + #pragma omp atomic capture + {a = b++ + a; c = a;} + #pragma omp atomic capture seq_cst + {c = a; a -= b;} + #pragma omp atomic capture seq_cst + {a = b & a; c = a;} + #pragma omp atomic capture seq_cst + {a -= b + b; c = a;} + #pragma omp atomic capture + {s3 = s1; s1 += s2;} //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + {a %= b; c = a;} //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture + {c = a; a = a & int(a); c = a;} //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture seq_cst + {a = b && a; c = a;} //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + #pragma omp atomic capture seq_cst + {a = b & c; c = a;} //expected-error {{statement form is not allowed for '#pragma omp atomic capture'}} + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp atomic + { // expected-error {{expected expression statement for '#pragma omp atomic update'}} + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp atomic read + { // expected-error {{expected expression statement for '#pragma omp atomic read'}} + foo(); + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/barrier_ast_print.cpp clang/test/OpenMP/barrier_ast_print.cpp --- clang-3.4/test/OpenMP/barrier_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/barrier_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp barrier +// CHECK-NEXT: #pragma omp barrier + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/barrier_messages.cpp clang/test/OpenMP/barrier_messages.cpp --- clang-3.4/test/OpenMP/barrier_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/barrier_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main(int argc, char **argv) { + #pragma omp barrier + ; + #pragma omp barrier untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp barrier'}} + #pragma omp barrier unknown // expected-warning {{extra tokens at the end of '#pragma omp barrier' are ignored}} + if (argc) + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + if (argc) { + #pragma omp barrier + } + while (argc) + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + while (argc) { + #pragma omp barrier + } + do + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + while (argc); + do { + #pragma omp barrier + } + while (argc); + switch (argc) + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp barrier + } + switch (argc) { + #pragma omp barrier + case 1: + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + break; + default: { + #pragma omp barrier + } + break; + } + for (;;) + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + for (;;) { + #pragma omp barrier + } + label: + #pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be immediate substatement}} + label1: { + #pragma omp barrier + } + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside a worksharing region}} + } + #pragma omp sections + { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside a worksharing region}} + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside a worksharing region}} + } + #pragma omp task + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside explicit task region}} + } + #pragma omp master + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside a master region}} + } + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside a critical region}} + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) + #pragma omp ordered + { + foo(); + #pragma omp barrier // expected-error {{region cannot be closely nested inside an ordered region}} + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/cancel_ast_print.cpp clang/test/OpenMP/cancel_ast_print.cpp --- clang-3.4/test/OpenMP/cancel_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/cancel_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +int main (int argc, char **argv) { +// CHECK: int main(int argc, char **argv) { +#pragma omp parallel +{ +#pragma omp cancel parallel +} +// CHECK: #pragma omp parallel +// CHECK-NEXT: { +// CHECK-NEXT: #pragma omp cancel parallel +// CHECK-NEXT: } +#pragma omp sections +{ +#pragma omp cancel sections if (argc) +} +// CHECK-NEXT: #pragma omp sections +// CHECK: { +// CHECK: #pragma omp cancel sections if( +// CHECK: } +#pragma omp for +for (int i = 0; i < argc; ++i) { +#pragma omp cancel for +} +// CHECK: #pragma omp for +// CHECK-NEXT: for (int i = 0; i < argc; ++i) { +// CHECK-NEXT: #pragma omp cancel for +// CHECK-NEXT: } +#pragma omp taskgroup +#pragma omp task +{ +#pragma omp cancel taskgroup, if(argc + 1) +} +// CHECK: #pragma omp taskgroup +// CHECK-NEXT: #pragma omp task +// CHECK: { +// CHECK: #pragma omp cancel taskgroup if( +// CHECK: } +// CHECK: return argc; + return argc; +} + +#endif diff -uNr clang-3.4/test/OpenMP/cancel_messages.cpp clang/test/OpenMP/cancel_messages.cpp --- clang-3.4/test/OpenMP/cancel_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/cancel_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main(int argc, char **argv) { + #pragma omp cancel // expected-error {{expected 'parallel', 'sections', 'for' or 'taskgroup' construct type}} + ; + #pragma omp cancel parallel untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp cancel'}} + #pragma omp cancel unknown // expected-error {{expected 'parallel', 'sections', 'for' or 'taskgroup' construct type}} + #pragma omp cancel sections ( // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} + #pragma omp cancel for, ) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} + #pragma omp cancel taskgroup () // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} + #pragma omp cancel parallel, if // expected-error {{expected expression}} expected-error {{expected '(' after 'if'}} + #pragma omp cancel sections if(argc,argv) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}} expected-error {{expected ')'}} expected-note{{to match this '('}} + if (argc) + #pragma omp cancel for, if (argc // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} expected-error {{expected ')'}} expected-note{{to match this '('}} + if (argc) { + #pragma omp taskgroup + #pragma omp task + #pragma omp parallel + { + #pragma omp cancel taskgroup // expected-error {{region cannot be closely nested inside a parallel region}} + } + } + #pragma omp parallel + #pragma omp taskgroup + { + #pragma omp cancel taskgroup // expected-error {{region cannot be closely nested inside a taskgroup region}} + } + #pragma omp parallel + { + #pragma omp cancel for // expected-error {{region cannot be closely nested inside a parallel region}} + } + #pragma omp task + { + #pragma omp cancel sections // expected-error {{region cannot be closely nested inside explicit task region}} + } + #pragma omp sections + { + #pragma omp cancel parallel // expected-error {{region cannot be closely nested inside a worksharing region}} + } + while (argc) + #pragma omp cancel for// expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + while (argc) { + #pragma omp cancel sections + } + do + #pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + while (argc); + do { + #pragma omp cancel taskgroup + } + while (argc); + switch (argc) + #pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp cancel sections // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp cancel for + } + switch (argc) { + #pragma omp cancel taskgroup + case 1: + #pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + break; + default: { + #pragma omp cancel sections + } + break; + } + for (;;) + #pragma omp cancel for // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + for (;;) { + #pragma omp cancel taskgroup + } + label: + #pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be immediate substatement}} + label1: { + #pragma omp cancel sections + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/cancellation_point_ast_print.cpp clang/test/OpenMP/cancellation_point_ast_print.cpp --- clang-3.4/test/OpenMP/cancellation_point_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/cancellation_point_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +int main (int argc, char **argv) { +// CHECK: int main(int argc, char **argv) { +#pragma omp parallel +{ +#pragma omp cancellation point parallel +} +// CHECK: #pragma omp parallel +// CHECK-NEXT: { +// CHECK-NEXT: #pragma omp cancellation point parallel +// CHECK-NEXT: } +#pragma omp sections +{ +#pragma omp cancellation point sections +} +// CHECK-NEXT: #pragma omp sections +// CHECK: { +// CHECK: #pragma omp cancellation point sections +// CHECK: } +#pragma omp for +for (int i = 0; i < argc; ++i) { +#pragma omp cancellation point for +} +// CHECK: #pragma omp for +// CHECK-NEXT: for (int i = 0; i < argc; ++i) { +// CHECK-NEXT: #pragma omp cancellation point for +// CHECK-NEXT: } +#pragma omp task +{ +#pragma omp cancellation point taskgroup +} +// CHECK: #pragma omp task +// CHECK: { +// CHECK: #pragma omp cancellation point taskgroup +// CHECK: } +// CHECK: return argc; + return argc; +} + +#endif diff -uNr clang-3.4/test/OpenMP/cancellation_point_messages.cpp clang/test/OpenMP/cancellation_point_messages.cpp --- clang-3.4/test/OpenMP/cancellation_point_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/cancellation_point_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main(int argc, char **argv) { + #pragma omp cancellation // expected-error {{expected an OpenMP directive}} + #pragma omp cancellation point // expected-error {{expected 'parallel', 'sections', 'for' or 'taskgroup' construct type}} + ; + #pragma omp cancellation point parallel untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp cancellation point'}} + #pragma omp cancellation point unknown // expected-error {{expected 'parallel', 'sections', 'for' or 'taskgroup' construct type}} + #pragma omp cancellation point sections ( // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}} + #pragma omp cancellation point for, ) // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}} + #pragma omp cancellation point taskgroup () // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}} + #pragma omp cancellation point parallel, if // expected-warning {{extra tokens at the end of '#pragma omp cancellation point' are ignored}} + if (argc) + #pragma omp cancellation point for // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + if (argc) { + #pragma omp taskgroup + #pragma omp task + #pragma omp parallel + { + #pragma omp cancellation point taskgroup // expected-error {{region cannot be closely nested inside a parallel region}} + } + } + #pragma omp parallel + #pragma omp taskgroup + { + #pragma omp cancellation point taskgroup // expected-error {{region cannot be closely nested inside a taskgroup region}} + } + #pragma omp parallel + { + #pragma omp cancellation point for // expected-error {{region cannot be closely nested inside a parallel region}} + } + #pragma omp task + { + #pragma omp cancellation point sections // expected-error {{region cannot be closely nested inside explicit task region}} + } + #pragma omp sections + { + #pragma omp cancellation point parallel // expected-error {{region cannot be closely nested inside a worksharing region}} + } + while (argc) + #pragma omp cancellation point for// expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + while (argc) { + #pragma omp cancellation point sections + } + do + #pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + while (argc); + do { + #pragma omp cancellation point taskgroup + } + while (argc); + switch (argc) + #pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp cancellation point sections // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp cancellation point for + } + switch (argc) { + #pragma omp cancellation point taskgroup + case 1: + #pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + break; + default: { + #pragma omp cancellation point sections + } + break; + } + for (;;) + #pragma omp cancellation point for // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + for (;;) { + #pragma omp cancellation point taskgroup + } + label: + #pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be immediate substatement}} + label1: { + #pragma omp cancellation point sections + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/critical_ast_print.cpp clang/test/OpenMP/critical_ast_print.cpp --- clang-3.4/test/OpenMP/critical_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/critical_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp critical (name) + a=2; +// CHECK-NEXT: #pragma omp critical (name) +// CHECK-NEXT: a = 2; + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/critical_messages.cpp clang/test/OpenMP/critical_messages.cpp --- clang-3.4/test/OpenMP/critical_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/critical_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp critical + ; + #pragma omp critical untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp critical'}} + #pragma omp critical unknown // expected-warning {{extra tokens at the end of '#pragma omp critical' are ignored}} + #pragma omp critical ( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp critical ( + // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp critical (name // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp critical (name1) + foo(); + { + #pragma omp critical + } // expected-error {{expected statement}} + #pragma omp critical (name) + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp parallel + #pragma omp for + for (int j = 0; j < 10; j++) { + foo(); + #pragma omp critical(name) // expected-error {{region cannot be nested inside a critical region with name 'name'}} + foo(); + } + } + #pragma omp critical (name) + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp parallel + #pragma omp for + for (int j = 0; j < 10; j++) { + #pragma omp critical + foo(); + } + } + #pragma omp critical (name) + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp parallel + #pragma omp for + for (int j = 0; j < 10; j++) { + #pragma omp critical (nam) + foo(); + } + } + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp critical + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp critical + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/declare_reduction_ast_print.c clang/test/OpenMP/declare_reduction_ast_print.c --- clang-3.4/test/OpenMP/declare_reduction_ast_print.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_reduction_ast_print.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +#pragma omp declare reduction (+ : int, char: omp_out *= omp_in) +// CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in) +// CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in) + +#pragma omp declare reduction (fun : float : omp_out += omp_in) initializer (omp_priv=omp_orig + 15) +// CHECK: #pragma omp declare reduction (fun : float : omp_out += omp_in) initializer(omp_priv = omp_orig + 15) + +struct SSS { + int field; +}; + +void init(struct SSS *priv, struct SSS orig); + +#pragma omp declare reduction (fun : struct SSS : omp_out = omp_in) initializer (init(&omp_priv, omp_orig)) +// CHECK: #pragma omp declare reduction (fun : struct SSS : omp_out = omp_in) initializer(init(&omp_priv, omp_orig)) + +#endif diff -uNr clang-3.4/test/OpenMP/declare_reduction_ast_print.cpp clang/test/OpenMP/declare_reduction_ast_print.cpp --- clang-3.4/test/OpenMP/declare_reduction_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_reduction_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +#pragma omp declare reduction (+ : int, char: omp_out *= omp_in) +// CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in) +// CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in) + +// CHECK: #pragma omp declare reduction (fun : int : omp_out += omp_in) initializer(omp_priv omp_orig + 15) + +template +class SSS { +public: +#pragma omp declare reduction (fun : T : omp_out += omp_in) initializer (omp_priv omp_orig + 15) +// CHECK: #pragma omp declare reduction (fun : T : omp_out += omp_in) initializer(omp_priv omp_orig + 15) +}; + +SSS d; + +void init(SSS &lhs, SSS rhs); + +#pragma omp declare reduction (fun : SSS : omp_out = omp_in) initializer (init(omp_priv, omp_orig)) +// CHECK: #pragma omp declare reduction (fun : SSS : omp_out = omp_in) initializer(init(omp_priv, omp_orig)) + +int main() { + int i = 0; + SSS sss; + #pragma omp parallel reduction(SSS::fun : i) +// CHECK: #pragma omp parallel reduction(SSS::fun: i) + { + i += 1; + } + #pragma omp parallel reduction(::fun:sss) +// CHECK: #pragma omp parallel reduction(::fun: sss) + { + } +} + +#endif diff -uNr clang-3.4/test/OpenMP/declare_reduction_messages.c clang/test/OpenMP/declare_reduction_messages.c --- clang-3.4/test/OpenMP/declare_reduction_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_reduction_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int temp; + +#pragma omp declare reduction // expected-error {{expected '(' after 'declare reduction'}} +#pragma omp declare reduction { // expected-error {{expected '(' after 'declare reduction'}} expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction ( // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (# // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (/ // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (+ // expected-error {{expected ':'}} +#pragma omp declare reduction (for // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (if : // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (oper : // expected-error {{expected a type}} +#pragma omp declare reduction (oper ; // expected-error {{expected ':'}} expected-error {{expected a type}} +#pragma omp declare reduction (fun : int // expected-error {{expected ':'}} expected-error {{expected expression}} +#pragma omp declare reduction (+ : const int : // expected-error {{a type name cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp declare reduction (- : volatile int : // expected-error {{a type name cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp declare reduction (* : int ; // expected-error {{expected ','}} expected-error {{expected a type}} +#pragma omp declare reduction (& : double char : // expected-error {{cannot combine with previous 'double' declaration specifier}} expected-error {{expected expression}} +#pragma omp declare reduction (^ : double, char, : // expected-error {{expected a type}} expected-error {{expected expression}} +#pragma omp declare reduction (&& : int, S : // expected-error {{unknown type name 'S'}} expected-error {{expected expression}} +#pragma omp declare reduction (|| : int, double : temp += omp_in) // expected-error 2 {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (| : char, float : omp_out += temp ) // expected-error 2 {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (fun : long : omp_out += omp_in ) { // expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} expected-note {{previous declaration is here}} +#pragma omp declare reduction (fun : unsigned : omp_out += temp)) // expected-error {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (fun : long (*)(void): omp_out += omp_in) // expected-error {{a type name cannot be a function type}} +#pragma omp declare reduction (fun : long [3]: omp_out += omp_in) // expected-error {{a type name cannot be an array type}} +#pragma omp declare reduction (fun23 : long, int, long: omp_out += omp_in) // expected-error {{previous declaration with type 'long' is found}} expected-note {{previous declaration is here}} + +#pragma omp declare reduction (fun : long : omp_out += omp_in ) // expected-error {{previous declaration with type 'long' is found}} +#pragma omp declare reduction (fun1 : long : omp_out += omp_in ) initializer // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun2 : long : omp_out += omp_in ) initializer { // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun3 : long : omp_out += omp_in ) initializer [ // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun4 : long : omp_out += omp_in ) initializer() // expected-error {{expected expression}} +#pragma omp declare reduction (fun5 : long : omp_out += omp_in ) initializer(temp) // expected-error {{variable 'temp' is not allowed in initializer expression for '#pragma omp declare reduction', only 'omp_priv' or 'omp_orig' are allowed}} +#pragma omp declare reduction (fun6 : long : omp_out += omp_in ) initializer(omp_orig // expected-error {{expected function call}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare reduction (fun7 : long : omp_out += omp_in ) initializer(omp_priv 12) // expected-error {{expected '=' after 'omp_priv'}} +#pragma omp declare reduction (fun8 : long : omp_out += omp_in ) initializer(omp_priv=23) // expected-note {{previous declaration is here}} +#pragma omp declare reduction (fun8 : long : omp_out += omp_in ) initializer(omp_priv=23)) // expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} expected-error {{previous declaration with type 'long' is found}} +#pragma omp declare reduction (fun9 : long : omp_out += omp_in ) initializer(omp_priv=) // expected-error {{expected expression}} + +int fun(int arg) { +#pragma omp declare reduction (red : int : omp_out++) + { +#pragma omp declare reduction (red : int : omp_out++) // expected-note {{previous declaration is here}} +#pragma omp declare reduction (red : int : omp_out++) // expected-error {{previous declaration with type 'int' is found}} + } + return arg; +} + diff -uNr clang-3.4/test/OpenMP/declare_reduction_messages.cpp clang/test/OpenMP/declare_reduction_messages.cpp --- clang-3.4/test/OpenMP/declare_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int temp; + +#pragma omp declare reduction // expected-error {{expected '(' after 'declare reduction'}} +#pragma omp declare reduction { // expected-error {{expected '(' after 'declare reduction'}} expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction ( // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (# // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (/ // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (+ // expected-error {{expected ':'}} +#pragma omp declare reduction (operator // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (operator : // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction (oper : // expected-error {{expected a type}} +#pragma omp declare reduction (oper ; // expected-error {{expected ':'}} expected-error {{expected a type}} +#pragma omp declare reduction (fun : int // expected-error {{expected ':'}} expected-error {{expected expression}} +#pragma omp declare reduction (+ : const int : // expected-error {{a type name cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp declare reduction (- : volatile int : // expected-error {{a type name cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp declare reduction (* : int ; // expected-error {{expected ','}} expected-error {{expected a type}} +#pragma omp declare reduction (& : double char : // expected-error {{cannot combine with previous 'double' declaration specifier}} expected-error {{expected expression}} +#pragma omp declare reduction (^ : double, char, : // expected-error {{expected a type}} expected-error {{expected expression}} +#pragma omp declare reduction (&& : int, S : // expected-error {{unknown type name 'S'}} expected-error {{expected expression}} +#pragma omp declare reduction (|| : int, double : temp += omp_in) // expected-error 2 {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (| : char, float : omp_out += ::temp ) // expected-error 2 {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (fun : long : omp_out += omp_in ) { // expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} expected-note {{previous declaration is here}} +#pragma omp declare reduction (fun : unsigned : omp_out += ::temp)) // expected-error {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (fun : long &: omp_out += omp_in) // expected-error {{a type name cannot be a reference type}} +#pragma omp declare reduction (fun : long (*)(void): omp_out += omp_in) // expected-error {{a type name cannot be a function type}} +#pragma omp declare reduction (fun : long [3]: omp_out += omp_in) // expected-error {{a type name cannot be an array type}} +#pragma omp declare reduction (fun23 : long, int, long: omp_out += omp_in) // expected-error {{previous declaration with type 'long' is found}} expected-note {{previous declaration is here}} + +template +class Class1 { +#pragma omp declare reduction (fun : T : temp) // expected-error {{variable 'temp' is not allowed in combiner expression for '#pragma omp declare reduction', only 'omp_in' or 'omp_out' are allowed}} +#pragma omp declare reduction (fun1 : T : omp_out++) // expected-note {{previous declaration is here}} expected-error {{a type name cannot be a reference type}} +#pragma omp declare reduction (fun1 : T : omp_out += omp_in) // expected-error {{previous declaration with type 'T' is found}} +#pragma omp declare reduction (fun2 : T, T : omp_out++) // expected-error {{previous declaration with type 'T' is found}} expected-note {{previous declaration is here}} +}; + +Class1 e; // expected-note {{in instantiation of template class 'Class1' requested here}} + +template +class Class2 { +#pragma omp declare reduction (fun : T : omp_out += omp_in ) // expected-note {{implicitly declared private here}} +}; + +#pragma omp declare reduction (fun : long : omp_out += omp_in ) // expected-error {{previous declaration with type 'long' is found}} +#pragma omp declare reduction (fun1 : long : omp_out += omp_in ) initializer // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun2 : long : omp_out += omp_in ) initializer { // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun3 : long : omp_out += omp_in ) initializer [ // expected-error {{expected '(' after 'initializer'}} expected-error {{expected expression}} +#pragma omp declare reduction (fun4 : long : omp_out += omp_in ) initializer() // expected-error {{expected expression}} +#pragma omp declare reduction (fun5 : long : omp_out += omp_in ) initializer(temp) // expected-error {{variable 'temp' is not allowed in initializer expression for '#pragma omp declare reduction', only 'omp_priv' or 'omp_orig' are allowed}} +#pragma omp declare reduction (fun6 : long : omp_out += omp_in ) initializer(omp_orig // expected-error {{expected function call}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare reduction (fun7 : long : omp_out += omp_in ) initializer(omp_priv Class1()) +#pragma omp declare reduction (fun7 : long : omp_out += omp_in ) initializer(omp_priv Class2()) // expected-error {{no viable conversion from 'Class2' to 'long'}} +#pragma omp declare reduction (fun8 : long : omp_out += omp_in ) initializer(omp_priv 23) // expected-note {{previous declaration is here}} +#pragma omp declare reduction (fun8 : long : omp_out += omp_in ) initializer(omp_priv 23)) // expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are ignored}} expected-error {{previous declaration with type 'long' is found}} +#pragma omp declare reduction (fun9 : long : omp_out += omp_in ) initializer(omp_priv=23) // expected-error {{expected expression}} + +template +T fun(T arg) { +#pragma omp declare reduction (red : T : omp_out++) + { +#pragma omp declare reduction (red : T : omp_out++) // expected-note {{previous declaration is here}} +#pragma omp declare reduction (red : T : omp_out++) // expected-error {{previous declaration with type 'T' is found}} + } + return arg; +} + +int main() { + Class1 c1; + int i; + #pragma omp parallel reduction (::fun : c1) // expected-error {{no member named 'fun' in the global namespace}} + { + } + #pragma omp parallel reduction (::Class1::fun : c1) // expected-error {{no member named 'fun' in 'Class1'}} + { + } + #pragma omp parallel reduction (::Class2::fun : i) // expected-error {{'fun' is a private member of 'Class2'}} + { + } + return fun(15); +} diff -uNr clang-3.4/test/OpenMP/declare_simd_ast_print.c clang/test/OpenMP/declare_simd_ast_print.c --- clang-3.4/test/OpenMP/declare_simd_ast_print.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_simd_ast_print.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +#pragma omp declare simd +void add_1(float *d, float *s1, float *s2); + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: void add_1(float *d, float *s1, float *s2) + +#define MY_ALIGN 2*8 + +#pragma omp declare simd inbranch uniform(hp) aligned(hp, hq:MY_ALIGN) linear(hq, lin:8) +#pragma omp declare simd notinbranch linear(hp, hq:MY_ALIGN) aligned(hq, lin:8) simdlen(4) +void h(char *hp, char *hp2, char *hq, char *lin) +{ +} + +// CHECK: #pragma omp declare simd inbranch uniform(hp) aligned(hp,hq: 16) linear(hq,lin: 8) +// CHECK-NEXT: #pragma omp declare simd notinbranch linear(hp,hq: 16) aligned(hq,lin: 8) simdlen(4) +// CHECK-NEXT: void h(char *hp, char *hp2, char *hq, char *lin) { +// CHECK-NEXT: } + + +#endif diff -uNr clang-3.4/test/OpenMP/declare_simd_ast_print.cpp clang/test/OpenMP/declare_simd_ast_print.cpp --- clang-3.4/test/OpenMP/declare_simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +#pragma omp declare simd uniform(d) +void add_1(float *d); + +// CHECK: #pragma omp declare simd uniform(d) +// CHECK-NEXT: void add_1(float *d); +// + +#define MY_ALIGN 2*8 + +#pragma omp declare simd uniform(hp) +#pragma omp declare simd simdlen(8) linear(hq, lin: MY_ALIGN) +template void h(C *hp, C *hp2, C *hq, C *lin) { +} + +// CHECK: #pragma omp declare simd uniform(hp) +// CHECK-NEXT: #pragma omp declare simd simdlen(8) linear(hq,lin: 16) +// CHECK: template void h(C *hp, C *hp2, C *hq, C *lin) { +// CHECK-NEXT: } +// + + +// Instatiate with explicitly. +// Pragmas need to be same, otherwise standard says that's undefined behavior. +#pragma omp declare simd uniform(hp) +#pragma omp declare simd simdlen(8) linear(hq, lin: MY_ALIGN) +template <> +void h(int *hp, int *hp2, int *hq, int *lin) +{ + // Instatiate with implicitly. + // This is special case where the directive is stored by Sema and is + // generated together with the (pending) function instatiation. + h((float*) hp, (float*) hp2, (float*) hq, (float*) lin); +} + +// CHECK: #pragma omp declare simd uniform(hp) +// CHECK-NEXT: #pragma omp declare simd simdlen(8) linear(hq,lin: 16) +// CHECK: void h(int *hp, int *hp2, int *hq, int *lin) { +// CHECK-NEXT: h((float *)hp, (float *)hp2, (float *)hq, (float *)lin); +// CHECK-NEXT: } +// + +class VV { + #pragma omp declare simd + int add(int a, int b) { return a + b; } + + #pragma omp declare simd aligned(a,b : 32) + float addpf(float *a, float *b) { return *a + *b; } +}; + +template +class TVV { +// CHECK: template class TVV { + #pragma omp declare simd + int tadd(int a, int b) { return a + b; } + +// CHECK: #pragma omp declare simd +// CHECK-NEXT: int tadd(int a, int b) { +// CHECK-NEXT: return a + b; +// CHECK-NEXT: } + + + #pragma omp declare simd aligned(a,b : X) + float taddpf(float *a, float *b) { return *a + *b; } + +// CHECK: #pragma omp declare simd aligned(a,b: X) +// CHECK-NEXT: float taddpf(float *a, float *b) { +// CHECK-NEXT: return *a + *b; +// CHECK-NEXT: } +}; +// CHECK: }; + +// CHECK-NEXT: TVV<16> t16; +TVV<16> t16; + +void f() { + float a = 1.0f, b = 2.0f; + float r = t16.taddpf(&a, &b); +} + +#endif diff -uNr clang-3.4/test/OpenMP/declare_simd_messages.cpp clang/test/OpenMP/declare_simd_messages.cpp --- clang-3.4/test/OpenMP/declare_simd_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_simd_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -x c++ -std=c++11 %s + +// expected-error@+3 {{expected '(' after 'uniform'}} +// expected-error@+2 {{expected unqualified-id}} +// expected-error@+1 {{expected identifier}} +#pragma omp declare simd uniform + +// expected-error@+1 {{expected '(' after 'uniform'}} +#pragma omp declare simd uniform d + +// expected-error@+3 {{expected '(' after 'uniform'}} +// expected-error@+2 {{expected unqualified-id}} +// expected-error@+1 {{expected identifier}} +#pragma omp declare simd uniform{d} + +// expected-error@+1 {{expression is not a positive integer value}} +#pragma omp declare simd simdlen(-32) + +void add_1(float *d); +// expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} +#pragma omp declare simd aligned(a : 32) +#pragma omp declare simd aligned(b : 32) // ok: b is array +#pragma omp declare simd aligned(c : 32) // ok: c is pointer +// expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} +#pragma omp declare simd aligned(d : 32) +#pragma omp declare simd aligned(e : 32) // ok: reference to pointer +// expected-error@+1 {{expression is not a positive integer value}} +#pragma omp declare simd aligned(f : 0) +#pragma omp declare simd linear(f : 4) // ok +#pragma omp declare simd linear(f : 8) // ok : different step in other simd variant +// expected-error@+2 {{each argument may be in at most one uniform or linear clause}} +// expected-note@+1 {{previously referenced here}} +#pragma omp declare simd linear(f : 2) linear(f : 2) +// expected-error@+2 {{each argument may be in at most one aligned clause}} +// expected-note@+1 {{previously referenced here}} +#pragma omp declare simd aligned(f : 2) aligned(f : 2) +#pragma omp declare simd inbranch inbranch inbranch inbranch // ok +#pragma omp declare simd notinbranch notinbranch notinbranch notinbranch // ok +// expected-error@+2 {{declare simd variant cannot be inbranch and notinbranch at the same time}} +// expected-note@+1 {{previously specified here}} +#pragma omp declare simd inbranch notinbranch +// expected-error@+2 {{declare simd variant cannot be inbranch and notinbranch at the same time}} +// expected-note@+1 {{previously specified here}} +#pragma omp declare simd notinbranch inbranch +// expected-error@+2 2 {{declare simd variant cannot be inbranch and notinbranch at the same time}} +// expected-note@+1 2 {{previously specified here}} +#pragma omp declare simd inbranch notinbranch notinbranch +float add_2(float a, float b[], float *c, float &d, float *&e, float **f); + + +#define MY_ALIGN -2*8 + +#pragma omp declare simd uniform(hp) +// expected-error@+1 {{expression is not a positive integer value}} +#pragma omp declare simd simdlen(8) linear(hq, lin: MY_ALIGN) +template +void h(C *hp, C *hp2, C *hq, C *lin) +{ +} + +#pragma omp declare simd uniform(hp) +// expected-error@+1 {{cannot find the function argument with the name requested in the openmp clause}} +#pragma omp declare simd simdlen(8) linear(hq, lin, lin2: -MY_ALIGN) +template <> +void h(int *hp, int *hp2, int *hq, int *lin) +{ + h((float*) hp, (float*) hp2, (float*) hq, (float*) lin); +} + + diff -uNr clang-3.4/test/OpenMP/declare_simd_metadata.c clang/test/OpenMP/declare_simd_metadata.c --- clang-3.4/test/OpenMP/declare_simd_metadata.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_simd_metadata.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -fopenmp -emit-llvm %s -o - | FileCheck %s + +#ifdef NOOMP +__attribute__((vector(uniform(x), linear(y:4), linear(z:1)))) +#else +#pragma omp declare simd uniform(x) linear(y:4) linear(z) +#endif +void g(int x, int y, int z) +{ +} + +// Metadata for g: +// CHECK: [[GN:![0-9]+]] = metadata !{metadata !"arg_name", metadata !"x", metadata !"y", metadata !"z"} +// CHECK: [[GS:![0-9]+]] = metadata !{metadata !"arg_step", i32 0, i32 4, i32 1} +// CHECK: [[GT:![0-9]+]] = metadata !{metadata !"vec_length", i32 undef, i32 {{[0-9]+}}} + +#define MY_ALIGN 16 + +#ifdef NOOMP +__attribute__((vector(uniform(hp)))) +#else +#pragma omp declare simd uniform(hp) aligned(hp, hq:MY_ALIGN) +#endif +void h(char *hp, char *hp2, char *hq) +{ +} + +// Metadata for h: +// CHECK: metadata !{metadata !"arg_name", metadata !"hp", metadata !"hp2", metadata !"hq"} +// CHECK: [[HS:![0-9]+]] = metadata !{metadata !"arg_step", i32 0, i32 undef, i32 undef} +// CHECK: [[HA:![0-9]+]] = metadata !{metadata !"arg_alig", i32 16, i32 undef, i32 16} +// CHECK: metadata !{metadata !"vec_length", i8* undef, i32 {{[0-9]+}}} + + +#ifdef NOOMP +__attribute__((vector(mask, vectorlength(64)))) +#else +#pragma omp declare simd inbranch simdlen(64) +#endif +void k(char (*kf)(int), int a) +{ + kf(a); +} + +// Metadata for k: +// CHECK: metadata !{metadata !"arg_name", metadata !"kf", metadata !"a"} +// CHECK: metadata !{metadata !"arg_step", i32 undef, i32 undef} +// CHECK: metadata !{metadata !"vec_length", i8 (i32)* undef, i32 64} + diff -uNr clang-3.4/test/OpenMP/declare_simd_metadata.cpp clang/test/OpenMP/declare_simd_metadata.cpp --- clang-3.4/test/OpenMP/declare_simd_metadata.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_simd_metadata.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-llvm %s -o - | FileCheck %s + +#pragma omp declare simd uniform(x) linear(y:4) +void g(int x, int y) +{ +} + +// Tests for global-function-template with 'omp declare simd' + +// Metadata for g: +// CHECK: [[G1:![0-9]+]] = metadata !{void (i32, i32)* @_Z1gii[[GMETA:(, metadata ![0-9]+)+]]} +// CHECK: [[GN:![0-9]+]] = metadata !{metadata !"arg_name", metadata !"x", metadata !"y"} +// CHECK: [[GS:![0-9]+]] = metadata !{metadata !"arg_step", i32 0, i32 4} +// CHECK: [[GT:![0-9]+]] = metadata !{metadata !"vec_length", i32 undef, i32 {{[0-9]+}}} + +#define MY_ALIGN 2*9 + +#pragma omp declare simd uniform(hp) +#pragma omp declare simd simdlen(8) linear(hq, lin: MY_ALIGN) +template +void h(C *hp, C *hp2, C *hq, C *lin) +{ +} + +// Instatiate with explicitly. +// Pragmas need to be same, otherwise standard says that's undefined behavior. +#pragma omp declare simd uniform(hp) +#pragma omp declare simd simdlen(8) linear(hq, lin: MY_ALIGN) +template <> +void h(int *hp, int *hp2, int *hq, int *lin) +{ + // Instatiate with implicitly. + // This is special case where the directive is stored by Sema and is + // generated together with the (pending) function instatiation. + h((float*) hp, (float*) hp2, (float*) hq, (float*) lin); +} + +// For the function template h we have 2 template instantiations +// (one implicit with and one explicit with ) and +// each of them should have 2 simd-variants, as specified by the pragma. +// CHECK: [[HI1:![0-9]+]] = metadata !{void (i32*, i32*, i32*, i32*)* @_Z1hIiEvPT_S1_S1_S1_[[HI1META:(, metadata ![0-9]+)+]]} +// CHECK: [[HI2:![0-9]+]] = metadata !{void (i32*, i32*, i32*, i32*)* @_Z1hIiEvPT_S1_S1_S1_[[HI2META:(, metadata ![0-9]+)+]]} +// CHECK: [[HF1:![0-9]+]] = metadata !{void (float*, float*, float*, float*)* @_Z1hIfEvPT_S1_S1_S1_[[HF1META:(, metadata ![0-9]+)+]]} +// CHECK: [[HF2:![0-9]+]] = metadata !{void (float*, float*, float*, float*)* @_Z1hIfEvPT_S1_S1_S1_[[HF2META:(, metadata ![0-9]+)+]]} + + +// Tests for special cases for class method and for class-template method + +class VV { + #pragma omp declare simd + int add(int a, int b) { return a + b; } + + #pragma omp declare simd aligned(a,b : 32) + float addpf(float *a, float *b) { return *a + *b; } +}; + + +template +class TVV { + #pragma omp declare simd + int tadd(int a, int b) { return a + b; } + + #pragma omp declare simd aligned(a,b : X) + float taddpf(float *a, float *b) { return *a + *b; } +}; + +TVV<16> t16; +VV vv; + +// The following function instantiates the class and template +void f() { + float a = 1.0f, b = 2.0f; + float r = t16.taddpf(&a, &b); + float q = vv.addpf(&a, &b); +} + +// Metadata for the class +// CHECK: [[C01:![0-9]+]] = metadata !{float (%class.VV*, float*, float*)* @_ZN2VV5addpfEPfS0_[[C01META:(, metadata ![0-9]+)+]]} +// +// Metadata for the class-template +// CHECK: [[CT1:![0-9]+]] = metadata !{float (%class.TVV*, float*, float*)* @_ZN3TVVILi16EE6taddpfEPfS1_[[CT1META:(, metadata ![0-9]+)+]]} + + diff -uNr clang-3.4/test/OpenMP/declare_target_ast_print.cpp clang/test/OpenMP/declare_target_ast_print.cpp --- clang-3.4/test/OpenMP/declare_target_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_target_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +#pragma omp declare target +// CHECK: #pragma omp declare target + +void foo() {} +// CHECK-NEXT: void foo() + +#pragma omp end declare target +// CHECK: #pragma omp end declare target + +int main (int argc, char **argv) { + foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/declare_target_messages.cpp clang/test/OpenMP/declare_target_messages.cpp --- clang-3.4/test/OpenMP/declare_target_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/declare_target_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + +int a, b; // expected-warning 2 {{declaration is not declared in any declare target region}} +__thread int t; // expected-error {{threadprivate variables cannot be used in target constructs}} +#pragma omp declare target private(a) // expected-warning {{extra tokens at the end of '#pragma omp declare target' are ignored}} +void f(); +#pragma omp end declare target shared(a) // expected-warning {{extra tokens at the end of '#pragma omp end declare target' are ignored}} +void c(); // expected-warning {{declaration is not declared in any declare target region}} + +extern int b; + +struct NonT { + int a; +}; + +typedef int sint; + +#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}} +#pragma omp threadprivate(a) // expected-error {{threadprivate variables cannot be used in target constructs}} expected-note {{used here}} +extern int b; +int g; + +struct T { // expected-note {{mappable type cannot be polymorphic}} + int a; + virtual int method(); +}; + +class VC { // expected-note {{mappable type cannot be polymorphic}} + T member; + NonT member1; + public: + virtual int method() { T a; return 0; } // expected-error {{type 'T' is not mappable to target}} +}; + +struct C { + NonT a; + sint b; + int method(); + int method1(); +}; + +int C::method1() { + return 0; +} + +void foo() { + a = 0; // expected-note {{used here}} + b = 0; // expected-note {{used here}} + t = 1; // expected-note {{used here}} + C object; + VC object1; // expected-error {{type 'VC' is not mappable to target}} + g = object.method(); + g += object.method1(); + g += object1.method(); + f(); + c(); // expected-note {{used here}} +} +#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} +void foo1() {} +#pragma omp end declare target +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + +int C::method() { + return 0; +} + +struct S { +#pragma omp declare target // expected-error {{directive must be at file or namespace scope}} + int v; +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} +}; + +int main (int argc, char **argv) { +#pragma omp declare target // expected-error {{unexpected OpenMP directive '#pragma omp declare target'}} + int v; +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + foo(); + return (0); +} + +#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}} diff -uNr clang-3.4/test/OpenMP/distribute_ast_print.cpp clang/test/OpenMP/distribute_ast_print.cpp --- clang-3.4/test/OpenMP/distribute_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp distribute +// CHECK-NEXT: #pragma omp distribute + for (int i=0; i < 2; ++i)a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: a = 2; +#pragma omp target +#pragma omp teams +#pragma omp distribute private(argc,b),firstprivate(argv, c), collapse(2), dist_schedule(static) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j)foo(); +// CHECK-NEXT: #pragma omp target +// CHECK-NEXT: #pragma omp teams +// CHECK-NEXT: #pragma omp distribute private(argc,b) firstprivate(argv,c) collapse(2) dist_schedule(static) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) +// CHECK-NEXT: foo(); + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute dist_schedule(static, argc) +// CHECK: #pragma omp distribute dist_schedule(static, argc) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/distribute_collapse_messages.cpp clang/test/OpenMP/distribute_collapse_messages.cpp --- clang-3.4/test/OpenMP/distribute_collapse_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_collapse_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } + operator bool() { return f; } +} v2; + +struct S3 { + int f; + operator int() { return f; } +} v3; + +int main(int argc, char **argv) { // expected-note {{declared here}} + #pragma omp distribute collapse // expected-error {{expected '(' after 'collapse'}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse () // expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (foobool(argc)) collapse(1) // expected-error {{directive '#pragma omp distribute' cannot contain more than one 'collapse' clause}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (v1) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (v2) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (v3) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (0) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute collapse (-1) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/distribute_dist_schedule_messages.cpp clang/test/OpenMP/distribute_dist_schedule_messages.cpp --- clang-3.4/test/OpenMP/distribute_dist_schedule_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_dist_schedule_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp distribute dist_schedule // expected-error {{expected '(' after 'dist_schedule'}} expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule ( // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule () // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static, // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (argc)) // expected-error {{expected 'static' in OpenMP clause 'dist_schedule'}} expected-warning {{extra tokens at the end of '#pragma omp distribute' are ignored}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static, argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static), dist_schedule (static, 1) // expected-error {{directive '#pragma omp distribute' cannot contain more than one 'dist_schedule' clause}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{statement requires expression of integer type ('char *' invalid)}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/distribute_firstprivate_messages.cpp clang/test/OpenMP/distribute_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/distribute_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,147 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } +public: + S5(int v):a(v) { } +}; +class S6 { + int a; +public: + S6() : a(0) { } +}; + +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); + S5 g(5); + S6 p; + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp distribute firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp distribute firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp distribute firstprivate () // expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (argc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate (argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(ba) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(ca) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(da) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(S2::S2s) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(S2::S2sc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams shared(i) + #pragma omp distribute firstprivate(i) + for (j = 0; j < argc; ++j) foo(); + #pragma omp target + #pragma omp teams shared(i) + #pragma omp distribute firstprivate(i) // expected-note {{defined as firstprivate}} + for (i = 0; i < argc; ++i) foo(); // expected-error {{loop iteration variable may not be firstprivate}} + #pragma omp target + #pragma omp teams private(argc) // expected-note {{defined as private}} + #pragma omp distribute firstprivate(argc) // expected-error {{private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams reduction(+:argc) // expected-note {{defined as reduction}} + #pragma omp distribute firstprivate(argc) // expected-error {{reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + for (i = 0; i < argc; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/distribute_loop_messages.cpp clang/test/OpenMP/distribute_loop_messages.cpp --- clang-3.4/test/OpenMP/distribute_loop_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_loop_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +namespace std { + +struct random_access_iterator_tag { }; + +template +struct iterator_traits { + typedef typename Iter::difference_type difference_type; // expected-error {{no type named 'difference_type' in 'Iter'}} expected-error {{no type named 'difference_type' in 'Iter1'}} + typedef typename Iter::iterator_category iterator_category; // expected-error {{no type named 'iterator_category' in 'Iter'}} expected-error {{no type named 'iterator_category' in 'Iter1'}} expected-error {{no type named 'iterator_category' in 'Iter2'}} +}; + +template +typename iterator_traits::difference_type distance(Iter first, Iter last) { + return first - last; +} +} + +class Iter { + public: + Iter() { } + Iter(const Iter &) { } + Iter operator ++() { return *this; } + Iter operator --() { return *this; } + bool operator <(Iter a) { return true; } + bool operator >=(Iter a) { return false; } +}; +int operator -(Iter a, Iter b) { return 0; } +class Iter1 { + public: + Iter1() { } + Iter1(const Iter1 &) { } + Iter1 operator ++() { return *this; } + Iter1 operator --() { return *this; } + bool operator <(Iter1 a) { return true; } + bool operator >=(Iter1 a) { return false; } +}; +class Iter2 { + public: + Iter2() { } + Iter2(const Iter2 &) { } + Iter2 operator ++() { return *this; } + Iter2 operator --() { return *this; } + bool operator <(Iter2 a) { return true; } + bool operator >=(Iter2 a) { return false; } + typedef int difference_type; +}; +int operator -(Iter2 a, Iter2 b) { return 0; } +class Iter3 { + public: + Iter3() { } + Iter3(const Iter3 &) { } + Iter3 operator ++() { return *this; } + Iter3 operator --() { return *this; } + bool operator <(Iter3 a) { return true; } + bool operator >=(Iter3 a) { return false; } + typedef int difference_type; + typedef int iterator_category; +}; +int operator -(Iter3 a, Iter3 b) { return 0; } +class Iter4 { + public: + Iter4() { } + Iter4(const Iter4 &) { } + Iter4 operator ++() { return *this; } + Iter4 operator --() { return *this; } + bool operator <(Iter4 a) { return true; } + bool operator >=(Iter4 a) { return false; } + Iter4 operator+=(int) const {return Iter4();} + Iter4 operator-=(int) const {return Iter4();} + typedef int difference_type; + typedef std::random_access_iterator_tag iterator_category; +}; +int operator -(Iter4 a, Iter4 b) { return 0; } + +int t; +#pragma omp threadprivate(t) + +int main() { + #pragma omp distribute + for (int i = 0; i < 10; i++) + ++i; + #pragma omp distribute + for (t = 0; t < 10; t++) + ++t; + #pragma omp distribute + for (int i; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp distribute + for (float i = 0; i < 10.0f; i++) // expected-error {{variable must be of integer or random access iterator type}} + ++i; + #pragma omp distribute + for (int i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp distribute + for (int i = 0; i < 10; i |= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + int i; + #pragma omp distribute + for (i = 0; i < 10; i++) + ++i; + #pragma omp distribute + for (i--; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp distribute + for (i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp distribute + for (i = 0; i < 10; i ^= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + Iter begin, end; + #pragma omp distribute + for (Iter I = begin; I >= end; ++I) // expected-error {{increment expression must cause 'I' to decrease on each iteration of the loop}} + ++I; + #pragma omp distribute + for (Iter I = end; I < begin; --I) // expected-error {{increment expression must cause 'I' to increase on each iteration of the loop}} + ++I; + #pragma omp distribute + for (Iter I = begin; I < end; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp distribute + for (Iter I = end; I >= begin; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter1 begin1; + #pragma omp distribute + for (Iter1 I = begin1; I < begin1; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp distribute + for (Iter1 I = begin1; I >= begin1; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter2 begin2; + #pragma omp distribute + for (Iter2 I = begin2; I < begin2; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp distribute + for (Iter2 I = begin2; I >= begin2; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter3 begin3; + #pragma omp distribute + for (Iter3 I = begin3; I < begin3; ++I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp distribute + for (Iter3 I = begin3; I >= begin3; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter4 begin4; + #pragma omp distribute + for (Iter4 I = begin4; I < begin4; ++I) + ++I; + #pragma omp distribute + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + goto label; // expected-error {{use of undeclared label 'label'}} + #pragma omp distribute + for (int i = 0; i < 100; ++i) { + label: ++i; + } + #pragma omp distribute collapse(1) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp distribute collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + for (Iter4 I1 = begin4; I1 >= begin4; --I1) + for (Iter4 I2 = begin4; I2 >= begin4; --I2) + ++I; + #pragma omp distribute collapse(0) // expected-error {{expression is not a positive integer value}} + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp distribute + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp distribute // expected-error {{region cannot be closely nested inside a distribute region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp single + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp distribute // expected-error {{region cannot be closely nested inside a worksharing region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp sections + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp distribute // expected-error {{region cannot be closely nested inside a worksharing region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp master + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp distribute // expected-error {{region cannot be closely nested inside a master region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp critical + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp distribute // expected-error {{region cannot be closely nested inside a critical region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp for ordered + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp ordered + #pragma omp distribute // expected-error {{region cannot be closely nested inside an ordered region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp distribute collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; // expected-error {{only for-loops are allowed for '#pragma omp distribute'}} + ++begin4; +} diff -uNr clang-3.4/test/OpenMP/distribute_loop_messages1.cpp clang/test/OpenMP/distribute_loop_messages1.cpp --- clang-3.4/test/OpenMP/distribute_loop_messages1.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_loop_messages1.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main() { + int i; + goto label; // expected-error {{use of undeclared label 'label'}} + #pragma omp distribute + for (i = 0; i < 100; ++i) { + label: ++i; + } +} diff -uNr clang-3.4/test/OpenMP/distribute_parallel_for_ast_print.cpp clang/test/OpenMP/distribute_parallel_for_ast_print.cpp --- clang-3.4/test/OpenMP/distribute_parallel_for_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_parallel_for_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp distribute parallel for reduction(+:sum) proc_bind(master) dist_schedule(static) +// CHECK-NEXT: #pragma omp distribute parallel for reduction(+: sum) proc_bind(master) dist_schedule(static) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp distribute parallel for lastprivate(res) if(m_a) +// CHECK-NEXT: #pragma omp distribute parallel for lastprivate(res) if(this->m_a) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp distribute parallel for +// CHECK-NEXT: #pragma omp distribute parallel for + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp distribute parallel for private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) dist_schedule(static, 3) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp distribute parallel for private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) dist_schedule(static, 3) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute parallel for collapse(1) +// CHECK: #pragma omp distribute parallel for collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/distribute_parallel_for_misc_messages.c clang/test/OpenMP/distribute_parallel_for_misc_messages.c --- clang-3.4/test/OpenMP/distribute_parallel_for_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_parallel_for_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,263 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for'}} */ +#pragma omp distribute parallel for + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for'}} */ +#pragma omp distribute parallel for foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for'}} */ +#pragma omp distribute parallel for collapse + +void test_no_clause() +{ + int i; + #pragma omp distribute parallel for + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} */ + #pragma omp distribute parallel for foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + #pragma omp distribute parallel for; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + #pragma omp distribute parallel for private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}} + #pragma omp distribute parallel for , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute parallel for private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute parallel for private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute parallel for lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp distribute parallel for reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp distribute parallel for reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp distribute parallel for reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp distribute parallel for reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp distribute parallel for private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp distribute parallel for reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp distribute parallel for reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp distribute parallel for + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp distribute parallel for + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp distribute parallel for + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp distribute parallel for + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute parallel for + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute parallel for + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/distribute_parallel_for_simd_misc_messages.c clang/test/OpenMP/distribute_parallel_for_simd_misc_messages.c --- clang-3.4/test/OpenMP/distribute_parallel_for_simd_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_parallel_for_simd_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,263 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for simd'}} */ +#pragma omp distribute parallel for simd + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for simd'}} */ +#pragma omp distribute parallel for simd foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute parallel for simd'}} */ +#pragma omp distribute parallel for simd collapse + +void test_no_clause() +{ + int i; + #pragma omp distribute parallel for simd + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for simd' are ignored}} */ + #pragma omp distribute parallel for simd foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for simd' are ignored}} + #pragma omp distribute parallel for simd; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for simd' are ignored}} + #pragma omp distribute parallel for simd private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute parallel for simd' are ignored}} + #pragma omp distribute parallel for simd , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute parallel for simd private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for simd private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for simd private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for simd private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute parallel for simd private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for simd lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for simd lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for simd lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute parallel for simd lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for simd reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for simd reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for simd reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp distribute parallel for simd reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute parallel for simd reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute parallel for simd reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp distribute parallel for simd reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute parallel for simd reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp distribute parallel for simd reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute parallel for simd reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp distribute parallel for simd reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp distribute parallel for simd private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp distribute parallel for simd reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp distribute parallel for simd reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp distribute parallel for simd + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp distribute parallel for simd + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for simd + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for simd + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute parallel for simd + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp distribute parallel for simd + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp distribute parallel for simd + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute parallel for simd + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute parallel for simd + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/distribute_private_messages.cpp clang/test/OpenMP/distribute_private_messages.cpp --- clang-3.4/test/OpenMP/distribute_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 distribute private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private () // expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (argc) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (S1) // expected-error {{'S1' does not refer to a value}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private (argv[1]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(ba) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(ca) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(da) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(S2::S2s) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp distribute'}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp target + #pragma omp teams + { + int i; // expected-note {{predetermined as private}} + #pragma omp distribute firstprivate(i), private(i) // expected-error {{private variable cannot be firstprivate}} + for (int k = 0; k < argc; ++k) ++k; + } + #pragma omp target + #pragma omp teams private(i) + #pragma omp distribute private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp parallel private(i) + #pragma omp target + #pragma omp teams firstprivate(i) + #pragma omp parallel private(i) + #pragma omp target + #pragma omp teams reduction(+:i) + #pragma omp distribute private(i) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp distribute private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + #pragma omp distribute private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp target + #pragma omp teams + #pragma omp distribute firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams firstprivate(i) + #pragma omp distribute private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp target + #pragma omp teams reduction(+:i) + #pragma omp distribute + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams reduction(+:i) + #pragma omp distribute private(i) + for (int x = 0; x < 10; ++x) foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/distribute_simd_ast_print.cpp clang/test/OpenMP/distribute_simd_ast_print.cpp --- clang-3.4/test/OpenMP/distribute_simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp distribute simd linear(ind), reduction(+:sum) +// CHECK-NEXT: #pragma omp distribute simd linear(ind) reduction(+: sum) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp distribute simd lastprivate(res) safelen(7) +// CHECK-NEXT: #pragma omp distribute simd lastprivate(res) safelen(7) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp distribute simd +// CHECK-NEXT: #pragma omp distribute simd + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp target +#pragma omp teams +#pragma omp distribute simd private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) safelen(2) aligned(a:4), linear(k1,k2:8) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp target +// CHECK-NEXT: #pragma omp teams +// CHECK-NEXT: #pragma omp distribute simd private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) safelen(2) aligned(a: 4) linear(k1,k2: 8) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute simd aligned(a) linear(a) +// CHECK-NEXT: #pragma omp distribute simd aligned(a) linear(a) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute simd collapse(1) +// CHECK: #pragma omp distribute simd collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + const int CLEN=4; +#pragma omp distribute simd safelen(CLEN) +// CHECK: #pragma omp distribute simd safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) +// CHECK-NEXT: #pragma omp distribute simd aligned(a: 4) linear(a: 4) safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/distribute_simd_misc_messages.c clang/test/OpenMP/distribute_simd_misc_messages.c --- clang-3.4/test/OpenMP/distribute_simd_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/distribute_simd_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,453 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute simd'}} */ +#pragma omp distribute simd + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute simd'}} */ +#pragma omp distribute simd foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp distribute simd'}} */ +#pragma omp distribute simd safelen(4) + +void test_no_clause() +{ + int i; + #pragma omp distribute simd + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} */ + #pragma omp distribute simd foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + #pragma omp distribute simd; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + #pragma omp distribute simd private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + #pragma omp distribute simd , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_safelen() +{ + int i; + /* expected-error@+1 {{expected '('}} expected-error@+1 {{expected expression}}*/ + #pragma omp distribute simd safelen + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen( + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd safelen() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp distribute simd safelen(, + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp distribute simd safelen(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected '('}} */ + #pragma omp distribute simd safelen 4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4 + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4, + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4,) + for (i = 0; i < 16; ++i) ; + /* xxpected-error@+1 {{expected expression}} */ + #pragma omp distribute simd safelen(4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4 4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4,,4) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd safelen(4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd safelen(4,8) + for (i = 0; i < 16; ++i) ; +} + +void test_linear() +{ + int i; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp distribute simd linear( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp distribute simd linear(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd linear(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd linear() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd linear(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute simd linear(0) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{use of undeclared identifier 'x'}} */ + #pragma omp distribute simd linear(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{use of undeclared identifier 'x'}} */ + /* expected-error@+1 {{use of undeclared identifier 'y'}} */ + #pragma omp distribute simd linear(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{use of undeclared identifier 'x'}} */ + /* expected-error@+2 {{use of undeclared identifier 'y'}} */ + /* expected-error@+1 {{use of undeclared identifier 'z'}} */ + #pragma omp distribute simd linear(x, y, z) + for (i = 0; i < 16; ++i) ; + + int x, y; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd linear(x:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd linear(x:,) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd linear(x:1) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd linear(x:2*2) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute simd linear(x:1,y) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp distribute simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute simd linear(x:1,y,z:1) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be linear}} + #pragma omp distribute simd linear(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as private}} + // expected-error@+1 {{private variable cannot be linear}} + #pragma omp distribute simd private(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be private}} + #pragma omp distribute simd linear(x) private(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be lastprivate}} + #pragma omp distribute simd linear(x) lastprivate(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as lastprivate}} + // expected-error@+1 {{lastprivate variable cannot be linear}} + #pragma omp distribute simd lastprivate(x) linear(x) + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute simd private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute simd private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute simd private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute simd lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp distribute simd lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute simd reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute simd reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute simd reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp distribute simd reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp distribute simd reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp distribute simd reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp distribute simd reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp distribute simd reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute simd reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_aligned() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp distribute simd aligned( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd aligned(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp distribute simd aligned(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd aligned() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp distribute simd aligned(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp distribute simd aligned(0) + for (i = 0; i < 16; ++i) ; + + int *x, y, z[25]; + #pragma omp distribute simd aligned(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp distribute simd aligned(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp distribute simd aligned(x, y, z) + for (i = 0; i < 16; ++i) ; + + #pragma omp distribute simd aligned(x:4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp distribute simd aligned(x, y:8) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp distribute simd aligned(x, y, z:10+6) + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} + // expected-error@+1 {{expression is not an integer constant expression}} + #pragma omp distribute simd aligned(x, y, z:x) + for (i = 0; i < 16; ++i) ; + // expected-note@+2 {{defined as aligned}} + // expected-error@+1 {{aligned variable cannot be aligned}} + #pragma omp distribute simd aligned(x:16) aligned(z,x:16) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp distribute simd safelen(4) reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp distribute simd private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp distribute simd safelen(4) reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp distribute simd reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp distribute simd + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp distribute simd + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute simd + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute simd + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp distribute simd + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp distribute simd + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp distribute simd + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute simd + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp distribute simd + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/dsitribute_parallel_for_simd_ast_print.cpp clang/test/OpenMP/dsitribute_parallel_for_simd_ast_print.cpp --- clang-3.4/test/OpenMP/dsitribute_parallel_for_simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/dsitribute_parallel_for_simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp distribute parallel for simd reduction(+:sum) proc_bind(master) dist_schedule(static) +// CHECK-NEXT: #pragma omp distribute parallel for simd reduction(+: sum) proc_bind(master) dist_schedule(static) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp distribute parallel for simd lastprivate(res) if(m_a) +// CHECK-NEXT: #pragma omp distribute parallel for simd lastprivate(res) if(this->m_a) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp distribute parallel for simd +// CHECK-NEXT: #pragma omp distribute parallel for simd + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp distribute parallel for simd private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) dist_schedule(static, 3) linear(k1) aligned(a:8) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp distribute parallel for simd private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) dist_schedule(static, 3) linear(k1) aligned(a: 8) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp distribute parallel for simd collapse(1) +// CHECK: #pragma omp distribute parallel for simd collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/flush_ast_print.cpp clang/test/OpenMP/flush_ast_print.cpp --- clang-3.4/test/OpenMP/flush_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/flush_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +int main (int argc, char **argv) { +// CHECK: int main(int argc, char **argv) { +#pragma omp flush(argc) +// CHECK-NEXT: #pragma omp flush(argc) +// CHECK-NEXT: return argc; + return argc; +} + +#endif diff -uNr clang-3.4/test/OpenMP/flush_messages.cpp clang/test/OpenMP/flush_messages.cpp --- clang-3.4/test/OpenMP/flush_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/flush_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main(int argc, char **argv) { + #pragma omp flush + ; + #pragma omp flush untied // expected-warning {{extra tokens at the end of '#pragma omp flush' are ignored}} + #pragma omp flush unknown // expected-warning {{extra tokens at the end of '#pragma omp flush' are ignored}} + #pragma omp flush ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp flush ) // expected-warning {{extra tokens at the end of '#pragma omp flush' are ignored}} + #pragma omp flush () // expected-error {{expected expression}} + #pragma omp flush (argc,) // expected-error {{expected expression}} + #pragma omp flush (argc,argv) + if (argc) + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + if (argc) { + #pragma omp flush + } + while (argc) + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + while (argc) { + #pragma omp flush + } + do + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + while (argc); + do { + #pragma omp flush + } + while (argc); + switch (argc) + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp flush + } + switch (argc) { + #pragma omp flush + case 1: + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + break; + default: { + #pragma omp flush + } + break; + } + for (;;) + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + for (;;) { + #pragma omp flush + } + label: + #pragma omp flush // expected-error {{'#pragma omp flush' cannot be immediate substatement}} + label1: { + #pragma omp flush + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_ast_print.cpp clang/test/OpenMP/for_ast_print.cpp --- clang-3.4/test/OpenMP/for_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp for +// CHECK-NEXT: #pragma omp for + for (int i=0; i < 2; ++i)a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: a = 2; +#pragma omp parallel +#pragma omp for private(argc,b),firstprivate(argv, c),lastprivate(d,f),reduction(+:e) reduction(min : g), ordered nowait, collapse(2), schedule(dynamic) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j)foo(); +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp for private(argc,b) firstprivate(argv,c) lastprivate(d,f) reduction(+: e) reduction(min: g) ordered nowait collapse(2) schedule(dynamic, 1) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) +// CHECK-NEXT: foo(); + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for nowait, schedule(guided, 12) +// CHECK-NEXT: #pragma omp for nowait schedule(guided, 12) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for schedule(static, argc) +// CHECK: #pragma omp for schedule(static, argc) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for ordered, schedule(auto) +// CHECK: #pragma omp for ordered schedule(auto) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for schedule(runtime) +// CHECK-NEXT: #pragma omp for schedule(runtime) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/for_collapse_messages.cpp clang/test/OpenMP/for_collapse_messages.cpp --- clang-3.4/test/OpenMP/for_collapse_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_collapse_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } + operator bool() { return f; } +} v2; + +struct S3 { + int f; + operator int() { return f; } +} v3; + +int main(int argc, char **argv) { // expected-note {{declared here}} + #pragma omp for collapse // expected-error {{expected '(' after 'collapse'}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse () // expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (foobool(argc)) collapse(1) // expected-error {{directive '#pragma omp for' cannot contain more than one 'collapse' clause}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (v1) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (v2) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (v3) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (0) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for collapse (-1) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_firstprivate_messages.cpp clang/test/OpenMP/for_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/for_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } +}; +class S6 { + int a; +public: + S6() : a(0) { } +}; + +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}} + S6 p; + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp for firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp for firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp for firstprivate () // expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (argc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(ba) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(ca) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(da) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(S2::S2s) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(S2::S2sc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(p),firstprivate(e, g, p) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel shared(i) + #pragma omp for firstprivate(i) + for (j = 0; j < argc; ++j) foo(); + #pragma omp parallel shared(i) + #pragma omp for firstprivate(i) // expected-note {{defined as firstprivate}} + for (i = 0; i < argc; ++i) foo(); // expected-error {{loop iteration variable may not be firstprivate}} + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp for firstprivate(i) // expected-error {{private variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp for'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp for firstprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp for'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + for (i = 0; i < argc; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_lastprivate_messages.cpp clang/test/OpenMP/for_lastprivate_messages.cpp --- clang-3.4/test/OpenMP/for_lastprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_lastprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,133 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{predetermined as shared}} +const S2 b; +const S2 ba[5]; +class S3 { // expected-note {{'S3' declared here}} + int a; + S3& operator =(const S3& s3); +public: + S3():a(0) { } + S3(S3 &s3):a(s3.a) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note 2 {{'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) {} +public: + S5(const S5 &s5):a(s5.a) { } + 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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + S4 e(4); // expected-note 2 {{'e' defined here}} + S5 g(5); // expected-note {{'g' defined here}} + S3 m; // expected-note {{'m' defined here}} + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp parallel + #pragma omp for lastprivate // expected-error {{expected '(' after 'lastprivate'}} expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate () // expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (argc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate (argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(ba) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(da) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for firstprivate (g), lastprivate(e, g) // expected-error {{lastprivate variable must have an accessible, unambiguous default constructor}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for private(i), lastprivate(i) // expected-error {{private variable cannot be lastprivate}} expected-note{{defined as private}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel shared(i) + #pragma omp for lastprivate(i) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp for lastprivate(i) // expected-error {{private variable in '#pragma omp parallel' cannot be lastprivate in '#pragma omp for'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp for lastprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be lastprivate in '#pragma omp for'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp for lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}} + for (i = 0; i < argc; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_loop_messages.cpp clang/test/OpenMP/for_loop_messages.cpp --- clang-3.4/test/OpenMP/for_loop_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_loop_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +namespace std { + +struct random_access_iterator_tag { }; + +template +struct iterator_traits { + typedef typename Iter::difference_type difference_type; // expected-error {{no type named 'difference_type' in 'Iter'}} expected-error {{no type named 'difference_type' in 'Iter1'}} + typedef typename Iter::iterator_category iterator_category; // expected-error {{no type named 'iterator_category' in 'Iter'}} expected-error {{no type named 'iterator_category' in 'Iter1'}} expected-error {{no type named 'iterator_category' in 'Iter2'}} +}; + +template +typename iterator_traits::difference_type distance(Iter first, Iter last) { + return first - last; +} +} + +class Iter { + public: + Iter() { } + Iter(const Iter &) { } + Iter operator ++() { return *this; } + Iter operator --() { return *this; } + bool operator <(Iter a) { return true; } + bool operator >=(Iter a) { return false; } +}; +int operator -(Iter a, Iter b) { return 0; } +class Iter1 { + public: + Iter1() { } + Iter1(const Iter1 &) { } + Iter1 operator ++() { return *this; } + Iter1 operator --() { return *this; } + bool operator <(Iter1 a) { return true; } + bool operator >=(Iter1 a) { return false; } +}; +class Iter2 { + public: + Iter2() { } + Iter2(const Iter2 &) { } + Iter2 operator ++() { return *this; } + Iter2 operator --() { return *this; } + bool operator <(Iter2 a) { return true; } + bool operator >=(Iter2 a) { return false; } + typedef int difference_type; +}; +int operator -(Iter2 a, Iter2 b) { return 0; } +class Iter3 { + public: + Iter3() { } + Iter3(const Iter3 &) { } + Iter3 operator ++() { return *this; } + Iter3 operator --() { return *this; } + bool operator <(Iter3 a) { return true; } + bool operator >=(Iter3 a) { return false; } + typedef int difference_type; + typedef int iterator_category; +}; +int operator -(Iter3 a, Iter3 b) { return 0; } +class Iter4 { + public: + Iter4() { } + Iter4(const Iter4 &) { } + Iter4 operator ++() { return *this; } + Iter4 operator --() { return *this; } + bool operator <(Iter4 a) { return true; } + bool operator >=(Iter4 a) { return false; } + Iter4 operator+=(int) const {return Iter4();} + Iter4 operator-=(int) const {return Iter4();} + typedef int difference_type; + typedef std::random_access_iterator_tag iterator_category; +}; +int operator -(Iter4 a, Iter4 b) { return 0; } + +int t; +#pragma omp threadprivate(t) + +int main() { + #pragma omp for + for (int i = 0; i < 10; i++) + ++i; + #pragma omp for + for (t = 0; t < 10; t++) + ++t; + #pragma omp for + for (int i; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp for + for (float i = 0; i < 10.0f; i++) // expected-error {{variable must be of integer or random access iterator type}} + ++i; + #pragma omp for + for (int i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp for + for (int i = 0; i < 10; i |= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + int i; + #pragma omp for + for (i = 0; i < 10; i++) + ++i; + #pragma omp for + for (i--; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp for + for (i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp for + for (i = 0; i < 10; i ^= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + Iter begin, end; + #pragma omp for + for (Iter I = begin; I >= end; ++I) // expected-error {{increment expression must cause 'I' to decrease on each iteration of the loop}} + ++I; + #pragma omp for + for (Iter I = end; I < begin; --I) // expected-error {{increment expression must cause 'I' to increase on each iteration of the loop}} + ++I; + #pragma omp for + for (Iter I = begin; I < end; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp for + for (Iter I = end; I >= begin; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter1 begin1; + #pragma omp for + for (Iter1 I = begin1; I < begin1; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp for + for (Iter1 I = begin1; I >= begin1; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter2 begin2; + #pragma omp for + for (Iter2 I = begin2; I < begin2; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp for + for (Iter2 I = begin2; I >= begin2; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter3 begin3; + #pragma omp for + for (Iter3 I = begin3; I < begin3; ++I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp for + for (Iter3 I = begin3; I >= begin3; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter4 begin4; + #pragma omp for + for (Iter4 I = begin4; I < begin4; ++I) + ++I; + #pragma omp for + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + goto label; // expected-error {{use of undeclared label 'label'}} + #pragma omp for + for (int i = 0; i < 100; ++i) { + label: ++i; + } + #pragma omp for collapse(1) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp for collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + for (Iter4 I1 = begin4; I1 >= begin4; --I1) + for (Iter4 I2 = begin4; I2 >= begin4; --I2) + ++I; + #pragma omp for collapse(0) // expected-error {{expression is not a positive integer value}} + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp for + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a worksharing region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp single + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a worksharing region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp sections + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a worksharing region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp master + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a master region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp critical + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a critical region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp for ordered + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp ordered + #pragma omp for // expected-error {{region cannot be closely nested inside an ordered region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp for collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; // expected-error {{only for-loops are allowed for '#pragma omp for'}} + ++begin4; +} diff -uNr clang-3.4/test/OpenMP/for_loop_messages1.cpp clang/test/OpenMP/for_loop_messages1.cpp --- clang-3.4/test/OpenMP/for_loop_messages1.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_loop_messages1.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main() { + int i; + goto label; // expected-error {{use of undeclared label 'label'}} + #pragma omp for + for (i = 0; i < 100; ++i) { + label: ++i; + } +} diff -uNr clang-3.4/test/OpenMP/for_private_messages.cpp clang/test/OpenMP/for_private_messages.cpp --- clang-3.4/test/OpenMP/for_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 for private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private () // expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (argc) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (S1) // expected-error {{'S1' does not refer to a value}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private (argv[1]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(ba) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(ca) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(da) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(S2::S2s) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp for'}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp parallel + { + int i; // expected-note {{predetermined as private}} + #pragma omp for firstprivate(i), private(i) // expected-error {{private variable cannot be firstprivate}} + for (int k = 0; k < argc; ++k) ++k; + } + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp for private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp parallel private(i) + #pragma omp parallel firstprivate(i) + #pragma omp parallel private(i) + #pragma omp parallel reduction(+:i) + #pragma omp for private(i) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + #pragma omp for private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel firstprivate(i) + #pragma omp for private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel reduction(+:i) + #pragma omp for private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel + #pragma omp for private(i) + for (int x = 0; x < 10; ++x) foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_reduction_messages.cpp clang/test/OpenMP/for_reduction_messages.cpp --- clang-3.4/test/OpenMP/for_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,164 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; //expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note {{'j' defined here}} + S3 &p = k; + const int &r = da[i]; // expected-note 2 {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; // expected-note {{'fl' defined here}} + #pragma omp parallel + #pragma omp for reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + for (int x = 0; x < 10; ++x) foo(); + #pragma omp for reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp for reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (&& :argc) + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction (max : argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(^ : fl) // expected-error {{arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(+ : o) // expected-error {{no viable overloaded '+='}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel private(i) + #pragma omp parallel shared(i, j, q) + #pragma omp for reduction(|| : i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int x = 0; x < 10; ++x) foo(); + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp for reduction(|| : i) // expected-error {{private variable in '#pragma omp parallel' cannot be reduction in '#pragma omp for'}} + for (int x = 0; x < 10; ++x) foo(); + #pragma omp parallel + #pragma omp for private(i), reduction(|| : i) // expected-error {{private variable cannot be reduction}} expected-note {{defined as private}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp for reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel shared(i) + #pragma omp parallel reduction(min : i) // expected-note {{defined as reduction}} + #pragma omp for reduction(max : i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be reduction in '#pragma omp for'}} + for (i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_schedule_messages.cpp clang/test/OpenMP/for_schedule_messages.cpp --- clang-3.4/test/OpenMP/for_schedule_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_schedule_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp for schedule // expected-error {{expected '(' after 'schedule'}} expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule ( // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule () // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (static // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (guided, // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (argc)) // expected-error {{expected 'static', 'dynamic', 'guided', 'auto' or 'runtime' in OpenMP clause 'schedule'}} expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (dynamic, argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (auto), schedule (runtime) // expected-error {{directive '#pragma omp for' cannot contain more than one 'schedule' clause}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (guided, S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp for schedule (dynamic, argv[1]=2) // expected-error {{statement requires expression of integer type ('char *' invalid)}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/for_simd_ast_print.cpp clang/test/OpenMP/for_simd_ast_print.cpp --- clang-3.4/test/OpenMP/for_simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp for simd linear(ind), reduction(+:sum) +// CHECK-NEXT: #pragma omp for simd linear(ind) reduction(+: sum) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp for simd lastprivate(res) safelen(7) +// CHECK-NEXT: #pragma omp for simd lastprivate(res) safelen(7) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp for simd +// CHECK-NEXT: #pragma omp for simd + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp parallel +#pragma omp for simd private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) safelen(2) aligned(a:4), linear(k1,k2:8) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp for simd private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) safelen(2) aligned(a: 4) linear(k1,k2: 8) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for simd aligned(a) linear(a) +// CHECK-NEXT: #pragma omp for simd aligned(a) linear(a) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for simd collapse(1) +// CHECK: #pragma omp for simd collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + const int CLEN=4; +#pragma omp for simd safelen(CLEN) +// CHECK: #pragma omp for simd safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp for simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) +// CHECK-NEXT: #pragma omp for simd aligned(a: 4) linear(a: 4) safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/for_simd_misc_messages.c clang/test/OpenMP/for_simd_misc_messages.c --- clang-3.4/test/OpenMP/for_simd_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/for_simd_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,453 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp for simd'}} */ +#pragma omp for simd + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp for simd'}} */ +#pragma omp for simd foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp for simd'}} */ +#pragma omp for simd safelen(4) + +void test_no_clause() +{ + int i; + #pragma omp for simd + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}} */ + #pragma omp for simd foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + #pragma omp for simd; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + #pragma omp for simd private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + #pragma omp for simd , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_safelen() +{ + int i; + /* expected-error@+1 {{expected '('}} expected-error@+1 {{expected expression}}*/ + #pragma omp for simd safelen + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen( + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd safelen() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp for simd safelen(, + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp for simd safelen(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected '('}} */ + #pragma omp for simd safelen 4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4 + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4, + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4,) + for (i = 0; i < 16; ++i) ; + /* xxpected-error@+1 {{expected expression}} */ + #pragma omp for simd safelen(4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4 4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4,,4) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd safelen(4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp for simd safelen(4,8) + for (i = 0; i < 16; ++i) ; +} + +void test_linear() +{ + int i; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp for simd linear( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp for simd linear(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd linear(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd linear() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd linear(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp for simd linear(0) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{use of undeclared identifier 'x'}} */ + #pragma omp for simd linear(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{use of undeclared identifier 'x'}} */ + /* expected-error@+1 {{use of undeclared identifier 'y'}} */ + #pragma omp for simd linear(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{use of undeclared identifier 'x'}} */ + /* expected-error@+2 {{use of undeclared identifier 'y'}} */ + /* expected-error@+1 {{use of undeclared identifier 'z'}} */ + #pragma omp for simd linear(x, y, z) + for (i = 0; i < 16; ++i) ; + + int x, y; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd linear(x:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd linear(x:,) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd linear(x:1) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd linear(x:2*2) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp for simd linear(x:1,y) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp for simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp for simd linear(x:1,y,z:1) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be linear}} + #pragma omp for simd linear(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as private}} + // expected-error@+1 {{private variable cannot be linear}} + #pragma omp for simd private(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be private}} + #pragma omp for simd linear(x) private(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be lastprivate}} + #pragma omp for simd linear(x) lastprivate(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as lastprivate}} + // expected-error@+1 {{lastprivate variable cannot be linear}} + #pragma omp for simd lastprivate(x) linear(x) + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp for simd private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp for simd private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp for simd private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp for simd lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp for simd lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp for simd reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp for simd reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp for simd reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp for simd reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp for simd reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp for simd reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp for simd reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp for simd reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp for simd reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_aligned() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp for simd aligned( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd aligned(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp for simd aligned(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd aligned() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp for simd aligned(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp for simd aligned(0) + for (i = 0; i < 16; ++i) ; + + int *x, y, z[25]; + #pragma omp for simd aligned(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp for simd aligned(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp for simd aligned(x, y, z) + for (i = 0; i < 16; ++i) ; + + #pragma omp for simd aligned(x:4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp for simd aligned(x, y:8) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp for simd aligned(x, y, z:10+6) + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} + // expected-error@+1 {{expression is not an integer constant expression}} + #pragma omp for simd aligned(x, y, z:x) + for (i = 0; i < 16; ++i) ; + // expected-note@+2 {{defined as aligned}} + // expected-error@+1 {{aligned variable cannot be aligned}} + #pragma omp for simd aligned(x:16) aligned(z,x:16) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp for simd safelen(4) reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp for simd private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp for simd safelen(4) reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp for simd reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp for simd + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp for simd + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp for simd + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp for simd + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp for simd + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp for simd + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp for simd + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp for simd + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp for simd + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/linking.c clang/test/OpenMP/linking.c --- clang-3.4/test/OpenMP/linking.c 2013-01-17 08:19:29.000000000 -0500 +++ clang/test/OpenMP/linking.c 2014-05-19 19:59:00.000000000 -0400 @@ -5,12 +5,12 @@ // RUN: -fopenmp -target i386-unknown-linux \ // RUN: | FileCheck --check-prefix=CHECK-LD-32 %s // CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" -// CHECK-LD-32: "-lgomp" "-lrt" "-lgcc" +// CHECK-LD-32: "-liomp5" "-lgcc" // CHECK-LD-32: "-lpthread" "-lc" // // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: -fopenmp -target x86_64-unknown-linux \ // RUN: | FileCheck --check-prefix=CHECK-LD-64 %s // CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" -// CHECK-LD-64: "-lgomp" "-lrt" "-lgcc" +// CHECK-LD-64: "-liomp5" "-lgcc" // CHECK-LD-64: "-lpthread" "-lc" diff -uNr clang-3.4/test/OpenMP/master_ast_print.cpp clang/test/OpenMP/master_ast_print.cpp --- clang-3.4/test/OpenMP/master_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/master_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp parallel +{ +#pragma omp master +{ + a=2; +} +} +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: { +// CHECK-NEXT: #pragma omp master +// CHECK-NEXT: { +// CHECK-NEXT: a = 2; +// CHECK-NEXT: } +// CHECK-NEXT: } + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/master_messages.cpp clang/test/OpenMP/master_messages.cpp --- clang-3.4/test/OpenMP/master_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/master_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp master + ; + #pragma omp master nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp master'}} + #pragma omp master unknown // expected-warning {{extra tokens at the end of '#pragma omp master' are ignored}} + foo(); + { + #pragma omp master + } // expected-error {{expected statement}} + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp master // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp sections + { + foo(); + #pragma omp master // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp master // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp master + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp master + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) + #pragma omp ordered + { + foo(); + #pragma omp master // expected-error {{region cannot be closely nested inside an ordered region}} + foo(); + } + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp master + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp master + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/openmp_common.c clang/test/OpenMP/openmp_common.c --- clang-3.4/test/OpenMP/openmp_common.c 2013-09-06 14:03:48.000000000 -0400 +++ clang/test/OpenMP/openmp_common.c 2014-05-19 19:59:00.000000000 -0400 @@ -6,4 +6,11 @@ void foo() { #pragma omp // expected-error {{expected an OpenMP directive}} #pragma omp unknown_directive // expected-error {{expected an OpenMP directive}} +#pragma omp parallel unknown_clause // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} +#pragma omp parallel ordered // expected-error {{unexpected OpenMP clause 'ordered' in directive '#pragma omp parallel'}} +#pragma omp for unknown_clause // expected-warning {{extra tokens at the end of '#pragma omp for' are ignored}} +for (int i = 0; i < 1; ++i) ++i; +#pragma omp for default(none) // expected-error {{unexpected OpenMP clause 'default' in directive '#pragma omp for'}} +for (int i = 0; i < 1; ++i) ++i; +foo(); } diff -uNr clang-3.4/test/OpenMP/ordered_ast_print.cpp clang/test/OpenMP/ordered_ast_print.cpp --- clang-3.4/test/OpenMP/ordered_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/ordered_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; + #pragma omp for ordered + for (int i =0 ; i < argc; ++i) + #pragma omp ordered + { + a=2; + } +// CHECK-NEXT: #pragma omp for ordered +// CHECK-NEXT: for (int i = 0; i < argc; ++i) +// CHECK-NEXT: #pragma omp ordered +// CHECK-NEXT: { +// CHECK-NEXT: a = 2; +// CHECK-NEXT: } + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/ordered_messages.cpp clang/test/OpenMP/ordered_messages.cpp --- clang-3.4/test/OpenMP/ordered_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/ordered_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp ordered + ; + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp ordered nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp ordered'}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp ordered unknown // expected-warning {{extra tokens at the end of '#pragma omp ordered' are ignored}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp ordered + } // expected-error {{expected statement}} + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp parallel + #pragma omp ordered // expected-error {{region must be closely nested inside loop or parallel loop region with 'ordered' clause}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp critical + #pragma omp ordered // expected-error {{region cannot be closely nested inside a critical region}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp atomic + #pragma omp ordered // expected-error {{region cannot be closely nested inside an atomic region}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp task + #pragma omp ordered // expected-error {{region cannot be closely nested inside explicit task region}} + foo(); + } + + return 0; +} + +int foo() { + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + L1: + foo(); + #pragma omp ordered + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) { + foo(); + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp ordered + { + L2: + foo(); + } + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_ast_print.cpp clang/test/OpenMP/parallel_ast_print.cpp --- clang-3.4/test/OpenMP/parallel_ast_print.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/test/OpenMP/parallel_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -50,8 +50,8 @@ // CHECK-NEXT: #pragma omp parallel a=2; // CHECK-NEXT: a = 2; -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) +#pragma omp parallel if(a) num_threads(a), default(none), private(argc,b),firstprivate(argv, c),shared(d,f),reduction(+:e) reduction(min : g) proc_bind(master) +// CHECK: #pragma omp parallel if(a) num_threads(a) default(none) private(argc,b) firstprivate(argv,c) shared(d,f) reduction(+: e) reduction(min: g) proc_bind(master) foo(); // CHECK-NEXT: foo(); return tmain(b, &b) + tmain(x, &x); diff -uNr clang-3.4/test/OpenMP/parallel_copyin_messages.cpp clang/test/OpenMP/parallel_copyin_messages.cpp --- clang-3.4/test/OpenMP/parallel_copyin_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_copyin_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +class S2 { + mutable int a; +public: + S2():a(0) { } + S2 & operator =(S2 &s2) { return *this; } +}; +class S3 { + int a; +public: + S3():a(0) { } + S3 &operator =(S3 &s3) { return *this; } +}; +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4 &operator =(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} + S5 &operator =(const S5 &s5) { return *this; } +public: + S5(int v):a(v) { } +}; + +S2 k; +S3 h; +S4 l(3); // expected-note {{'l' defined here}} +S5 m(4); // expected-note {{'m' defined here}} +#pragma omp threadprivate(h, k, l, m) + +int main(int argc, char **argv) { + int i; + #pragma omp parallel copyin // expected-error {{expected '(' after 'copyin'}} expected-error {{expected expression}} + #pragma omp parallel copyin ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin () // expected-error {{expected expression}} + #pragma omp parallel copyin (k // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin (h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel copyin (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel copyin (l) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}} + #pragma omp parallel copyin (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel copyin (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel copyin(i) // expected-error {{copyin variable must be threadprivate}} + #pragma omp parallel copyin(m) // expected-error {{copyin variable must have an accessible, unambiguous copy assignment operator}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_default_messages.cpp clang/test/OpenMP/parallel_default_messages.cpp --- clang-3.4/test/OpenMP/parallel_default_messages.cpp 2013-09-06 14:03:48.000000000 -0400 +++ clang/test/OpenMP/parallel_default_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -3,7 +3,7 @@ void foo(); int main(int argc, char **argv) { - #pragma omp parallel default // expected-error {{expected '(' after 'default'}} + #pragma omp parallel default // expected-error {{expected '(' after 'default'}} expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} #pragma omp parallel default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp parallel default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} #pragma omp parallel default (none // expected-error {{expected ')'}} expected-note {{to match this '('}} diff -uNr clang-3.4/test/OpenMP/parallel_firstprivate_messages.cpp clang/test/OpenMP/parallel_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/parallel_firstprivate_messages.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/test/OpenMP/parallel_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -54,7 +54,7 @@ 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 '(' after 'firstprivate'}} expected-error {{expected expression}} #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 '('}} diff -uNr clang-3.4/test/OpenMP/parallel_for_ast_print.cpp clang/test/OpenMP/parallel_for_ast_print.cpp --- clang-3.4/test/OpenMP/parallel_for_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_for_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp parallel for reduction(+:sum) proc_bind(master) +// CHECK-NEXT: #pragma omp parallel for reduction(+: sum) proc_bind(master) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp parallel for lastprivate(res) if(m_a) +// CHECK-NEXT: #pragma omp parallel for lastprivate(res) if(this->m_a) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp parallel for +// CHECK-NEXT: #pragma omp parallel for + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp parallel for private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp parallel for private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp parallel for collapse(1) +// CHECK: #pragma omp parallel for collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/parallel_for_misc_messages.c clang/test/OpenMP/parallel_for_misc_messages.c --- clang-3.4/test/OpenMP/parallel_for_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_for_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,263 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for'}} */ +#pragma omp parallel for + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for'}} */ +#pragma omp parallel for foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for'}} */ +#pragma omp parallel for collapse + +void test_no_clause() +{ + int i; + #pragma omp parallel for + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for' are ignored}} */ + #pragma omp parallel for foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for' are ignored}} + #pragma omp parallel for; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for' are ignored}} + #pragma omp parallel for private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for' are ignored}} + #pragma omp parallel for , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp parallel for private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp parallel for private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp parallel for lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp parallel for reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp parallel for reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp parallel for reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp parallel for reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp parallel for private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp parallel for reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp parallel for reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp parallel for + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp parallel for + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp parallel for + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp parallel for + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp parallel for + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp parallel for + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/parallel_for_simd_ast_print.cpp clang/test/OpenMP/parallel_for_simd_ast_print.cpp --- clang-3.4/test/OpenMP/parallel_for_simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_for_simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp parallel for simd linear(ind), reduction(+:sum) proc_bind(master) +// CHECK-NEXT: #pragma omp parallel for simd linear(ind) reduction(+: sum) proc_bind(master) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp parallel for simd lastprivate(res) safelen(7) if(m_a) +// CHECK-NEXT: #pragma omp parallel for simd lastprivate(res) safelen(7) if(this->m_a) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp parallel for simd +// CHECK-NEXT: #pragma omp parallel for simd + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp parallel for simd private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) safelen(2) aligned(a:4), linear(k1,k2:8) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp parallel for simd private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) safelen(2) aligned(a: 4) linear(k1,k2: 8) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp parallel for simd aligned(a) linear(a) +// CHECK-NEXT: #pragma omp parallel for simd aligned(a) linear(a) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp parallel for simd collapse(1) +// CHECK-NEXT: #pragma omp parallel for simd collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + const int CLEN=4; +#pragma omp parallel for simd safelen(CLEN) +// CHECK: #pragma omp parallel for simd safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp parallel for simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) +// CHECK-NEXT: #pragma omp parallel for simd aligned(a: 4) linear(a: 4) safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/parallel_for_simd_misc_messages.c clang/test/OpenMP/parallel_for_simd_misc_messages.c --- clang-3.4/test/OpenMP/parallel_for_simd_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_for_simd_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,453 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for simd'}} */ +#pragma omp parallel for simd + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for simd'}} */ +#pragma omp parallel for simd foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp parallel for simd'}} */ +#pragma omp parallel for simd safelen(4) + +void test_no_clause() +{ + int i; + #pragma omp parallel for simd + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} */ + #pragma omp parallel for simd foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + #pragma omp parallel for simd; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + #pragma omp parallel for simd private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + #pragma omp parallel for simd , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_safelen() +{ + int i; + /* expected-error@+1 {{expected '('}} expected-error@+1 {{expected expression}}*/ + #pragma omp parallel for simd safelen + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen( + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd safelen() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp parallel for simd safelen(, + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp parallel for simd safelen(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected '('}} */ + #pragma omp parallel for simd safelen 4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4 + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4, + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4,) + for (i = 0; i < 16; ++i) ; + /* xxpected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd safelen(4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4 4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4,,4) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd safelen(4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd safelen(4,8) + for (i = 0; i < 16; ++i) ; +} + +void test_linear() +{ + int i; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp parallel for simd linear( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp parallel for simd linear(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd linear(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd linear() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd linear(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for simd linear(0) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{use of undeclared identifier 'x'}} */ + #pragma omp parallel for simd linear(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{use of undeclared identifier 'x'}} */ + /* expected-error@+1 {{use of undeclared identifier 'y'}} */ + #pragma omp parallel for simd linear(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{use of undeclared identifier 'x'}} */ + /* expected-error@+2 {{use of undeclared identifier 'y'}} */ + /* expected-error@+1 {{use of undeclared identifier 'z'}} */ + #pragma omp parallel for simd linear(x, y, z) + for (i = 0; i < 16; ++i) ; + + int x, y; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd linear(x:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd linear(x:,) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd linear(x:1) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd linear(x:2*2) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp parallel for simd linear(x:1,y) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp parallel for simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp parallel for simd linear(x:1,y,z:1) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be linear}} + #pragma omp parallel for simd linear(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as private}} + // expected-error@+1 {{private variable cannot be linear}} + #pragma omp parallel for simd private(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be private}} + #pragma omp parallel for simd linear(x) private(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be lastprivate}} + #pragma omp parallel for simd linear(x) lastprivate(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as lastprivate}} + // expected-error@+1 {{lastprivate variable cannot be linear}} + #pragma omp parallel for simd lastprivate(x) linear(x) + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp parallel for simd private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for simd private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp parallel for simd private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + // TODO: tests on this. + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for simd lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp parallel for simd lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for simd reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for simd reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for simd reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp parallel for simd reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp parallel for simd reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp parallel for simd reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp parallel for simd reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp parallel for simd reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for simd reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_aligned() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp parallel for simd aligned( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd aligned(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp parallel for simd aligned(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd aligned() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp parallel for simd aligned(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp parallel for simd aligned(0) + for (i = 0; i < 16; ++i) ; + + int *x, y, z[25]; + #pragma omp parallel for simd aligned(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp parallel for simd aligned(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp parallel for simd aligned(x, y, z) + for (i = 0; i < 16; ++i) ; + + #pragma omp parallel for simd aligned(x:4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp parallel for simd aligned(x, y:8) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp parallel for simd aligned(x, y, z:10+6) + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} + // expected-error@+1 {{expression is not an integer constant expression}} + #pragma omp parallel for simd aligned(x, y, z:x) + for (i = 0; i < 16; ++i) ; + // expected-note@+2 {{defined as aligned}} + // expected-error@+1 {{aligned variable cannot be aligned}} + #pragma omp parallel for simd aligned(x:16) aligned(z,x:16) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp parallel for simd safelen(4) reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp parallel for simd private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp parallel for simd safelen(4) reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp parallel for simd reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp parallel for simd + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp parallel for simd + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for simd + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for simd + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp parallel for simd + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp parallel for simd + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp parallel for simd + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp parallel for simd + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp parallel for simd + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/parallel_if_messages.cpp clang/test/OpenMP/parallel_if_messages.cpp --- clang-3.4/test/OpenMP/parallel_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_if_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp parallel if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + #pragma omp parallel if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel if () // expected-error {{expected expression}} + #pragma omp parallel if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}} + #pragma omp parallel if (argc > 0 ? argv[1] : argv[2]) + #pragma omp parallel if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'if' clause}} + #pragma omp parallel if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_messages.c clang/test/OpenMP/parallel_messages.c --- clang-3.4/test/OpenMP/parallel_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { } + +int main(int argc, char **argv) { + L1: + foo(); + #pragma omp parallel + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp parallel + L2: + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_num_threads_messages.cpp clang/test/OpenMP/parallel_num_threads_messages.cpp --- clang-3.4/test/OpenMP/parallel_num_threads_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_num_threads_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp parallel num_threads // expected-error {{expected '(' after 'num_threads'}} expected-error {{expected expression}} + #pragma omp parallel num_threads ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads () // expected-error {{expected expression}} + #pragma omp parallel num_threads (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel num_threads (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp parallel num_threads (foobool(argc)) num_threads(3) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'num_threads' clause}} + #pragma omp parallel num_threads (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel num_threads (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp parallel num_threads (v1) // expected-error {{expression has incomplete type 'S1'}} + #pragma omp parallel num_threads (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + #pragma omp parallel num_threads (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + #pragma omp parallel num_threads (0) // expected-error {{expression is not a positive integer value}} + #pragma omp parallel num_threads (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_private_messages.cpp clang/test/OpenMP/parallel_private_messages.cpp --- clang-3.4/test/OpenMP/parallel_private_messages.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/test/OpenMP/parallel_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -48,7 +48,7 @@ S5 g(5); // expected-note {{'g' defined here}} int i; int &j = i; // expected-note {{'j' defined here}} - #pragma omp parallel private // expected-error {{expected '(' after 'private'}} + #pragma omp parallel private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} #pragma omp parallel private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp parallel private () // expected-error {{expected expression}} #pragma omp parallel private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} @@ -66,16 +66,48 @@ #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 shared(i) #pragma omp parallel private(i) - #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}} + #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} foo(); + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } + #pragma omp parallel + #pragma omp for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } + #pragma omp parallel + #pragma omp for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } + #pragma omp parallel + #pragma omp for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } + #pragma omp parallel private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } #pragma omp parallel firstprivate(i) for (int k = 0; k < 10; ++k) { #pragma omp parallel private(i) foo(); } + #pragma omp parallel reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } return 0; } diff -uNr clang-3.4/test/OpenMP/parallel_proc_bind_messages.cpp clang/test/OpenMP/parallel_proc_bind_messages.cpp --- clang-3.4/test/OpenMP/parallel_proc_bind_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_proc_bind_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp parallel proc_bind // expected-error {{expected '(' after 'proc_bind'}} expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} + #pragma omp parallel proc_bind ( // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel proc_bind () // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} + #pragma omp parallel proc_bind (master // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel proc_bind (close), proc_bind(spread) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'proc_bind' clause}} + #pragma omp parallel proc_bind (x) // expected-error {{expected 'master', 'close' or 'spread' in OpenMP clause 'proc_bind'}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_reduction_messages.cpp clang/test/OpenMP/parallel_reduction_messages.cpp --- clang-3.4/test/OpenMP/parallel_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/parallel_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note 2 {{'j' defined here}} + S3 &p = k; // expected-note 2 {{'p' defined here}} + const int &r = da[i]; // expected-note {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; // expected-note {{'fl' defined here}} + #pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + #pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + #pragma omp parallel reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + #pragma omp parallel reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + #pragma omp parallel reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + #pragma omp parallel reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel reduction (&& :argc) + #pragma omp parallel reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + #pragma omp parallel reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + #pragma omp parallel reduction (max : argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + #pragma omp parallel reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + #pragma omp parallel reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + #pragma omp parallel reduction(^ : fl) // expected-error {{arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type}} + #pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + #pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + #pragma omp parallel reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + #pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + #pragma omp parallel reduction(+ : o) // expected-error {{no viable overloaded '+='}} + #pragma omp parallel private(i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + {} + #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + #pragma omp parallel reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp parallel shared(i) + #pragma omp parallel reduction(min : i) + #pragma omp parallel reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/parallel_shared_messages.cpp clang/test/OpenMP/parallel_shared_messages.cpp --- clang-3.4/test/OpenMP/parallel_shared_messages.cpp 2013-10-01 01:32:34.000000000 -0400 +++ clang/test/OpenMP/parallel_shared_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -51,7 +51,7 @@ S5 g(5); int i; int &j = i; - #pragma omp parallel shared // expected-error {{expected '(' after 'shared'}} + #pragma omp parallel shared // expected-error {{expected '(' after 'shared'}} expected-error {{expected expression}} #pragma omp parallel shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp parallel shared () // expected-error {{expected expression}} #pragma omp parallel shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} diff -uNr clang-3.4/test/OpenMP/sections_ast_print.cpp clang/test/OpenMP/sections_ast_print.cpp --- clang-3.4/test/OpenMP/sections_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp sections +{ + a=2; +} +// CHECK-NEXT: #pragma omp sections +// CHECK-NEXT: { +// CHECK-NEXT: a = 2; +// CHECK-NEXT: } +#pragma omp parallel +#pragma omp sections private(argc,b),firstprivate(argv, c),lastprivate(d,f),reduction(+:e) reduction(min : g), nowait +{ + foo(); + #pragma omp section + #pragma omp sections + { + #pragma omp section + foo(); + } +} +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp sections private(argc,b) firstprivate(argv,c) lastprivate(d,f) reduction(+: e) reduction(min: g) nowait +// CHECK-NEXT: { +// CHECK-NEXT: foo(); +// CHECK-NEXT: #pragma omp section +// CHECK-NEXT: #pragma omp sections +// CHECK-NEXT: { +// CHECK-NEXT: #pragma omp section +// CHECK-NEXT: foo(); +// CHECK-NEXT: } +// CHECK-NEXT: } + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/sections_firstprivate_messages.cpp clang/test/OpenMP/sections_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/sections_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } +}; +class S6 { + int a; +public: + S6() : a(0) { } +}; + +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}} + S6 p; + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp sections firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections firstprivate () // expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (argc) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (argv[1]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(ba) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(ca) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(da) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(S2::S2s) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(S2::S2sc) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(p),firstprivate(e, g, p) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i) + #pragma omp sections firstprivate(i) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp sections firstprivate(i) // expected-error {{private variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp sections firstprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + { + foo(); + #pragma omp section + foo(); + } + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/sections_lastprivate_messages.cpp clang/test/OpenMP/sections_lastprivate_messages.cpp --- clang-3.4/test/OpenMP/sections_lastprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_lastprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,226 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{predetermined as shared}} +const S2 b; +const S2 ba[5]; +class S3 { // expected-note {{'S3' declared here}} + int a; + S3& operator =(const S3& s3); +public: + S3():a(0) { } + S3(S3 &s3):a(s3.a) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note 2 {{'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) {} +public: + S5(const S5 &s5):a(s5.a) { } + 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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + S4 e(4); // expected-note 2 {{'e' defined here}} + S5 g(5); // expected-note {{'g' defined here}} + S3 m; // expected-note {{'m' defined here}} + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp sections lastprivate // expected-error {{expected '(' after 'lastprivate'}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections lastprivate () // expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (argc) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (S1) // expected-error {{'S1' does not refer to a value}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate (argv[1]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(ba) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(da) // expected-error {{shared variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate (g), lastprivate(e, g) // expected-error {{lastprivate variable must have an accessible, unambiguous default constructor}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections private(i), lastprivate(i) // expected-error {{private variable cannot be lastprivate}} expected-note{{defined as private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i) + #pragma omp sections lastprivate(i) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp sections lastprivate(i) // expected-error {{private variable in '#pragma omp parallel' cannot be lastprivate in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp sections lastprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be lastprivate in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}} + { + foo(); + #pragma omp section + foo(); + } + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/sections_messages.cpp clang/test/OpenMP/sections_messages.cpp --- clang-3.4/test/OpenMP/sections_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,123 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp section // expected-error {{orphaned '#pragma omp section' is prohibited}} + ; + #pragma omp section // expected-error {{orphaned '#pragma omp section' is prohibited}} + foo(); + #pragma omp sections + { + foo(); + #pragma omp parallel + #pragma omp section // expected-error {{orphaned '#pragma omp section' is prohibited}} + foo(); + } + #pragma omp sections + { + foo(); + foo(); // expected-error {{the statement for '#pragma omp sections' must be '#pragma omp section'}} + } + #pragma omp sections + { + #pragma omp section + foo(); + foo(); // expected-error {{the statement for '#pragma omp sections' must be '#pragma omp section'}} + } + #pragma omp sections + foo(); // expected-error {{the statement for '#pragma omp sections' must be compound statement}} + #pragma omp sections nowait nowait // expected-error {{directive '#pragma omp sections' cannot contain more than one 'nowait' clause}} + { + foo(); + } + #pragma omp sections + { + foo(); + #pragma omp section + { + foo(); + foo(); + } + #pragma omp section + } // expected-error {{expected statement}} + #pragma omp sections + { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside a worksharing region}} + { + foo(); + } + } + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside a worksharing region}} + { + foo(); + } + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside a worksharing region}} + { + foo(); + } + } + #pragma omp master + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside a master region}} + { + foo(); + } + } + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside a critical region}} + { + foo(); + } + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) + #pragma omp ordered + { + foo(); + #pragma omp sections // expected-error {{region cannot be closely nested inside an ordered region}} + { + foo(); + } + } + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp sections + { + LS: + #pragma omp section + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + #pragma omp section + { + foo(); + goto LS; // expected-error {{use of undeclared label 'LS'}} + } + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp sections + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/sections_private_messages.cpp clang/test/OpenMP/sections_private_messages.cpp --- clang-3.4/test/OpenMP/sections_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,219 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 sections private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private () // expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (argc) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (S1) // expected-error {{'S1' does not refer to a value}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private (argv[1]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(ba) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(ca) // expected-error {{shared variable cannot be private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(da) // expected-error {{shared variable cannot be private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(S2::S2s) // expected-error {{shared variable cannot be private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections firstprivate(i), private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp sections private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp parallel firstprivate(i) + #pragma omp parallel reduction(+:i) + #pragma omp sections private(i) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections private(i) + { + foo(); + #pragma omp section + #pragma omp sections private(i) + { + foo(); + } + } + #pragma omp parallel + #pragma omp sections firstprivate(i) + { + foo(); + #pragma omp section + #pragma omp sections private(i) + { + foo(); + } + } + #pragma omp parallel + #pragma omp sections reduction(+:i) + { + foo(); + #pragma omp section + #pragma omp sections private(i) + { + foo(); + } + } + #pragma omp parallel + #pragma omp sections lastprivate(i) + { + foo(); + #pragma omp section + #pragma omp sections private(i) + { + foo(); + } + } + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/sections_reduction_messages.cpp clang/test/OpenMP/sections_reduction_messages.cpp --- clang-3.4/test/OpenMP/sections_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/sections_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,286 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note {{'j' defined here}} + S3 &p = k; + const int &r = da[i]; // expected-note 2 {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; // expected-note {{'fl' defined here}} + #pragma omp sections reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp sections reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (&& :argc) + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction (max : argv[1]) // expected-error {{expected variable name}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(^ : fl) // expected-error {{arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(+ : o) // expected-error {{no viable overloaded '+='}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i, j, q) + #pragma omp sections reduction(|| : i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp sections reduction(|| : i) // expected-error {{private variable in '#pragma omp parallel' cannot be reduction in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections private(i), reduction(|| : i) // expected-error {{private variable cannot be reduction}} expected-note {{defined as private}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel + #pragma omp sections reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + { + foo(); + #pragma omp section + foo(); + } + #pragma omp parallel shared(i) + #pragma omp parallel reduction(min : i) // expected-note {{defined as reduction}} + #pragma omp sections reduction(max : i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be reduction in '#pragma omp sections'}} + { + foo(); + #pragma omp section + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/simd_ast_print.cpp clang/test/OpenMP/simd_ast_print.cpp --- clang-3.4/test/OpenMP/simd_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template T reduct(T* arr, N num) { + N i; + N ind; + T sum = (T)0; +// CHECK: T sum = (T)0; +#pragma omp simd linear(ind), reduction(+:sum) +// CHECK-NEXT: #pragma omp simd linear(ind) reduction(+: sum) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + +template struct S { + S(const T &a) + :m_a(a) + {} + T result(T *v) const { + T res; +// CHECK: T res; +#pragma omp simd lastprivate(res) safelen(7) +// CHECK-NEXT: #pragma omp simd lastprivate(res) safelen(7) + for (T i = 7; i < m_a; ++i) { + res = v[i-7] + m_a; + } + return res; + } + ~S() + {} + T m_a; +}; + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int k1=0,k2=0; + static int *a; +// CHECK: static int *a; +#pragma omp simd +// CHECK-NEXT: #pragma omp simd + for (int i=0; i < 2; ++i)*a=2; +// CHECK-NEXT: for (int i = 0; i < 2; ++i) +// CHECK-NEXT: *a = 2; +#pragma omp parallel +#pragma omp simd private(argc,b),lastprivate(d,f),reduction(+:e) reduction(min : g), collapse(2) safelen(2) aligned(a:4), linear(k1,k2:8) + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp simd private(argc,b) lastprivate(d,f) reduction(+: e) reduction(min: g) collapse(2) safelen(2) aligned(a: 4) linear(k1,k2: 8) +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: for (int j = 0; j < 10; ++j) { +// CHECK-NEXT: foo(); +// CHECK-NEXT: k1 += 8; +// CHECK-NEXT: k2 += 8; +// CHECK-NEXT: } + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp simd aligned(a) linear(a) +// CHECK-NEXT: #pragma omp simd aligned(a) linear(a) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp simd collapse(1) +// CHECK: #pragma omp simd collapse(1) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + const int CLEN=4; +#pragma omp simd safelen(CLEN) +// CHECK: #pragma omp simd safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); +#pragma omp simd aligned(a:CLEN) linear(a:CLEN) safelen(CLEN) +// CHECK-NEXT: #pragma omp simd aligned(a: 4) linear(a: 4) safelen(4) + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/simd_collapse_messages.cpp clang/test/OpenMP/simd_collapse_messages.cpp --- clang-3.4/test/OpenMP/simd_collapse_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_collapse_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s +// This test is same as for_collapse_messages.cpp, but regarding 'simd' instead of 'for'. + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } + operator bool() { return f; } +} v2; + +struct S3 { + int f; + operator int() { return f; } +} v3; + +int main(int argc, char **argv) { // expected-note {{declared here}} + #pragma omp simd collapse // expected-error {{expected '(' after 'collapse'}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse () // expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (argc > 0 ? argv[1] : argv[2]) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (foobool(argc)) collapse(1) // expected-error {{directive '#pragma omp simd' cannot contain more than one 'collapse' clause}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (v1) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (v2) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (v3) // expected-error {{expression is not an integral constant expression}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (0) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + #pragma omp simd collapse (-1) // expected-error {{expression is not a positive integer value}} + for (int i = 0; i < 10; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/simd_lastprivate_messages.cpp clang/test/OpenMP/simd_lastprivate_messages.cpp --- clang-3.4/test/OpenMP/simd_lastprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_lastprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,115 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{predetermined as shared}} +const S2 b; +const S2 ba[5]; +class S3 { // expected-note {{'S3' declared here}} + int a; + S3& operator =(const S3& s3); +public: + S3():a(0) { } + S3(S3 &s3):a(s3.a) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +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) {} +public: + S5(const S5 &s5):a(s5.a) { } + 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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); // expected-note {{'g' defined here}} + S3 m; // expected-note {{'m' defined here}} + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp simd lastprivate // expected-error {{expected '(' after 'lastprivate'}} expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate () // expected-error {{expected expression}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (argc) + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (a, b, c, d, f) // expected-error {{lastprivate variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate (2*2) // expected-error {{expected variable name}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(ba) + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(ca) // expected-error {{shared variable cannot be lastprivate}} // TODO: is it true for simd? + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(da) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(S2::S2s) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(S2::S2sc) // expected-error {{shared variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd firstprivate (g) // expected-error {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(e, g) // expected-error 2 {{lastprivate variable must have an accessible, unambiguous default constructor}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(m) // expected-error {{lastprivate variable must have an accessible, unambiguous copy assignment operator}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd lastprivate(h) // expected-error {{threadprivate or thread local variable cannot be lastprivate}} + for (i = 0; i < argc; ++i) foo(); + #pragma omp simd private(i), lastprivate(i) // expected-error {{private variable cannot be lastprivate}} expected-note 2 {{defined as private}} + for (i = 0; i < argc; ++i) foo(); // expected-error {{loop iteration variable may not be private}} + #pragma omp parallel shared(i) + #pragma omp simd lastprivate(i) + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel private(i) + #pragma omp simd lastprivate(i) // OK: may be lastprivate + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel reduction(+:i) + #pragma omp simd lastprivate(i) // OK: may be lastprivate + for (i = 0; i < argc; ++i) foo(); + #pragma omp parallel + #pragma omp simd lastprivate(j) // expected-error {{arguments of OpenMP clause 'lastprivate' cannot be of reference type}} + for (i = 0; i < argc; ++i) foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/simd_linear_messages.cpp clang/test/OpenMP/simd_linear_messages.cpp --- clang-3.4/test/OpenMP/simd_linear_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_linear_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 0 -fopenmp -verify %s + +namespace X { + int x; +}; + +struct A { + int a; + void bar() { + #pragma omp simd linear(X::x) + for (int i = 0; i < 10; i++) ; + int j; + #pragma omp simd linear(j) + for (int i = 0; i < 10; i++) ; + + // TODO: Should be error here or no error in next directive? + #pragma omp simd linear(j:this->a) + for (int i = 0; i < 10; i++) ; + // expected-error@+1 {{expected variable name}} + #pragma omp simd linear(a) + for (int i = 0; i < 10; i++) ; + } +}; + + +int z; +const int C1 = 1; +const int C2 = 2; +void test_linear() +{ + int y; + char c; + A a; + a.a = 2; + + #pragma omp simd linear(X::x) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(y:z) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(X::x : ::z) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(y,::z, X::x) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(::z) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(y:C1+C2) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(c:y) + for (int i = 0; i < 10; ++i) ; + #pragma omp simd linear(y:c) + for (int i = 0; i < 10; ++i) ; +} + +template T test_template(T* arr, N num) { + N i; + float ind; + T sum = (T)0; + // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}} +#pragma omp simd linear(ind), reduction(+:sum) + for (i = 0; i < num; ++i) { + T cur = arr[ind]; + ++ind; + sum += cur; + } +} + + diff -uNr clang-3.4/test/OpenMP/simd_loop_messages.cpp clang/test/OpenMP/simd_loop_messages.cpp --- clang-3.4/test/OpenMP/simd_loop_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_loop_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,221 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s +// This test is same as for_loop_messages.cpp, but regarding 'simd' instead of 'for'. + +namespace std { + +struct random_access_iterator_tag { }; + +template +struct iterator_traits { + typedef typename Iter::difference_type difference_type; // expected-error {{no type named 'difference_type' in 'Iter'}} expected-error {{no type named 'difference_type' in 'Iter1'}} + typedef typename Iter::iterator_category iterator_category; // expected-error {{no type named 'iterator_category' in 'Iter'}} expected-error {{no type named 'iterator_category' in 'Iter1'}} expected-error {{no type named 'iterator_category' in 'Iter2'}} +}; + +template +typename iterator_traits::difference_type distance(Iter first, Iter last) { + return first - last; +} +} + +class Iter { + public: + Iter() { } + Iter(const Iter &) { } + Iter operator ++() { return *this; } + Iter operator --() { return *this; } + bool operator <(Iter a) { return true; } + bool operator >=(Iter a) { return false; } +}; +int operator -(Iter a, Iter b) { return 0; } +class Iter1 { + public: + Iter1() { } + Iter1(const Iter1 &) { } + Iter1 operator ++() { return *this; } + Iter1 operator --() { return *this; } + bool operator <(Iter1 a) { return true; } + bool operator >=(Iter1 a) { return false; } +}; +class Iter2 { + public: + Iter2() { } + Iter2(const Iter2 &) { } + Iter2 operator ++() { return *this; } + Iter2 operator --() { return *this; } + bool operator <(Iter2 a) { return true; } + bool operator >=(Iter2 a) { return false; } + typedef int difference_type; +}; +int operator -(Iter2 a, Iter2 b) { return 0; } +class Iter3 { + public: + Iter3() { } + Iter3(const Iter3 &) { } + Iter3 operator ++() { return *this; } + Iter3 operator --() { return *this; } + bool operator <(Iter3 a) { return true; } + bool operator >=(Iter3 a) { return false; } + typedef int difference_type; + typedef int iterator_category; +}; +int operator -(Iter3 a, Iter3 b) { return 0; } +class Iter4 { + public: + Iter4() { } + Iter4(const Iter4 &) { } + Iter4 operator ++() { return *this; } + Iter4 operator --() { return *this; } + bool operator <(Iter4 a) { return true; } + bool operator >=(Iter4 a) { return false; } + Iter4 operator+=(int) const {return Iter4();} + Iter4 operator-=(int) const {return Iter4();} + typedef int difference_type; + typedef std::random_access_iterator_tag iterator_category; +}; +int operator -(Iter4 a, Iter4 b) { return 0; } + +int t; +#pragma omp threadprivate(t) + +int main() { + #pragma omp simd + for (int i = 0; i < 10; i++) + ++i; + #pragma omp simd + for (t = 0; t < 10; t++) + ++t; + #pragma omp simd + for (int i; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp simd + for (float i = 0; i < 10.0f; i++) // expected-error {{variable must be of integer or random access iterator type}} + ++i; + #pragma omp simd + for (int i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp simd + for (int i = 0; i < 10; i |= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + int i; + #pragma omp simd + for (i = 0; i < 10; i++) + ++i; + #pragma omp simd + for (i--; i < 10; i++) // expected-error {{initialization of for-loop does not have canonical form}} + ++i; + #pragma omp simd + for (i = 0; i != 10; i++) // expected-error {{condition of for-loop does not have canonical form}} + ++i; + #pragma omp simd + for (i = 0; i < 10; i ^= 2) // expected-error {{increment of for-loop does not have canonical form}} + ++i; + Iter begin, end; + #pragma omp simd + for (Iter I = begin; I >= end; ++I) // expected-error {{increment expression must cause 'I' to decrease on each iteration of the loop}} + ++I; + #pragma omp simd + for (Iter I = end; I < begin; --I) // expected-error {{increment expression must cause 'I' to increase on each iteration of the loop}} + ++I; + #pragma omp simd + for (Iter I = begin; I < end; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp simd + for (Iter I = end; I >= begin; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter1 begin1; + #pragma omp simd + for (Iter1 I = begin1; I < begin1; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp simd + for (Iter1 I = begin1; I >= begin1; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter2 begin2; + #pragma omp simd + for (Iter2 I = begin2; I < begin2; ++I) // expected-note {{in instantiation of template class 'std::iterator_traits' requested here}} expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp simd + for (Iter2 I = begin2; I >= begin2; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter3 begin3; + #pragma omp simd + for (Iter3 I = begin3; I < begin3; ++I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + #pragma omp simd + for (Iter3 I = begin3; I >= begin3; --I) // expected-error {{iteration variable is not of a random access iterator type}} + ++I; + Iter4 begin4; + #pragma omp simd + for (Iter4 I = begin4; I < begin4; ++I) + ++I; + #pragma omp simd + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + goto label; // expected-error {{use of undeclared label 'label'}} + #pragma omp simd + for (int i = 0; i < 100; ++i) { + label: ++i; + } + #pragma omp simd collapse(1) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp simd collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + for (Iter4 I1 = begin4; I1 >= begin4; --I1) + for (Iter4 I2 = begin4; I2 >= begin4; --I2) + ++I; + #pragma omp simd collapse(0) // expected-error {{expression is not a positive integer value}} + for (Iter4 I = begin4; I >= begin4; --I) + ++I; + #pragma omp simd + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp for // expected-error {{region cannot be closely nested inside a simd region}} + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp for + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp simd + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp single + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp simd + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp sections + { + #pragma omp simd + for (Iter4 I = begin4; I >= begin4; --I) + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + } +#pragma omp sections + { +#pragma omp section + { + #pragma omp simd + for (Iter4 I = begin4; I >= begin4; --I) + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + } + } + #pragma omp master + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp simd + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp critical + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp simd + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp simd ordered // expected-error {{unexpected OpenMP clause 'ordered' in directive '#pragma omp simd'}} + for (Iter4 I = begin4; I >= begin4; --I) + #pragma omp ordered // expected-error {{region cannot be closely nested inside a simd region}} + #pragma omp simd + for (Iter4 J = begin4; J >= begin4; --J) + ++I; + #pragma omp simd collapse(3) + for (Iter4 I = begin4; I >= begin4; --I) + ++I; // expected-error {{only for-loops are allowed for '#pragma omp simd'}} + ++begin4; +} diff -uNr clang-3.4/test/OpenMP/simd_metadata.c clang/test/OpenMP/simd_metadata.c --- clang-3.4/test/OpenMP/simd_metadata.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_metadata.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -fopenmp -emit-llvm %s -o - | FileCheck %s + +void h1(float *c, float *a, float *b, int size) +{ +// CHECK-LABEL: define void @h1 + int t = 0; +#pragma omp simd safelen(16) aligned(a, b, c) linear(t) + for (int i = 0; i < size; ++i) { + c[i] = a[i] * a[i] + b[i] * b[t]; + ++t; +// do not emit parallel_loop_access metadata due to usage of safelen clause. +// CHECK-NOT: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.mem.parallel_loop_access {{![0-9]+}} + } +} + +void h2(float *c, float *a, float *b, int size) +{ +// CHECK-LABEL: define void @h2 + int t = 0; +#pragma omp simd aligned(a, b, c) linear(t) + for (int i = 0; i < size; ++i) { + c[i] = a[i] * a[i] + b[i] * b[t]; + ++t; +// CHECK: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.mem.parallel_loop_access [[LOOP_H2_HEADER:![0-9]+]] + } +} + +void h3(float *c, float *a, float *b, int size) +{ +// CHECK-LABEL: define void @h3 +#pragma omp simd aligned(a, b, c) + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) { + c[j*i] = a[i] * b[j]; + } + } +// do not emit parallel_loop_access for nested loop. +// CHECK-NOT: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.mem.parallel_loop_access {{![0-9]+}} +} + +void h4(float *c, float *a, float *b, int size) +{ +// CHECK-LABEL: define void @h4 +#pragma omp simd aligned(a, b, c) collapse(2) + for (int i = 0; i < size; ++i) { + for (int j = 0; j < size; ++j) { + c[j*i] = a[i] * b[j]; + } + } +// emit parallel_loop_access: nested loop is collapsed. +// CHECK: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.mem.parallel_loop_access [[LOOP_H4_HEADER:![0-9]+]] +} + +// Metadata for h1: +// CHECK: [[LOOP_H1_HEADER:![0-9]+]] = metadata !{metadata [[LOOP_H1_HEADER]], metadata [[LOOP_WIDTH_16:![0-9]+]], metadata [[LOOP_VEC_ENABLE:![0-9]+]]} +// CHECK: [[LOOP_WIDTH_16]] = metadata !{metadata !"llvm.vectorizer.width", i32 16} +// CHECK: [[LOOP_VEC_ENABLE]] = metadata !{metadata !"llvm.vectorizer.enable", i1 true} +// +// Metadata for h2: +// CHECK: [[LOOP_H2_HEADER]] = metadata !{metadata [[LOOP_H2_HEADER]], metadata [[LOOP_VEC_ENABLE]]} +// +// Metadata for h3: +// CHECK: [[LOOP_H3_HEADER:![0-9]+]] = metadata !{metadata [[LOOP_H3_HEADER]], metadata [[LOOP_VEC_ENABLE]]} +// +// Metadata for h4: +// CHECK: [[LOOP_H4_HEADER]] = metadata !{metadata [[LOOP_H4_HEADER]], metadata [[LOOP_VEC_ENABLE]]} +// diff -uNr clang-3.4/test/OpenMP/simd_misc_messages.c clang/test/OpenMP/simd_misc_messages.c --- clang-3.4/test/OpenMP/simd_misc_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_misc_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,455 @@ +// RUN: %clang_cc1 -fsyntax-only -ferror-limit 100000 -fopenmp -verify %s +// This test was initially supposed for '#pragma simd' and was +// changed to apply to '#pragma omp simd', which is similar. + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp simd'}} */ +#pragma omp simd + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp simd'}} */ +#pragma omp simd foo + +/* expected-error@+1 {{unexpected OpenMP directive '#pragma omp simd'}} */ +#pragma omp simd safelen(4) + +void test_no_clause() +{ + int i; + #pragma omp simd + for (i = 0; i < 16; ++i) ; +} + +void test_invalid_clause() +{ + int i; + /* expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}} */ + #pragma omp simd foo bar + for (i = 0; i < 16; ++i) ; +} + +void test_non_identifiers() +{ + int i, x; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}} + #pragma omp simd; + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}} + #pragma omp simd private(x); + for (i = 0; i < 16; ++i) ; + + // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}} + #pragma omp simd , private(x); + for (i = 0; i < 16; ++i) ; +} + +void test_safelen() +{ + int i; + /* expected-error@+1 {{expected '('}} expected-error@+1 {{expected expression}}*/ + #pragma omp simd safelen + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen( + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd safelen() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp simd safelen(, + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}} + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp simd safelen(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected '('}} */ + #pragma omp simd safelen 4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4 + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4, + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4,) + for (i = 0; i < 16; ++i) ; + /* xxpected-error@+1 {{expected expression}} */ + #pragma omp simd safelen(4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4 4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4,,4) + for (i = 0; i < 16; ++i) ; + #pragma omp simd safelen(4) + for (i = 0; i < 16; ++i) ; + // expected-warning@+3 {{extra tokens at the end of '#pragma omp simd' are ignored}} + /* expected-error@+2 {{expected ')'}} */ + /* expected-note@+1 {{to match this '('}} */ + #pragma omp simd safelen(4,8) + for (i = 0; i < 16; ++i) ; +} + +void test_linear() +{ + int i; + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} */ + #pragma omp simd linear( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}*/ + #pragma omp simd linear(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd linear(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd linear() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd linear(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp simd linear(0) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{use of undeclared identifier 'x'}} */ + #pragma omp simd linear(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{use of undeclared identifier 'x'}} */ + /* expected-error@+1 {{use of undeclared identifier 'y'}} */ + #pragma omp simd linear(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{use of undeclared identifier 'x'}} */ + /* expected-error@+2 {{use of undeclared identifier 'y'}} */ + /* expected-error@+1 {{use of undeclared identifier 'z'}} */ + #pragma omp simd linear(x, y, z) + for (i = 0; i < 16; ++i) ; + + int x, y; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd linear(x:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd linear(x:,) + for (i = 0; i < 16; ++i) ; + #pragma omp simd linear(x:1) + for (i = 0; i < 16; ++i) ; + #pragma omp simd linear(x:2*2) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp simd linear(x:1,y) + for (i = 0; i < 16; ++i) ; + // expected-warning@+2 {{extra tokens at the end of '#pragma omp simd' are ignored}} + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp simd linear(x:1,y,z:1) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be linear}} + #pragma omp simd linear(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as private}} + // expected-error@+1 {{private variable cannot be linear}} + #pragma omp simd private(x) linear(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be private}} + #pragma omp simd linear(x) private(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as linear}} + // expected-error@+1 {{linear variable cannot be lastprivate}} + #pragma omp simd linear(x) lastprivate(x) + for (i = 0; i < 16; ++i) ; + + // expected-note@+2 {{defined as lastprivate}} + // expected-error@+1 {{lastprivate variable cannot be linear}} + #pragma omp simd lastprivate(x) linear(x) + for (i = 0; i < 16; ++i) ; +} + +void test_private() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp simd private( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd private(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd private(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd private() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd private(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp simd private(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp simd private(x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd private(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp simd private(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_firstprivate() +{ + int i; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd firstprivate( + for (i = 0; i < 16; ++i) ; +} + +void test_lastprivate() +{ + int i; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd lastprivate( + for (i = 0; i < 16; ++i) ; + + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd lastprivate(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd lastprivate(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd lastprivate() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd lastprivate(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp simd lastprivate(0) + for (i = 0; i < 16; ++i) ; + + int x, y, z; + #pragma omp simd lastprivate(x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd lastprivate(x, y) + for (i = 0; i < 16; ++i) ; + #pragma omp simd lastprivate(x, y, z) + for (i = 0; i < 16; ++i) ; +} + +void test_reduction() +{ + int i, x, y; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp simd reduction( + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected identifier}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp simd reduction() + for (i = 0; i < 16; ++i) ; + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp simd reduction(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected identifier}} */ + #pragma omp simd reduction(:x) + for (i = 0; i < 16; ++i) ; + // expected-error@+4 {{expected ')'}} expected-note@+4 {{to match this '('}} + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd reduction(, + for (i = 0; i < 16; ++i) ; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + /* expected-error@+2 {{expected expression}} */ + /* expected-error@+1 {{expected ':' in 'reduction' clause}} */ + #pragma omp simd reduction(+ + for (i = 0; i < 16; ++i) ; + + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd reduction(+: + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd reduction(+:) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd reduction(+:,y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd reduction(+:x,+:y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+3 {{expected identifier}} */ + /* expected-error@+2 {{expected ':' in 'reduction' clause}} */ + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd reduction(%:x) + for (i = 0; i < 16; ++i) ; + + #pragma omp simd reduction(+:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(*:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(-:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(|:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(^:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(&&:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(||:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(max:x) + for (i = 0; i < 16; ++i) ; + #pragma omp simd reduction(min:x) + for (i = 0; i < 16; ++i) ; + struct X { int x; }; + struct X X; + // TODO: Is the following error correct? + // expected-error@+1 {{expected variable name}} + #pragma omp simd reduction(+:X.x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp simd reduction(+:x+x) + for (i = 0; i < 16; ++i) ; +} + +void test_aligned() +{ + int i; + /* expected-error@+2 {{expected expression}} */ + // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} + #pragma omp simd aligned( + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{expected ')'}} expected-note@+2 {{to match this '('}} + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd aligned(, + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 2 {{expected expression}} */ + #pragma omp simd aligned(,) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd aligned() + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected expression}} */ + #pragma omp simd aligned(int) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{expected variable name}} */ + #pragma omp simd aligned(0) + for (i = 0; i < 16; ++i) ; + + int *x, y, z[25]; + #pragma omp simd aligned(x) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp simd aligned(x, y) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp simd aligned(x, y, z) + for (i = 0; i < 16; ++i) ; + + #pragma omp simd aligned(x:4) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp simd aligned(x, y:8) + for (i = 0; i < 16; ++i) ; + /* expected-error@+1 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} */ + #pragma omp simd aligned(x, y, z:10+6) + for (i = 0; i < 16; ++i) ; + // expected-error@+2 {{argument of an aligned clause should be array, pointer, reference to array or reference to pointer}} + // expected-error@+1 {{expression is not an integer constant expression}} + #pragma omp simd aligned(x, y, z:x) + for (i = 0; i < 16; ++i) ; + // expected-note@+2 {{defined as aligned}} + // expected-error@+1 {{aligned variable cannot be aligned}} + #pragma omp simd aligned(x:16) aligned(z,x:16) + for (i = 0; i < 16; ++i) ; +} + +void test_multiple_clauses() +{ + int i; + float x = 0, y = 0, z = 0; + #pragma omp simd safelen(4) reduction(+:x, y) reduction(-:z) // OK + for (i = 0; i < 16; ++i); + + // expected-error@+1 {{private variable cannot be lastprivate}} expected-note@+1 {{defined as private}} + #pragma omp simd private(x), lastprivate(x) + for (i = 0; i < 16; ++i); + + #pragma omp simd safelen(4) reduction(+:x, y), reduction(-:z) + for (i = 0; i < 16; ++i); + + #pragma omp simd reduction(+:x, y) reduction(-:z) + for (i = 0; i < 16; ++i); +} + +void test_for() +{ + // expected-error@+3 {{expected '(' after 'for'}} + // expected-error@+2 2{{use of undeclared identifier 'i'}} + #pragma omp simd + for int i = 0; i < 16; i++); + + // expected-error@+3 {{expected ')'}} + // expected-note@+2 {{to match this '('}} + #pragma omp simd + for (int i = 0; i < 16; i++; + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp simd + for (int i = 0 i < 16; i++); + + // expected-error@+2 {{expected ';' in 'for' statement specifier}} + #pragma omp simd + for (int i = 0; i < 16 i++); + + // expected-error@+2 2 {{expected ';' in 'for' statement specifier}} + #pragma omp simd + for (int i = 0 i < 16 i++); + + int i = 0; + // expected-error@+2 {{initialization of for-loop does not have canonical form}} + #pragma omp simd + for (; i < 16; ++i); + + // expected-error@+2 {{condition of for-loop does not have canonical form}} + #pragma omp simd + for (int i = 0; ; ++i); + + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp simd + for (int i = 0; i < 16; ); + + // expected-error@+3 {{condition of for-loop does not have canonical form}} + // expected-error@+2 {{increment of for-loop does not have canonical form}} + #pragma omp simd + for (int i = 0; ;); + +} diff -uNr clang-3.4/test/OpenMP/simd_private_messages.cpp clang/test/OpenMP/simd_private_messages.cpp --- clang-3.4/test/OpenMP/simd_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 simd private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private () // expected-error {{expected expression}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (argc) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (S1) // expected-error {{'S1' does not refer to a value}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private (argv[1]) // expected-error {{expected variable name}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(ba) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(ca) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(da) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(S2::S2s) // expected-error {{shared variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp simd shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp simd'}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp parallel + { + int i; // expected-note {{predetermined as private}} + #pragma omp simd lastprivate(i), private(i) // expected-error {{private variable cannot be lastprivate}} + for (int k = 0; k < argc; ++k) ++k; + } + // TODO: The following seems to be incorrect -- why cannot it be lastprivate in simd? + #pragma omp parallel + { + int i; // expected-note {{predetermined as private}} + #pragma omp simd lastprivate(i) // expected-error {{private variable cannot be lastprivate}} + for (int k = 0; k < argc; ++k) ++k; + } + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp simd private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + for (int k = 0; k < argc; ++k) ++k; + #pragma omp parallel private(i) + #pragma omp parallel firstprivate(i) + #pragma omp parallel private(i) + #pragma omp parallel reduction(+:i) + #pragma omp simd private(i) + for (int k = 0; k < argc; ++k) ++k; + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + #pragma omp simd private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel firstprivate(i) + #pragma omp simd private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel reduction(+:i) + #pragma omp simd private(i) + for (int x = 0; x < 10; ++x) foo(); + } + #pragma omp parallel + #pragma omp for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel + #pragma omp simd private(i) + for (int x = 0; x < 10; ++x) foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/simd_reduction_messages.cpp clang/test/OpenMP/simd_reduction_messages.cpp --- clang-3.4/test/OpenMP/simd_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,141 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note {{'j' defined here}} + S3 &p = k; + const int &r = da[i]; // expected-note 2 {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + #pragma omp simd reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + for (int x = 0; x < 10; ++x) foo(); + #pragma omp simd reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (&& :argc) + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction (max : argv[1]) // expected-error {{expected variable name}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp simd reduction(+ : o) // expected-error {{no viable overloaded '+='}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel shared(i, j, q) + #pragma omp simd reduction(|| : i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int x = 0; x < 10; ++x) foo(); + #pragma omp parallel private(i) + #pragma omp simd reduction(|| : i) + for (int x = 0; x < 10; ++x) foo(); + #pragma omp parallel + #pragma omp simd private(i), reduction(|| : i) // expected-error {{private variable cannot be reduction}} expected-note 2 {{defined as private}} + for (i = 0; i < 10; ++i) foo(); // expected-error {{loop iteration variable may not be private}} + #pragma omp parallel + #pragma omp simd reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel + #pragma omp simd reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + for (i = 0; i < 10; ++i) foo(); + #pragma omp parallel shared(i) + #pragma omp simd reduction(max : i) // expected-note {{defined as reduction}} + for (i = 0; i < 10; ++i) foo(); // expected-error {{loop iteration variable may not be reduction}} + + return 0; +} diff -uNr clang-3.4/test/OpenMP/simd_safelen_messages.cpp clang/test/OpenMP/simd_safelen_messages.cpp --- clang-3.4/test/OpenMP/simd_safelen_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/simd_safelen_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -verify -fopenmp %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +template // expected-note {{declared here}} +T tmain(T argc, S **argv) { //expected-note 2 {{declared here}} + #pragma omp simd safelen // expected-error {{expected '(' after 'safelen'}} // expected-error {{expected expression}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen () // expected-error {{expected expression}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + // expected-error@+3 {{expected ')'}} expected-note@+3 {{to match this '('}} + // expected-error@+2 2 {{expression is not an integral constant expression}} + // expected-note@+1 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} + #pragma omp simd safelen (argc + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + // expected-error@+1 {{expression is not a positive integer value}} + #pragma omp simd safelen (ST // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen (1)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen ((ST > 0) ? 1 + ST : 2) + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + // expected-error@+3 2 {{directive '#pragma omp simd' cannot contain more than one 'safelen' clause}} + // expected-error@+2 2 {{expression is not a positive integer value}} + // expected-error@+1 2 {{expression is not an integral constant expression}} + #pragma omp simd safelen (foobool(argc)), safelen (true), safelen (-5) + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen (S) // expected-error {{'S' does not refer to a value}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + // expected-error@+1 2 {{expression is not an integral constant expression}} + #pragma omp simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen (4) + for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + #pragma omp simd safelen (N) // expected-error {{expression is not a positive integer value}} + for (T i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST]; + return argc; +} + +int main(int argc, char **argv) { + #pragma omp simd safelen // expected-error {{expected '(' after 'safelen'}} expected-error {{expected expression}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen () // expected-error {{expected expression}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen (4 // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen (2+2)) // expected-warning {{extra tokens at the end of '#pragma omp simd' are ignored}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen (foobool(1) > 0 ? 1 : 2) // expected-error {{expression is not an integral constant expression}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + // expected-error@+3 {{expression is not an integral constant expression}} + // expected-error@+2 2 {{directive '#pragma omp simd' cannot contain more than one 'safelen' clause}} + // expected-error@+1 2 {{expression is not a positive integer value}} + #pragma omp simd safelen (foobool(argc)), safelen (true), safelen (-5) + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + #pragma omp simd safelen (S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + // expected-error@+1 {{expression is not an integral constant expression}} + #pragma omp simd safelen (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 4; i < 12; i++) argv[0][i] = argv[0][i] - argv[0][i-4]; + // expected-error@+3 {{only for-loops are allowed for '#pragma omp simd'}} + // expected-note@+1 {{in instantiation of function template specialization 'tmain' requested here}} + #pragma omp simd safelen(safelen(tmain(argc, argv) // expected-error 2 {{expected ')'}} expected-note 2 {{to match this '('}} + foo(); + // expected-note@+1 {{in instantiation of function template specialization 'tmain' requested here}} + return tmain(argc, argv); +} + diff -uNr clang-3.4/test/OpenMP/single_ast_print.cpp clang/test/OpenMP/single_ast_print.cpp --- clang-3.4/test/OpenMP/single_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/single_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; + #pragma omp threadprivate(a) +// CHECK: static int a; +// CHECK-NEXT: #pragma omp threadprivate(a) +#pragma omp single + a=2; +// CHECK-NEXT: #pragma omp single +// CHECK-NEXT: a = 2; +#pragma omp parallel +#pragma omp single private(argc,b),firstprivate(argv, c),copyprivate(a) nowait + foo(); +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) copyprivate(a) nowait +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/single_copyprivate_messages.cpp clang/test/OpenMP/single_copyprivate_messages.cpp --- clang-3.4/test/OpenMP/single_copyprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/single_copyprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +class S2 { + mutable int a; +public: + S2():a(0) { } + S2 & operator =(S2 &s2) { return *this; } +}; +class S3 { + int a; +public: + S3():a(0) { } + S3 &operator =(S3 &s3) { return *this; } +}; +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4 &operator =(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} + S5 &operator =(const S5 &s5) { return *this; } +public: + S5(int v):a(v) { } +}; + +S2 k; +S3 h; +S4 l(3); // expected-note {{'l' defined here}} +S5 m(4); // expected-note {{'m' defined here}} +#pragma omp threadprivate(h, k, l, m) + +int main(int argc, char **argv) { + int i; + #pragma omp parallel + #pragma omp single copyprivate // expected-error {{expected '(' after 'copyprivate'}} expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single copyprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single copyprivate () // expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single copyprivate (k // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single copyprivate (h, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single copyprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single copyprivate (l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} + #pragma omp parallel + #pragma omp single copyprivate (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel + #pragma omp single copyprivate (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + #pragma omp parallel + #pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}} + foo(); + #pragma omp parallel private(i) + { + #pragma omp single copyprivate(i) + foo(); + } + #pragma omp parallel shared(i) // expected-note {{defined as shared}} + { + #pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } + #pragma omp parallel private(i) + #pragma omp parallel default(shared) + { + #pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/single_firstprivate_messages.cpp clang/test/OpenMP/single_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/single_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/single_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } +}; +class S6 { + int a; +public: + S6() : a(0) { } +}; + +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}} + S6 p; + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp single firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single firstprivate () // expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single firstprivate (argc) + #pragma omp parallel + #pragma omp single firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel + #pragma omp single firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + #pragma omp parallel + #pragma omp single firstprivate (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single firstprivate(ba) + #pragma omp parallel + #pragma omp single firstprivate(ca) + #pragma omp parallel + #pragma omp single firstprivate(da) + #pragma omp parallel + #pragma omp single firstprivate(S2::S2s) + #pragma omp parallel + #pragma omp single firstprivate(S2::S2sc) + #pragma omp parallel + #pragma omp single firstprivate(e, g, p) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + #pragma omp parallel + #pragma omp single firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + #pragma omp parallel + #pragma omp single private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + foo(); + #pragma omp parallel shared(i) + #pragma omp single firstprivate(i) + foo(); + #pragma omp parallel private(i) // expected-note {{defined as private}} + #pragma omp single firstprivate(i) // expected-error {{private variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp single'}} + foo(); + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp single firstprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp single'}} + foo(); + #pragma omp single firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + foo(); + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/single_messages.cpp clang/test/OpenMP/single_messages.cpp --- clang-3.4/test/OpenMP/single_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/single_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp single + ; + #pragma omp single nowait nowait // expected-error {{directive '#pragma omp single' cannot contain more than one 'nowait' clause}} + foo(); + { + #pragma omp single + } // expected-error {{expected statement}} + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp sections + { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside a worksharing region}} + foo(); + } + #pragma omp master + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside a master region}} + foo(); + } + #pragma omp critical + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside a critical region}} + foo(); + } + #pragma omp for ordered + for (int i = 0; i < 10; ++i) + #pragma omp ordered + { + foo(); + #pragma omp single // expected-error {{region cannot be closely nested inside an ordered region}} + foo(); + } + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp single + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp single + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/single_private_messages.cpp clang/test/OpenMP/single_private_messages.cpp --- clang-3.4/test/OpenMP/single_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/single_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 single private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single private () // expected-error {{expected expression}} + #pragma omp parallel + #pragma omp single private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel + #pragma omp single private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single private (argc) + #pragma omp parallel + #pragma omp single private (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel + #pragma omp single private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + #pragma omp parallel + #pragma omp single private (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel + #pragma omp single private(ba) + #pragma omp parallel + #pragma omp single private(ca) // expected-error {{shared variable cannot be private}} + #pragma omp parallel + #pragma omp single private(da) // expected-error {{shared variable cannot be private}} + #pragma omp parallel + #pragma omp single private(S2::S2s) // expected-error {{shared variable cannot be private}} + #pragma omp parallel + #pragma omp single private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp parallel + #pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + #pragma omp parallel + #pragma omp single shared(i) // expected-error {{unexpected OpenMP clause 'shared' in directive '#pragma omp single'}} + #pragma omp parallel + #pragma omp single firstprivate(i), private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}} + foo(); + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp single private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + foo(); + #pragma omp parallel shared(i) + #pragma omp parallel private(i) + #pragma omp parallel firstprivate(i) + #pragma omp parallel reduction(+:i) + #pragma omp single private(i) + foo(); + #pragma omp single private(i) + { + #pragma omp parallel + #pragma omp single private(i) + foo(); + } + #pragma omp parallel + #pragma omp single firstprivate(i) + { + #pragma omp parallel + #pragma omp single private(i) + foo(); + } + #pragma omp parallel private(i) + #pragma omp single copyprivate(i) + { + #pragma omp parallel + #pragma omp single private(i) + foo(); + } + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/target_ast_print.cpp clang/test/OpenMP/target_ast_print.cpp --- clang-3.4/test/OpenMP/target_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp target +// CHECK: #pragma omp target + a=2; +// CHECK-NEXT: a = 2; +#pragma omp target if(b) device(c+e) map(b,c) map(to:d) map(from:e) map(alloc:f) map(tofrom: g) +// CHECK: #pragma omp target if(b) device(c + e) map(tofrom: b,c) map(to: d) map(from: e) map(alloc: f) map(tofrom: g) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/target_data_ast_print.cpp clang/test/OpenMP/target_data_ast_print.cpp --- clang-3.4/test/OpenMP/target_data_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_data_ast_print.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp target data +// CHECK: #pragma omp target data + a=2; +// CHECK-NEXT: a = 2; +#pragma omp target data if(b) device(c+e) map(b,c) map(to:d) map(from:e) map(alloc:f) map(tofrom: g) +// CHECK: #pragma omp target data if(b) device(c + e) map(tofrom: b,c) map(to: d) map(from: e) map(alloc: f) map(tofrom: g) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/target_data_device_messages.cpp clang/test/OpenMP/target_data_device_messages.cpp --- clang-3.4/test/OpenMP/target_data_device_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_data_device_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target data device // expected-error {{expected '(' after 'device'}} expected-error {{expected expression}} + #pragma omp target data device ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data device () // expected-error {{expected expression}} + #pragma omp target data device (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data device (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target data device (foobool(argc)) device(3) // expected-error {{directive '#pragma omp target data' cannot contain more than one 'device' clause}} + #pragma omp target data device (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target data device (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target data device (v1) // expected-error {{expression has incomplete type 'S1'}} + #pragma omp target data device (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + #pragma omp target data device (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + #pragma omp target data device (0) + #pragma omp target data device (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_data_if_messages.cpp clang/test/OpenMP/target_data_if_messages.cpp --- clang-3.4/test/OpenMP/target_data_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_data_if_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp target data if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + #pragma omp target data if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data if () // expected-error {{expected expression}} + #pragma omp target data if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target data' are ignored}} + #pragma omp target data if (argc > 0 ? argv[1] : argv[2]) + #pragma omp target data if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target data' cannot contain more than one 'if' clause}} + #pragma omp target data if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target data if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_data_map_messages.cpp clang/test/OpenMP/target_data_map_messages.cpp --- clang-3.4/test/OpenMP/target_data_map_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_data_map_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note 2 {{mappable type cannot contain static members}} + static const float S2sc; // expected-note 2 {{mappable type cannot contain static members}} +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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-error {{threadprivate variables cannot be used in target constructs}} + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); + S5 g(5); + int i; + int &j = i; + int *k = &j; + const int (&l)[5] = da; + #pragma omp target data map // expected-error {{expected '(' after 'map'}} expected-error {{expected expression}} + #pragma omp target data map ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data map () // expected-error {{expected expression}} + #pragma omp target data map (alloc) // expected-error {{expected expression}} expected-error {{expected ':' in 'map' clause}} + #pragma omp target data map (to argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error{{expected ':' in 'map' clause}} + #pragma omp target data map (from: argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target data map (tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp target data map (argc) + #pragma omp target data map (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target data map (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target data map (argv[1]) + #pragma omp target data map(ba) // expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target data map(ca) + #pragma omp target data map(da) + #pragma omp target data map(S2::S2s) + #pragma omp target data map(S2::S2sc) + #pragma omp target data map(e, g) + #pragma omp target data map(h) // expected-note {{used here}} + #pragma omp target data map(k), map(k[:10]) // expected-error {{variable already marked as mapped in current construct}} expected-note {{used here}} + foo(); + #pragma omp target data map(da) + #pragma omp target data map(da[:4]) + foo(); + #pragma omp target data map(k, j, l) // expected-note 2 {{used here}} + #pragma omp target data map(k[:4]) // expected-error {{variable already marked as mapped in current construct}} + #pragma omp target data map(j) + #pragma omp target data map(l[:5]) // expected-error {{variable already marked as mapped in current construct}} + foo(); + #pragma omp target data map(k[:4], j, l[:5]) // expected-note 2 {{used here}} + #pragma omp target data map(k) // expected-error {{variable already marked as mapped in current construct}} + #pragma omp target data map(j) + #pragma omp target data map(l) // expected-error {{variable already marked as mapped in current construct}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_data_messages.c clang/test/OpenMP/target_data_messages.c --- clang-3.4/test/OpenMP/target_data_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_data_messages.c 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { } + +int main(int argc, char **argv) { + L1: + foo(); + #pragma omp target data + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp target data + L2: + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_device_messages.cpp clang/test/OpenMP/target_device_messages.cpp --- clang-3.4/test/OpenMP/target_device_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_device_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target device // expected-error {{expected '(' after 'device'}} expected-error {{expected expression}} + #pragma omp target device ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target device () // expected-error {{expected expression}} + #pragma omp target device (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target device (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target device (foobool(argc)) device(3) // expected-error {{directive '#pragma omp target' cannot contain more than one 'device' clause}} + #pragma omp target device (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target device (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target device (v1) // expected-error {{expression has incomplete type 'S1'}} + #pragma omp target device (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + #pragma omp target device (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + #pragma omp target device (0) + #pragma omp target device (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_if_messages.cpp clang/test/OpenMP/target_if_messages.cpp --- clang-3.4/test/OpenMP/target_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_if_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp target if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + #pragma omp target if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target if () // expected-error {{expected expression}} + #pragma omp target if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}} + #pragma omp target if (argc > 0 ? argv[1] : argv[2]) + #pragma omp target if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target' cannot contain more than one 'if' clause}} + #pragma omp target if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_map_messages.cpp clang/test/OpenMP/target_map_messages.cpp --- clang-3.4/test/OpenMP/target_map_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_map_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note 2 {{mappable type cannot contain static members}} + static const float S2sc; // expected-note 2 {{mappable type cannot contain static members}} +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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-error {{threadprivate variables cannot be used in target constructs}} + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); + S5 g(5); + int i; + int &j = i; + int *k = &j; + const int (&l)[5] = da; + #pragma omp target map // expected-error {{expected '(' after 'map'}} expected-error {{expected expression}} + #pragma omp target map ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target map () // expected-error {{expected expression}} + #pragma omp target map (alloc) // expected-error {{expected expression}} expected-error {{expected ':' in 'map' clause}} + #pragma omp target map (to argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error{{expected ':' in 'map' clause}} + #pragma omp target map (from: argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target map (tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp target map (argc) + #pragma omp target map (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target map (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target map (argv[1]) + #pragma omp target map(ba) // expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target map(ca) + #pragma omp target map(da) + #pragma omp target map(S2::S2s) + #pragma omp target map(S2::S2sc) + #pragma omp target map(e, g) + #pragma omp target map(h) // expected-note {{used here}} + #pragma omp target map(k), map(k[:10]) // expected-error {{variable already marked as mapped in current construct}} expected-note {{used here}} + foo(); + #pragma omp target map(da) + #pragma omp target map(da[:4]) + foo(); + #pragma omp target map(k, j, l) // expected-note 2 {{used here}} + #pragma omp target map(k[:4]) // expected-error {{variable already marked as mapped in current construct}} + #pragma omp target map(j) + #pragma omp target map(l[:5]) // expected-error {{variable already marked as mapped in current construct}} + foo(); + #pragma omp target map(k[:4], j, l[:5]) // expected-note 2 {{used here}} + #pragma omp target map(k) // expected-error {{variable already marked as mapped in current construct}} + #pragma omp target map(j) + #pragma omp target map(l) // expected-error {{variable already marked as mapped in current construct}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_messages.c clang/test/OpenMP/target_messages.c --- clang-3.4/test/OpenMP/target_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { } + +int main(int argc, char **argv) { + L1: + foo(); + #pragma omp target + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp target + L2: + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_ast_print.cpp clang/test/OpenMP/target_teams_ast_print.cpp --- clang-3.4/test/OpenMP/target_teams_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_ast_print.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp target teams +// CHECK: #pragma omp target teams + a=2; +// CHECK-NEXT: a = 2; +#pragma omp target if(b) device(c+e) map(b,c) map(to:d) map(from:e) map(alloc:f) map(tofrom: g) + +#pragma omp target teams num_teams(a), thread_limit(c), default(none), private(argc,b),firstprivate(argv, c),shared(d,f),reduction(+:e) reduction(min : g) if(b) device(c+e) map(b,c) map(to:d) map(from:e) map(alloc:f) map(tofrom: g) +// CHECK: #pragma omp target teams num_teams(a) thread_limit(c) default(none) private(argc,b) firstprivate(argv,c) shared(d,f) reduction(+: e) reduction(min: g) if(b) device(c + e) map(tofrom: b,c) map(to: d) map(from: e) map(alloc: f) map(tofrom: g) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/target_teams_default_messages.cpp clang/test/OpenMP/target_teams_default_messages.cpp --- clang-3.4/test/OpenMP/target_teams_default_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_default_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp target teams default // expected-error {{expected '(' after 'default'}} expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + #pragma omp target teams default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + #pragma omp target teams default (none // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams default (shared), default(shared) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'default' clause}} + foo(); + #pragma omp target teams default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_device_messages.cpp clang/test/OpenMP/target_teams_device_messages.cpp --- clang-3.4/test/OpenMP/target_teams_device_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_device_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target teams device // expected-error {{expected '(' after 'device'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams device ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams device () // expected-error {{expected expression}} + foo(); + #pragma omp target teams device (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams device (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams device (foobool(argc)) device(3) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'device' clause}} + foo(); + #pragma omp target teams device (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams device (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams device (v1) // expected-error {{expression has incomplete type 'S1'}} + foo(); + #pragma omp target teams device (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + foo(); + #pragma omp target teams device (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + foo(); + #pragma omp target teams device (0) + foo(); + #pragma omp target teams device (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_firstprivate_messages.cpp clang/test/OpenMP/target_teams_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/target_teams_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_firstprivate_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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 target teams firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams firstprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target teams firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams firstprivate (argc) + foo(); + #pragma omp target teams firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + foo(); + #pragma omp target teams firstprivate (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams firstprivate(ba) + foo(); + #pragma omp target teams firstprivate(ca) + foo(); + #pragma omp target teams firstprivate(da) + foo(); + #pragma omp target teams firstprivate(S2::S2s) + foo(); + #pragma omp target teams firstprivate(S2::S2sc) + foo(); + #pragma omp target teams firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + foo(); + #pragma omp target teams firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + foo(); + #pragma omp target teams private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + foo(); + #pragma omp target teams firstprivate(i) + foo(); + #pragma omp target teams firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_if_messages.cpp clang/test/OpenMP/target_teams_if_messages.cpp --- clang-3.4/test/OpenMP/target_teams_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_if_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp target teams if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams if () // expected-error {{expected expression}} + foo(); + #pragma omp target teams if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target teams' are ignored}} + foo(); + #pragma omp target teams if (argc > 0 ? argv[1] : argv[2]) + foo(); + #pragma omp target teams if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'if' clause}} + foo(); + #pragma omp target teams if (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_map_messages.cpp clang/test/OpenMP/target_teams_map_messages.cpp --- clang-3.4/test/OpenMP/target_teams_map_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_map_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,114 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note 2 {{mappable type cannot contain static members}} + static const float S2sc; // expected-note 2 {{mappable type cannot contain static members}} +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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-error {{threadprivate variables cannot be used in target constructs}} + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); + S5 g(5); + int i; + int &j = i; + int *k = &j; + const int (&l)[5] = da; + #pragma omp target teams map // expected-error {{expected '(' after 'map'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams map ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams map () // expected-error {{expected expression}} + foo(); + #pragma omp target teams map (alloc) // expected-error {{expected expression}} expected-error {{expected ':' in 'map' clause}} + foo(); + #pragma omp target teams map (to argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error{{expected ':' in 'map' clause}} + foo(); + #pragma omp target teams map (from: argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams map (tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams map (argc) + foo(); + #pragma omp target teams map (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams map (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} + foo(); + #pragma omp target teams map (argv[1]) + foo(); + #pragma omp target teams map(ba) // expected-error 2 {{type 'S2' is not mappable to target}} + foo(); + #pragma omp target teams map(ca) + foo(); + #pragma omp target teams map(da) + foo(); + #pragma omp target teams map(S2::S2s) + foo(); + #pragma omp target teams map(S2::S2sc) + foo(); + #pragma omp target teams map(e, g) + foo(); + #pragma omp target teams map(h) // expected-note {{used here}} + foo(); + #pragma omp target teams map(k), map(k[:10]) // expected-error {{variable already marked as mapped in current construct}} expected-note {{used here}} + foo(); + #pragma omp target map(da) + #pragma omp target teams map(da[:4]) + foo(); + #pragma omp target map(k, j, l) // expected-note {{used here}} + #pragma omp target teams map(k[:4]) // expected-error {{variable already marked as mapped in current construct}} + foo(); + #pragma omp target map(k, j, l) // expected-note {{used here}} + #pragma omp target map(j) + #pragma omp target teams map(l[:5]) // expected-error {{variable already marked as mapped in current construct}} + foo(); + #pragma omp target map(k[:4], j, l[:5]) // expected-note 2 {{used here}} + #pragma omp target teams map(k) // expected-error {{variable already marked as mapped in current construct}} + #pragma omp target map(j) + #pragma omp target teams map(l) // expected-error {{variable already marked as mapped in current construct}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_messages.c clang/test/OpenMP/target_teams_messages.c --- clang-3.4/test/OpenMP/target_teams_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_messages.c 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { } + +int main(int argc, char **argv) { + L1: + foo(); + #pragma omp target teams + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp target teams + L2: + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_messages.cpp clang/test/OpenMP/target_teams_messages.cpp --- clang-3.4/test/OpenMP/target_teams_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +#pragma omp target teams // expected-error {{unexpected OpenMP directive '#pragma omp target teams'}} + +int main(int argc, char **argv) { + #pragma omp target teams + foo(); + #pragma omp target teams unknown() // expected-warning {{extra tokens at the end of '#pragma omp target teams' are ignored}} + foo(); + L1: + foo(); + #pragma omp target teams + ; + #pragma omp target teams + { + goto L1; // expected-error {{use of undeclared label 'L1'}} + argc++; + } + + for (int i = 0; i < 10; ++i) { + switch(argc) { + case (0): + #pragma omp target teams + { + foo(); + break; // expected-error {{'break' statement not in loop or switch statement}} + continue; // expected-error {{'continue' statement not in loop statement}} + } + default: + break; + } + } + #pragma omp target teams default(none) + ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}} + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_num_teams_messages.cpp clang/test/OpenMP/target_teams_num_teams_messages.cpp --- clang-3.4/test/OpenMP/target_teams_num_teams_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_num_teams_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target teams num_teams // expected-error {{expected '(' after 'num_teams'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams num_teams ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams num_teams () // expected-error {{expected expression}} + foo(); + #pragma omp target teams num_teams (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams num_teams (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams num_teams (foobool(argc)) num_teams(3) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'num_teams' clause}} + foo(); + #pragma omp target teams num_teams (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams num_teams (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams num_teams (v1) // expected-error {{expression has incomplete type 'S1'}} + foo(); + #pragma omp target teams num_teams (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + foo(); + #pragma omp target teams num_teams (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + foo(); + #pragma omp target teams num_teams (0) // expected-error {{expression is not a positive integer value}} + foo(); + #pragma omp target teams num_teams (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_private_messages.cpp clang/test/OpenMP/target_teams_private_messages.cpp --- clang-3.4/test/OpenMP/target_teams_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_private_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 target teams private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams private () // expected-error {{expected expression}} + foo(); + #pragma omp target teams private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams private (argc) + foo(); + #pragma omp target teams private (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + foo(); + #pragma omp target teams private (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams private(ba) + foo(); + #pragma omp target teams private(ca) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target teams private(da) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target teams private(S2::S2s) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target teams private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + foo(); + #pragma omp target teams private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + foo(); + #pragma omp target teams shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} + foo(); + #pragma omp target teams private(i) + foo(); + #pragma omp target teams private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + foo(); + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp target teams + #pragma omp parallel for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp target teams + #pragma omp parallel for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp target teams + #pragma omp parallel for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp parallel private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp parallel firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + #pragma omp parallel reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp target teams private(i) + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_reduction_messages.cpp clang/test/OpenMP/target_teams_reduction_messages.cpp --- clang-3.4/test/OpenMP/target_teams_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_reduction_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,136 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note 2 {{'j' defined here}} + S3 &p = k; + const int &r = da[i]; // expected-note {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; // expected-note {{'fl' defined here}} + #pragma omp target teams reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + foo(); + #pragma omp target teams reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target teams reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + foo(); + #pragma omp target teams reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target teams reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target teams reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams reduction (&& :argc) + foo(); + #pragma omp target teams reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target teams reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target teams reduction (max : argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target teams reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target teams reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target teams reduction(^ : fl) // expected-error {{arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type}} + foo(); + #pragma omp target teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + foo(); + #pragma omp target teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target teams reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + foo(); + #pragma omp target teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + foo(); + #pragma omp target teams reduction(+ : o) // expected-error {{no viable overloaded '+='}} + foo(); + #pragma omp target teams private(i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + foo(); + #pragma omp target teams reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + foo(); + #pragma omp target teams reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp parallel shared(i) + #pragma omp target teams reduction(min : i) + foo(); + #pragma omp parallel reduction(min : i) + #pragma omp target teams reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_shared_messages.cpp clang/test/OpenMP/target_teams_shared_messages.cpp --- clang-3.4/test/OpenMP/target_teams_shared_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_shared_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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); + S5 g(5); + int i; + int &j = i; + #pragma omp target teams shared // expected-error {{expected '(' after 'shared'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams shared () // expected-error {{expected expression}} + foo(); + #pragma omp target teams shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams shared (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams shared (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams shared (argc) + foo(); + #pragma omp target teams shared (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams shared (a, b, c, d, f) + foo(); + #pragma omp target teams shared (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target teams shared(ba) + foo(); + #pragma omp target teams shared(ca) + foo(); + #pragma omp target teams shared(da) + foo(); + #pragma omp target teams shared(e, g) + foo(); + #pragma omp target teams shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}} + foo(); + #pragma omp target teams private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}} + foo(); + #pragma omp parallel private(i) + #pragma omp target teams shared(i) + foo(); + #pragma omp target teams shared(j) + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_teams_thread_limit_messages.cpp clang/test/OpenMP/target_teams_thread_limit_messages.cpp --- clang-3.4/test/OpenMP/target_teams_thread_limit_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_teams_thread_limit_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target teams thread_limit // expected-error {{expected '(' after 'thread_limit'}} expected-error {{expected expression}} + foo(); + #pragma omp target teams thread_limit ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams thread_limit () // expected-error {{expected expression}} + foo(); + #pragma omp target teams thread_limit (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target teams thread_limit (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams thread_limit (foobool(argc)) thread_limit(3) // expected-error {{directive '#pragma omp target teams' cannot contain more than one 'thread_limit' clause}} + foo(); + #pragma omp target teams thread_limit (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target teams thread_limit (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target teams thread_limit (v1) // expected-error {{expression has incomplete type 'S1'}} + foo(); + #pragma omp target teams thread_limit (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + foo(); + #pragma omp target teams thread_limit (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + foo(); + #pragma omp target teams thread_limit (0) // expected-error {{expression is not a positive integer value}} + foo(); + #pragma omp target teams thread_limit (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_update_ast_print.cpp clang/test/OpenMP/target_update_ast_print.cpp --- clang-3.4/test/OpenMP/target_update_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_update_ast_print.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp target update +// CHECK: #pragma omp target update + a=2; +// CHECK-NEXT: a = 2; +#pragma omp target update if(b) device(c+e) from(c) to(e, f) +// CHECK: #pragma omp target update if(b) device(c + e) from(c) to(e,f) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/target_update_device_messages.cpp clang/test/OpenMP/target_update_device_messages.cpp --- clang-3.4/test/OpenMP/target_update_device_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_update_device_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target update device // expected-error {{expected '(' after 'device'}} expected-error {{expected expression}} + #pragma omp target update device ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update device () // expected-error {{expected expression}} + #pragma omp target update device (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update device (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target update device (foobool(argc)) device(3) // expected-error {{directive '#pragma omp target update' cannot contain more than one 'device' clause}} + #pragma omp target update device (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target update device (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + #pragma omp target update device (v1) // expected-error {{expression has incomplete type 'S1'}} + #pragma omp target update device (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + #pragma omp target update device (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + #pragma omp target update device (0) + #pragma omp target update device (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_update_from_to_messages.cpp clang/test/OpenMP/target_update_from_to_messages.cpp --- clang-3.4/test/OpenMP/target_update_from_to_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_update_from_to_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note 2 {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note 4 {{mappable type cannot contain static members}} + static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}} +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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-error 2 {{threadprivate variables cannot be used in target constructs}} + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); + S5 g(5); + int i; + int &j = i; + int *k = &j; + const int (&l)[5] = da; + #pragma omp target update from // expected-error {{expected '(' after 'from'}} expected-error {{expected expression}} + #pragma omp target update from ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update from () // expected-error {{expected expression}} + #pragma omp target update from (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update from (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update from (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp target update from (argc) + #pragma omp target update from (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target update from (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target update from (argv[1]) + #pragma omp target update from(ba) // expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target update from(ca) + #pragma omp target update from(da) + #pragma omp target update from(S2::S2s) + #pragma omp target update from(S2::S2sc) + #pragma omp target update from(e, g) + #pragma omp target update from(h) // expected-note {{used here}} + #pragma omp target update from(k), from(k[:10]) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}} + foo(); + #pragma omp target update from(da) + #pragma omp target update from(da[:4]) + foo(); + + #pragma omp target update to // expected-error {{expected '(' after 'to'}} expected-error {{expected expression}} + #pragma omp target update to ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update to () // expected-error {{expected expression}} + #pragma omp target update to (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update to (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update to (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp target update to (argc) + #pragma omp target update to (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target update to (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target update to (argv[1]) + #pragma omp target update to(ba) // expected-error 2 {{type 'S2' is not mappable to target}} + #pragma omp target update to(ca) + #pragma omp target update to(da) + #pragma omp target update to(S2::S2s) + #pragma omp target update to(S2::S2sc) + #pragma omp target update to(e, g) + #pragma omp target update to(h) // expected-note {{used here}} + #pragma omp target update to(k), to(k[:10]) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}} + foo(); + #pragma omp target update to(da) + #pragma omp target update to(da[:4]) + foo(); + #pragma omp target update to(da[:4]) from(da) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}} + return 0; +} diff -uNr clang-3.4/test/OpenMP/target_update_if_messages.cpp clang/test/OpenMP/target_update_if_messages.cpp --- clang-3.4/test/OpenMP/target_update_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/target_update_if_messages.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp target update if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + #pragma omp target update if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update if () // expected-error {{expected expression}} + #pragma omp target update if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp target update if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target update' are ignored}} + #pragma omp target update if (argc > 0 ? argv[1] : argv[2]) + #pragma omp target update if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp target update' cannot contain more than one 'if' clause}} + #pragma omp target update if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp target update if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_ast_print.cpp clang/test/OpenMP/task_ast_print.cpp --- clang-3.4/test/OpenMP/task_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +template +T tmain (T argc, S **argv) { + T b = argc, c, d, e, f, g; + T arr[25][123][2234]; + static T a; +// CHECK: static int a; +#pragma omp task + a=2; +// CHECK-NEXT: #pragma omp task +// CHECK-NEXT: a = 2; +#pragma omp task if(b), final(a), untied, default(shared) mergeable, private(argc,b),firstprivate(argv, c),shared(d,f) depend(in:argc) depend(out : c) depend(inout:arr[1:argc][:][0:23], argc) + foo(); +// CHECK: #pragma omp task if(b) final(a) untied default(shared) mergeable private(argc,b) firstprivate(argv,c) shared(d,f) depend(in: argc) depend(out: c) depend(inout: arr[1:argc][0:123 - 0][0:23],argc) +// CHECK-NEXT: foo(); + return T(); +} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + int arr[25][123][2234]; + static int a; +// CHECK: static int a; +#pragma omp task + a=2; +// CHECK-NEXT: #pragma omp task +// CHECK-NEXT: a = 2; +#pragma omp task if(b), final(a), untied, default(shared) mergeable, private(argc,b),firstprivate(argv, c),shared(d,f) depend(in:argc) depend(out : c) depend(inout:arr[1:argc][:][0:23], argc) + foo(); +// CHECK: #pragma omp task if(b) final(a) untied default(shared) mergeable private(argc,b) firstprivate(argv,c) shared(d,f) depend(in: argc) depend(out: c) depend(inout: arr[1:argc][0:123 - 0][0:23],argc) +// CHECK-NEXT: foo(); + return tmain(argc, argv); +} + +#endif diff -uNr clang-3.4/test/OpenMP/task_default_messages.cpp clang/test/OpenMP/task_default_messages.cpp --- clang-3.4/test/OpenMP/task_default_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_default_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp task default // expected-error {{expected '(' after 'default'}} expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + #pragma omp task default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + #pragma omp task default (none // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task default (shared), default(shared) // expected-error {{directive '#pragma omp task' cannot contain more than one 'default' clause}} + #pragma omp task default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_depend_messages.cpp clang/test/OpenMP/task_depend_messages.cpp --- clang-3.4/test/OpenMP/task_depend_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_depend_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +class vector { + public: + int operator[](int index) { return 0; } +}; + +int main(int argc, char **argv) { + vector vec; + typedef float V __attribute__((vector_size(16))); + V a; + + #pragma omp task depend // expected-error {{expected '(' after 'depend'}} expected-error {{expected dependence type 'in', 'out' or 'inout'}} + #pragma omp task depend ( // expected-error {{expected dependence type 'in', 'out' or 'inout'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task depend () // expected-error {{expected dependence type 'in', 'out' or 'inout'}} + #pragma omp task depend (argc // expected-error {{expected dependence type 'in', 'out' or 'inout'}} expected-error {{expected ':' in 'depend' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} + #pragma omp task depend (out: ) // expected-error {{expected expression}} + #pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{argument expression must be an l-value}} expected-error {{expected ':' in 'depend' clause}} expected-error {{expected expression}} + #pragma omp task depend (out :S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task depend (in : argv[1][1]='2') // expected-error {{expected variable name or an array item}} + #pragma omp task depend (in : vec[1:2]) // expected-error {{argument expression must be an l-value}} + #pragma omp task depend (in : argv[0:-1]) // expected-error {{length of the array section must be greater than 0}} + #pragma omp task depend (in : argv[:]) // expected-error {{cannot define default length for non-array type 'char **'}} + #pragma omp task depend (in : argv[3:4:1]) // expected-error {{expected ']'}} expected-note {{to match this '['}} + #pragma omp task depend(in:a[0:1]) // expected-error{{extended array notation is not allowed}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_final_messages.cpp clang/test/OpenMP/task_final_messages.cpp --- clang-3.4/test/OpenMP/task_final_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_final_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp task final // expected-error {{expected '(' after 'final'}} expected-error {{expected expression}} + #pragma omp task final ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task final () // expected-error {{expected expression}} + #pragma omp task final (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task final (argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} + #pragma omp task final (argc > 0 ? argv[1] : argv[2]) + #pragma omp task final (foobool(argc)), final (true) // expected-error {{directive '#pragma omp task' cannot contain more than one 'final' clause}} + #pragma omp task final (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task final (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_firstprivate_messages.cpp clang/test/OpenMP/task_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/task_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } +}; +class S6 { + int a; +public: + S6() : a(0) { } +}; + +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}} + S6 p; + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp task firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + #pragma omp task firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task firstprivate () // expected-error {{expected expression}} + #pragma omp task firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp task firstprivate (argc) + #pragma omp task firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + #pragma omp task firstprivate (argv[1]) // expected-error {{expected variable name}} + #pragma omp task firstprivate(ba) + #pragma omp task firstprivate(ca) + #pragma omp task firstprivate(da) + #pragma omp task firstprivate(S2::S2s) + #pragma omp task firstprivate(S2::S2sc) + #pragma omp task firstprivate(e, g, p) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + #pragma omp task firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + #pragma omp task private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + foo(); + #pragma omp parallel shared(i) + #pragma omp task firstprivate(i) + foo(); + #pragma omp parallel private(i) + #pragma omp parallel shared(i) + #pragma omp task firstprivate(i) + foo(); + #pragma omp parallel reduction(+:i) // expected-note {{defined as reduction}} + #pragma omp task firstprivate(i) // expected-error {{reduction variable in '#pragma omp parallel' cannot be firstprivate in '#pragma omp task'}} + foo(); + #pragma omp task firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + foo(); + + return 0; +} \ No newline at end of file diff -uNr clang-3.4/test/OpenMP/task_if_messages.cpp clang/test/OpenMP/task_if_messages.cpp --- clang-3.4/test/OpenMP/task_if_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_if_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} + +int main(int argc, char **argv) { + #pragma omp task if // expected-error {{expected '(' after 'if'}} expected-error {{expected expression}} + #pragma omp task if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task if () // expected-error {{expected expression}} + #pragma omp task if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}} + #pragma omp task if (argc > 0 ? argv[1] : argv[2]) + #pragma omp task if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp task' cannot contain more than one 'if' clause}} + #pragma omp task if (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_messages.cpp clang/test/OpenMP/task_messages.cpp --- clang-3.4/test/OpenMP/task_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp task + ; + #pragma omp task untied untied // expected-error {{directive '#pragma omp task' cannot contain more than one 'untied' clause}} + foo(); + #pragma omp task mergeable mergeable // expected-error {{directive '#pragma omp task' cannot contain more than one 'mergeable' clause}} + foo(); + { + #pragma omp task + } // expected-error {{expected statement}} + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp task + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp task + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_private_messages.cpp clang/test/OpenMP/task_private_messages.cpp --- clang-3.4/test/OpenMP/task_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,114 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 task private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + #pragma omp task private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task private () // expected-error {{expected expression}} + #pragma omp task private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp task private (argc) + #pragma omp task private (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + #pragma omp task private (argv[1]) // expected-error {{expected variable name}} + #pragma omp task private(ba) + #pragma omp task private(ca) // expected-error {{shared variable cannot be private}} + #pragma omp task private(da) // expected-error {{shared variable cannot be private}} + #pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}} + #pragma omp task private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp task private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + #pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} + foo(); + #pragma omp parallel + #pragma omp task shared(i) + #pragma omp task private(i) + #pragma omp task private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + foo(); + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp parallel + #pragma omp for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp parallel + #pragma omp for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp parallel + #pragma omp for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp task private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp task firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + #pragma omp parallel reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp task private(i) + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/task_shared_messages.cpp clang/test/OpenMP/task_shared_messages.cpp --- clang-3.4/test/OpenMP/task_shared_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/task_shared_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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); + S5 g(5); + int i; + int &j = i; + #pragma omp parallel + #pragma omp task shared // expected-error {{expected '(' after 'shared'}} expected-error {{expected expression}} + #pragma omp task shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task shared () // expected-error {{expected expression}} + #pragma omp task shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task shared (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp task shared (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp task shared (argc) + #pragma omp task shared (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp task shared (a, b, c, d, f) + #pragma omp task shared (argv[1]) // expected-error {{expected variable name}} + #pragma omp task shared(ba) + #pragma omp task shared(ca) + #pragma omp task shared(da) + #pragma omp task shared(e, g) + #pragma omp task shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}} + #pragma omp task private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}} + foo(); + #pragma omp parallel + #pragma omp task private(i) + #pragma omp task shared(i) + #pragma omp task shared(j) + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/taskgroup_ast_print.cpp clang/test/OpenMP/taskgroup_ast_print.cpp --- clang-3.4/test/OpenMP/taskgroup_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskgroup_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp taskgroup +{ + a=2; +} +// CHECK-NEXT: #pragma omp taskgroup +// CHECK-NEXT: { +// CHECK-NEXT: a = 2; +// CHECK-NEXT: } + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/taskgroup_messages.cpp clang/test/OpenMP/taskgroup_messages.cpp --- clang-3.4/test/OpenMP/taskgroup_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskgroup_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int foo(); + +int main() { + #pragma omp taskgroup + ; + #pragma omp taskgroup nowait // expected-error {{unexpected OpenMP clause 'nowait' in directive '#pragma omp taskgroup'}} + #pragma omp taskgroup unknown // expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}} + foo(); + { + #pragma omp taskgroup + } // expected-error {{expected statement}} + #pragma omp for + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp taskgroup + foo(); + } + #pragma omp sections + { + #pragma omp taskgroup + foo(); + } + #pragma omp single + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp taskgroup + foo(); + } + #pragma omp task + for (int i = 0; i < 10; ++i) { + foo(); + #pragma omp taskgroup + foo(); + } + + return 0; +} + +int foo() { + L1: + foo(); + #pragma omp taskgroup + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp taskgroup + { + L2: + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/taskwait_ast_printer.cpp clang/test/OpenMP/taskwait_ast_printer.cpp --- clang-3.4/test/OpenMP/taskwait_ast_printer.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskwait_ast_printer.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp taskwait +// CHECK-NEXT: #pragma omp taskwait + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/taskwait_messages.cpp clang/test/OpenMP/taskwait_messages.cpp --- clang-3.4/test/OpenMP/taskwait_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskwait_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main(int argc, char **argv) { + #pragma omp taskwait + ; + #pragma omp taskwait untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp taskwait'}} + #pragma omp taskwait unknown // expected-warning {{extra tokens at the end of '#pragma omp taskwait' are ignored}} + if (argc) + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + if (argc) { + #pragma omp taskwait + } + while (argc) + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + while (argc) { + #pragma omp taskwait + } + do + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + while (argc); + do { + #pragma omp taskwait + } + while (argc); + switch (argc) + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp taskwait + } + switch (argc) { + #pragma omp taskwait + case 1: + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + break; + default: { + #pragma omp taskwait + } + break; + } + for (;;) + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + for (;;) { + #pragma omp taskwait + } + label: + #pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be immediate substatement}} + label1: { + #pragma omp taskwait + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/taskyield_ast_print.cpp clang/test/OpenMP/taskyield_ast_print.cpp --- clang-3.4/test/OpenMP/taskyield_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskyield_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp taskyield +// CHECK-NEXT: #pragma omp taskyield + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/taskyield_messages.cpp clang/test/OpenMP/taskyield_messages.cpp --- clang-3.4/test/OpenMP/taskyield_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/taskyield_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +int main(int argc, char **argv) { + #pragma omp taskyield + ; + #pragma omp taskyield untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp taskyield'}} + #pragma omp taskyield unknown // expected-warning {{extra tokens at the end of '#pragma omp taskyield' are ignored}} + if (argc) + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + if (argc) { + #pragma omp taskyield + } + while (argc) + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + while (argc) { + #pragma omp taskyield + } + do + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + while (argc); + do { + #pragma omp taskyield + } + while (argc); + switch (argc) + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + switch (argc) + case 1: + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + switch (argc) + case 1: { + #pragma omp taskyield + } + switch (argc) { + #pragma omp taskyield + case 1: + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + break; + default: { + #pragma omp taskyield + } + break; + } + for (;;) + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + for (;;) { + #pragma omp taskyield + } + label: + #pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be immediate substatement}} + label1: { + #pragma omp taskyield + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_ast_print.cpp clang/test/OpenMP/teams_ast_print.cpp --- clang-3.4/test/OpenMP/teams_ast_print.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp target +#pragma omp teams +// CHECK: #pragma omp target +// CHECK-NEXT: #pragma omp teams + a=2; +// CHECK-NEXT: a = 2; +#pragma omp target +#pragma omp teams num_teams(a), thread_limit(c), default(none), private(argc,b),firstprivate(argv, c),shared(d,f),reduction(+:e) reduction(min : g) +// CHECK: #pragma omp target +// CHECK-NEXT: #pragma omp teams num_teams(a) thread_limit(c) default(none) private(argc,b) firstprivate(argv,c) shared(d,f) reduction(+: e) reduction(min: g) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff -uNr clang-3.4/test/OpenMP/teams_default_messages.cpp clang/test/OpenMP/teams_default_messages.cpp --- clang-3.4/test/OpenMP/teams_default_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_default_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp target + #pragma omp teams default // expected-error {{expected '(' after 'default'}} expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + #pragma omp target + #pragma omp teams default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + #pragma omp target + #pragma omp teams default (none // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams default (shared), default(shared) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'default' clause}} + foo(); + #pragma omp target + #pragma omp teams default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_firstprivate_messages.cpp clang/test/OpenMP/teams_firstprivate_messages.cpp --- clang-3.4/test/OpenMP/teams_firstprivate_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_firstprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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 target + #pragma omp teams firstprivate // expected-error {{expected '(' after 'firstprivate'}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams firstprivate () // expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (argc) + foo(); + #pragma omp target + #pragma omp teams firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + foo(); + #pragma omp target + #pragma omp teams firstprivate (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams firstprivate(ba) + foo(); + #pragma omp target + #pragma omp teams firstprivate(ca) + foo(); + #pragma omp target + #pragma omp teams firstprivate(da) + foo(); + #pragma omp target + #pragma omp teams firstprivate(S2::S2s) + foo(); + #pragma omp target + #pragma omp teams firstprivate(S2::S2sc) + foo(); + #pragma omp target + #pragma omp teams firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + foo(); + #pragma omp target + #pragma omp teams firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + foo(); + #pragma omp target + #pragma omp teams private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + foo(); + #pragma omp target + #pragma omp teams firstprivate(i) + foo(); + #pragma omp target + #pragma omp teams firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_messages.c clang/test/OpenMP/teams_messages.c --- clang-3.4/test/OpenMP/teams_messages.c 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_messages.c 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { } + +int main(int argc, char **argv) { + L1: + foo(); + #pragma omp target + #pragma omp teams + { + foo(); + goto L1; // expected-error {{use of undeclared label 'L1'}} + } + goto L2; // expected-error {{use of undeclared label 'L2'}} + #pragma omp target + #pragma omp teams + L2: + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_messages.cpp clang/test/OpenMP/teams_messages.cpp --- clang-3.4/test/OpenMP/teams_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo() { +} + +#pragma omp teams // expected-error {{unexpected OpenMP directive '#pragma omp teams'}} + +int main(int argc, char **argv) { + #pragma omp target + #pragma omp teams + foo(); + #pragma omp target + { + #pragma omp teams + foo(); + } + #pragma omp target + { + foo(); + #pragma omp teams // expected-error {{the teams construct must be the only construct inside of target region}} + foo(); + } + #pragma omp target + #pragma omp teams unknown() // expected-warning {{extra tokens at the end of '#pragma omp teams' are ignored}} + foo(); + L1: + foo(); + #pragma omp target + #pragma omp teams + ; + #pragma omp target + #pragma omp teams + { + goto L1; // expected-error {{use of undeclared label 'L1'}} + argc++; + } + + for (int i = 0; i < 10; ++i) { + switch(argc) { + case (0): + #pragma omp target + #pragma omp teams + { + foo(); + break; // expected-error {{'break' statement not in loop or switch statement}} + continue; // expected-error {{'continue' statement not in loop statement}} + } + default: + break; + } + } + #pragma omp target + #pragma omp teams default(none) + ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}} + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_num_teams_messages.cpp clang/test/OpenMP/teams_num_teams_messages.cpp --- clang-3.4/test/OpenMP/teams_num_teams_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_num_teams_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target + #pragma omp teams num_teams // expected-error {{expected '(' after 'num_teams'}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams num_teams ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams num_teams () // expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams num_teams (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams num_teams (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target + #pragma omp teams num_teams (foobool(argc)) num_teams(3) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'num_teams' clause}} + foo(); + #pragma omp target + #pragma omp teams num_teams (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams num_teams (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target + #pragma omp teams num_teams (v1) // expected-error {{expression has incomplete type 'S1'}} + foo(); + #pragma omp target + #pragma omp teams num_teams (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + foo(); + #pragma omp target + #pragma omp teams num_teams (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + foo(); + #pragma omp target + #pragma omp teams num_teams (0) // expected-error {{expression is not a positive integer value}} + foo(); + #pragma omp target + #pragma omp teams num_teams (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_private_messages.cpp clang/test/OpenMP/teams_private_messages.cpp --- clang-3.4/test/OpenMP/teams_private_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_private_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,158 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -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) { } + static float S2s; // expected-note {{predetermined as shared}} +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; // expected-note {{predetermined as shared}} +const S3 ca[5]; // expected-note {{predetermined as shared}} +extern const int f; // expected-note {{predetermined as shared}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +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; // expected-note {{predetermined as shared}} + const int da[5] = { 0 }; // expected-note {{predetermined as shared}} + 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 target + #pragma omp teams private // expected-error {{expected '(' after 'private'}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams private () // expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams private (argc) + foo(); + #pragma omp target + #pragma omp teams private (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams private (a, b, c, d, f) // expected-error {{private variable with incomplete type 'S1'}} expected-error 3 {{shared variable cannot be private}} + foo(); + #pragma omp target + #pragma omp teams private (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams private(ba) + foo(); + #pragma omp target + #pragma omp teams private(ca) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target + #pragma omp teams private(da) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target + #pragma omp teams private(S2::S2s) // expected-error {{shared variable cannot be private}} + foo(); + #pragma omp target + #pragma omp teams private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + foo(); + #pragma omp target + #pragma omp teams private(h) // expected-error {{threadprivate or thread local variable cannot be private}} + foo(); + #pragma omp target + #pragma omp teams shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} + foo(); + #pragma omp target + #pragma omp teams private(i) + foo(); + #pragma omp target + #pragma omp teams private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type}} + foo(); + #pragma omp for private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp target + #pragma omp teams + #pragma omp parallel for firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp target + #pragma omp teams + #pragma omp parallel for reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp target + #pragma omp teams + #pragma omp parallel for lastprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp parallel private(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp parallel firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + #pragma omp parallel reduction(+:i) + for (int k = 0; k < 10; ++k) { + #pragma omp target + #pragma omp teams private(i) + foo(); + } + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_reduction_messages.cpp clang/test/OpenMP/teams_reduction_messages.cpp --- clang-3.4/test/OpenMP/teams_reduction_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_reduction_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,165 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note 2 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator +=(const S2 &arg) {return (*this);} // expected-note {{implicitly declared private here}} +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; // expected-note {{predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note {{'S2sc' defined here}} +S2 b; // expected-note {{'b' defined here}} +const S2 ba[5]; // expected-note {{'ba' defined here}} +class S3 { + int a; +public: + S3():a(0) { } + S3(const S3 &s3):a(s3.a) { } + S3 operator +=(const S3 &arg1) {return arg1;} +}; +int operator +=(const S3 &arg1, const S3 &arg2) {return 5;} // expected-note {{candidate function not viable: no known conversion from 'class S6' to 'const S3' for 1st argument}} +S3 c; // expected-note {{'c' defined here}} +const S3 ca[5]; // expected-note {{'ca' defined here}} +extern const int f; // expected-note 2 {{'f' declared here}} +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); + S4 &operator +=(const S4 &arg) {return (*this);} +public: + S4(int v):a(v) { } +}; +S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;} // expected-note {{candidate function not viable: no known conversion from 'S5' to 'S4 &' for 1st argument}} +class S5 { + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } + S5 &operator +=(const S5 &arg); +public: + S5(int v):a(v) { } +}; +class S6 { + int a; + public: + S6():a(6){ } + operator int() { return 6; } +} o; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = { 0 }; // expected-note {{'da' defined here}} + int qa[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); + int i; + int &j = i; // expected-note 2 {{'j' defined here}} + S3 &p = k; + const int &r = da[i]; // expected-note {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; // expected-note {{'fl' defined here}} + #pragma omp target + #pragma omp teams reduction // expected-error {{expected '(' after 'reduction'}} expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + foo(); + #pragma omp target + #pragma omp teams reduction + // expected-error {{expected '(' after 'reduction'}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams reduction ( // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams reduction (- // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams reduction () // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} + foo(); + #pragma omp target + #pragma omp teams reduction (*) // expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams reduction (\) // expected-error {{expected unqualified-id}} expected-error {{expected ':' in 'reduction' clause}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams reduction (&& :argc) + foo(); + #pragma omp target + #pragma omp teams reduction (^ : S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error {{'operator+=' is a private member of 'S2'}} expected-error 2 {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target + #pragma omp teams reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' and 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target + #pragma omp teams reduction (max : argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams reduction(+ : ba) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target + #pragma omp teams reduction(* : ca) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target + #pragma omp teams reduction(- : da) // expected-error {{arguments of OpenMP clause 'reduction' cannot be of array type}} + foo(); + #pragma omp target + #pragma omp teams reduction(^ : fl) // expected-error {{arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type}} + foo(); + #pragma omp target + #pragma omp teams reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + foo(); + #pragma omp target + #pragma omp teams reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp target + #pragma omp teams reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{no viable overloaded '&='}} + foo(); + #pragma omp target + #pragma omp teams reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + foo(); + #pragma omp target + #pragma omp teams reduction(+ : o) // expected-error {{no viable overloaded '+='}} + foo(); + #pragma omp target + #pragma omp teams private(i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + foo(); + #pragma omp target + #pragma omp teams reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + foo(); + #pragma omp target + #pragma omp teams reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}} + foo(); + #pragma omp parallel shared(i) + #pragma omp target + #pragma omp teams reduction(min : i) + foo(); + #pragma omp parallel reduction(min : i) + #pragma omp target + #pragma omp teams reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_shared_messages.cpp clang/test/OpenMP/teams_shared_messages.cpp --- clang-3.4/test/OpenMP/teams_shared_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_shared_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,111 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } +}; +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 { + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { + 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); + S5 g(5); + int i; + int &j = i; + #pragma omp target + #pragma omp teams shared // expected-error {{expected '(' after 'shared'}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams shared ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams shared () // expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams shared (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams shared (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams shared (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams shared (argc) + foo(); + #pragma omp target + #pragma omp teams shared (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams shared (a, b, c, d, f) + foo(); + #pragma omp target + #pragma omp teams shared (argv[1]) // expected-error {{expected variable name}} + foo(); + #pragma omp target + #pragma omp teams shared(ba) + foo(); + #pragma omp target + #pragma omp teams shared(ca) + foo(); + #pragma omp target + #pragma omp teams shared(da) + foo(); + #pragma omp target + #pragma omp teams shared(e, g) + foo(); + #pragma omp target + #pragma omp teams shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}} + foo(); + #pragma omp target + #pragma omp teams private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}} + foo(); + #pragma omp parallel private(i) + #pragma omp target + #pragma omp teams shared(i) + foo(); + #pragma omp target + #pragma omp teams shared(j) + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/teams_thread_limit_messages.cpp clang/test/OpenMP/teams_thread_limit_messages.cpp --- clang-3.4/test/OpenMP/teams_thread_limit_messages.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/teams_thread_limit_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note {{forward declaration of 'S1'}} + +extern S1 v1; + +struct S2{ + int f; + operator int() { return f; } // expected-note {{conversion to integral type 'int'}} + operator bool() { return f; } // expected-note {{conversion to integral type 'bool'}} +} v2; + +struct S3 { + int f; + explicit operator int() { return f; } // expected-note {{conversion to integral type 'int'}} +} v3; + +int main(int argc, char **argv) { + #pragma omp target + #pragma omp teams thread_limit // expected-error {{expected '(' after 'thread_limit'}} expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams thread_limit ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams thread_limit () // expected-error {{expected expression}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (argc > 0 ? argv[1] : argv[2]) // expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (foobool(argc)) thread_limit(3) // expected-error {{directive '#pragma omp teams' cannot contain more than one 'thread_limit' clause}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (S1) // expected-error {{'S1' does not refer to a value}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{statement requires expression of integer type ('char *' invalid)}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (v1) // expected-error {{expression has incomplete type 'S1'}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (v2) // expected-error {{multiple conversions from expression type 'struct S2' to an integral or enumeration type}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (v3) // expected-error {{expression type 'struct S3' requires explicit conversion to 'int'}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (0) // expected-error {{expression is not a positive integer value}} + foo(); + #pragma omp target + #pragma omp teams thread_limit (-1) // expected-error {{expression is not a positive integer value}} + foo(); + + return 0; +} diff -uNr clang-3.4/test/OpenMP/threadprivate_ast_print.cpp clang/test/OpenMP/threadprivate_ast_print.cpp --- clang-3.4/test/OpenMP/threadprivate_ast_print.cpp 2013-11-05 08:27:19.000000000 -0500 +++ clang/test/OpenMP/threadprivate_ast_print.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -2,8 +2,6 @@ // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print // expected-no-diagnostics -// FIXME: This test has been crashing since r186647. -// REQUIRES: disabled #ifndef HEADER #define HEADER diff -uNr clang-3.4/test/OpenMP/threadprivate_codegen.cpp clang/test/OpenMP/threadprivate_codegen.cpp --- clang-3.4/test/OpenMP/threadprivate_codegen.cpp 1969-12-31 19:00:00.000000000 -0500 +++ clang/test/OpenMP/threadprivate_codegen.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -emit-llvm -o - %s | FileCheck %s +// expected-no-diagnostics + +// CHECK: gs = internal global %class.S zeroinitializer +// CHECK: gs1 = internal global %class.S zeroinitializer +// CHECK: gs.cache. = common global i8** null +// CHECK: arr_x = global [5 x [10 x %class.S]] zeroinitializer +// CHECK: arr_x.cache. = common global i8** null +// CHECK: s1 = internal global %class.S zeroinitializer +// CHECK: s1.cache. = common global i8** null + +class S{ + public: + int a; + S() : a(0) {} + S(int a) : a(a) {} + S(const S& s) {a = 12 + s.a;} +}; + +static S gs(5), gs1(5); +#pragma omp threadprivate(gs) +// CHECK: define internal i8* @__kmpc_ctor_{{[a-zA-Z0-9_]+}}gs(i8*) +// CHECK: %{{[a-zA-Z0-9_.]+}} = alloca i8* +// CHECK: store i8* %0, i8** %{{[a-zA-Z0-9_.]+}} +// CHECK: %{{.*}} = bitcast i8* %0 to %class.S* +// CHECK: call void @{{[a-zA-Z0-9_]+}}(%class.S* %{{.*}}, i32 5) +// CHECK: ret i8* %0 +// CHECK: define internal void @__omp_threadprivate_{{[a-zA-Z0-9_]+}}gs() +// CHECK: %{{[a-zA-Z0-9_.]+}} = alloca i8* +// CHECK: call void @__kmpc_threadprivate_register({ i32, i32, i32, i32, i8* }* %{{[a-zA-Z0-9_.]+}}, i8* bitcast (%class.S* @{{[a-zA-Z0-9_]+}}gs to i8*), i8* (i8*)* @__kmpc_ctor_{{[a-zA-Z0-9_]+}}gs, i8* (i8*, i8*)* null, i8* (i8*)* null) +// CHECK: ret void +S arr_x[5][10]; +#pragma omp threadprivate(arr_x) +// CHECK: define internal i8* @__kmpc_ctor_{{.+}}arr_x(i8*) +// CHECK: %{{[a-zA-Z0-9_.]+}} = alloca i8* +// CHECK: store i8* %0, i8** %{{[a-zA-Z0-9_.]+}} +// CHECK: {{.*}} = bitcast i8* %0 to {{.*}}%class.S]]* +// CHECK: call void @{{.+}}(%class.S* +// CHECK: ret i8* %0 +// CHECK: define internal void @__omp_threadprivate_vec_{{.*}}arr_x() +// CHECK: %{{.*}} = alloca i8* +// CHECK: call void @__kmpc_threadprivate_register({ i32, i32, i32, i32, i8* }* %{{[a-zA-Z0-9_.]+}}, i8* bitcast ([5 x [10 x %class.S]]* @{{[a-zA-Z0-9_]*}}arr_x to i8*), i8* (i8*)* @__kmpc_ctor_{{[a-zA-Z0-9_]*}}arr_x, i8* (i8*, i8*)* null, i8* (i8*)* null) +// CHECK: ret void + +// CHECK: define i32 @main(i32 %argc, i8** %argv) +int main(int argc, char **argv) { + static S s1(gs.a); +// CHECK: %{{[0-9]+}} = call i32 @__kmpc_global_thread_num({ i32, i32, i32, i32, i8* }* %{{[a-zA-Z0-9_.]+}}) +// CHECK-NEXT: store i32 %{{[0-9]+}}, i32* %{{[a-zA-Z0-9_.]+}} +// CHECK: call i32 @__cxa_guard_acquire +// CHECK: = call i8* @__kmpc_threadprivate_cached({ i32, i32, i32, i32, i8* }* %{{[a-zA-Z0-9_.]+}}, i32 %{{[a-zA-Z0-9_.]+}}, i8* bitcast (%class.S* @{{[a-zA-Z0-9_]+}}gs to i8*), i64 4, i8*** @{{[a-zA-Z0-9_]+}}gs.cache.) +// CHECK: call void @__cxa_guard_release + #pragma omp threadprivate(s1) +// CHECK: = call i8* @__kmpc_threadprivate_cached({ i32, i32, i32, i32, i8* }* %{{[a-zA-Z0-9_.]+}}, i32 %{{[a-zA-Z0-9_.]+}}, i8* bitcast (%class.S* @{{[a-zA-Z0-9_]+}}s1 to i8*), i64 4, i8*** @{{[a-zA-Z0-9_]+}}s1.cache.) + return s1.a; +} +// CHECK: } +// CHECK: define internal void @_GLOBAL__I_a() +// CHECK: call void @__cxx_global_var_init() +// CHECK: call void @__cxx_global_var_init1() +// CHECK: call void @__omp_threadprivate_{{[a-zA-Z0-9_]+}}gs() +// CHECK: call void @__cxx_global_var_init2() +// CHECK: call void @__omp_threadprivate_vec_arr_x() +// CHECK: ret void + diff -uNr clang-3.4/test/OpenMP/threadprivate_messages.cpp clang/test/OpenMP/threadprivate_messages.cpp --- clang-3.4/test/OpenMP/threadprivate_messages.cpp 2013-09-25 23:24:06.000000000 -0400 +++ clang/test/OpenMP/threadprivate_messages.cpp 2014-05-19 19:59:00.000000000 -0400 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s -#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} +#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}} #pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp threadprivate() // expected-error {{expected identifier}} #pragma omp threadprivate(1) // expected-error {{expected unqualified-id}} @@ -24,7 +24,7 @@ return (a); } -#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} +#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} #pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} #pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} int x, y; diff -uNr clang-3.4/test/Preprocessor/assembler-with-cpp.c clang/test/Preprocessor/assembler-with-cpp.c --- clang-3.4/test/Preprocessor/assembler-with-cpp.c 2013-10-21 01:02:28.000000000 -0400 +++ clang/test/Preprocessor/assembler-with-cpp.c 2014-05-19 19:59:01.000000000 -0400 @@ -80,7 +80,3 @@ // rdar://8823139 # ## // CHECK-Identifiers-False: # ## - -#define X(a) # # # 1 -X(1) -// CHECK-Identifiers-False: # # # 1 diff -uNr clang-3.4/tools/libclang/CIndex.cpp clang/tools/libclang/CIndex.cpp --- clang-3.4/tools/libclang/CIndex.cpp 2013-11-13 17:16:51.000000000 -0500 +++ clang/tools/libclang/CIndex.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -1848,6 +1848,37 @@ void VisitLambdaExpr(const LambdaExpr *E); void VisitOMPExecutableDirective(const OMPExecutableDirective *D); void VisitOMPParallelDirective(const OMPParallelDirective *D); + void VisitOMPForDirective(const OMPForDirective *D); + void VisitOMPParallelForDirective(const OMPParallelForDirective *D); + void VisitOMPParallelForSimdDirective(const OMPParallelForSimdDirective *D); + void VisitOMPSimdDirective(const OMPSimdDirective *D); + void VisitOMPForSimdDirective(const OMPForSimdDirective *D); + void VisitOMPDistributeSimdDirective(const OMPDistributeSimdDirective *D); + void VisitOMPDistributeParallelForDirective(const OMPDistributeParallelForDirective *D); + void VisitOMPDistributeParallelForSimdDirective(const OMPDistributeParallelForSimdDirective *D); + void VisitOMPSectionsDirective(const OMPSectionsDirective *D); + void VisitOMPParallelSectionsDirective(const OMPParallelSectionsDirective *D); + void VisitOMPSectionDirective(const OMPSectionDirective *D); + void VisitOMPSingleDirective(const OMPSingleDirective *D); + void VisitOMPTaskDirective(const OMPTaskDirective *D); + void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D); + void VisitOMPMasterDirective(const OMPMasterDirective *D); + void VisitOMPCriticalDirective(const OMPCriticalDirective *D); + void VisitOMPBarrierDirective(const OMPBarrierDirective *D); + void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D); + void VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D); + void VisitOMPAtomicDirective(const OMPAtomicDirective *D); + void VisitOMPFlushDirective(const OMPFlushDirective *D); + void VisitOMPOrderedDirective(const OMPOrderedDirective *D); + void VisitOMPTeamsDirective(const OMPTeamsDirective *D); + void VisitOMPTargetTeamsDirective(const OMPTargetTeamsDirective *D); + void VisitOMPDistributeDirective(const OMPDistributeDirective *D); + void VisitOMPCancelDirective(const OMPCancelDirective *D); + void VisitOMPCancellationPointDirective( + const OMPCancellationPointDirective *D); + void VisitOMPTargetDirective(const OMPTargetDirective *D); + void VisitOMPTargetDataDirective(const OMPTargetDataDirective *D); + void VisitOMPTargetUpdateDirective(const OMPTargetUpdateDirective *D); private: void AddDeclarationNameInfo(const Stmt *S); @@ -1907,39 +1938,137 @@ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); std::reverse(I, E); } + namespace { class OMPClauseEnqueue : public ConstOMPClauseVisitor { EnqueueVisitor *Visitor; /// \brief Process clauses with list of variables. - template - void VisitOMPClauseList(T *Node); + template void VisitOMPClauseList(const T *Node); + public: - OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) { } -#define OPENMP_CLAUSE(Name, Class) \ - void Visit##Class(const Class *C); + OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) {} +#define OPENMP_CLAUSE(Name, Class) void Visit##Class(const Class *C); #include "clang/Basic/OpenMPKinds.def" }; -void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { } - -template -void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { +template void OMPClauseEnqueue::VisitOMPClauseList(const T *Node) { for (typename T::varlist_const_iterator I = Node->varlist_begin(), E = Node->varlist_end(); - I != E; ++I) + I != E; ++I) Visitor->AddStmt(*I); } +void OMPClauseEnqueue::VisitOMPIfClause(const OMPIfClause *C) {} + +void OMPClauseEnqueue::VisitOMPFinalClause(const OMPFinalClause *C) {} + +void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {} + +void OMPClauseEnqueue::VisitOMPCollapseClause(const OMPCollapseClause *C) {} + +void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) {} + +void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) {} + +void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {} + +void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) {} + +void +OMPClauseEnqueue::VisitOMPDistScheduleClause(const OMPDistScheduleClause *C) {} + void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); } -void OMPClauseEnqueue::VisitOMPFirstprivateClause( - const OMPFirstprivateClause *C) { + +void +OMPClauseEnqueue::VisitOMPFirstPrivateClause(const OMPFirstPrivateClause *C) { + VisitOMPClauseList(C); +} + +void +OMPClauseEnqueue::VisitOMPLastPrivateClause(const OMPLastPrivateClause *C) { VisitOMPClauseList(C); } + void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); } + +void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) { + VisitOMPClauseList(C); +} + +void +OMPClauseEnqueue::VisitOMPCopyPrivateClause(const OMPCopyPrivateClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) {} + +void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *C) {} + +void OMPClauseEnqueue::VisitOMPUntiedClause(const OMPUntiedClause *C) {} + +void OMPClauseEnqueue::VisitOMPMergeableClause(const OMPMergeableClause *C) {} + +void OMPClauseEnqueue::VisitOMPReadClause(const OMPReadClause *C) {} + +void OMPClauseEnqueue::VisitOMPWriteClause(const OMPWriteClause *C) {} + +void OMPClauseEnqueue::VisitOMPUpdateClause(const OMPUpdateClause *C) {} + +void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *C) {} + +void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *C) {} + +void OMPClauseEnqueue::VisitOMPInBranchClause(const OMPInBranchClause *C) {} + +void +OMPClauseEnqueue::VisitOMPNotInBranchClause(const OMPNotInBranchClause *C) {} + +void OMPClauseEnqueue::VisitOMPFlushClause(const OMPFlushClause *C) {} + +void OMPClauseEnqueue::VisitOMPDependClause(const OMPDependClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPMapClause(const OMPMapClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPToClause(const OMPToClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPFromClause(const OMPFromClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPUniformClause(const OMPUniformClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPSafelenClause(const OMPSafelenClause *C) {} + +void OMPClauseEnqueue::VisitOMPSimdlenClause(const OMPSimdlenClause *C) {} + +void OMPClauseEnqueue::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {} + +void +OMPClauseEnqueue::VisitOMPThreadLimitClause(const OMPThreadLimitClause *C) {} + +void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) { + VisitOMPClauseList(C); +} + +void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) { + VisitOMPClauseList(C); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { @@ -2230,8 +2359,8 @@ Visit(E->getSyntacticForm()); } -void EnqueueVisitor::VisitOMPExecutableDirective( - const OMPExecutableDirective *D) { +void +EnqueueVisitor::VisitOMPExecutableDirective(const OMPExecutableDirective *D) { EnqueueChildren(D); for (ArrayRef::iterator I = D->clauses().begin(), E = D->clauses().end(); @@ -2243,6 +2372,139 @@ VisitOMPExecutableDirective(D); } +void EnqueueVisitor::VisitOMPForDirective(const OMPForDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPParallelForDirective(const OMPParallelForDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelForSimdDirective( + const OMPParallelForSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSimdDirective(const OMPSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPForSimdDirective(const OMPForSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeSimdDirective( + const OMPDistributeSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeParallelForDirective( + const OMPDistributeParallelForDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeParallelForSimdDirective( + const OMPDistributeParallelForSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSectionsDirective(const OMPSectionsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelSectionsDirective( + const OMPParallelSectionsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSectionDirective(const OMPSectionDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSingleDirective(const OMPSingleDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskDirective(const OMPTaskDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPMasterDirective(const OMPMasterDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCriticalDirective(const OMPCriticalDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPBarrierDirective(const OMPBarrierDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPAtomicDirective(const OMPAtomicDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPFlushDirective(const OMPFlushDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPOrderedDirective(const OMPOrderedDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDirective(const OMPTeamsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPTargetTeamsDirective(const OMPTargetTeamsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPDistributeDirective(const OMPDistributeDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCancelDirective(const OMPCancelDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCancellationPointDirective( + const OMPCancellationPointDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetDirective(const OMPTargetDirective *D) { + VisitOMPExecutableDirective(D); +} + +void +EnqueueVisitor::VisitOMPTargetDataDirective(const OMPTargetDataDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetUpdateDirective( + const OMPTargetUpdateDirective *D) { + VisitOMPExecutableDirective(D); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); } @@ -3819,7 +4081,67 @@ case CXCursor_ModuleImportDecl: return cxstring::createRef("ModuleImport"); case CXCursor_OMPParallelDirective: - return cxstring::createRef("OMPParallelDirective"); + return cxstring::createRef("OMPParallelDirective"); + case CXCursor_OMPForDirective: + return cxstring::createRef("OMPForDirective"); + case CXCursor_OMPParallelForDirective: + return cxstring::createRef("OMPParallelForDirective"); + case CXCursor_OMPSimdDirective: + return cxstring::createRef("OMPSimdDirective"); + case CXCursor_OMPForSimdDirective: + return cxstring::createRef("OMPForSimdDirective"); + case CXCursor_OMPParallelForSimdDirective: + return cxstring::createRef("OMPParallelForSimdDirective"); + case CXCursor_OMPDistributeSimdDirective: + return cxstring::createRef("OMPDistributeSimdDirective"); + case CXCursor_OMPDistributeParallelForDirective: + return cxstring::createRef("OMPDistributeParallelForDirective"); + case CXCursor_OMPDistributeParallelForSimdDirective: + return cxstring::createRef("OMPDistributeParallelForSimdDirective"); + case CXCursor_OMPSectionsDirective: + return cxstring::createRef("OMPSectionsDirective"); + case CXCursor_OMPParallelSectionsDirective: + return cxstring::createRef("OMPParallelSectionsDirective"); + case CXCursor_OMPSectionDirective: + return cxstring::createRef("OMPSectionDirective"); + case CXCursor_OMPSingleDirective: + return cxstring::createRef("OMPSingleDirective"); + case CXCursor_OMPTaskDirective: + return cxstring::createRef("OMPTaskDirective"); + case CXCursor_OMPTaskyieldDirective: + return cxstring::createRef("OMPTaskyieldDirective"); + case CXCursor_OMPMasterDirective: + return cxstring::createRef("OMPMasterDirective"); + case CXCursor_OMPCriticalDirective: + return cxstring::createRef("OMPCriticalDirective"); + case CXCursor_OMPBarrierDirective: + return cxstring::createRef("OMPBarrierDirective"); + case CXCursor_OMPTaskwaitDirective: + return cxstring::createRef("OMPTaskwaitDirective"); + case CXCursor_OMPTaskgroupDirective: + return cxstring::createRef("OMPTaskgroupDirective"); + case CXCursor_OMPAtomicDirective: + return cxstring::createRef("OMPAtomicDirective"); + case CXCursor_OMPFlushDirective: + return cxstring::createRef("OMPFlushDirective"); + case CXCursor_OMPOrderedDirective: + return cxstring::createRef("OMPOrderedDirective"); + case CXCursor_OMPTeamsDirective: + return cxstring::createRef("OMPTeamsDirective"); + case CXCursor_OMPTargetTeamsDirective: + return cxstring::createRef("OMPTargetTeamsDirective"); + case CXCursor_OMPDistributeDirective: + return cxstring::createRef("OMPDisitributeDirective"); + case CXCursor_OMPCancelDirective: + return cxstring::createRef("OMPCancelDirective"); + case CXCursor_OMPCancellationPointDirective: + return cxstring::createRef("OMPCancellationPointDirective"); + case CXCursor_OMPTargetDirective: + return cxstring::createRef("OMPTargetDirective"); + case CXCursor_OMPTargetDataDirective: + return cxstring::createRef("OMPTargetDataDirective"); + case CXCursor_OMPTargetUpdateDirective: + return cxstring::createRef("OMPTargetUpdateDirective"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -4553,6 +4875,9 @@ case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareSimd: + case Decl::OMPDeclareTarget: return C; // Declaration kinds that don't make any sense here, but are diff -uNr clang-3.4/tools/libclang/CXCursor.cpp clang/tools/libclang/CXCursor.cpp --- clang-3.4/tools/libclang/CXCursor.cpp 2013-09-24 20:14:38.000000000 -0400 +++ clang/tools/libclang/CXCursor.cpp 2014-06-09 10:05:34.000000000 -0400 @@ -242,6 +242,7 @@ case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCBoxedExprClass: case Stmt::ObjCSubscriptRefExprClass: + case Stmt::CEANIndexExprClass: K = CXCursor_UnexposedExpr; break; @@ -511,7 +512,96 @@ case Stmt::OMPParallelDirectiveClass: K = CXCursor_OMPParallelDirective; break; - + case Stmt::OMPForDirectiveClass: + K = CXCursor_OMPForDirective; + break; + case Stmt::OMPParallelForDirectiveClass: + K = CXCursor_OMPParallelForDirective; + break; + case Stmt::OMPParallelForSimdDirectiveClass: + K = CXCursor_OMPParallelForSimdDirective; + break; + case Stmt::OMPSimdDirectiveClass: + K = CXCursor_OMPSimdDirective; + break; + case Stmt::OMPForSimdDirectiveClass: + K = CXCursor_OMPForSimdDirective; + break; + case Stmt::OMPDistributeSimdDirectiveClass: + K = CXCursor_OMPDistributeSimdDirective; + break; + case Stmt::OMPDistributeParallelForDirectiveClass: + K = CXCursor_OMPDistributeParallelForDirective; + break; + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + K = CXCursor_OMPDistributeParallelForSimdDirective; + break; + case Stmt::OMPSectionsDirectiveClass: + K = CXCursor_OMPSectionsDirective; + break; + case Stmt::OMPParallelSectionsDirectiveClass: + K = CXCursor_OMPParallelSectionsDirective; + break; + case Stmt::OMPSectionDirectiveClass: + K = CXCursor_OMPSectionDirective; + break; + case Stmt::OMPSingleDirectiveClass: + K = CXCursor_OMPSingleDirective; + break; + case Stmt::OMPTaskDirectiveClass: + K = CXCursor_OMPTaskDirective; + break; + case Stmt::OMPTaskyieldDirectiveClass: + K = CXCursor_OMPTaskyieldDirective; + break; + case Stmt::OMPMasterDirectiveClass: + K = CXCursor_OMPMasterDirective; + break; + case Stmt::OMPCriticalDirectiveClass: + K = CXCursor_OMPCriticalDirective; + break; + case Stmt::OMPBarrierDirectiveClass: + K = CXCursor_OMPBarrierDirective; + break; + case Stmt::OMPTaskwaitDirectiveClass: + K = CXCursor_OMPTaskwaitDirective; + break; + case Stmt::OMPTaskgroupDirectiveClass: + K = CXCursor_OMPTaskgroupDirective; + break; + case Stmt::OMPAtomicDirectiveClass: + K = CXCursor_OMPAtomicDirective; + break; + case Stmt::OMPFlushDirectiveClass: + K = CXCursor_OMPFlushDirective; + break; + case Stmt::OMPOrderedDirectiveClass: + K = CXCursor_OMPOrderedDirective; + break; + case Stmt::OMPTeamsDirectiveClass: + K = CXCursor_OMPTeamsDirective; + break; + case Stmt::OMPTargetTeamsDirectiveClass: + K = CXCursor_OMPTargetTeamsDirective; + break; + case Stmt::OMPDistributeDirectiveClass: + K = CXCursor_OMPDistributeDirective; + break; + case Stmt::OMPTargetDirectiveClass: + K = CXCursor_OMPTargetDirective; + break; + case Stmt::OMPTargetDataDirectiveClass: + K = CXCursor_OMPTargetDataDirective; + break; + case Stmt::OMPTargetUpdateDirectiveClass: + K = CXCursor_OMPTargetUpdateDirective; + break; + case Stmt::OMPCancelDirectiveClass: + K = CXCursor_OMPCancelDirective; + break; + case Stmt::OMPCancellationPointDirectiveClass: + K = CXCursor_OMPCancellationPointDirective; + break; } CXCursor C = { K, 0, { Parent, S, TU } }; diff -uNr clang-3.4/tools/libclang/RecursiveASTVisitor.h clang/tools/libclang/RecursiveASTVisitor.h --- clang-3.4/tools/libclang/RecursiveASTVisitor.h 2013-10-01 01:32:34.000000000 -0400 +++ clang/tools/libclang/RecursiveASTVisitor.h 2014-06-09 10:05:34.000000000 -0400 @@ -248,6 +248,9 @@ #include "clang/AST/StmtNodes.inc" // The above header #undefs ABSTRACT_STMT and STMT upon exit. + /// \brief Traverses OMPExecutableDirective class. + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); + // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); } bool VisitStmt(Stmt *S) { return true; } @@ -406,13 +409,6 @@ bool TraverseDeclContextHelper(DeclContext *DC); bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); - bool TraverseOMPClause(OMPClause *C); -#define OPENMP_CLAUSE(Name, Class) \ - bool Visit##Class(Class *C); -#include "clang/Basic/OpenMPKinds.def" - /// \brief Process clauses with list of variables. - template - void VisitOMPClauseList(T *Node); typedef SmallVector StmtsTy; typedef SmallVector QueuesTy; @@ -1360,6 +1356,22 @@ } }) +DEF_TRAVERSE_DECL(OMPDeclareSimdDecl, { + if (D->getFunction()) { TRY_TO(TraverseDecl(D->getFunction())); } + }) + +DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, { + for (OMPDeclareReductionDecl::datalist_iterator I = D->datalist_begin(), + E = D->datalist_end(); + I != E; ++I) { + TRY_TO(TraverseType(I->QTy)); + TRY_TO(TraverseStmt(I->CombinerFunction)); + TRY_TO(TraverseStmt(I->InitFunction)); + } + }) + +DEF_TRAVERSE_DECL(OMPDeclareTargetDecl, { }) + // A helper method for TemplateDecl's children. template bool RecursiveASTVisitor::TraverseTemplateParameterListHelper( @@ -2191,6 +2203,7 @@ // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, { }) DEF_TRAVERSE_STMT(ArraySubscriptExpr, { }) +DEF_TRAVERSE_STMT(CEANIndexExpr, { }) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. @@ -2302,60 +2315,158 @@ // Traverse OpenCL: AsType, Convert. DEF_TRAVERSE_STMT(AsTypeExpr, { }) -// OpenMP directives. -DEF_TRAVERSE_STMT(OMPParallelDirective, { +// OpenMP directives +namespace { +template +class RecursiveOMPClauseVisitor : + public OMPClauseVisitor, bool> { + RecursiveASTVisitor *Visitor; + RecursiveASTVisitor &getDerived() { return *Visitor; } +public: + RecursiveOMPClauseVisitor(RecursiveASTVisitor *V) : Visitor(V) { } +#define OPENMP_CLAUSE(Name, Class) \ + bool Visit##Class(Class *S) { \ + for (Stmt::child_range Range = S->children(); Range; ++Range) { \ + if (!Visitor->TraverseStmt(*Range)) return false; \ + } \ + return true; \ + } +#include "clang/Basic/OpenMPKinds.def" +}; +} + +DEF_TRAVERSE_STMT(OMPExecutableDirective, { + RecursiveOMPClauseVisitor V(this); ArrayRef Clauses = S->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) - if (!TraverseOMPClause(*I)) return false; + if (!V.Visit(*I)) return false; }) -// OpenMP clauses. -template -bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { - if (!C) return true; - switch (C->getClauseKind()) { -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_##Name: \ - return getDerived().Visit##Class(static_cast(C)); -#include "clang/Basic/OpenMPKinds.def" - default: break; - } - return true; -} +DEF_TRAVERSE_STMT(OMPParallelDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { - return true; -} +DEF_TRAVERSE_STMT(OMPForDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -template -void RecursiveASTVisitor::VisitOMPClauseList(T *Node) { - for (typename T::varlist_iterator I = Node->varlist_begin(), - E = Node->varlist_end(); - I != E; ++I) - TraverseStmt(*I); -} +DEF_TRAVERSE_STMT(OMPParallelForDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPParallelForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPFirstprivateClause( - OMPFirstprivateClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) -template -bool RecursiveASTVisitor::VisitOMPSharedClause(OMPSharedClause *C) { - VisitOMPClauseList(C); - return true; -} +DEF_TRAVERSE_STMT(OMPForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeParallelForDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeParallelForSimdDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSectionsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPParallelSectionsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSectionDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPSingleDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskyieldDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPMasterDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCriticalDirective, { + TRY_TO(TraverseDeclarationNameInfo(S->getDirectiveName())); + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPBarrierDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskwaitDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTaskgroupDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPAtomicDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPFlushDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPOrderedDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTeamsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetTeamsDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPDistributeDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCancelDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPCancellationPointDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetDataDirective, { + return TraverseOMPExecutableDirective(S); +}) + +DEF_TRAVERSE_STMT(OMPTargetUpdateDirective, { + return TraverseOMPExecutableDirective(S); +}) // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods diff -uNr clang-3.4/tools/scan-build/scan-build.1 clang/tools/scan-build/scan-build.1 --- clang-3.4/tools/scan-build/scan-build.1 2012-11-07 12:12:37.000000000 -0500 +++ clang/tools/scan-build/scan-build.1 2014-05-19 19:59:02.000000000 -0400 @@ -1,6 +1,6 @@ .\" This file is distributed under the University of Illinois Open Source .\" License. See LICENSE.TXT for details. -.\" $Id: scan-build.1 167537 2012-11-07 17:12:37Z jrose $ +.\" $Id$ .Dd May 25, 2012 .Dt SCAN-BUILD 1 .Os "clang" "3.1" diff -uNr clang-3.4/tools/scan-build/scan-build.bat clang/tools/scan-build/scan-build.bat --- clang-3.4/tools/scan-build/scan-build.bat 2013-05-01 20:52:46.000000000 -0400 +++ clang/tools/scan-build/scan-build.bat 2014-05-19 19:59:02.000000000 -0400 @@ -1 +1 @@ -perl -S scan-build %* +perl -S scan-build %*