[PATCH] [OPENMP] Initial support of 'reduction' clause

Alp Toker alp at nuanti.com
Thu May 15 06:34:40 PDT 2014


Couple of remarks inline...


On 15/05/2014 11:30, Alexey Bataev wrote:
> Hi doug.gregor, gribozavr, hfinkel, cbergstrom, fraggamuffin, rsmith,
>
> Parsing and sema analysis for OpenMP clause 'reduction'
>
> http://reviews.llvm.org/D3776
>
> Files:
>    include/clang/AST/DataRecursiveASTVisitor.h
>    include/clang/AST/OpenMPClause.h
>    include/clang/AST/RecursiveASTVisitor.h
>    include/clang/Basic/DiagnosticSemaKinds.td
>    include/clang/Basic/OpenMPKinds.def
>    include/clang/Sema/Sema.h
>    lib/AST/Stmt.cpp
>    lib/AST/StmtPrinter.cpp
>    lib/AST/StmtProfile.cpp
>    lib/Basic/OpenMPKinds.cpp
>    lib/Parse/ParseOpenMP.cpp
>    lib/Sema/SemaOpenMP.cpp
>    lib/Sema/TreeTransform.h
>    lib/Serialization/ASTReaderStmt.cpp
>    lib/Serialization/ASTWriterStmt.cpp
>    test/OpenMP/parallel_ast_print.cpp
>    test/OpenMP/parallel_reduction_messages.cpp
>    test/OpenMP/simd_linear_messages.cpp
>    tools/libclang/CIndex.cpp
>
> D3776.9411.patch
>
>
> Index: include/clang/AST/DataRecursiveASTVisitor.h
> ===================================================================
> --- include/clang/AST/DataRecursiveASTVisitor.h
> +++ include/clang/AST/DataRecursiveASTVisitor.h
> @@ -2412,6 +2412,15 @@
>   }
>   
>   template<typename Derived>
> +bool DataRecursiveASTVisitor<Derived>::VisitOMPReductionClause(
> +                                                    OMPReductionClause *C) {
> +  TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
> +  TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
> +  VisitOMPClauseList(C);
> +  return true;
> +}
> +
> +template<typename Derived>
>   bool
>   DataRecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
>     VisitOMPClauseList(C);
> Index: include/clang/AST/OpenMPClause.h
> ===================================================================
> --- include/clang/AST/OpenMPClause.h
> +++ include/clang/AST/OpenMPClause.h
> @@ -623,6 +623,99 @@
>     }
>   };
>   
> +/// \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 the variables 'a' and 'b'.
> +///
> +class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
> +  friend class OMPClauseReader;
> +  /// \brief Location of ':'.
> +  SourceLocation ColonLoc;
> +  /// \brief Nested name specifier for C++.
> +  NestedNameSpecifierLoc QualifierLoc;
> +  /// \brief Name of custom operator.
> +  DeclarationNameInfo NameInfo;
> +
> +  /// \brief Build clause with number of variables \a N.
> +  ///
> +  /// \param StartLoc Starting location of the clause.
> +  /// \param LParenLoc Location of '('.
> +  /// \param EndLoc Ending location of the clause.
> +  /// \param ColonLoc Location of ':'.
> +  /// \param N Number of the variables in the clause.
> +  /// \param QualifierLoc The nested-name qualifier with location information
> +  /// \param NameInfo The full name info for reduction identifier.
> +  ///
> +  OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
> +                     SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N,
> +                     NestedNameSpecifierLoc QualifierLoc,
> +                     const DeclarationNameInfo &NameInfo)
> +      : OMPVarListClause<OMPReductionClause>(OMPC_reduction, StartLoc,
> +                                             LParenLoc, EndLoc, N),
> +        ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
> +
> +  /// \brief Build an empty clause.
> +  ///
> +  /// \param N Number of variables.
> +  ///
> +  explicit OMPReductionClause(unsigned N)
> +      : OMPVarListClause<OMPReductionClause>(OMPC_reduction, SourceLocation(),
> +                                             SourceLocation(), SourceLocation(),
> +                                             N),
> +        ColonLoc(), QualifierLoc(), NameInfo() {}
> +
> +  /// \brief Sets location of ':' symbol in clause.
> +  void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
> +  /// \brief Sets the name info for specified reduction identifier.
> +  void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
> +  /// \brief Sets the nested name specifier.
> +  void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
> +
> +public:
> +  /// \brief Creates clause with a list of variables \a VL.
> +  ///
> +  /// \param StartLoc Starting location of the clause.
> +  /// \param LParenLoc Location of '('.
> +  /// \param ColonLoc Location of ':'.
> +  /// \param EndLoc Ending location of the clause.
> +  /// \param N Number of the variables in the clause.
> +  /// \param QualifierLoc The nested-name qualifier with location information
> +  /// \param NameInfo The full name info for reduction identifier.
> +  ///
> +  static OMPReductionClause *
> +  Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
> +         SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
> +         NestedNameSpecifierLoc QualifierLoc,
> +         const DeclarationNameInfo &NameInfo);
> +  /// \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 Gets location of ':' symbol in clause.
> +  SourceLocation getColonLoc() const { return ColonLoc; }
> +  /// \brief Gets the name info for specified reduction identifier.
> +  const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
> +  /// \brief Gets the nested name specifier.
> +  NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
> +
> +  StmtRange children() {
> +    return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
> +                     reinterpret_cast<Stmt **>(varlist_end()));
> +  }
> +
> +  static bool classof(const OMPClause *T) {
> +    return T->getClauseKind() == OMPC_reduction;
> +  }
> +};
> +
>   /// \brief This represents clause 'linear' in the '#pragma omp ...'
>   /// directives.
>   ///
> Index: include/clang/AST/RecursiveASTVisitor.h
> ===================================================================
> --- include/clang/AST/RecursiveASTVisitor.h
> +++ include/clang/AST/RecursiveASTVisitor.h
> @@ -2448,6 +2448,15 @@
>   }
>   
>   template<typename Derived>
> +bool RecursiveASTVisitor<Derived>::VisitOMPReductionClause(
> +                                                    OMPReductionClause *C) {
> +  TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
> +  TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
> +  VisitOMPClauseList(C);
> +  return true;
> +}
> +
> +template<typename Derived>
>   bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
>     VisitOMPClauseList(C);
>     TraverseStmt(C->getStep());
> Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td
> +++ include/clang/Basic/DiagnosticSemaKinds.td
> @@ -6907,6 +6907,8 @@
>     "a private variable with incomplete type %0">;
>   def err_omp_firstprivate_incomplete_type : Error<
>     "a firstprivate variable with incomplete type %0">;
> +def err_omp_reduction_incomplete_type : Error<
> +  "a reduction variable with incomplete type %0">;
>   def err_omp_unexpected_clause_value : Error<
>     "expected %0 in OpenMP clause '%1'">;
>   def err_omp_expected_var_name : Error<
> @@ -6953,6 +6955,24 @@
>   def warn_omp_linear_step_zero : Warning<
>     "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">,
>     InGroup<OpenMPClauses>;
> +def err_omp_unknown_reduction_identifier : Error<
> +  "incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'">;
> +def err_omp_reduction_type_array : Error<
> +  "a reduction variable with array type %0">;
> +def err_omp_reduction_ref_type_arg : Error<
> +  "argument of OpenMP clause 'reduction' must reference the same object in all threads">;
> +def err_omp_clause_not_arithmetic_type_arg : Error<
> +  "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 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_once_referenced : Error<
> +  "variable can appear only once in OpenMP '%0' clause">;
> +def note_omp_referenced : Note<
> +  "previously referenced here">;
> +def err_omp_reduction_in_task : Error<
> +  "reduction variables may not be accessed in an explicit task">;
> +def err_omp_reduction_id_not_compatible : Error<
> +  "variable of type %0 is not valid for specified reduction operation">;
>   } // end of OpenMP category
>   
>   let CategoryName = "Related Result Type Issue" in {
> Index: include/clang/Basic/OpenMPKinds.def
> ===================================================================
> --- include/clang/Basic/OpenMPKinds.def
> +++ include/clang/Basic/OpenMPKinds.def
> @@ -45,6 +45,7 @@
>   OPENMP_CLAUSE(private, OMPPrivateClause)
>   OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
>   OPENMP_CLAUSE(shared,  OMPSharedClause)
> +OPENMP_CLAUSE(reduction,  OMPReductionClause)
>   OPENMP_CLAUSE(linear,  OMPLinearClause)
>   OPENMP_CLAUSE(copyin,  OMPCopyinClause)
>   OPENMP_CLAUSE(proc_bind, OMPProcBindClause)
> @@ -57,6 +58,7 @@
>   OPENMP_PARALLEL_CLAUSE(private)
>   OPENMP_PARALLEL_CLAUSE(firstprivate)
>   OPENMP_PARALLEL_CLAUSE(shared)
> +OPENMP_PARALLEL_CLAUSE(reduction)
>   OPENMP_PARALLEL_CLAUSE(copyin)
>   
>   // FIXME: more clauses allowed for directive 'omp simd'.
> Index: include/clang/Sema/Sema.h
> ===================================================================
> --- include/clang/Sema/Sema.h
> +++ include/clang/Sema/Sema.h
> @@ -7329,13 +7329,13 @@
>                                          SourceLocation LParenLoc,
>                                          SourceLocation EndLoc);
>   
> -  OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
> -                                      ArrayRef<Expr *> Vars,
> -                                      Expr *TailExpr,
> -                                      SourceLocation StartLoc,
> -                                      SourceLocation LParenLoc,
> -                                      SourceLocation ColonLoc,
> -                                      SourceLocation EndLoc);
> +  OMPClause *
> +  ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars,
> +                           Expr *TailExpr, SourceLocation StartLoc,
> +                           SourceLocation LParenLoc, SourceLocation ColonLoc,
> +                           SourceLocation EndLoc,
> +                           CXXScopeSpec &ReductionIdScopeSpec,
> +                           const DeclarationNameInfo &ReductionId);
>     /// \brief Called on well-formed 'private' clause.
>     OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
>                                         SourceLocation StartLoc,
> @@ -7351,6 +7351,13 @@
>                                        SourceLocation StartLoc,
>                                        SourceLocation LParenLoc,
>                                        SourceLocation EndLoc);
> +  /// \brief Called on well-formed 'reduction' clause.
> +  OMPClause *
> +  ActOnOpenMPReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc,
> +                             SourceLocation LParenLoc, SourceLocation ColonLoc,
> +                             SourceLocation EndLoc,
> +                             CXXScopeSpec &ReductionIdScopeSpec,
> +                             const DeclarationNameInfo &ReductionId);
>     /// \brief Called on well-formed 'linear' clause.
>     OMPClause *ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
>                                        Expr *Step,
> Index: lib/AST/Stmt.cpp
> ===================================================================
> --- lib/AST/Stmt.cpp
> +++ lib/AST/Stmt.cpp
> @@ -1242,6 +1242,27 @@
>     std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
>   }
>   
> +OMPReductionClause *OMPReductionClause::Create(
> +    const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
> +    SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
> +    NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) {
> +  void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
> +                                                  llvm::alignOf<Expr *>()) +
> +                         sizeof(Expr *) * VL.size());
> +  OMPReductionClause *Clause = new (Mem) OMPReductionClause(
> +      StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
> +  Clause->setVarRefs(VL);
> +  return Clause;
> +}
> +
> +OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
> +                                                    unsigned N) {
> +  void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
> +                                                  llvm::alignOf<Expr *>()) +
> +                         sizeof(Expr *) * N);
> +  return new (Mem) OMPReductionClause(N);
> +}
> +
>   OMPParallelDirective *OMPParallelDirective::Create(
>                                                 const ASTContext &C,
>                                                 SourceLocation StartLoc,
> Index: lib/AST/StmtPrinter.cpp
> ===================================================================
> --- lib/AST/StmtPrinter.cpp
> +++ lib/AST/StmtPrinter.cpp
> @@ -659,6 +659,28 @@
>     }
>   }
>   
> +void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
> +  if (!Node->varlist_empty()) {
> +    OS << "reduction(";
> +    NestedNameSpecifier *QualifierLoc =
> +        Node->getQualifierLoc().getNestedNameSpecifier();
> +    OverloadedOperatorKind OOK =
> +        Node->getNameInfo().getName().getCXXOverloadedOperator();
> +    if (QualifierLoc == nullptr && OOK != OO_None) {
> +      // Print reduction identifier in C format
> +      OS << getOperatorSpelling(OOK);
> +    } else {
> +      // Use C++ format
> +      if (QualifierLoc != nullptr)
> +        QualifierLoc->print(OS, Policy);
> +      OS << Node->getNameInfo();
> +    }
> +    OS << ":";
> +    VisitOMPClauseList(Node, ' ');
> +    OS << ")";
> +  }
> +}
> +
>   void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
>     if (!Node->varlist_empty()) {
>       OS << "linear";
> Index: lib/AST/StmtProfile.cpp
> ===================================================================
> --- lib/AST/StmtProfile.cpp
> +++ lib/AST/StmtProfile.cpp
> @@ -299,6 +299,13 @@
>   void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
>     VisitOMPClauseList(C);
>   }
> +void OMPClauseProfiler::VisitOMPReductionClause(
> +                                         const OMPReductionClause *C) {
> +  Profiler->VisitNestedNameSpecifier(
> +      C->getQualifierLoc().getNestedNameSpecifier());
> +  Profiler->VisitName(C->getNameInfo().getName());
> +  VisitOMPClauseList(C);
> +}
>   void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
>     VisitOMPClauseList(C);
>     Profiler->VisitStmt(C->getStep());
> Index: lib/Basic/OpenMPKinds.cpp
> ===================================================================
> --- lib/Basic/OpenMPKinds.cpp
> +++ lib/Basic/OpenMPKinds.cpp
> @@ -86,6 +86,7 @@
>     case OMPC_private:
>     case OMPC_firstprivate:
>     case OMPC_shared:
> +  case OMPC_reduction:
>     case OMPC_linear:
>     case OMPC_copyin:
>       break;
> @@ -122,6 +123,7 @@
>     case OMPC_private:
>     case OMPC_firstprivate:
>     case OMPC_shared:
> +  case OMPC_reduction:
>     case OMPC_linear:
>     case OMPC_copyin:
>       break;
> Index: lib/Parse/ParseOpenMP.cpp
> ===================================================================
> --- lib/Parse/ParseOpenMP.cpp
> +++ lib/Parse/ParseOpenMP.cpp
> @@ -257,7 +257,8 @@
>   ///
>   ///    clause:
>   ///       if-clause | num_threads-clause | safelen-clause | default-clause |
> -///       private-clause | firstprivate-clause | shared-clause | linear-clause
> +///       private-clause | firstprivate-clause | shared-clause | linear-clause |
> +///       reduction-clause
>   ///
>   OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
>                                        OpenMPClauseKind CKind, bool FirstClause) {
> @@ -303,6 +304,7 @@
>     case OMPC_private:
>     case OMPC_firstprivate:
>     case OMPC_shared:
> +  case OMPC_reduction:
>     case OMPC_linear:
>     case OMPC_copyin:
>       Clause = ParseOpenMPVarListClause(CKind);
> @@ -388,6 +390,52 @@
>                                            Tok.getLocation());
>   }
>   
> +static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
> +                             UnqualifiedId &ReductionId) {
> +  SourceLocation TemplateKWLoc;
> +  if (ReductionIdScopeSpec.isEmpty()) {
> +    auto OOK = OO_None;

Not convinced this 'auto' is clearer than writing out the type.

> +    switch (P.getCurToken().getKind()) {
> +    case tok::plus:
> +      OOK = OO_Plus;
> +      break;
> +    case tok::minus:
> +      OOK = OO_Minus;
> +      break;
> +    case tok::star:
> +      OOK = OO_Star;
> +      break;
> +    case tok::amp:
> +      OOK = OO_Amp;
> +      break;
> +    case tok::pipe:
> +      OOK = OO_Pipe;
> +      break;
> +    case tok::caret:
> +      OOK = OO_Caret;
> +      break;
> +    case tok::ampamp:
> +      OOK = OO_AmpAmp;
> +      break;
> +    case tok::pipepipe:
> +      OOK = OO_PipePipe;
> +      break;
> +    default:
> +      break;
> +    }
> +    if (OOK != OO_None) {
> +      SourceLocation OpLoc = P.ConsumeToken();
> +      SourceLocation SymbolLocations[] = { OpLoc, OpLoc, SourceLocation() };
> +      ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
> +      return false;
> +    }
> +  }
> +  return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
> +                              /*AllowDestructorName*/ false,
> +                              /*AllowConstructorName*/ false, ParsedType(),
> +                              TemplateKWLoc, ReductionId);
> +}
> +
>   /// \brief Parsing of OpenMP clause 'private', 'firstprivate',
>   /// 'shared', 'copyin', or 'reduction'.
>   ///
> @@ -399,19 +447,44 @@
>   ///       'shared' '(' list ')'
>   ///    linear-clause:
>   ///       'linear' '(' list [ ':' linear-step ] ')'
> +///    reduction-clause:
> +///       'reduction' '(' reduction-identifier ':' list ')'
>   ///
>   OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
>     SourceLocation Loc = Tok.getLocation();
>     SourceLocation LOpen = ConsumeToken();
>     SourceLocation ColonLoc = SourceLocation();
> +  // Optional scope specifier and unqualified id for reduction identifier.
> +  CXXScopeSpec ReductionIdScopeSpec;
> +  UnqualifiedId ReductionId;
> +  bool InvalidReductionId = false;
>     // Parse '('.
>     BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
>     if (T.expectAndConsume(diag::err_expected_lparen_after,
>                            getOpenMPClauseName(Kind)))
> -    return 0;
> +    return nullptr;
> +
> +  // Handle reduction-identifier for reduction clause.
> +  if (Kind == OMPC_reduction) {
> +    ColonProtectionRAIIObject ColonRAII(*this);
> +    if (getLangOpts().CPlusPlus) {
> +      ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
> +    }
> +    InvalidReductionId =
> +        ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
> +    if (InvalidReductionId) {
> +      SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
> +                StopBeforeMatch);
> +    }
> +    if (Tok.is(tok::colon)) {
> +      ColonLoc = ConsumeToken();
> +    } else {
> +      Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
> +    }
> +  }
>   
>     SmallVector<Expr *, 5> Vars;
> -  bool IsComma = true;
> +  bool IsComma = !InvalidReductionId;
>     const bool MayHaveTail = (Kind == OMPC_linear);
>     while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
>                        Tok.isNot(tok::annot_pragma_openmp_end))) {
> @@ -435,7 +508,7 @@
>     }
>   
>     // Parse ':' linear-step
> -  Expr *TailExpr = 0;
> +  Expr *TailExpr = nullptr;
>     const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
>     if (MustHaveTail) {
>       ColonLoc = Tok.getLocation();
> @@ -450,10 +523,13 @@
>   
>     // Parse ')'.
>     T.consumeClose();
> -  if (Vars.empty() || (MustHaveTail && !TailExpr))
> -    return 0;
> +  if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
> +    return nullptr;
>   
> -  return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc, LOpen,
> -                                          ColonLoc, Tok.getLocation());
> +  return Actions.ActOnOpenMPVarListClause(
> +      Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
> +      ReductionIdScopeSpec,
> +      ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
> +                            : DeclarationNameInfo());
>   }
>   
> Index: lib/Sema/SemaOpenMP.cpp
> ===================================================================
> --- lib/Sema/SemaOpenMP.cpp
> +++ lib/Sema/SemaOpenMP.cpp
> @@ -111,6 +111,10 @@
>     /// attribute in \a DKind directive.
>     DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
>                       OpenMPDirectiveKind DKind = OMPD_unknown);
> +  /// \brief Checks if the specified variables has \a CKind data-sharing
> +  /// attribute in an innermost \a DKind directive.
> +  DSAVarData hasInnermostDSA(VarDecl *D, OpenMPClauseKind CKind,
> +                             OpenMPDirectiveKind DKind);
>   
>     /// \brief Returns currently analyzed directive.
>     OpenMPDirectiveKind getCurrentDirective() const {
> @@ -146,7 +150,6 @@
>       //  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;
>   
> @@ -207,7 +210,6 @@
>       //  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 = std::next(Iter),
> @@ -375,6 +377,21 @@
>     return DSAVarData();
>   }
>   
> +DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D,
> +                                                   OpenMPClauseKind CKind,
> +                                                   OpenMPDirectiveKind DKind) {
> +  assert(DKind != OMPD_unknown && "Directive must be specified explicitly");
> +  for (auto I = Stack.rbegin(), EE = std::prev(Stack.rend()); I != EE; ++I) {
> +    if (DKind != I->Directive)
> +      continue;
> +    DSAVarData DVar = getDSA(I, D);
> +    if (DVar.CKind == CKind)
> +      return DVar;
> +    return DSAVarData();
> +  }
> +  return DSAVarData();
> +}
> +
>   void Sema::InitDataSharingAttributesStack() {
>     VarDataSharingAttributesStack = new DSAStackTy(*this);
>   }
> @@ -638,7 +655,16 @@
>         //  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:
> +      DVar = Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel);
> +      if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
> +        ErrorFound = true;
> +        Actions.Diag(ELoc, diag::err_omp_reduction_in_task);
> +        if (DVar.RefExpr) {
> +          Actions.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
> +              << getOpenMPClauseName(OMPC_reduction);
> +        }
> +        return;
> +      }
>   
>         // Define implicit data-sharing attributes for task.
>         DVar = Stack->getImplicitDSA(VD);
> @@ -814,6 +840,7 @@
>     case OMPC_private:
>     case OMPC_firstprivate:
>     case OMPC_shared:
> +  case OMPC_reduction:
>     case OMPC_linear:
>     case OMPC_copyin:
>     case OMPC_threadprivate:
> @@ -974,6 +1001,7 @@
>     case OMPC_private:
>     case OMPC_firstprivate:
>     case OMPC_shared:
> +  case OMPC_reduction:
>     case OMPC_linear:
>     case OMPC_copyin:
>     case OMPC_threadprivate:
> @@ -1058,13 +1086,11 @@
>                                            EndLoc);
>   }
>   
> -OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
> -                                          ArrayRef<Expr *> VarList,
> -                                          Expr *TailExpr,
> -                                          SourceLocation StartLoc,
> -                                          SourceLocation LParenLoc,
> -                                          SourceLocation ColonLoc,
> -                                          SourceLocation EndLoc) {
> +OMPClause *Sema::ActOnOpenMPVarListClause(
> +    OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
> +    SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
> +    SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
> +    const DeclarationNameInfo &ReductionId) {
>     OMPClause *Res = 0;
>     switch (Kind) {
>     case OMPC_private:
> @@ -1076,6 +1102,11 @@
>     case OMPC_shared:
>       Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
>       break;
> +  case OMPC_reduction:
> +    Res =
> +        ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
> +                                   EndLoc, ReductionIdScopeSpec, ReductionId);
> +    break;
>     case OMPC_linear:
>       Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
>                                     ColonLoc, EndLoc);
> @@ -1462,6 +1493,323 @@
>     return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
>   }
>   
> +namespace {
> +class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
> +  DSAStackTy *Stack;
> +
> +public:
> +  bool VisitDeclRefExpr(DeclRefExpr *E) {
> +    if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
> +      DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
> +      if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
> +        return false;
> +      if (DVar.CKind != OMPC_unknown)
> +        return true;
> +      DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(VD, OMPC_private);
> +      DSAStackTy::DSAVarData DVarFirstprivate =
> +          Stack->hasDSA(VD, OMPC_firstprivate);
> +      DSAStackTy::DSAVarData DVarReduction = Stack->hasDSA(VD, OMPC_reduction);
> +      if (DVarPrivate.CKind != OMPC_unknown ||
> +          DVarFirstprivate.CKind != OMPC_unknown ||
> +          DVarReduction.CKind != OMPC_unknown)
> +        return true;
> +      return false;
> +    }
> +    return false;
> +  }
> +  bool VisitStmt(Stmt *S) {
> +    for (auto Child : S->children()) {
> +      if (Child && Visit(Child))
> +        return true;
> +    }
> +    return false;
> +  }
> +  DSARefChecker(DSAStackTy *S) : Stack(S) {}
> +};
> +}
> +
> +OMPClause *Sema::ActOnOpenMPReductionClause(
> +    ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
> +    SourceLocation ColonLoc, SourceLocation EndLoc,
> +    CXXScopeSpec &ReductionIdScopeSpec,
> +    const DeclarationNameInfo &ReductionId) {
> +  // TODO: Allow scope specification search when 'declare reduction' is
> +  // supported.
> +  assert(ReductionIdScopeSpec.isEmpty() &&
> +         "No support for scoped reduction identifiers yet.");
> +
> +  auto DN = ReductionId.getName();
> +  auto OOK = DN.getCXXOverloadedOperator();
> +  auto BOK = BO_Comma;
> +
> +  // OpenMP [2.14.3.6, reduction clause]
> +  // C
> +  // reduction-identifier is either an identifier or one of the following
> +  // operators: +, -, *,  &, |, ^, && and ||
> +  // C++
> +  // reduction-identifier is either an id-expression or one of the following
> +  // operators: +, -, *, &, |, ^, && and ||
> +  // FIXME: Only 'min' and 'max' identifiers are supported for now.
> +  switch (OOK) {
> +  case OO_Plus:
> +  case OO_Minus:
> +    BOK = BO_AddAssign;
> +    break;
> +  case OO_Star:
> +    BOK = BO_MulAssign;
> +    break;
> +  case OO_Amp:
> +    BOK = BO_AndAssign;
> +    break;
> +  case OO_Pipe:
> +    BOK = BO_OrAssign;
> +    break;
> +  case OO_Caret:
> +    BOK = BO_XorAssign;
> +    break;
> +  case OO_AmpAmp:
> +    BOK = BO_LAnd;
> +    break;
> +  case OO_PipePipe:
> +    BOK = BO_LOr;
> +    break;
> +  default:
> +    if (auto II = DN.getAsIdentifierInfo()) {
> +      if (II->isStr("max"))
> +        BOK = BO_GT;
> +      else if (II->isStr("min"))
> +        BOK = BO_LT;
> +    }
> +    break;
> +  }
> +  SourceRange ReductionIdRange;
> +  if (ReductionIdScopeSpec.isValid()) {
> +    ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
> +  }
> +  ReductionIdRange.setEnd(ReductionId.getEndLoc());
> +  if (BOK == BO_Comma) {
> +    // Not allowed reduction identifier is found.
> +    Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier)
> +        << ReductionIdRange;
> +    return nullptr;
> +  }
> +
> +  SmallVector<Expr *, 8> Vars;
> +  for (auto RefExpr : VarList) {
> +    assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
> +    if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
> +      // It will be analyzed later.
> +      Vars.push_back(RefExpr);
> +      continue;
> +    }
> +
> +    if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
> +        RefExpr->isInstantiationDependent() ||
> +        RefExpr->containsUnexpandedParameterPack()) {
> +      // It will be analyzed later.
> +      Vars.push_back(RefExpr);
> +      continue;
> +    }
> +
> +    auto ELoc = RefExpr->getExprLoc();
> +    auto ERange = RefExpr->getSourceRange();
> +    // OpenMP [2.1, C/C++]
> +    //  A list item is a variable or array section, subject to the restrictions
> +    //  specified in Section 2.4 on page 42 and in each of the sections
> +    // describing clauses and directives for which a list appears.
> +    // 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.
> +    auto DE = dyn_cast<DeclRefExpr>(RefExpr);
> +    if (!DE || !isa<VarDecl>(DE->getDecl())) {
> +      Diag(ELoc, diag::err_omp_expected_var_name) << ERange;
> +      continue;
> +    }
> +    auto D = DE->getDecl();
> +    auto VD = cast<VarDecl>(D);
> +    auto Type = VD->getType();
> +    // 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_reduction_incomplete_type))
> +      continue;
> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
> +    // Arrays may not appear in a reduction clause.
> +    if (Type.getNonReferenceType()->isArrayType()) {
> +      Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
> +      bool IsDecl =
> +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
> +      Diag(VD->getLocation(),
> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
> +          << VD;
> +      continue;
> +    }
> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
> +    // A list item that appears in a reduction clause must not be
> +    // const-qualified.
> +    if (Type.getNonReferenceType().isConstant(Context)) {
> +      Diag(ELoc, diag::err_omp_const_variable)
> +          << getOpenMPClauseName(OMPC_reduction) << Type << ERange;
> +      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.4]
> +    //  If a list-item is a reference type then it must bind to the same object
> +    //  for all threads of the team.
> +    VarDecl *VDDef = VD->getDefinition();
> +    if (Type->isReferenceType() && VDDef) {
> +      DSARefChecker Check(DSAStack);
> +      if (Check.Visit(VDDef->getInit())) {
> +        Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
> +        Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
> +        continue;
> +      }
> +    }
> +    // OpenMP [2.14.3.6, reduction clause, Restrictions]
> +    // The type of a list item that appears in a reduction clause must be valid
> +    // for the reduction-identifier. For a max or min reduction in C, the type
> +    // of the list item must be an allowed arithmetic data type: char, int,
> +    // float, double, or _Bool, possibly modified with long, short, signed, or
> +    // unsigned. For a max or min reduction in C++, the type of the list item
> +    // must be an allowed arithmetic data type: char, wchar_t, int, float,
> +    // double, or bool, possibly modified with long, short, signed, or unsigned.
> +    if ((BOK == BO_GT || BOK == BO_LT) &&
> +        !(Type->isScalarType() ||
> +          (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
> +      Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
> +          << getLangOpts().CPlusPlus;
> +      bool IsDecl =
> +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
> +      Diag(VD->getLocation(),
> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
> +          << VD;
> +      continue;
> +    }
> +    if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
> +        !getLangOpts().CPlusPlus && 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;
> +    }
> +    bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
> +    getDiagnostics().setSuppressAllDiagnostics(true);

Could you explain what the intention is here? An error trap might be 
more appropriate.

Alp.

> +    ExprResult ReductionOp =
> +        BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
> +                   RefExpr, RefExpr);
> +    getDiagnostics().setSuppressAllDiagnostics(Suppress);
> +    if (ReductionOp.isInvalid()) {
> +      Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
> +          << ReductionIdRange;
> +      bool IsDecl =
> +          VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
> +      Diag(VD->getLocation(),
> +           IsDecl ? diag::note_previous_decl : diag::note_defined_here)
> +          << VD;
> +      continue;
> +    }
> +
> +    // OpenMP [2.14.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.14.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.
> +    DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
> +    if (DVar.CKind == OMPC_reduction) {
> +      Diag(ELoc, diag::err_omp_once_referenced)
> +          << getOpenMPClauseName(OMPC_reduction);
> +      if (DVar.RefExpr) {
> +        Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
> +      }
> +    } else if (DVar.CKind != OMPC_unknown) {
> +      Diag(ELoc, diag::err_omp_wrong_dsa)
> +          << getOpenMPClauseName(DVar.CKind)
> +          << getOpenMPClauseName(OMPC_reduction);
> +      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);
> +      }
> +      continue;
> +    }
> +
> +    // OpenMP [2.14.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.
> +    // TODO Implement it later.
> +
> +    CXXRecordDecl *RD = getLangOpts().CPlusPlus
> +                            ? Type.getNonReferenceType()->getAsCXXRecordDecl()
> +                            : nullptr;
> +    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) {
> +        if (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;
> +        }
> +        MarkFunctionReferenced(ELoc, DD);
> +        DiagnoseUseOfDecl(DD, ELoc);
> +      }
> +    }
> +
> +    DSAStack->addDSA(VD, DE, OMPC_reduction);
> +    Vars.push_back(DE);
> +  }
> +
> +  if (Vars.empty())
> +    return nullptr;
> +
> +  return OMPReductionClause::Create(
> +      Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
> +      ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
> +}
> +
>   OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
>                                            SourceLocation StartLoc,
>                                            SourceLocation LParenLoc,
> Index: lib/Sema/TreeTransform.h
> ===================================================================
> --- lib/Sema/TreeTransform.h
> +++ lib/Sema/TreeTransform.h
> @@ -1394,6 +1394,22 @@
>                                                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<Expr *> VarList,
> +                                       SourceLocation StartLoc,
> +                                       SourceLocation LParenLoc,
> +                                       SourceLocation ColonLoc,
> +                                       SourceLocation EndLoc,
> +                                       CXXScopeSpec &ReductionIdScopeSpec,
> +                                       const DeclarationNameInfo &ReductionId) {
> +    return getSema().ActOnOpenMPReductionClause(
> +        VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
> +        ReductionId);
> +  }
> +
>     /// \brief Build a new OpenMP 'linear' clause.
>     ///
>     /// By default, performs semantic analysis to build the new statement.
> @@ -6320,21 +6336,16 @@
>          I != E; ++I) {
>       if (*I) {
>         OMPClause *Clause = getDerived().TransformOMPClause(*I);
> -      if (!Clause) {
> -        return StmtError();
> -      }
> -      TClauses.push_back(Clause);
> -    }
> -    else {
> -      TClauses.push_back(nullptr);
> +      if (Clause)
> +        TClauses.push_back(Clause);
>       }
>     }
>     if (!D->getAssociatedStmt()) {
>       return StmtError();
>     }
>     StmtResult AssociatedStmt =
>       getDerived().TransformStmt(D->getAssociatedStmt());
> -  if (AssociatedStmt.isInvalid()) {
> +  if (AssociatedStmt.isInvalid() || TClauses.size() != Clauses.size()) {
>       return StmtError();
>     }
>   
> @@ -6469,6 +6480,31 @@
>                                                C->getLocEnd());
>   }
>   
> +template <typename Derived>
> +OMPClause *
> +TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
> +  llvm::SmallVector<Expr *, 16> Vars;
> +  Vars.reserve(C->varlist_size());
> +  for (auto *VE : C->varlists()) {
> +    ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
> +    if (EVar.isInvalid())
> +      return nullptr;
> +    Vars.push_back(EVar.take());
> +  }
> +  CXXScopeSpec ReductionIdScopeSpec;
> +  ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
> +
> +  DeclarationNameInfo NameInfo = C->getNameInfo();
> +  if (NameInfo.getName()) {
> +    NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
> +    if (!NameInfo.getName())
> +      return nullptr;
> +  }
> +  return getDerived().RebuildOMPReductionClause(
> +      Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
> +      C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
> +}
> +
>   template<typename Derived>
>   OMPClause *
>   TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
> Index: lib/Serialization/ASTReaderStmt.cpp
> ===================================================================
> --- lib/Serialization/ASTReaderStmt.cpp
> +++ lib/Serialization/ASTReaderStmt.cpp
> @@ -1697,6 +1697,9 @@
>     case OMPC_shared:
>       C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
>       break;
> +  case OMPC_reduction:
> +    C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]);
> +    break;
>     case OMPC_linear:
>       C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
>       break;
> @@ -1770,6 +1773,24 @@
>     C->setVarRefs(Vars);
>   }
>   
> +void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
> +  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
> +  C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
> +  NestedNameSpecifierLoc NNSL =
> +    Reader->Reader.ReadNestedNameSpecifierLoc(Reader->F, Record, Idx);
> +  DeclarationNameInfo DNI;
> +  Reader->ReadDeclarationNameInfo(DNI, Record, Idx);
> +  C->setQualifierLoc(NNSL);
> +  C->setNameInfo(DNI);
> +
> +  unsigned NumVars = C->varlist_size();
> +  SmallVector<Expr *, 16> Vars;
> +  Vars.reserve(NumVars);
> +  for (unsigned i = 0; i != NumVars; ++i)
> +    Vars.push_back(Reader->Reader.ReadSubExpr());
> +  C->setVarRefs(Vars);
> +}
> +
>   void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
>     C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
>     C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
> Index: lib/Serialization/ASTWriterStmt.cpp
> ===================================================================
> --- lib/Serialization/ASTWriterStmt.cpp
> +++ lib/Serialization/ASTWriterStmt.cpp
> @@ -1723,6 +1723,16 @@
>       Writer->Writer.AddStmt(VE);
>   }
>   
> +void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
> +  Record.push_back(C->varlist_size());
> +  Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
> +  Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
> +  Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(), Record);
> +  Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
> +  for (auto *VE : C->varlists())
> +    Writer->Writer.AddStmt(VE);
> +}
> +
>   void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
>     Record.push_back(C->varlist_size());
>     Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
> Index: test/OpenMP/parallel_ast_print.cpp
> ===================================================================
> --- test/OpenMP/parallel_ast_print.cpp
> +++ test/OpenMP/parallel_ast_print.cpp
> @@ -35,9 +35,9 @@
>     S<T> s;
>   #pragma omp parallel
>     a=2;
> -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master)
> +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master) reduction(+:c) reduction(max:e)
>     foo();
> -#pragma omp parallel if (C) num_threads(s) proc_bind(close)
> +#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f) reduction(&& : g)
>     foo();
>     return 0;
>   }
> @@ -48,29 +48,29 @@
>   // CHECK-NEXT: S<int> s;
>   // CHECK-NEXT: #pragma omp parallel
>   // CHECK-NEXT: a = 2;
> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S<int>::TS) proc_bind(master)
> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S<int>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>   // CHECK-NEXT: foo()
> -// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close)
> +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
>   // CHECK-NEXT: foo()
>   // CHECK: template <typename T = long, int C = 1> long tmain(long argc, long *argv) {
>   // CHECK-NEXT: long b = argc, c, d, e, f, g;
>   // CHECK-NEXT: static long a;
>   // CHECK-NEXT: S<long> s;
>   // CHECK-NEXT: #pragma omp parallel
>   // CHECK-NEXT: a = 2;
> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S<long>::TS) proc_bind(master)
> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S<long>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>   // CHECK-NEXT: foo()
> -// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close)
> +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
>   // CHECK-NEXT: foo()
>   // CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
>   // CHECK-NEXT: T b = argc, c, d, e, f, g;
>   // CHECK-NEXT: static T a;
>   // CHECK-NEXT: S<T> s;
>   // CHECK-NEXT: #pragma omp parallel
>   // CHECK-NEXT: a = 2;
> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master)
> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
>   // CHECK-NEXT: foo()
> -// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close)
> +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
>   // CHECK-NEXT: foo()
>   
>   enum Enum { };
> @@ -86,8 +86,8 @@
>   // CHECK-NEXT: #pragma omp parallel
>     a=2;
>   // CHECK-NEXT: a = 2;
> -#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) proc_bind(spread)
> -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) proc_bind(spread)
> +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) proc_bind(spread) reduction(| : c, d) reduction(* : e)
> +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) proc_bind(spread) reduction(|: c,d) reduction(*: e)
>     foo();
>   // CHECK-NEXT: foo();
>     return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
> Index: test/OpenMP/parallel_reduction_messages.cpp
> ===================================================================
> --- test/OpenMP/parallel_reduction_messages.cpp
> +++ test/OpenMP/parallel_reduction_messages.cpp
> @@ -0,0 +1,215 @@
> +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
> +
> +void foo() {
> +}
> +
> +bool foobool(int argc) {
> +  return argc;
> +}
> +
> +struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
> +extern S1 a;
> +class S2 {
> +  mutable int a;
> +  S2 &operator +=(const S2 &arg) {return (*this);}
> +public:
> +  S2():a(0) { }
> +  S2(S2 &s2):a(s2.a) { }
> +  static float S2s; // expected-note 2 {{predetermined as shared}}
> +  static const float S2sc;
> +};
> +const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
> +S2 b; // expected-note 2 {{'b' defined here}}
> +const S2 ba[5]; // expected-note 2 {{'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;}
> +S3 c; // expected-note 2 {{'c' defined here}}
> +const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
> +extern const int f; // expected-note 4 {{'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;}
> +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; // expected-note 2 {{'o' defined here}}
> +
> +S3 h, k;
> +#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
> +
> +template <class T> // expected-note {{declared here}}
> +T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
> +  const T d = T(); // expected-note 4 {{'d' defined here}}
> +  const T da[5] = { T() }; // expected-note 2 {{'da' defined here}}
> +  T qa[5] = { T() };
> +  T i;
> +  T &j = i; // expected-note 4 {{'j' defined here}}
> +  S3 &p = k; // expected-note 2 {{'p' defined here}}
> +  const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
> +  T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
> +  T fl; // expected-note {{'fl' defined here}}
> +  #pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}}
> +  foo();
> +  #pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
> +  foo();
> +  #pragma omp parallel reduction ( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
> +  foo();
> +  #pragma omp parallel reduction (- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
> +  foo();
> +  #pragma omp parallel reduction () // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
> +  foo();
> +  #pragma omp parallel reduction (*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
> +  foo();
> +  #pragma omp parallel reduction (\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
> +  foo();
> +  #pragma omp parallel reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel reduction (|| :argc ? i : argc) // expected-error 2 {{expected variable name}}
> +  foo();
> +  #pragma omp parallel reduction (foo:argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
> +  foo();
> +  #pragma omp parallel reduction (&& :argc)
> +  foo();
> +  #pragma omp parallel reduction (^ : T) // expected-error {{'T' does not refer to a value}}
> +  foo();
> +  #pragma omp parallel reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #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' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction (max : qa[1]) // expected-error 2 {{expected variable name}}
> +  foo();
> +  #pragma omp parallel reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel private(i), reduction(+ : j), reduction(+:q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
> +  foo();
> +  #pragma omp parallel private(k)
> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
> +  foo();
> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 3 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 3 {{previously referenced here}}
> +  foo();
> +  #pragma omp parallel reduction(+ : r) // expected-error 2 {{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 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
> +  foo();
> +
> +  return T();
> +}
> +
> +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); // expected-note {{'g' defined here}}
> +  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'}}
> +  foo();
> +  #pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
> +  foo();
> +  #pragma omp parallel reduction ( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
> +  foo();
> +  #pragma omp parallel reduction (- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
> +  foo();
> +  #pragma omp parallel reduction () // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
> +  foo();
> +  #pragma omp parallel reduction (*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
> +  foo();
> +  #pragma omp parallel reduction (\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
> +  foo();
> +  #pragma omp parallel reduction (foo: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
> +  foo();
> +  #pragma omp parallel reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
> +  foo();
> +  #pragma omp parallel reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
> +  foo();
> +  #pragma omp parallel reduction (~:argc) // expected-error {{expected unqualified-id}}
> +  foo();
> +  #pragma omp parallel reduction (&& :argc)
> +  foo();
> +  #pragma omp parallel reduction (^ : S1) // expected-error {{'S1' does not refer to a value}}
> +  foo();
> +  #pragma omp parallel reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #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' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction (max : argv[1]) // expected-error {{expected variable name}}
> +  foo();
> +  #pragma omp parallel reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
> +  foo();
> +  #pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
> +  foo();
> +  #pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
> +  foo();
> +  #pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
> +  foo();
> +  #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}}
> +  foo();
> +  #pragma omp parallel private(k)
> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
> +  foo();
> +  #pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
> +  foo();
> +  #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 tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
> +}
> Index: test/OpenMP/simd_linear_messages.cpp
> ===================================================================
> --- test/OpenMP/simd_linear_messages.cpp
> +++ test/OpenMP/simd_linear_messages.cpp
> @@ -50,10 +50,11 @@
>     // expected-error at +1 {{argument of a linear clause should be of integral or pointer type}}
>   #pragma omp simd linear(ind2:L)
>     for (i = 0; i < num; ++i) {
> -    T cur = arr[ind2];
> +    T cur = arr[(int)ind2];
>       ind2 += L;
>       sum += cur;
>     }
> +  return T();
>   }
>   
>   template<int LEN> int test_warn() {
> Index: tools/libclang/CIndex.cpp
> ===================================================================
> --- tools/libclang/CIndex.cpp
> +++ tools/libclang/CIndex.cpp
> @@ -1955,6 +1955,9 @@
>   void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
>     VisitOMPClauseList(C);
>   }
> +void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
> +  VisitOMPClauseList(C);
> +}
>   void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
>     VisitOMPClauseList(C);
>     Visitor->AddStmt(C->getStep());
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

-- 
http://www.nuanti.com
the browser experts




More information about the cfe-commits mailing list