text: //===- OpenMPClause.cpp - Classes for OpenMP clauses ----------------------===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  // This file implements the subclesses of Stmt class declared in OpenMPClause.h
  //
  //===----------------------------------------------------------------------===//
  
  #include "clang/AST/OpenMPClause.h"
  #include "clang/AST/ASTContext.h"
  #include "clang/AST/Attr.h"
  #include "clang/AST/Decl.h"
  #include "clang/AST/DeclOpenMP.h"
  #include "clang/Basic/LLVM.h"
  #include "clang/Basic/OpenMPKinds.h"
  #include "llvm/ADT/SmallPtrSet.h"
  #include "llvm/Support/Casting.h"
  #include "llvm/Support/ErrorHandling.h"
  #include <algorithm>
  #include <cassert>
  
  using namespace clang;
  using namespace llvm;
  using namespace omp;
  
  OMPClause::child_range OMPClause::children() {
    switch (getClauseKind()) {
    default:
      break;
  #define OMP_CLAUSE_CLASS(Enum, Str, Class)                                           \
    case Enum:                                                                   \
      return static_cast<Class *>(this)->children();
  #include "llvm/Frontend/OpenMP/OMPKinds.def"
    }
    llvm_unreachable("unknown OMPClause");
  }
  
  OMPClause::child_range OMPClause::used_children() {
    switch (getClauseKind()) {
  #define OMP_CLAUSE_CLASS(Enum, Str, Class)                                           \
    case Enum:                                                                   \
      return static_cast<Class *>(this)->used_children();
  #include "llvm/Frontend/OpenMP/OMPKinds.def"
    case OMPC_threadprivate:
    case OMPC_uniform:
    case OMPC_device_type:
    case OMPC_match:
    case OMPC_unknown:
      break;
    }
    llvm_unreachable("unknown OMPClause");
  }
  
  OMPClauseWithPreInit *OMPClauseWithPreInit::get(OMPClause *C) {
    auto *Res = OMPClauseWithPreInit::get(const_cast<const OMPClause *>(C));
    return Res ? const_cast<OMPClauseWithPreInit *>(Res) : nullptr;
  }
  
  const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
    switch (C->getClauseKind()) {
    case OMPC_schedule:
      return static_cast<const OMPScheduleClause *>(C);
    case OMPC_dist_schedule:
      return static_cast<const OMPDistScheduleClause *>(C);
    case OMPC_firstprivate:
      return static_cast<const OMPFirstprivateClause *>(C);
    case OMPC_lastprivate:
      return static_cast<const OMPLastprivateClause *>(C);
    case OMPC_reduction:
      return static_cast<const OMPReductionClause *>(C);
    case OMPC_task_reduction:
      return static_cast<const OMPTaskReductionClause *>(C);
    case OMPC_in_reduction:
      return static_cast<const OMPInReductionClause *>(C);
    case OMPC_linear:
      return static_cast<const OMPLinearClause *>(C);
    case OMPC_if:
      return static_cast<const OMPIfClause *>(C);
    case OMPC_num_threads:
      return static_cast<const OMPNumThreadsClause *>(C);
    case OMPC_num_teams:
      return static_cast<const OMPNumTeamsClause *>(C);
    case OMPC_thread_limit:
      return static_cast<const OMPThreadLimitClause *>(C);
    case OMPC_device:
      return static_cast<const OMPDeviceClause *>(C);
    case OMPC_grainsize:
      return static_cast<const OMPGrainsizeClause *>(C);
    case OMPC_num_tasks:
      return static_cast<const OMPNumTasksClause *>(C);
    case OMPC_final:
      return static_cast<const OMPFinalClause *>(C);
    case OMPC_priority:
      return static_cast<const OMPPriorityClause *>(C);
    case OMPC_default:
    case OMPC_proc_bind:
    case OMPC_safelen:
    case OMPC_simdlen:
    case OMPC_allocator:
    case OMPC_allocate:
    case OMPC_collapse:
    case OMPC_private:
    case OMPC_shared:
    case OMPC_aligned:
    case OMPC_copyin:
    case OMPC_copyprivate:
    case OMPC_ordered:
    case OMPC_nowait:
    case OMPC_untied:
    case OMPC_mergeable:
    case OMPC_threadprivate:
    case OMPC_flush:
    case OMPC_depobj:
    case OMPC_read:
    case OMPC_write:
    case OMPC_update:
    case OMPC_capture:
    case OMPC_seq_cst:
    case OMPC_acq_rel:
    case OMPC_acquire:
    case OMPC_release:
    case OMPC_relaxed:
    case OMPC_depend:
    case OMPC_threads:
    case OMPC_simd:
    case OMPC_map:
    case OMPC_nogroup:
    case OMPC_hint:
    case OMPC_defaultmap:
    case OMPC_unknown:
    case OMPC_uniform:
    case OMPC_to:
    case OMPC_from:
    case OMPC_use_device_ptr:
    case OMPC_is_device_ptr:
    case OMPC_unified_address:
    case OMPC_unified_shared_memory:
    case OMPC_reverse_offload:
    case OMPC_dynamic_allocators:
    case OMPC_atomic_default_mem_order:
    case OMPC_device_type:
    case OMPC_match:
    case OMPC_nontemporal:
    case OMPC_order:
    case OMPC_destroy:
    case OMPC_detach:
    case OMPC_inclusive:
    case OMPC_exclusive:
    case OMPC_uses_allocators:
      break;
    }
  
    return nullptr;
  }
  
  OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(OMPClause *C) {
    auto *Res = OMPClauseWithPostUpdate::get(const_cast<const OMPClause *>(C));
    return Res ? const_cast<OMPClauseWithPostUpdate *>(Res) : nullptr;
  }
  
  const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) {
    switch (C->getClauseKind()) {
    case OMPC_lastprivate:
      return static_cast<const OMPLastprivateClause *>(C);
    case OMPC_reduction:
      return static_cast<const OMPReductionClause *>(C);
    case OMPC_task_reduction:
      return static_cast<const OMPTaskReductionClause *>(C);
    case OMPC_in_reduction:
      return static_cast<const OMPInReductionClause *>(C);
    case OMPC_linear:
      return static_cast<const OMPLinearClause *>(C);
    case OMPC_schedule:
    case OMPC_dist_schedule:
    case OMPC_firstprivate:
    case OMPC_default:
    case OMPC_proc_bind:
    case OMPC_if:
    case OMPC_final:
    case OMPC_num_threads:
    case OMPC_safelen:
    case OMPC_simdlen:
    case OMPC_allocator:
    case OMPC_allocate:
    case OMPC_collapse:
    case OMPC_private:
    case OMPC_shared:
    case OMPC_aligned:
    case OMPC_copyin:
    case OMPC_copyprivate:
    case OMPC_ordered:
    case OMPC_nowait:
    case OMPC_untied:
    case OMPC_mergeable:
    case OMPC_threadprivate:
    case OMPC_flush:
    case OMPC_depobj:
    case OMPC_read:
    case OMPC_write:
    case OMPC_update:
    case OMPC_capture:
    case OMPC_seq_cst:
    case OMPC_acq_rel:
    case OMPC_acquire:
    case OMPC_release:
    case OMPC_relaxed:
    case OMPC_depend:
    case OMPC_device:
    case OMPC_threads:
    case OMPC_simd:
    case OMPC_map:
    case OMPC_num_teams:
    case OMPC_thread_limit:
    case OMPC_priority:
    case OMPC_grainsize:
    case OMPC_nogroup:
    case OMPC_num_tasks:
    case OMPC_hint:
    case OMPC_defaultmap:
    case OMPC_unknown:
    case OMPC_uniform:
    case OMPC_to:
    case OMPC_from:
    case OMPC_use_device_ptr:
    case OMPC_is_device_ptr:
    case OMPC_unified_address:
    case OMPC_unified_shared_memory:
    case OMPC_reverse_offload:
    case OMPC_dynamic_allocators:
    case OMPC_atomic_default_mem_order:
    case OMPC_device_type:
    case OMPC_match:
    case OMPC_nontemporal:
    case OMPC_order:
    case OMPC_destroy:
    case OMPC_detach:
    case OMPC_inclusive:
    case OMPC_exclusive:
    case OMPC_uses_allocators:
      break;
    }
  
    return nullptr;
  }
  
  /// Gets the address of the original, non-captured, expression used in the
  /// clause as the preinitializer.
  static Stmt **getAddrOfExprAsWritten(Stmt *S) {
    if (!S)
      return nullptr;
    if (auto *DS = dyn_cast<DeclStmt>(S)) {
      assert(DS->isSingleDecl() && "Only single expression must be captured.");
      if (auto *OED = dyn_cast<OMPCapturedExprDecl>(DS->getSingleDecl()))
        return OED->getInitAddress();
    }
    return nullptr;
  }
  
  OMPClause::child_range OMPIfClause::used_children() {
    if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
      return child_range(C, C + 1);
    return child_range(&Condition, &Condition + 1);
  }
  
  OMPClause::child_range OMPGrainsizeClause::used_children() {
    if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
      return child_range(C, C + 1);
    return child_range(&Grainsize, &Grainsize + 1);
  }
  
  OMPClause::child_range OMPNumTasksClause::used_children() {
    if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
      return child_range(C, C + 1);
    return child_range(&NumTasks, &NumTasks + 1);
  }
  
  OMPClause::child_range OMPFinalClause::used_children() {
    if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
      return child_range(C, C + 1);
    return child_range(&Condition, &Condition + 1);
  }
  
  OMPClause::child_range OMPPriorityClause::used_children() {
    if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
      return child_range(C, C + 1);
    return child_range(&Priority, &Priority + 1);
  }
  
  OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
                                             unsigned NumLoops,
                                             SourceLocation StartLoc,
                                             SourceLocation LParenLoc,
                                             SourceLocation EndLoc) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * NumLoops));
    auto *Clause =
        new (Mem) OMPOrderedClause(Num, NumLoops, StartLoc, LParenLoc, EndLoc);
    for (unsigned I = 0; I < NumLoops; ++I) {
      Clause->setLoopNumIterations(I, nullptr);
      Clause->setLoopCounter(I, nullptr);
    }
    return Clause;
  }
  
  OMPOrderedClause *OMPOrderedClause::CreateEmpty(const ASTContext &C,
                                                  unsigned NumLoops) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * NumLoops));
    auto *Clause = new (Mem) OMPOrderedClause(NumLoops);
    for (unsigned I = 0; I < NumLoops; ++I) {
      Clause->setLoopNumIterations(I, nullptr);
      Clause->setLoopCounter(I, nullptr);
    }
    return Clause;
  }
  
  void OMPOrderedClause::setLoopNumIterations(unsigned NumLoop,
                                              Expr *NumIterations) {
    assert(NumLoop < NumberOfLoops && "out of loops number.");
    getTrailingObjects<Expr *>()[NumLoop] = NumIterations;
  }
  
  ArrayRef<Expr *> OMPOrderedClause::getLoopNumIterations() const {
    return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
  }
  
  void OMPOrderedClause::setLoopCounter(unsigned NumLoop, Expr *Counter) {
    assert(NumLoop < NumberOfLoops && "out of loops number.");
    getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop] = Counter;
  }
  
  Expr *OMPOrderedClause::getLoopCounter(unsigned NumLoop) {
    assert(NumLoop < NumberOfLoops && "out of loops number.");
    return getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop];
  }
  
  const Expr *OMPOrderedClause::getLoopCounter(unsigned NumLoop) const {
    assert(NumLoop < NumberOfLoops && "out of loops number.");
    return getTrailingObjects<Expr *>()[NumberOfLoops + NumLoop];
  }
  
  OMPUpdateClause *OMPUpdateClause::Create(const ASTContext &C,
                                           SourceLocation StartLoc,
                                           SourceLocation EndLoc) {
    return new (C) OMPUpdateClause(StartLoc, EndLoc, /*IsExtended=*/false);
  }
  
  OMPUpdateClause *
  OMPUpdateClause::Create(const ASTContext &C, SourceLocation StartLoc,
                          SourceLocation LParenLoc, SourceLocation ArgumentLoc,
                          OpenMPDependClauseKind DK, SourceLocation EndLoc) {
    void *Mem =
        C.Allocate(totalSizeToAlloc<SourceLocation, OpenMPDependClauseKind>(2, 1),
                   alignof(OMPUpdateClause));
    auto *Clause =
        new (Mem) OMPUpdateClause(StartLoc, EndLoc, /*IsExtended=*/true);
    Clause->setLParenLoc(LParenLoc);
    Clause->setArgumentLoc(ArgumentLoc);
    Clause->setDependencyKind(DK);
    return Clause;
  }
  
  OMPUpdateClause *OMPUpdateClause::CreateEmpty(const ASTContext &C,
                                                bool IsExtended) {
    if (!IsExtended)
      return new (C) OMPUpdateClause(/*IsExtended=*/false);
    void *Mem =
        C.Allocate(totalSizeToAlloc<SourceLocation, OpenMPDependClauseKind>(2, 1),
                   alignof(OMPUpdateClause));
    auto *Clause = new (Mem) OMPUpdateClause(/*IsExtended=*/true);
    Clause->IsExtended = true;
    return Clause;
  }
  
  void OMPPrivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), varlist_end());
  }
  
  OMPPrivateClause *
  OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
                           SourceLocation LParenLoc, SourceLocation EndLoc,
                           ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL) {
    // Allocate space for private variables and initializer expressions.
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size()));
    OMPPrivateClause *Clause =
        new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setPrivateCopies(PrivateVL);
    return Clause;
  }
  
  OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
                                                  unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N));
    return new (Mem) OMPPrivateClause(N);
  }
  
  void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), varlist_end());
  }
  
  void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() &&
           "Number of inits is not the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
  }
  
  OMPFirstprivateClause *
  OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
                                SourceLocation LParenLoc, SourceLocation EndLoc,
                                ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
                                ArrayRef<Expr *> InitVL, Stmt *PreInit) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(3 * VL.size()));
    OMPFirstprivateClause *Clause =
        new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setPrivateCopies(PrivateVL);
    Clause->setInits(InitVL);
    Clause->setPreInitStmt(PreInit);
    return Clause;
  }
  
  OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
                                                            unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(3 * N));
    return new (Mem) OMPFirstprivateClause(N);
  }
  
  void OMPLastprivateClause::setPrivateCopies(ArrayRef<Expr *> PrivateCopies) {
    assert(PrivateCopies.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(PrivateCopies.begin(), PrivateCopies.end(), varlist_end());
  }
  
  void OMPLastprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
    assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
                                                "not the same as the "
                                                "preallocated buffer");
    std::copy(SrcExprs.begin(), SrcExprs.end(), getPrivateCopies().end());
  }
  
  void OMPLastprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
    assert(DstExprs.size() == varlist_size() && "Number of destination "
                                                "expressions is not the same as "
                                                "the preallocated buffer");
    std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
  }
  
  void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
    assert(AssignmentOps.size() == varlist_size() &&
           "Number of assignment expressions is not the same as the preallocated "
           "buffer");
    std::copy(AssignmentOps.begin(), AssignmentOps.end(),
              getDestinationExprs().end());
  }
  
  OMPLastprivateClause *OMPLastprivateClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
      ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps,
      OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc,
      SourceLocation ColonLoc, Stmt *PreInit, Expr *PostUpdate) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
    OMPLastprivateClause *Clause = new (Mem) OMPLastprivateClause(
        StartLoc, LParenLoc, EndLoc, LPKind, LPKindLoc, ColonLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setSourceExprs(SrcExprs);
    Clause->setDestinationExprs(DstExprs);
    Clause->setAssignmentOps(AssignmentOps);
    Clause->setPreInitStmt(PreInit);
    Clause->setPostUpdateExpr(PostUpdate);
    return Clause;
  }
  
  OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C,
                                                          unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
    return new (Mem) OMPLastprivateClause(N);
  }
  
  OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
                                           SourceLocation StartLoc,
                                           SourceLocation LParenLoc,
                                           SourceLocation EndLoc,
                                           ArrayRef<Expr *> VL) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
    OMPSharedClause *Clause =
        new (Mem) OMPSharedClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
    return new (Mem) OMPSharedClause(N);
  }
  
  void OMPLinearClause::setPrivates(ArrayRef<Expr *> PL) {
    assert(PL.size() == varlist_size() &&
           "Number of privates is not the same as the preallocated buffer");
    std::copy(PL.begin(), PL.end(), varlist_end());
  }
  
  void OMPLinearClause::setInits(ArrayRef<Expr *> IL) {
    assert(IL.size() == varlist_size() &&
           "Number of inits is not the same as the preallocated buffer");
    std::copy(IL.begin(), IL.end(), getPrivates().end());
  }
  
  void OMPLinearClause::setUpdates(ArrayRef<Expr *> UL) {
    assert(UL.size() == varlist_size() &&
           "Number of updates is not the same as the preallocated buffer");
    std::copy(UL.begin(), UL.end(), getInits().end());
  }
  
  void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) {
    assert(FL.size() == varlist_size() &&
           "Number of final updates is not the same as the preallocated buffer");
    std::copy(FL.begin(), FL.end(), getUpdates().end());
  }
  
  void OMPLinearClause::setUsedExprs(ArrayRef<Expr *> UE) {
    assert(
        UE.size() == varlist_size() + 1 &&
        "Number of used expressions is not the same as the preallocated buffer");
    std::copy(UE.begin(), UE.end(), getFinals().end() + 2);
  }
  
  OMPLinearClause *OMPLinearClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc,
      SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
      ArrayRef<Expr *> PL, ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep,
      Stmt *PreInit, Expr *PostUpdate) {
    // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
    // (Step and CalcStep), list of used expression + step.
    void *Mem =
        C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2 + VL.size() + 1));
    OMPLinearClause *Clause = new (Mem) OMPLinearClause(
        StartLoc, LParenLoc, Modifier, ModifierLoc, ColonLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setPrivates(PL);
    Clause->setInits(IL);
    // Fill update and final expressions with zeroes, they are provided later,
    // after the directive construction.
    std::fill(Clause->getInits().end(), Clause->getInits().end() + VL.size(),
              nullptr);
    std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(),
              nullptr);
    std::fill(Clause->getUsedExprs().begin(), Clause->getUsedExprs().end(),
              nullptr);
    Clause->setStep(Step);
    Clause->setCalcStep(CalcStep);
    Clause->setPreInitStmt(PreInit);
    Clause->setPostUpdateExpr(PostUpdate);
    return Clause;
  }
  
  OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
                                                unsigned NumVars) {
    // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
    // (Step and CalcStep), list of used expression + step.
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2 + NumVars  +1));
    return new (Mem) OMPLinearClause(NumVars);
  }
  
  OMPClause::child_range OMPLinearClause::used_children() {
    // Range includes only non-nullptr elements.
    return child_range(
        reinterpret_cast<Stmt **>(getUsedExprs().begin()),
        reinterpret_cast<Stmt **>(llvm::find(getUsedExprs(), nullptr)));
  }
  
  OMPAlignedClause *
  OMPAlignedClause::Create(const ASTContext &C, SourceLocation StartLoc,
                           SourceLocation LParenLoc, SourceLocation ColonLoc,
                           SourceLocation EndLoc, ArrayRef<Expr *> VL, Expr *A) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
    OMPAlignedClause *Clause = new (Mem)
        OMPAlignedClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setAlignment(A);
    return Clause;
  }
  
  OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C,
                                                  unsigned NumVars) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumVars + 1));
    return new (Mem) OMPAlignedClause(NumVars);
  }
  
  void OMPCopyinClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
    assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
                                                "not the same as the "
                                                "preallocated buffer");
    std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end());
  }
  
  void OMPCopyinClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
    assert(DstExprs.size() == varlist_size() && "Number of destination "
                                                "expressions is not the same as "
                                                "the preallocated buffer");
    std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
  }
  
  void OMPCopyinClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
    assert(AssignmentOps.size() == varlist_size() &&
           "Number of assignment expressions is not the same as the preallocated "
           "buffer");
    std::copy(AssignmentOps.begin(), AssignmentOps.end(),
              getDestinationExprs().end());
  }
  
  OMPCopyinClause *OMPCopyinClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
      ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * VL.size()));
    OMPCopyinClause *Clause =
        new (Mem) OMPCopyinClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setSourceExprs(SrcExprs);
    Clause->setDestinationExprs(DstExprs);
    Clause->setAssignmentOps(AssignmentOps);
    return Clause;
  }
  
  OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * N));
    return new (Mem) OMPCopyinClause(N);
  }
  
  void OMPCopyprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
    assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
                                                "not the same as the "
                                                "preallocated buffer");
    std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end());
  }
  
  void OMPCopyprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
    assert(DstExprs.size() == varlist_size() && "Number of destination "
                                                "expressions is not the same as "
                                                "the preallocated buffer");
    std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
  }
  
  void OMPCopyprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
    assert(AssignmentOps.size() == varlist_size() &&
           "Number of assignment expressions is not the same as the preallocated "
           "buffer");
    std::copy(AssignmentOps.begin(), AssignmentOps.end(),
              getDestinationExprs().end());
  }
  
  OMPCopyprivateClause *OMPCopyprivateClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
      ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * VL.size()));
    OMPCopyprivateClause *Clause =
        new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    Clause->setSourceExprs(SrcExprs);
    Clause->setDestinationExprs(DstExprs);
    Clause->setAssignmentOps(AssignmentOps);
    return Clause;
  }
  
  OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C,
                                                          unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(4 * N));
    return new (Mem) OMPCopyprivateClause(N);
  }
  
  void OMPReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
    assert(Privates.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(Privates.begin(), Privates.end(), varlist_end());
  }
  
  void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
    assert(
        LHSExprs.size() == varlist_size() &&
        "Number of LHS expressions is not the same as the preallocated buffer");
    std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
  }
  
  void OMPReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
    assert(
        RHSExprs.size() == varlist_size() &&
        "Number of RHS expressions is not the same as the preallocated buffer");
    std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
  }
  
  void OMPReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
    assert(ReductionOps.size() == varlist_size() && "Number of reduction "
                                                    "expressions is not the same "
                                                    "as the preallocated buffer");
    std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
  }
  
  OMPReductionClause *OMPReductionClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation ModifierLoc, SourceLocation EndLoc, SourceLocation ColonLoc,
      OpenMPReductionClauseModifier Modifier, ArrayRef<Expr *> VL,
      NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
      ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
      ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, Stmt *PreInit,
      Expr *PostUpdate) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
    auto *Clause = new (Mem)
        OMPReductionClause(StartLoc, LParenLoc, ModifierLoc, EndLoc, ColonLoc,
                           Modifier, VL.size(), QualifierLoc, NameInfo);
    Clause->setVarRefs(VL);
    Clause->setPrivates(Privates);
    Clause->setLHSExprs(LHSExprs);
    Clause->setRHSExprs(RHSExprs);
    Clause->setReductionOps(ReductionOps);
    Clause->setPreInitStmt(PreInit);
    Clause->setPostUpdateExpr(PostUpdate);
    return Clause;
  }
  
  OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
                                                      unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
    return new (Mem) OMPReductionClause(N);
  }
  
  void OMPTaskReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
    assert(Privates.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(Privates.begin(), Privates.end(), varlist_end());
  }
  
  void OMPTaskReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
    assert(
        LHSExprs.size() == varlist_size() &&
        "Number of LHS expressions is not the same as the preallocated buffer");
    std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
  }
  
  void OMPTaskReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
    assert(
        RHSExprs.size() == varlist_size() &&
        "Number of RHS expressions is not the same as the preallocated buffer");
    std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
  }
  
  void OMPTaskReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
    assert(ReductionOps.size() == varlist_size() && "Number of task reduction "
                                                    "expressions is not the same "
                                                    "as the preallocated buffer");
    std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
  }
  
  OMPTaskReductionClause *OMPTaskReductionClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
      NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
      ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
      ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, Stmt *PreInit,
      Expr *PostUpdate) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
    OMPTaskReductionClause *Clause = new (Mem) OMPTaskReductionClause(
        StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
    Clause->setVarRefs(VL);
    Clause->setPrivates(Privates);
    Clause->setLHSExprs(LHSExprs);
    Clause->setRHSExprs(RHSExprs);
    Clause->setReductionOps(ReductionOps);
    Clause->setPreInitStmt(PreInit);
    Clause->setPostUpdateExpr(PostUpdate);
    return Clause;
  }
  
  OMPTaskReductionClause *OMPTaskReductionClause::CreateEmpty(const ASTContext &C,
                                                              unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
    return new (Mem) OMPTaskReductionClause(N);
  }
  
  void OMPInReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
    assert(Privates.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(Privates.begin(), Privates.end(), varlist_end());
  }
  
  void OMPInReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
    assert(
        LHSExprs.size() == varlist_size() &&
        "Number of LHS expressions is not the same as the preallocated buffer");
    std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
  }
  
  void OMPInReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
    assert(
        RHSExprs.size() == varlist_size() &&
        "Number of RHS expressions is not the same as the preallocated buffer");
    std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
  }
  
  void OMPInReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
    assert(ReductionOps.size() == varlist_size() && "Number of in reduction "
                                                    "expressions is not the same "
                                                    "as the preallocated buffer");
    std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
  }
  
  void OMPInReductionClause::setTaskgroupDescriptors(
      ArrayRef<Expr *> TaskgroupDescriptors) {
    assert(TaskgroupDescriptors.size() == varlist_size() &&
           "Number of in reduction descriptors is not the same as the "
           "preallocated buffer");
    std::copy(TaskgroupDescriptors.begin(), TaskgroupDescriptors.end(),
              getReductionOps().end());
  }
  
  OMPInReductionClause *OMPInReductionClause::Create(
      const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
      SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
      NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
      ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
      ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps,
      ArrayRef<Expr *> TaskgroupDescriptors, Stmt *PreInit, Expr *PostUpdate) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * VL.size()));
    OMPInReductionClause *Clause = new (Mem) OMPInReductionClause(
        StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
    Clause->setVarRefs(VL);
    Clause->setPrivates(Privates);
    Clause->setLHSExprs(LHSExprs);
    Clause->setRHSExprs(RHSExprs);
    Clause->setReductionOps(ReductionOps);
    Clause->setTaskgroupDescriptors(TaskgroupDescriptors);
    Clause->setPreInitStmt(PreInit);
    Clause->setPostUpdateExpr(PostUpdate);
    return Clause;
  }
  
  OMPInReductionClause *OMPInReductionClause::CreateEmpty(const ASTContext &C,
                                                          unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * N));
    return new (Mem) OMPInReductionClause(N);
  }
  
  OMPAllocateClause *
  OMPAllocateClause::Create(const ASTContext &C, SourceLocation StartLoc,
                            SourceLocation LParenLoc, Expr *Allocator,
                            SourceLocation ColonLoc, SourceLocation EndLoc,
                            ArrayRef<Expr *> VL) {
    // Allocate space for private variables and initializer expressions.
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
    auto *Clause = new (Mem) OMPAllocateClause(StartLoc, LParenLoc, Allocator,
                                               ColonLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPAllocateClause *OMPAllocateClause::CreateEmpty(const ASTContext &C,
                                                    unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
    return new (Mem) OMPAllocateClause(N);
  }
  
  OMPFlushClause *OMPFlushClause::Create(const ASTContext &C,
                                         SourceLocation StartLoc,
                                         SourceLocation LParenLoc,
                                         SourceLocation EndLoc,
                                         ArrayRef<Expr *> VL) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
    OMPFlushClause *Clause =
        new (Mem) OMPFlushClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
    return new (Mem) OMPFlushClause(N);
  }
  
  OMPDepobjClause *OMPDepobjClause::Create(const ASTContext &C,
                                           SourceLocation StartLoc,
                                           SourceLocation LParenLoc,
                                           SourceLocation RParenLoc,
                                           Expr *Depobj) {
    auto *Clause = new (C) OMPDepobjClause(StartLoc, LParenLoc, RParenLoc);
    Clause->setDepobj(Depobj);
    return Clause;
  }
  
  OMPDepobjClause *OMPDepobjClause::CreateEmpty(const ASTContext &C) {
    return new (C) OMPDepobjClause();
  }
  
  OMPDependClause *
  OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc,
                          SourceLocation LParenLoc, SourceLocation EndLoc,
                          Expr *DepModifier, OpenMPDependClauseKind DepKind,
                          SourceLocation DepLoc, SourceLocation ColonLoc,
                          ArrayRef<Expr *> VL, unsigned NumLoops) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *>(VL.size() + /*depend-modifier*/ 1 + NumLoops),
        alignof(OMPDependClause));
    OMPDependClause *Clause = new (Mem)
        OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops);
    Clause->setVarRefs(VL);
    Clause->setDependencyKind(DepKind);
    Clause->setDependencyLoc(DepLoc);
    Clause->setColonLoc(ColonLoc);
    Clause->setModifier(DepModifier);
    for (unsigned I = 0 ; I < NumLoops; ++I)
      Clause->setLoopData(I, nullptr);
    return Clause;
  }
  
  OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N,
                                                unsigned NumLoops) {
    void *Mem =
        C.Allocate(totalSizeToAlloc<Expr *>(N + /*depend-modifier*/ 1 + NumLoops),
                   alignof(OMPDependClause));
    return new (Mem) OMPDependClause(N, NumLoops);
  }
  
  void OMPDependClause::setLoopData(unsigned NumLoop, Expr *Cnt) {
    assert((getDependencyKind() == OMPC_DEPEND_sink ||
            getDependencyKind() == OMPC_DEPEND_source) &&
           NumLoop < NumLoops &&
           "Expected sink or source depend + loop index must be less number of "
           "loops.");
    auto *It = std::next(getVarRefs().end(), NumLoop + 1);
    *It = Cnt;
  }
  
  Expr *OMPDependClause::getLoopData(unsigned NumLoop) {
    assert((getDependencyKind() == OMPC_DEPEND_sink ||
            getDependencyKind() == OMPC_DEPEND_source) &&
           NumLoop < NumLoops &&
           "Expected sink or source depend + loop index must be less number of "
           "loops.");
    auto *It = std::next(getVarRefs().end(), NumLoop + 1);
    return *It;
  }
  
  const Expr *OMPDependClause::getLoopData(unsigned NumLoop) const {
    assert((getDependencyKind() == OMPC_DEPEND_sink ||
            getDependencyKind() == OMPC_DEPEND_source) &&
           NumLoop < NumLoops &&
           "Expected sink or source depend + loop index must be less number of "
           "loops.");
    const auto *It = std::next(getVarRefs().end(), NumLoop + 1);
    return *It;
  }
  
  void OMPDependClause::setModifier(Expr *DepModifier) {
    *getVarRefs().end() = DepModifier;
  }
  Expr *OMPDependClause::getModifier() { return *getVarRefs().end(); }
  
  unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber(
      MappableExprComponentListsRef ComponentLists) {
    unsigned TotalNum = 0u;
    for (auto &C : ComponentLists)
      TotalNum += C.size();
    return TotalNum;
  }
  
  unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber(
      ArrayRef<const ValueDecl *> Declarations) {
    unsigned TotalNum = 0u;
    llvm::SmallPtrSet<const ValueDecl *, 8> Cache;
    for (const ValueDecl *D : Declarations) {
      const ValueDecl *VD = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
      if (Cache.count(VD))
        continue;
      ++TotalNum;
      Cache.insert(VD);
    }
    return TotalNum;
  }
  
  OMPMapClause *OMPMapClause::Create(
      const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
      ArrayRef<ValueDecl *> Declarations,
      MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
      ArrayRef<OpenMPMapModifierKind> MapModifiers,
      ArrayRef<SourceLocation> MapModifiersLoc,
      NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId,
      OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) {
    OMPMappableExprListSizeTy Sizes;
    Sizes.NumVars = Vars.size();
    Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
    Sizes.NumComponentLists = ComponentLists.size();
    Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
  
    // We need to allocate:
    // 2 x NumVars x Expr* - we have an original list expression and an associated
    // user-defined mapper for each clause list entry.
    // NumUniqueDeclarations x ValueDecl* - unique base declarations associated
    // with each component list.
    // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
    // number of lists for each unique declaration and the size of each component
    // list.
    // NumComponents x MappableComponent - the total of all the components in all
    // the lists.
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    OMPMapClause *Clause = new (Mem)
        OMPMapClause(MapModifiers, MapModifiersLoc, UDMQualifierLoc, MapperId,
                     Type, TypeIsImplicit, TypeLoc, Locs, Sizes);
  
    Clause->setVarRefs(Vars);
    Clause->setUDMapperRefs(UDMapperRefs);
    Clause->setClauseInfo(Declarations, ComponentLists);
    Clause->setMapType(Type);
    Clause->setMapLoc(TypeLoc);
    return Clause;
  }
  
  OMPMapClause *
  OMPMapClause::CreateEmpty(const ASTContext &C,
                            const OMPMappableExprListSizeTy &Sizes) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    return new (Mem) OMPMapClause(Sizes);
  }
  
  OMPToClause *OMPToClause::Create(
      const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
      ArrayRef<ValueDecl *> Declarations,
      MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
      NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) {
    OMPMappableExprListSizeTy Sizes;
    Sizes.NumVars = Vars.size();
    Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
    Sizes.NumComponentLists = ComponentLists.size();
    Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
  
    // We need to allocate:
    // 2 x NumVars x Expr* - we have an original list expression and an associated
    // user-defined mapper for each clause list entry.
    // NumUniqueDeclarations x ValueDecl* - unique base declarations associated
    // with each component list.
    // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
    // number of lists for each unique declaration and the size of each component
    // list.
    // NumComponents x MappableComponent - the total of all the components in all
    // the lists.
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
  
    auto *Clause = new (Mem) OMPToClause(UDMQualifierLoc, MapperId, Locs, Sizes);
  
    Clause->setVarRefs(Vars);
    Clause->setUDMapperRefs(UDMapperRefs);
    Clause->setClauseInfo(Declarations, ComponentLists);
    return Clause;
  }
  
  OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C,
                                        const OMPMappableExprListSizeTy &Sizes) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    return new (Mem) OMPToClause(Sizes);
  }
  
  OMPFromClause *OMPFromClause::Create(
      const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
      ArrayRef<ValueDecl *> Declarations,
      MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
      NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) {
    OMPMappableExprListSizeTy Sizes;
    Sizes.NumVars = Vars.size();
    Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
    Sizes.NumComponentLists = ComponentLists.size();
    Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
  
    // We need to allocate:
    // 2 x NumVars x Expr* - we have an original list expression and an associated
    // user-defined mapper for each clause list entry.
    // NumUniqueDeclarations x ValueDecl* - unique base declarations associated
    // with each component list.
    // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
    // number of lists for each unique declaration and the size of each component
    // list.
    // NumComponents x MappableComponent - the total of all the components in all
    // the lists.
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
  
    auto *Clause =
        new (Mem) OMPFromClause(UDMQualifierLoc, MapperId, Locs, Sizes);
  
    Clause->setVarRefs(Vars);
    Clause->setUDMapperRefs(UDMapperRefs);
    Clause->setClauseInfo(Declarations, ComponentLists);
    return Clause;
  }
  
  OMPFromClause *
  OMPFromClause::CreateEmpty(const ASTContext &C,
                             const OMPMappableExprListSizeTy &Sizes) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    return new (Mem) OMPFromClause(Sizes);
  }
  
  void OMPUseDevicePtrClause::setPrivateCopies(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() &&
           "Number of private copies is not the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), varlist_end());
  }
  
  void OMPUseDevicePtrClause::setInits(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() &&
           "Number of inits is not the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
  }
  
  OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create(
      const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
      ArrayRef<Expr *> PrivateVars, ArrayRef<Expr *> Inits,
      ArrayRef<ValueDecl *> Declarations,
      MappableExprComponentListsRef ComponentLists) {
    OMPMappableExprListSizeTy Sizes;
    Sizes.NumVars = Vars.size();
    Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
    Sizes.NumComponentLists = ComponentLists.size();
    Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
  
    // We need to allocate:
    // 3 x NumVars x Expr* - we have an original list expression for each clause
    // list entry and an equal number of private copies and inits.
    // NumUniqueDeclarations x ValueDecl* - unique base declarations associated
    // with each component list.
    // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
    // number of lists for each unique declaration and the size of each component
    // list.
    // NumComponents x MappableComponent - the total of all the components in all
    // the lists.
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            3 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
  
    OMPUseDevicePtrClause *Clause = new (Mem) OMPUseDevicePtrClause(Locs, Sizes);
  
    Clause->setVarRefs(Vars);
    Clause->setPrivateCopies(PrivateVars);
    Clause->setInits(Inits);
    Clause->setClauseInfo(Declarations, ComponentLists);
    return Clause;
  }
  
  OMPUseDevicePtrClause *
  OMPUseDevicePtrClause::CreateEmpty(const ASTContext &C,
                                     const OMPMappableExprListSizeTy &Sizes) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            3 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    return new (Mem) OMPUseDevicePtrClause(Sizes);
  }
  
  OMPIsDevicePtrClause *
  OMPIsDevicePtrClause::Create(const ASTContext &C, const OMPVarListLocTy &Locs,
                               ArrayRef<Expr *> Vars,
                               ArrayRef<ValueDecl *> Declarations,
                               MappableExprComponentListsRef ComponentLists) {
    OMPMappableExprListSizeTy Sizes;
    Sizes.NumVars = Vars.size();
    Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations);
    Sizes.NumComponentLists = ComponentLists.size();
    Sizes.NumComponents = getComponentsTotalNumber(ComponentLists);
  
    // We need to allocate:
    // NumVars x Expr* - we have an original list expression for each clause list
    // entry.
    // NumUniqueDeclarations x ValueDecl* - unique base declarations associated
    // with each component list.
    // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the
    // number of lists for each unique declaration and the size of each component
    // list.
    // NumComponents x MappableComponent - the total of all the components in all
    // the lists.
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
  
    OMPIsDevicePtrClause *Clause = new (Mem) OMPIsDevicePtrClause(Locs, Sizes);
  
    Clause->setVarRefs(Vars);
    Clause->setClauseInfo(Declarations, ComponentLists);
    return Clause;
  }
  
  OMPIsDevicePtrClause *
  OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C,
                                    const OMPMappableExprListSizeTy &Sizes) {
    void *Mem = C.Allocate(
        totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
                         OMPClauseMappableExprCommon::MappableComponent>(
            Sizes.NumVars, Sizes.NumUniqueDeclarations,
            Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
            Sizes.NumComponents));
    return new (Mem) OMPIsDevicePtrClause(Sizes);
  }
  
  OMPNontemporalClause *OMPNontemporalClause::Create(const ASTContext &C,
                                                     SourceLocation StartLoc,
                                                     SourceLocation LParenLoc,
                                                     SourceLocation EndLoc,
                                                     ArrayRef<Expr *> VL) {
    // Allocate space for nontemporal variables + private references.
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size()));
    auto *Clause =
        new (Mem) OMPNontemporalClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPNontemporalClause *OMPNontemporalClause::CreateEmpty(const ASTContext &C,
                                                          unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N));
    return new (Mem) OMPNontemporalClause(N);
  }
  
  void OMPNontemporalClause::setPrivateRefs(ArrayRef<Expr *> VL) {
    assert(VL.size() == varlist_size() && "Number of private references is not "
                                          "the same as the preallocated buffer");
    std::copy(VL.begin(), VL.end(), varlist_end());
  }
  
  OMPInclusiveClause *OMPInclusiveClause::Create(const ASTContext &C,
                                                 SourceLocation StartLoc,
                                                 SourceLocation LParenLoc,
                                                 SourceLocation EndLoc,
                                                 ArrayRef<Expr *> VL) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
    auto *Clause =
        new (Mem) OMPInclusiveClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPInclusiveClause *OMPInclusiveClause::CreateEmpty(const ASTContext &C,
                                                      unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
    return new (Mem) OMPInclusiveClause(N);
  }
  
  OMPExclusiveClause *OMPExclusiveClause::Create(const ASTContext &C,
                                                 SourceLocation StartLoc,
                                                 SourceLocation LParenLoc,
                                                 SourceLocation EndLoc,
                                                 ArrayRef<Expr *> VL) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
    auto *Clause =
        new (Mem) OMPExclusiveClause(StartLoc, LParenLoc, EndLoc, VL.size());
    Clause->setVarRefs(VL);
    return Clause;
  }
  
  OMPExclusiveClause *OMPExclusiveClause::CreateEmpty(const ASTContext &C,
                                                      unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
    return new (Mem) OMPExclusiveClause(N);
  }
  
  void OMPUsesAllocatorsClause::setAllocatorsData(
      ArrayRef<OMPUsesAllocatorsClause::Data> Data) {
    assert(Data.size() == NumOfAllocators &&
           "Size of allocators data is not the same as the preallocated buffer.");
    for (unsigned I = 0, E = Data.size(); I < E; ++I) {
      const OMPUsesAllocatorsClause::Data &D = Data[I];
      getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
                                   static_cast<int>(ExprOffsets::Allocator)] =
          D.Allocator;
      getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
                                   static_cast<int>(
                                       ExprOffsets::AllocatorTraits)] =
          D.AllocatorTraits;
      getTrailingObjects<
          SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
                            static_cast<int>(ParenLocsOffsets::LParen)] =
          D.LParenLoc;
      getTrailingObjects<
          SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
                            static_cast<int>(ParenLocsOffsets::RParen)] =
          D.RParenLoc;
    }
  }
  
  OMPUsesAllocatorsClause::Data
  OMPUsesAllocatorsClause::getAllocatorData(unsigned I) const {
    OMPUsesAllocatorsClause::Data Data;
    Data.Allocator =
        getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
                                     static_cast<int>(ExprOffsets::Allocator)];
    Data.AllocatorTraits =
        getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
                                     static_cast<int>(
                                         ExprOffsets::AllocatorTraits)];
    Data.LParenLoc = getTrailingObjects<
        SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
                          static_cast<int>(ParenLocsOffsets::LParen)];
    Data.RParenLoc = getTrailingObjects<
        SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
                          static_cast<int>(ParenLocsOffsets::RParen)];
    return Data;
  }
  
  OMPUsesAllocatorsClause *
  OMPUsesAllocatorsClause::Create(const ASTContext &C, SourceLocation StartLoc,
                                  SourceLocation LParenLoc, SourceLocation EndLoc,
                                  ArrayRef<OMPUsesAllocatorsClause::Data> Data) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *, SourceLocation>(
        static_cast<int>(ExprOffsets::Total) * Data.size(),
        static_cast<int>(ParenLocsOffsets::Total) * Data.size()));
    auto *Clause = new (Mem)
        OMPUsesAllocatorsClause(StartLoc, LParenLoc, EndLoc, Data.size());
    Clause->setAllocatorsData(Data);
    return Clause;
  }
  
  OMPUsesAllocatorsClause *
  OMPUsesAllocatorsClause::CreateEmpty(const ASTContext &C, unsigned N) {
    void *Mem = C.Allocate(totalSizeToAlloc<Expr *, SourceLocation>(
        static_cast<int>(ExprOffsets::Total) * N,
        static_cast<int>(ParenLocsOffsets::Total) * N));
    return new (Mem) OMPUsesAllocatorsClause(N);
  }
  
  //===----------------------------------------------------------------------===//
  //  OpenMP clauses printing methods
  //===----------------------------------------------------------------------===//
  
  void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) {
    OS << "if(";
    if (Node->getNameModifier() != OMPD_unknown)
      OS << getOpenMPDirectiveName(Node->getNameModifier()) << ": ";
    Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPFinalClause(OMPFinalClause *Node) {
    OS << "final(";
    Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) {
    OS << "num_threads(";
    Node->getNumThreads()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) {
    OS << "safelen(";
    Node->getSafelen()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) {
    OS << "simdlen(";
    Node->getSimdlen()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPAllocatorClause(OMPAllocatorClause *Node) {
    OS << "allocator(";
    Node->getAllocator()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) {
    OS << "collapse(";
    Node->getNumForLoops()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPDetachClause(OMPDetachClause *Node) {
    OS << "detach(";
    Node->getEventHandler()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
    OS << "default("
       << getOpenMPSimpleClauseTypeName(OMPC_default,
                                        unsigned(Node->getDefaultKind()))
       << ")";
  }
  
  void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
    OS << "proc_bind("
       << getOpenMPSimpleClauseTypeName(OMPC_proc_bind,
                                        unsigned(Node->getProcBindKind()))
       << ")";
  }
  
  void OMPClausePrinter::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {
    OS << "unified_address";
  }
  
  void OMPClausePrinter::VisitOMPUnifiedSharedMemoryClause(
      OMPUnifiedSharedMemoryClause *) {
    OS << "unified_shared_memory";
  }
  
  void OMPClausePrinter::VisitOMPReverseOffloadClause(OMPReverseOffloadClause *) {
    OS << "reverse_offload";
  }
  
  void OMPClausePrinter::VisitOMPDynamicAllocatorsClause(
      OMPDynamicAllocatorsClause *) {
    OS << "dynamic_allocators";
  }
  
  void OMPClausePrinter::VisitOMPAtomicDefaultMemOrderClause(
      OMPAtomicDefaultMemOrderClause *Node) {
    OS << "atomic_default_mem_order("
       << getOpenMPSimpleClauseTypeName(OMPC_atomic_default_mem_order,
                                        Node->getAtomicDefaultMemOrderKind())
       << ")";
  }
  
  void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
    OS << "schedule(";
    if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
      OS << getOpenMPSimpleClauseTypeName(OMPC_schedule,
                                          Node->getFirstScheduleModifier());
      if (Node->getSecondScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
        OS << ", ";
        OS << getOpenMPSimpleClauseTypeName(OMPC_schedule,
                                            Node->getSecondScheduleModifier());
      }
      OS << ": ";
    }
    OS << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind());
    if (auto *E = Node->getChunkSize()) {
      OS << ", ";
      E->printPretty(OS, nullptr, Policy);
    }
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *Node) {
    OS << "ordered";
    if (auto *Num = Node->getNumForLoops()) {
      OS << "(";
      Num->printPretty(OS, nullptr, Policy, 0);
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *) {
    OS << "nowait";
  }
  
  void OMPClausePrinter::VisitOMPUntiedClause(OMPUntiedClause *) {
    OS << "untied";
  }
  
  void OMPClausePrinter::VisitOMPNogroupClause(OMPNogroupClause *) {
    OS << "nogroup";
  }
  
  void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) {
    OS << "mergeable";
  }
  
  void OMPClausePrinter::VisitOMPReadClause(OMPReadClause *) { OS << "read"; }
  
  void OMPClausePrinter::VisitOMPWriteClause(OMPWriteClause *) { OS << "write"; }
  
  void OMPClausePrinter::VisitOMPUpdateClause(OMPUpdateClause *Node) {
    OS << "update";
    if (Node->isExtended()) {
      OS << "(";
      OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
                                          Node->getDependencyKind());
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPCaptureClause(OMPCaptureClause *) {
    OS << "capture";
  }
  
  void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) {
    OS << "seq_cst";
  }
  
  void OMPClausePrinter::VisitOMPAcqRelClause(OMPAcqRelClause *) {
    OS << "acq_rel";
  }
  
  void OMPClausePrinter::VisitOMPAcquireClause(OMPAcquireClause *) {
    OS << "acquire";
  }
  
  void OMPClausePrinter::VisitOMPReleaseClause(OMPReleaseClause *) {
    OS << "release";
  }
  
  void OMPClausePrinter::VisitOMPRelaxedClause(OMPRelaxedClause *) {
    OS << "relaxed";
  }
  
  void OMPClausePrinter::VisitOMPThreadsClause(OMPThreadsClause *) {
    OS << "threads";
  }
  
  void OMPClausePrinter::VisitOMPSIMDClause(OMPSIMDClause *) { OS << "simd"; }
  
  void OMPClausePrinter::VisitOMPDeviceClause(OMPDeviceClause *Node) {
    OS << "device(";
    OpenMPDeviceClauseModifier Modifier = Node->getModifier();
    if (Modifier != OMPC_DEVICE_unknown) {
      OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
         << ": ";
    }
    Node->getDevice()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPNumTeamsClause(OMPNumTeamsClause *Node) {
    OS << "num_teams(";
    Node->getNumTeams()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPThreadLimitClause(OMPThreadLimitClause *Node) {
    OS << "thread_limit(";
    Node->getThreadLimit()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPPriorityClause(OMPPriorityClause *Node) {
    OS << "priority(";
    Node->getPriority()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPGrainsizeClause(OMPGrainsizeClause *Node) {
    OS << "grainsize(";
    Node->getGrainsize()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPNumTasksClause(OMPNumTasksClause *Node) {
    OS << "num_tasks(";
    Node->getNumTasks()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPHintClause(OMPHintClause *Node) {
    OS << "hint(";
    Node->getHint()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPDestroyClause(OMPDestroyClause *) {
    OS << "destroy";
  }
  
  template<typename T>
  void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
    for (typename T::varlist_iterator I = Node->varlist_begin(),
                                      E = Node->varlist_end();
         I != E; ++I) {
      assert(*I && "Expected non-null Stmt");
      OS << (I == Node->varlist_begin() ? StartSym : ',');
      if (auto *DRE = dyn_cast<DeclRefExpr>(*I)) {
        if (isa<OMPCapturedExprDecl>(DRE->getDecl()))
          DRE->printPretty(OS, nullptr, Policy, 0);
        else
          DRE->getDecl()->printQualifiedName(OS);
      } else
        (*I)->printPretty(OS, nullptr, Policy, 0);
    }
  }
  
  void OMPClausePrinter::VisitOMPAllocateClause(OMPAllocateClause *Node) {
    if (Node->varlist_empty())
      return;
    OS << "allocate";
    if (Expr *Allocator = Node->getAllocator()) {
      OS << "(";
      Allocator->printPretty(OS, nullptr, Policy, 0);
      OS << ":";
      VisitOMPClauseList(Node, ' ');
    } else {
      VisitOMPClauseList(Node, '(');
    }
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "private";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "firstprivate";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "lastprivate";
      OpenMPLastprivateModifier LPKind = Node->getKind();
      if (LPKind != OMPC_LASTPRIVATE_unknown) {
        OS << "("
           << getOpenMPSimpleClauseTypeName(OMPC_lastprivate, Node->getKind())
           << ":";
      }
      VisitOMPClauseList(Node, LPKind == OMPC_LASTPRIVATE_unknown ? '(' : ' ');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "shared";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "reduction(";
      if (Node->getModifierLoc().isValid())
        OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier())
           << ", ";
      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::VisitOMPTaskReductionClause(
      OMPTaskReductionClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "task_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::VisitOMPInReductionClause(OMPInReductionClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "in_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";
      if (Node->getModifierLoc().isValid()) {
        OS << '('
           << getOpenMPSimpleClauseTypeName(OMPC_linear, Node->getModifier());
      }
      VisitOMPClauseList(Node, '(');
      if (Node->getModifierLoc().isValid())
        OS << ')';
      if (Node->getStep() != nullptr) {
        OS << ": ";
        Node->getStep()->printPretty(OS, nullptr, Policy, 0);
      }
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPAlignedClause(OMPAlignedClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "aligned";
      VisitOMPClauseList(Node, '(');
      if (Node->getAlignment() != nullptr) {
        OS << ": ";
        Node->getAlignment()->printPretty(OS, nullptr, Policy, 0);
      }
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "copyin";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPCopyprivateClause(OMPCopyprivateClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "copyprivate";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPFlushClause(OMPFlushClause *Node) {
    if (!Node->varlist_empty()) {
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPDepobjClause(OMPDepobjClause *Node) {
    OS << "(";
    Node->getDepobj()->printPretty(OS, nullptr, Policy, 0);
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) {
    OS << "depend(";
    if (Expr *DepModifier = Node->getModifier()) {
      DepModifier->printPretty(OS, nullptr, Policy);
      OS << ", ";
    }
    OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
                                        Node->getDependencyKind());
    if (!Node->varlist_empty()) {
      OS << " :";
      VisitOMPClauseList(Node, ' ');
    }
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "map(";
      if (Node->getMapType() != OMPC_MAP_unknown) {
        for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) {
          if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) {
            OS << getOpenMPSimpleClauseTypeName(OMPC_map,
                                                Node->getMapTypeModifier(I));
            if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper) {
              OS << '(';
              NestedNameSpecifier *MapperNNS =
                  Node->getMapperQualifierLoc().getNestedNameSpecifier();
              if (MapperNNS)
                MapperNNS->print(OS, Policy);
              OS << Node->getMapperIdInfo() << ')';
            }
            OS << ',';
          }
        }
        OS << getOpenMPSimpleClauseTypeName(OMPC_map, Node->getMapType());
        OS << ':';
      }
      VisitOMPClauseList(Node, ' ');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "to";
      DeclarationNameInfo MapperId = Node->getMapperIdInfo();
      if (MapperId.getName() && !MapperId.getName().isEmpty()) {
        OS << '(';
        OS << "mapper(";
        NestedNameSpecifier *MapperNNS =
            Node->getMapperQualifierLoc().getNestedNameSpecifier();
        if (MapperNNS)
          MapperNNS->print(OS, Policy);
        OS << MapperId << "):";
        VisitOMPClauseList(Node, ' ');
      } else {
        VisitOMPClauseList(Node, '(');
      }
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPFromClause(OMPFromClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "from";
      DeclarationNameInfo MapperId = Node->getMapperIdInfo();
      if (MapperId.getName() && !MapperId.getName().isEmpty()) {
        OS << '(';
        OS << "mapper(";
        NestedNameSpecifier *MapperNNS =
            Node->getMapperQualifierLoc().getNestedNameSpecifier();
        if (MapperNNS)
          MapperNNS->print(OS, Policy);
        OS << MapperId << "):";
        VisitOMPClauseList(Node, ' ');
      } else {
        VisitOMPClauseList(Node, '(');
      }
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPDistScheduleClause(OMPDistScheduleClause *Node) {
    OS << "dist_schedule(" << getOpenMPSimpleClauseTypeName(
                             OMPC_dist_schedule, Node->getDistScheduleKind());
    if (auto *E = Node->getChunkSize()) {
      OS << ", ";
      E->printPretty(OS, nullptr, Policy);
    }
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPDefaultmapClause(OMPDefaultmapClause *Node) {
    OS << "defaultmap(";
    OS << getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
                                        Node->getDefaultmapModifier());
    if (Node->getDefaultmapKind() != OMPC_DEFAULTMAP_unknown) {
      OS << ": ";
      OS << getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
                                          Node->getDefaultmapKind());
    }
    OS << ")";
  }
  
  void OMPClausePrinter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "use_device_ptr";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "is_device_ptr";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "nontemporal";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPOrderClause(OMPOrderClause *Node) {
    OS << "order(" << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind())
       << ")";
  }
  
  void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "inclusive";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPExclusiveClause(OMPExclusiveClause *Node) {
    if (!Node->varlist_empty()) {
      OS << "exclusive";
      VisitOMPClauseList(Node, '(');
      OS << ")";
    }
  }
  
  void OMPClausePrinter::VisitOMPUsesAllocatorsClause(
      OMPUsesAllocatorsClause *Node) {
    if (Node->getNumberOfAllocators() == 0)
      return;
    OS << "uses_allocators(";
    for (unsigned I = 0, E = Node->getNumberOfAllocators(); I < E; ++I) {
      OMPUsesAllocatorsClause::Data Data = Node->getAllocatorData(I);
      Data.Allocator->printPretty(OS, nullptr, Policy);
      if (Data.AllocatorTraits) {
        OS << "(";
        Data.AllocatorTraits->printPretty(OS, nullptr, Policy);
        OS << ")";
      }
      if (I < E - 1)
        OS << ",";
    }
    OS << ")";
  }
  
  void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
                                           VariantMatchInfo &VMI) const {
    for (const OMPTraitSet &Set : Sets) {
      for (const OMPTraitSelector &Selector : Set.Selectors) {
  
        // User conditions are special as we evaluate the condition here.
        if (Selector.Kind == TraitSelector::user_condition) {
          assert(Selector.ScoreOrCondition &&
                 "Ill-formed user condition, expected condition expression!");
          assert(Selector.Properties.size() == 1 &&
                 Selector.Properties.front().Kind ==
                     TraitProperty::user_condition_unknown &&
                 "Ill-formed user condition, expected unknown trait property!");
  
          llvm::APSInt CondVal;
          if (Selector.ScoreOrCondition->isIntegerConstantExpr(CondVal, ASTCtx))
            VMI.addTrait(CondVal.isNullValue()
                            ? TraitProperty::user_condition_false
                            : TraitProperty::user_condition_true);
          else
            VMI.addTrait(TraitProperty::user_condition_false);
          continue;
        }
  
        llvm::APSInt Score;
        llvm::APInt *ScorePtr = nullptr;
        if (Selector.ScoreOrCondition) {
          if (Selector.ScoreOrCondition->isIntegerConstantExpr(Score, ASTCtx))
            ScorePtr = &Score;
          else
            VMI.addTrait(TraitProperty::user_condition_false);
        }
  
        for (const OMPTraitProperty &Property : Selector.Properties)
          VMI.addTrait(Set.Kind, Property.Kind, ScorePtr);
  
        if (Set.Kind != TraitSet::construct)
          continue;
  
        // TODO: This might not hold once we implement SIMD properly.
        assert(Selector.Properties.size() == 1 &&
               Selector.Properties.front().Kind ==
                   getOpenMPContextTraitPropertyForSelector(
                       Selector.Kind) &&
               "Ill-formed construct selector!");
  
        VMI.ConstructTraits.push_back(Selector.Properties.front().Kind);
      }
    }
  }
  
  void OMPTraitInfo::print(llvm::raw_ostream &OS,
                           const PrintingPolicy &Policy) const {
    bool FirstSet = true;
    for (const OMPTraitSet &Set : Sets) {
      if (!FirstSet)
        OS << ", ";
      FirstSet = false;
      OS << getOpenMPContextTraitSetName(Set.Kind) << "={";
  
      bool FirstSelector = true;
      for (const OMPTraitSelector &Selector : Set.Selectors) {
        if (!FirstSelector)
          OS << ", ";
        FirstSelector = false;
        OS << getOpenMPContextTraitSelectorName(Selector.Kind);
  
        bool AllowsTraitScore = false;
        bool RequiresProperty = false;
        isValidTraitSelectorForTraitSet(
            Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty);
  
        if (!RequiresProperty)
          continue;
  
        OS << "(";
        if (Selector.Kind == TraitSelector::user_condition) {
          Selector.ScoreOrCondition->printPretty(OS, nullptr, Policy);
        } else {
  
          if (Selector.ScoreOrCondition) {
            OS << "score(";
            Selector.ScoreOrCondition->printPretty(OS, nullptr, Policy);
            OS << "): ";
          }
  
          bool FirstProperty = true;
          for (const OMPTraitProperty &Property : Selector.Properties) {
            if (!FirstProperty)
              OS << ", ";
            FirstProperty = false;
            OS << getOpenMPContextTraitPropertyName(Property.Kind);
          }
        }
        OS << ")";
      }
      OS << "}";
    }
  }
  
  std::string OMPTraitInfo::getMangledName() const {
    std::string MangledName;
    llvm::raw_string_ostream OS(MangledName);
    for (const OMPTraitSet &Set : Sets) {
      OS << '.' << 'S' << unsigned(Set.Kind);
      for (const OMPTraitSelector &Selector : Set.Selectors) {
  
        bool AllowsTraitScore = false;
        bool RequiresProperty = false;
        isValidTraitSelectorForTraitSet(
            Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty);
        OS << '.' << 's' << unsigned(Selector.Kind);
  
        if (!RequiresProperty ||
            Selector.Kind == TraitSelector::user_condition)
          continue;
  
        for (const OMPTraitProperty &Property : Selector.Properties)
          OS << '.' << 'P'
             << getOpenMPContextTraitPropertyName(Property.Kind);
      }
    }
    return OS.str();
  }
  
  OMPTraitInfo::OMPTraitInfo(StringRef MangledName) {
    unsigned long U;
    do {
      if (!MangledName.consume_front(".S"))
        break;
      if (MangledName.consumeInteger(10, U))
        break;
      Sets.push_back(OMPTraitSet());
      OMPTraitSet &Set = Sets.back();
      Set.Kind = TraitSet(U);
      do {
        if (!MangledName.consume_front(".s"))
          break;
        if (MangledName.consumeInteger(10, U))
          break;
        Set.Selectors.push_back(OMPTraitSelector());
        OMPTraitSelector &Selector = Set.Selectors.back();
        Selector.Kind = TraitSelector(U);
        do {
          if (!MangledName.consume_front(".P"))
            break;
          Selector.Properties.push_back(OMPTraitProperty());
          OMPTraitProperty &Property = Selector.Properties.back();
          std::pair<StringRef, StringRef> PropRestPair = MangledName.split('.');
          Property.Kind =
              getOpenMPContextTraitPropertyKind(Set.Kind, PropRestPair.first);
          MangledName = PropRestPair.second;
        } while (true);
      } while (true);
    } while (true);
  }
  
  llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
                                       const OMPTraitInfo &TI) {
    LangOptions LO;
    PrintingPolicy Policy(LO);
    TI.print(OS, Policy);
    return OS;
  }
  llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
                                       const OMPTraitInfo *TI) {
    return TI ? OS << *TI : OS;
  }
  