From 5d61097dd909206f99d08ae580f56ed49c2f138c Mon Sep 17 00:00:00 2001 From: Mahesha S Date: Sat, 27 Oct 2012 09:05:45 +0000 Subject: [PATCH] Feature: OpenMP support. Sub-Feature: Support for "#pragma omp ..." registration with Preprocessor. Files Changed/Added: * include/clang/Basic/DiagnosticGroups.td (C) * include/clang/Basic/DiagnosticParseKinds.td (C) * include/clang/Basic/TokenKinds.def (C) * include/clang/Parse/Parser.h (C) * lib/Parse/Parser.cpp (C) Test Cases Changed/Added: * test/Preprocessor/pragma_omp.c (A) * test/Preprocessor/pragma_omp_ignored_warning.c (A) llvm-svn: 166869 --- clang/include/clang/Basic/DiagnosticGroups.td | 1 + clang/include/clang/Basic/DiagnosticParseKinds.td | 5 + clang/include/clang/Basic/TokenKinds.def | 36 ++++ clang/include/clang/Parse/Parser.h | 3 + clang/lib/Parse/Parser.cpp | 235 +++++++++++++++++++++ clang/test/Preprocessor/pragma_omp.c | 18 ++ .../test/Preprocessor/pragma_omp_ignored_warning.c | 13 ++ 7 files changed, 311 insertions(+) create mode 100644 clang/test/Preprocessor/pragma_omp.c create mode 100644 clang/test/Preprocessor/pragma_omp_ignored_warning.c diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 1635633..e6c10e5 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -251,6 +251,7 @@ def UninitializedMaybe : DiagGroup<"conditional-uninitialized">; def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">; def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes]>; def UnknownPragmas : DiagGroup<"unknown-pragmas">; +def OpenMPPragmas : DiagGroup<"openmp-pragmas">; def NSobjectAttribute : DiagGroup<"NSObject-attribute">; def UnknownAttributes : DiagGroup<"attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 51270ab..ca1ed31 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -734,6 +734,11 @@ def err_pragma_fp_contract_scope : Error< "'#pragma fp_contract' should only appear at file scope or at the start of a " "compound expression">; +// OpenMP +def warn_pragma_omp_ignored : Warning< + "pragma omp ignored; did you forget to add '-fopenmp' flag?">, + InGroup; + // OpenCL Section 6.8.g def err_not_opencl_storage_class_specifier : Error< "OpenCL does not support the '%0' storage class specifier">; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 25e8d5a..ed43e17 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -637,6 +637,42 @@ ANNOTATION(pragma_fp_contract) // handles them. ANNOTATION(pragma_opencl_extension) +// Annotations for OpenMP pragma directive statements - "\#pragam omp ..." +// The lexer produces these so that they only take effect when the parser +// handles them. +// +// Note that OpenMP pragma annotations below are listed in the same order +// as listed in the OpenMP 3.1 standard specification document. Please do +// *adhere* to the same order. + +// OpenMP parallel constructs. +ANNOTATION(pragma_omp_parallel) + +// OpenMP work sharing constructs. +ANNOTATION(pragma_omp_for) +ANNOTATION(pragma_omp_sections) +ANNOTATION(pragma_omp_single) +ANNOTATION(pragma_omp_section) + +// OpenMP combined parallel work sharing constructs. +// TODO + +// OpenMP tasking constructs. +ANNOTATION(pragma_omp_task) +ANNOTATION(pragma_omp_taskyield) + +// OpenMP master and synchronization constructs. +ANNOTATION(pragma_omp_master) +ANNOTATION(pragma_omp_critical) +ANNOTATION(pragma_omp_barrier) +ANNOTATION(pragma_omp_taskwait) +ANNOTATION(pragma_omp_atomic) +ANNOTATION(pragma_omp_flush) +ANNOTATION(pragma_omp_ordered) + +// OpenMP data environment related constructs. +ANNOTATION(pragma_omp_threadprivate) + #undef ANNOTATION #undef TESTING_KEYWORD #undef OBJC2_AT_KEYWORD diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 20b13ba..852e77f 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -43,6 +43,7 @@ namespace clang { class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class VersionTuple; + class OpenMP; /// PrettyStackTraceParserEntry - If a crash happens while the parser is active, /// an entry is printed for it. @@ -180,6 +181,8 @@ class Parser : public CodeCompletionHandler { OwningPtr OpenCLExtensionHandler; OwningPtr CommentSemaHandler; + OwningPtr OpenMPHandler; + /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ /// template argument list, where the '>' closes the template diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 99c3636..5a235733 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,6 +23,237 @@ #include "clang/AST/ASTConsumer.h" using namespace clang; + +namespace clang { + +/// \brief An instance of this interface is defined to initiate OpenMP parsing, +/// and to help Parser during subsequent parsing of OpenMP constrcuts. +class OpenMP { + // Private Member Objects. +private: + // \brief The member object reference to the Preprocessor. + Preprocessor &PP; + + // \brief Handler objects which handle different OpenMP pragma directive + // statements. + OwningPtr ParallelHandler; + OwningPtr ForHandler; + OwningPtr SectionsHandler; + OwningPtr SectionHandler; + OwningPtr SingleHandler; + OwningPtr TaskHandler; + OwningPtr MasterHandler; + OwningPtr CriticalHandler; + OwningPtr BarrierHandler; + OwningPtr TaskwaitHandler; + OwningPtr TaskyieldHandler; + OwningPtr AtomicHandler; + OwningPtr FlushHandler; + OwningPtr OrderedHandler; + OwningPtr ThreadPrivateHandler; + + // \brief When an OpenMP pragma is ignored, we emit a warning message + // saying so, but only once per translation unit irrespective of the + // number of OpenMP pragmas appeared in the translation unit. This flag + // keeps track of whether the unkown pragma warning message is emitted + // or not for the current translation unit. + bool OmpUnknownWarned; + + // Private Member Methods. +private: + // \brief When source contains omp pragmas, but user does not pass the + // '-fopenmp' flag, we emit a warning message saying so, but only once per + // source file. + void SetPragmaOmpUnknownWarned() { OmpUnknownWarned = true; } + void ResetPragmaOmpUnknownWarned() { OmpUnknownWarned = false; } + bool PragmaOmpUnknownWarned() { return OmpUnknownWarned; } + + // \brief Handles "\#pragma omp ...". + // It Checks if the user has passed the flag, '-fopenmp', if so, + // it enters the *token* which is *representing* the current OpenMP + // pragma *directive* into the TokenStream, so that the Parser can + // recognizes it and can parse the respective OpenMP pragma directive + // statement. Otherwise, it reports a warning that the current OpenMP + // directive statement will be ignored. However, note that only + // *one* warning message per translation unit is reported + // irrespective of the number of OpenMP directive statments which + // appear in the translation unit. + void HandlePragma(Token &OmpTok, tok::TokenKind TKind) { + if (!PP.getLangOpts().OpenMP) { + if (!PragmaOmpUnknownWarned()) { + PP.Diag(OmpTok, diag::warn_pragma_omp_ignored); + SetPragmaOmpUnknownWarned(); + } + } else { + Token *Toks = new Token[1]; + Toks[0].startToken(); + Toks[0].setKind(TKind); + Toks[0].setLocation(OmpTok.getLocation()); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); + } + } + + // Constructors and Destructors. +public: + OpenMP(Preprocessor &pp); + ~OpenMP(); + +private: + // \brief An OpenMP pragma handler interface. It acts as an intermediate + // between the Preprocessor class and the OpenMP (this) class. It by passes + // the omp pragma handling call to OpenMP class upon requested by the + // Preprocessor. + struct PragmaOmpHandler : public PragmaHandler { + friend class OpenMP; + tok::TokenKind TKind; + OpenMP *Omp; + PragmaOmpHandler(tok::TokenKind Kind, StringRef Name, OpenMP *omp) + : PragmaHandler(Name), TKind(Kind), Omp(omp) {} + virtual ~PragmaOmpHandler() { Omp = 0; } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &OmpTok) { + Omp->HandlePragma(OmpTok, TKind); + } + }; +}; + +} // end of namespace clang + +OpenMP::OpenMP(Preprocessor &pp) + : PP(pp) { + + // Add "#pragma omp ..." handlers. These are removed and destroyed + // in the destructor. + // + // Note that OpenMP pragma annotations below are listed in the same order + // as listed in the OpenMP 3.1 standard specification document. Please + // do *adhere* to the same order. + + // OpenMP parallel constructs. + ParallelHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_parallel, "parallel", this)); + PP.AddPragmaHandler("omp", ParallelHandler.get()); + + // OpenMP work sharing constructs. + ForHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_for, "for", this)); + PP.AddPragmaHandler("omp", ForHandler.get()); + + SectionsHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_sections, "sections", this)); + PP.AddPragmaHandler("omp", SectionsHandler.get()); + + SingleHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_single, "single", this)); + PP.AddPragmaHandler("omp", SingleHandler.get()); + + SectionHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_section, "section", this)); + PP.AddPragmaHandler("omp", SectionHandler.get()); + + // OpenMP combined parallel work sharing constructs. + // FIXME: not supported yet. + + // OpenMP tasking constructs. + TaskHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_task, "task", this)); + PP.AddPragmaHandler("omp", TaskHandler.get()); + + TaskyieldHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_taskyield, "taskyield", this)); + PP.AddPragmaHandler("omp", TaskyieldHandler.get()); + + // OpenMP master and synchronization constructs. + MasterHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_master, "master", this)); + PP.AddPragmaHandler("omp", MasterHandler.get()); + + CriticalHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_critical, "critical", this)); + PP.AddPragmaHandler("omp", CriticalHandler.get()); + + BarrierHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_barrier, "barrier", this)); + PP.AddPragmaHandler("omp", BarrierHandler.get()); + + TaskwaitHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_taskwait, "taskwait", this)); + PP.AddPragmaHandler("omp", TaskwaitHandler.get()); + + AtomicHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_atomic, "atomic", this)); + PP.AddPragmaHandler("omp", AtomicHandler.get()); + + FlushHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_flush, "flush", this)); + PP.AddPragmaHandler("omp", FlushHandler.get()); + + OrderedHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_ordered, "ordered", this)); + PP.AddPragmaHandler("omp", OrderedHandler.get()); + + // OpenMP data environment related constructs. + ThreadPrivateHandler.reset(new PragmaOmpHandler( + tok::annot_pragma_omp_threadprivate, "threadprivate", this)); + PP.AddPragmaHandler("omp", ThreadPrivateHandler.get()); + + // We have not yet reported the unknown OpenMP pragma *warning* message + // as we have not yet started the processing of translation unit. + ResetPragmaOmpUnknownWarned(); +} + +OpenMP::~OpenMP() { + // Remove the "#pragma omp ..." handlers we installed. + // + // Note that OpenMP pragma annotations below are listed in the same order + // as listed in the OpenMP 3.1 standard specification document. Please + // do *adhere* to the same order. + + // OpenMP parallel constructs. + PP.RemovePragmaHandler("omp", ParallelHandler.get()); + ParallelHandler.reset(); + + // OpenMP work sharing constructs. + PP.RemovePragmaHandler("omp", ForHandler.get()); + ForHandler.reset(); + PP.RemovePragmaHandler("omp", SectionsHandler.get()); + SectionsHandler.reset(); + PP.RemovePragmaHandler("omp", SingleHandler.get()); + SingleHandler.reset(); + PP.RemovePragmaHandler("omp", SectionHandler.get()); + SectionHandler.reset(); + + // OpenMP combined parallel work sharing constructs. + // FIXME: Yet to support. + + // OpenMP tasking constructs. + PP.RemovePragmaHandler("omp", TaskHandler.get()); + TaskHandler.reset(); + PP.RemovePragmaHandler("omp", TaskyieldHandler.get()); + TaskyieldHandler.reset(); + + // OpenMP master and synchronization constructs. + PP.RemovePragmaHandler("omp", MasterHandler.get()); + MasterHandler.reset(); + PP.RemovePragmaHandler("omp", CriticalHandler.get()); + CriticalHandler.reset(); + PP.RemovePragmaHandler("omp", BarrierHandler.get()); + BarrierHandler.reset(); + PP.RemovePragmaHandler("omp", TaskwaitHandler.get()); + TaskwaitHandler.reset(); + PP.RemovePragmaHandler("omp", AtomicHandler.get()); + AtomicHandler.reset(); + PP.RemovePragmaHandler("omp", FlushHandler.get()); + FlushHandler.reset(); + PP.RemovePragmaHandler("omp", OrderedHandler.get()); + OrderedHandler.reset(); + + // OpenMP data environment related constructs. + PP.RemovePragmaHandler("omp", ThreadPrivateHandler.get()); + ThreadPrivateHandler.reset(); +} + namespace { /// \brief A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -98,6 +329,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) PP.addCommentHandler(CommentSemaHandler.get()); PP.setCodeCompletionHandler(*this); + + OpenMPHandler.reset(new OpenMP(pp)); } /// If a crash happens while the parser is active, print out a line indicating @@ -456,6 +689,8 @@ Parser::~Parser() { PP.clearCodeCompletionHandler(); + OpenMPHandler.reset(); + assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); } diff --git a/clang/test/Preprocessor/pragma_omp.c b/clang/test/Preprocessor/pragma_omp.c new file mode 100644 index 0000000..deb162c --- /dev/null +++ b/clang/test/Preprocessor/pragma_omp.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -E -verify %s +// RUN: %clang_cc1 -E -verify -fopenmp %s +// RUN: %clang_cc1 -Eonly -verify %s +// RUN: %clang_cc1 -Eonly -verify -fopenmp %s +// RUN: %clang_cc1 -E -P -verify %s +// RUN: %clang_cc1 -E -P -verify -fopenmp %s + +int pragma_omp_test() { + int i, VarA; + #pragma omp parallel // expected-no-diagnostics + { + #pragma omp for // expected-no-diagnostics + for(i=0; i<10; i++) { + VarA = 29; + } + } + return VarA; +} diff --git a/clang/test/Preprocessor/pragma_omp_ignored_warning.c b/clang/test/Preprocessor/pragma_omp_ignored_warning.c new file mode 100644 index 0000000..1b6ac8a --- /dev/null +++ b/clang/test/Preprocessor/pragma_omp_ignored_warning.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int pragma_omp_ignored_warning_test() { + int i, VarA; + #pragma omp parallel // expected-warning {{pragma omp ignored; did you forget to add '-fopenmp' flag?}} + { + #pragma omp for + for(i=0; i<10; i++) { + VarA = 29; + } + } + return VarA; +} -- 2.7.4