diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 9c37ac745bb5..02abfcab30f8 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2135,7 +2135,11 @@ enum CXCursorKind { */ CXCursor_OMPParallelDirective = 232, - CXCursor_LastStmt = CXCursor_OMPParallelDirective, + /** \brief OpenMP simd directive. + */ + CXCursor_OMPSimdDirective = 233, + + CXCursor_LastStmt = CXCursor_OMPSimdDirective, /** * \brief Cursor that represents the translation unit itself. diff --git a/clang/include/clang/AST/DataRecursiveASTVisitor.h b/clang/include/clang/AST/DataRecursiveASTVisitor.h index df26f0a04db3..cbefbdc287ef 100644 --- a/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -424,6 +424,7 @@ private: bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); bool TraverseOMPClause(OMPClause *C); + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); #define OPENMP_CLAUSE(Name, Class) \ bool Visit##Class(Class *C); #include "clang/Basic/OpenMPKinds.def" @@ -2331,11 +2332,22 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { }) DEF_TRAVERSE_STMT(AsTypeExpr, { }) // OpenMP directives. -DEF_TRAVERSE_STMT(OMPParallelDirective, { +template +bool DataRecursiveASTVisitor::TraverseOMPExecutableDirective( + OMPExecutableDirective *S) { ArrayRef Clauses = S->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) if (!TraverseOMPClause(*I)) return false; + return true; +} + +DEF_TRAVERSE_STMT(OMPParallelDirective, { + if (!TraverseOMPExecutableDirective(S)) return false; +}) + +DEF_TRAVERSE_STMT(OMPSimdDirective, { + if (!TraverseOMPExecutableDirective(S)) return false; }) // OpenMP clauses. diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f1396aabdef1..8e3c9f724daf 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -441,6 +441,7 @@ private: bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); bool TraverseOMPClause(OMPClause *C); + bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); #define OPENMP_CLAUSE(Name, Class) \ bool Visit##Class(Class *C); #include "clang/Basic/OpenMPKinds.def" @@ -2355,11 +2356,22 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { }) DEF_TRAVERSE_STMT(AsTypeExpr, { }) // OpenMP directives. -DEF_TRAVERSE_STMT(OMPParallelDirective, { +template +bool RecursiveASTVisitor::TraverseOMPExecutableDirective( + OMPExecutableDirective *S) { ArrayRef Clauses = S->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) if (!TraverseOMPClause(*I)) return false; + return true; +} + +DEF_TRAVERSE_STMT(OMPParallelDirective, { + if (!TraverseOMPExecutableDirective(S)) return false; +}) + +DEF_TRAVERSE_STMT(OMPSimdDirective, { + if (!TraverseOMPExecutableDirective(S)) return false; }) // OpenMP clauses. diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index a9e2855a6a38..5e1a04b042dd 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -140,17 +140,18 @@ class OMPParallelDirective : public OMPExecutableDirective { /// \param EndLoc Ending Location of the directive. /// OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc, - unsigned N) + unsigned NumClauses) : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, - StartLoc, EndLoc, N, 1) {} + StartLoc, EndLoc, NumClauses, 1) {} /// \brief Build an empty directive. /// - /// \param N Number of clauses. + /// \param NumClauses Number of clauses. /// - explicit OMPParallelDirective(unsigned N) + explicit OMPParallelDirective(unsigned NumClauses) : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, - SourceLocation(), SourceLocation(), N, 1) {} + SourceLocation(), SourceLocation(), + NumClauses, 1) {} public: /// \brief Creates directive with a list of \a Clauses. @@ -168,9 +169,10 @@ public: /// \brief Creates an empty directive with the place for \a N clauses. /// /// \param C AST context. - /// \param N The number of clauses. + /// \param NumClauses Number of clauses. /// - static OMPParallelDirective *CreateEmpty(const ASTContext &C, unsigned N, + static OMPParallelDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); static bool classof(const Stmt *T) { @@ -178,6 +180,76 @@ public: } }; +/// \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; + /// \brief Number of collapsed loops as specified by 'collapse' clause. + 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 CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + OMPSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, unsigned NumClauses) + : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd, + StartLoc, EndLoc, NumClauses, 1), + CollapsedNum(CollapsedNum) { } + + /// \brief Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + explicit OMPSimdDirective(unsigned CollapsedNum, unsigned NumClauses) + : OMPExecutableDirective(this, OMPSimdDirectiveClass, OMPD_simd, + SourceLocation(), SourceLocation(), + NumClauses, 1), + CollapsedNum(CollapsedNum) { } +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); + + /// \brief Creates an empty directive with the place + /// for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param CollapsedNum Number of collapsed nested loops. + /// \param NumClauses Number of clauses. + /// + static OMPSimdDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + unsigned getCollapsedNumber() const { return CollapsedNum; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPSimdDirectiveClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index eb2bc4f1f76b..059a28ab88da 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6835,24 +6835,26 @@ 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_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 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 < +def err_omp_no_dsa_for_variable : Error< "variable %0 must have explicitly specified data sharing attributes">; def err_omp_wrong_dsa : Error< "%0 variable cannot be %1">; -def note_omp_explicit_dsa : Note < +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 err_omp_not_for : Error< + "statement after '#pragma omp %0' must be a for loop">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 529bf1b384c2..956a886e8a72 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -21,6 +21,9 @@ #ifndef OPENMP_PARALLEL_CLAUSE # define OPENMP_PARALLEL_CLAUSE(Name) #endif +#ifndef OPENMP_SIMD_CLAUSE +# define OPENMP_SIMD_CLAUSE(Name) +#endif #ifndef OPENMP_DEFAULT_KIND # define OPENMP_DEFAULT_KIND(Name) #endif @@ -29,6 +32,7 @@ OPENMP_DIRECTIVE(threadprivate) OPENMP_DIRECTIVE(parallel) OPENMP_DIRECTIVE(task) +OPENMP_DIRECTIVE(simd) // OpenMP clauses. OPENMP_CLAUSE(if, OMPIfClause) @@ -44,6 +48,8 @@ OPENMP_PARALLEL_CLAUSE(private) OPENMP_PARALLEL_CLAUSE(firstprivate) OPENMP_PARALLEL_CLAUSE(shared) +// FIXME: clauses allowed for directive 'omp simd'. + // Static attributes for 'default' clause. OPENMP_DEFAULT_KIND(none) OPENMP_DEFAULT_KIND(shared) @@ -52,3 +58,5 @@ OPENMP_DEFAULT_KIND(shared) #undef OPENMP_DIRECTIVE #undef OPENMP_CLAUSE #undef OPENMP_PARALLEL_CLAUSE +#undef OPENMP_SIMD_CLAUSE + diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 57417d39f207..0f0f28447661 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -178,3 +178,4 @@ def AsTypeExpr : DStmt; // OpenMP Directives. def OMPExecutableDirective : Stmt<1>; def OMPParallelDirective : DStmt; +def OMPSimdDirective : DStmt; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 09c1db4c2c24..37c8874520af 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7111,6 +7111,12 @@ public: Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp simd' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPSimdDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index eccf7404ced8..c24177913f69 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1333,6 +1333,7 @@ namespace clang { // OpenMP drectives STMT_OMP_PARALLEL_DIRECTIVE, + STMT_OMP_SIMD_DIRECTIVE, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index f4d90eaded22..9118751a4b9c 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -1217,10 +1217,39 @@ OMPParallelDirective *OMPParallelDirective::Create( } OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C, - unsigned N, + unsigned NumClauses, EmptyShell) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelDirective), llvm::alignOf()); - void *Mem = C.Allocate(Size + sizeof(OMPClause *) * N + sizeof(Stmt *)); - return new (Mem) OMPParallelDirective(N); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *)); + return new (Mem) OMPParallelDirective(NumClauses); } + +OMPSimdDirective *OMPSimdDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf()); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *)); + OMPSimdDirective *Dir = new (Mem) OMPSimdDirective(StartLoc, EndLoc, + 1, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), + llvm::alignOf()); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *)); + return new (Mem) OMPSimdDirective(CollapsedNum, NumClauses); +} + diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index a9f49990ee52..eb983b2db013 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -70,6 +70,7 @@ namespace { void PrintCallArgs(CallExpr *E); void PrintRawSEHExceptHandler(SEHExceptStmt *S); void PrintRawSEHFinallyStmt(SEHFinallyStmt *S); + void PrintOMPExecutableDirective(OMPExecutableDirective *S); void PrintExpr(Expr *E) { if (E) @@ -89,7 +90,7 @@ namespace { return; else StmtVisitor::Visit(S); } - + void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED { Indent() << "<>\n"; } @@ -656,11 +657,9 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { // OpenMP directives printing methods //===----------------------------------------------------------------------===// -void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { - Indent() << "#pragma omp parallel "; - +void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S) { OMPClausePrinter Printer(OS, Policy); - ArrayRef Clauses = Node->clauses(); + ArrayRef Clauses = S->clauses(); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) if (*I && !(*I)->isImplicit()) { @@ -668,13 +667,24 @@ void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { OS << ' '; } OS << "\n"; - if (Node->getAssociatedStmt()) { - assert(isa(Node->getAssociatedStmt()) && + if (S->getAssociatedStmt()) { + assert(isa(S->getAssociatedStmt()) && "Expected captured statement!"); - Stmt *CS = cast(Node->getAssociatedStmt())->getCapturedStmt(); + Stmt *CS = cast(S->getAssociatedStmt())->getCapturedStmt(); PrintStmt(CS); } } + +void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { + Indent() << "#pragma omp parallel "; + PrintOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) { + Indent() << "#pragma omp simd "; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index ae3b36007869..e9b1da49dd4a 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -293,7 +293,7 @@ void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { } void -StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { +StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) { VisitStmt(S); OMPClauseProfiler P(this); ArrayRef Clauses = S->clauses(); @@ -303,6 +303,14 @@ StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { P.Visit(*I); } +void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 4e0ab1298b43..99c2fd2ebddf 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -120,6 +120,15 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, switch (CKind) { #define OPENMP_PARALLEL_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; diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 918103fcbd58..a13828e85edc 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -77,6 +77,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::SEHFinallyStmtClass: case Stmt::MSDependentExistsStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPSimdDirectiveClass: llvm_unreachable("invalid statement class to emit generically"); case Stmt::NullStmtClass: case Stmt::CompoundStmtClass: diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index b3c7cb597e4d..3a8f2ee88093 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -60,6 +60,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { Diag(Tok, diag::err_omp_unknown_directive); break; case OMPD_parallel: + case OMPD_simd: case OMPD_task: case NUM_OPENMP_DIRECTIVES: Diag(Tok, diag::err_omp_unexpected_directive) @@ -114,7 +115,8 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { } SkipUntil(tok::annot_pragma_openmp_end); break; - case OMPD_parallel: { + case OMPD_parallel: + case OMPD_simd: { ConsumeToken(); Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope()); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index fee9b1d2ce48..63b64801fe3a 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -699,6 +699,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; + case OMPD_simd: + Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + break; case OMPD_threadprivate: case OMPD_task: llvm_unreachable("OpenMP Directive is not allowed"); @@ -721,6 +725,29 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Clauses, AStmt)); } +StmtResult Sema::ActOnOpenMPSimdDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + 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(); + ForStmt *For = dyn_cast(CStmt); + if (!For) { + Diag(CStmt->getLocStart(), diag::err_omp_not_for) + << getOpenMPDirectiveName(OMPD_simd); + return StmtError(); + } + + // FIXME: Checking loop canonical form, collapsing etc. + + getCurFunction()->setHasBranchProtectedScope(); + return Owned(OMPSimdDirective::Create(Context, StartLoc, EndLoc, + Clauses, AStmt)); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index d9ed6f5f027d..5d2124f7ce6c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -607,6 +607,7 @@ public: ExprResult TransformAddressOfOperand(Expr *E); ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E, bool IsAddressOfOperand); + StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S); // FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous // amount of stack usage with clang. @@ -1286,16 +1287,17 @@ public: 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, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPExecutableDirective(Kind, Clauses, AStmt, + StartLoc, EndLoc); } /// \brief Build a new OpenMP 'if' clause. @@ -6248,9 +6250,8 @@ StmtResult TreeTransform::TransformSEHHandler(Stmt *Handler) { template StmtResult -TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { - DeclarationNameInfo DirName; - getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0); +TreeTransform::TransformOMPExecutableDirective( + OMPExecutableDirective *D) { // Transform the clauses llvm::SmallVector TClauses; @@ -6261,7 +6262,6 @@ TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { if (*I) { OMPClause *Clause = getDerived().TransformOMPClause(*I); if (!Clause) { - getSema().EndOpenMPDSABlock(0); return StmtError(); } TClauses.push_back(Clause); @@ -6271,21 +6271,38 @@ TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { } } if (!D->getAssociatedStmt()) { - getSema().EndOpenMPDSABlock(0); return StmtError(); } StmtResult AssociatedStmt = getDerived().TransformStmt(D->getAssociatedStmt()); if (AssociatedStmt.isInvalid()) { - getSema().EndOpenMPDSABlock(0); return StmtError(); } - StmtResult Res = getDerived().RebuildOMPParallelDirective(TClauses, - AssociatedStmt.take(), - D->getLocStart(), - D->getLocEnd()); - getSema().EndOpenMPDSABlock(Res.get()); + return getDerived().RebuildOMPExecutableDirective(D->getDirectiveKind(), + TClauses, + AssociatedStmt.take(), + D->getLocStart(), + D->getLocEnd()); +} + +template +StmtResult +TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { + DeclarationNameInfo DirName; + getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template +StmtResult +TreeTransform::TransformOMPSimdDirective(OMPSimdDirective *D) { + DeclarationNameInfo DirName; + getSema().StartOpenMPDSABlock(OMPD_simd, DirName, 0); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index e1ca51fcc198..3f83beb0a03f 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1742,8 +1742,6 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { // 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); @@ -1755,6 +1753,16 @@ void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { } void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; + VisitOMPExecutableDirective(D); +} + +void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { + VisitStmt(D); + // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream. + Idx += 2; VisitOMPExecutableDirective(D); } @@ -2230,13 +2238,22 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { DeclarationNameInfo(), 0); break; + case STMT_OMP_PARALLEL_DIRECTIVE: S = OMPParallelDirective::CreateEmpty(Context, Record[ASTStmtReader::NumStmtFields], Empty); break; - + + case STMT_OMP_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(Context, Empty); break; @@ -2244,11 +2261,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_CXX_MEMBER_CALL: S = new (Context) CXXMemberCallExpr(Context, Empty); break; - + case EXPR_CXX_CONSTRUCT: S = new (Context) CXXConstructExpr(Empty); break; - + case EXPR_CXX_TEMPORARY_OBJECT: S = new (Context) CXXTemporaryObjectExpr(Empty); break; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 428881bb69a9..08228d07544e 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1721,8 +1721,6 @@ void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { // 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); @@ -1733,10 +1731,20 @@ void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { } void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE; } +void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + Record.push_back(D->getCollapsedNumber()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_SIMD_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 94274c39cac2..fbcd2630829c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -731,6 +731,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Expr::MSDependentExistsStmtClass: case Stmt::CapturedStmtClass: case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPSimdDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: diff --git a/clang/test/OpenMP/simd_ast_print.cpp b/clang/test/OpenMP/simd_ast_print.cpp new file mode 100644 index 000000000000..e51d5165e8da --- /dev/null +++ b/clang/test/OpenMP/simd_ast_print.cpp @@ -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 simd +// CHECK-NEXT: #pragma omp simd + 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 +// CHECK-NEXT: #pragma omp simd + 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 simd + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) {foo(); k1 += 8; k2 += 8;} +// CHECK-NEXT: #pragma omp simd +// 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 +// CHECK-NEXT: #pragma omp simd + for (int i = 0; i < 10; ++i)foo(); +// CHECK-NEXT: for (int i = 0; i < 10; ++i) +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff --git a/clang/test/OpenMP/simd_misc_messages.c b/clang/test/OpenMP/simd_misc_messages.c new file mode 100644 index 000000000000..aabcb02aefd0 --- /dev/null +++ b/clang/test/OpenMP/simd_misc_messages.c @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -fsyntax-only -fopenmp -verify %s + +// 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) ; + + // expected-error@+2 {{statement after '#pragma omp simd' must be a for loop}} + #pragma omp simd + ++i; +} + +void test_branch_protected_scope() +{ + int i = 0; +L1: + ++i; + + int x[24]; + + #pragma omp simd + for (i = 0; i < 16; ++i) { + if (i == 5) + goto L1; // expected-error {{use of undeclared label 'L1'}} + else if (i == 6) + return; // expected-error {{cannot return from OpenMP region}} + else if (i == 7) + goto L2; + else if (i == 8) { +L2: + x[i]++; + } + } + + if (x[0] == 0) + goto L2; // expected-error {{use of undeclared label 'L2'}} + else if (x[1] == 1) + goto L1; +} + +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-error@+2 {{unexpected OpenMP clause 'firstprivate' in directive '#pragma omp simd'}} + // expected-warning@+1 {{extra tokens at the end of '#pragma omp simd' are ignored}} + #pragma omp simd firstprivate(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) ; +} + diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index f217d795dc93..fa106e990d9b 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1867,6 +1867,7 @@ public: void VisitLambdaExpr(const LambdaExpr *E); void VisitOMPExecutableDirective(const OMPExecutableDirective *D); void VisitOMPParallelDirective(const OMPParallelDirective *D); + void VisitOMPSimdDirective(const OMPSimdDirective *D); private: void AddDeclarationNameInfo(const Stmt *S); @@ -2257,6 +2258,10 @@ void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) { VisitOMPExecutableDirective(D); } +void EnqueueVisitor::VisitOMPSimdDirective(const OMPSimdDirective *D) { + VisitOMPExecutableDirective(D); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); } @@ -3911,7 +3916,9 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { case CXCursor_ModuleImportDecl: return cxstring::createRef("ModuleImport"); case CXCursor_OMPParallelDirective: - return cxstring::createRef("OMPParallelDirective"); + return cxstring::createRef("OMPParallelDirective"); + case CXCursor_OMPSimdDirective: + return cxstring::createRef("OMPSimdDirective"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index b01491a5d4f7..d682986b3f3c 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -509,9 +509,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OMPParallelDirectiveClass: K = CXCursor_OMPParallelDirective; break; - + case Stmt::OMPSimdDirectiveClass: + K = CXCursor_OMPSimdDirective; + break; } - + CXCursor C = { K, 0, { Parent, S, TU } }; return C; }