//===--- ExprOpenMP.h - Classes for representing expressions ----*- C++ -*-===//
 
//
 
// 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 defines the Expr interface and subclasses.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_EXPROPENMP_H
 
#define LLVM_CLANG_AST_EXPROPENMP_H
 
 
 
#include "clang/AST/ComputeDependence.h"
 
#include "clang/AST/Expr.h"
 
 
 
namespace clang {
 
/// OpenMP 5.0 [2.1.5, Array Sections].
 
/// To specify an array section in an OpenMP construct, array subscript
 
/// expressions are extended with the following syntax:
 
/// \code
 
/// [ lower-bound : length : stride ]
 
/// [ lower-bound : length : ]
 
/// [ lower-bound : length ]
 
/// [ lower-bound : : stride ]
 
/// [ lower-bound : : ]
 
/// [ lower-bound : ]
 
/// [ : length : stride ]
 
/// [ : length : ]
 
/// [ : length ]
 
/// [ : : stride ]
 
/// [ : : ]
 
/// [ : ]
 
/// \endcode
 
/// The array section must be a subset of the original array.
 
/// Array sections are allowed on multidimensional arrays. Base language array
 
/// subscript expressions can be used to specify length-one dimensions of
 
/// multidimensional array sections.
 
/// Each of the lower-bound, length, and stride expressions if specified must be
 
/// an integral type expressions of the base language. When evaluated
 
/// they represent a set of integer values as follows:
 
/// \code
 
/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... ,
 
/// lower-bound + ((length - 1) * stride) }
 
/// \endcode
 
/// The lower-bound and length must evaluate to non-negative integers.
 
/// The stride must evaluate to a positive integer.
 
/// When the size of the array dimension is not known, the length must be
 
/// specified explicitly.
 
/// When the stride is absent it defaults to 1.
 
/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉,
 
/// where size is the size of the array dimension. When the lower-bound is
 
/// absent it defaults to 0.
 
class OMPArraySectionExpr : public Expr {
 
  enum { BASE, LOWER_BOUND, LENGTH, STRIDE, END_EXPR };
 
  Stmt *SubExprs[END_EXPR];
 
  SourceLocation ColonLocFirst;
 
  SourceLocation ColonLocSecond;
 
  SourceLocation RBracketLoc;
 
 
 
public:
 
  OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride,
 
                      QualType Type, ExprValueKind VK, ExprObjectKind OK,
 
                      SourceLocation ColonLocFirst,
 
                      SourceLocation ColonLocSecond, SourceLocation RBracketLoc)
 
      : Expr(OMPArraySectionExprClass, Type, VK, OK),
 
        ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond),
 
        RBracketLoc(RBracketLoc) {
 
    SubExprs[BASE] = Base;
 
    SubExprs[LOWER_BOUND] = LowerBound;
 
    SubExprs[LENGTH] = Length;
 
    SubExprs[STRIDE] = Stride;
 
    setDependence(computeDependence(this));
 
  }
 
 
 
  /// Create an empty array section expression.
 
  explicit OMPArraySectionExpr(EmptyShell Shell)
 
      : Expr(OMPArraySectionExprClass, Shell) {}
 
 
 
  /// An array section can be written only as Base[LowerBound:Length].
 
 
 
  /// Get base of the array section.
 
  Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
 
  const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
 
  /// Set base of the array section.
 
  void setBase(Expr *E) { SubExprs[BASE] = E; }
 
 
 
  /// Return original type of the base expression for array section.
 
  static QualType getBaseOriginalType(const Expr *Base);
 
 
 
  /// Get lower bound of array section.
 
  Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); }
 
  const Expr *getLowerBound() const {
 
    return cast_or_null<Expr>(SubExprs[LOWER_BOUND]);
 
  }
 
  /// Set lower bound of the array section.
 
  void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; }
 
 
 
  /// Get length of array section.
 
  Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); }
 
  const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); }
 
  /// Set length of the array section.
 
  void setLength(Expr *E) { SubExprs[LENGTH] = E; }
 
 
 
  /// Get stride of array section.
 
  Expr *getStride() { return cast_or_null<Expr>(SubExprs[STRIDE]); }
 
  const Expr *getStride() const { return cast_or_null<Expr>(SubExprs[STRIDE]); }
 
  /// Set length of the array section.
 
  void setStride(Expr *E) { SubExprs[STRIDE] = E; }
 
 
 
  SourceLocation getBeginLoc() const LLVM_READONLY {
 
    return getBase()->getBeginLoc();
 
  }
 
  SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; }
 
 
 
  SourceLocation getColonLocFirst() const { return ColonLocFirst; }
 
  void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; }
 
 
 
  SourceLocation getColonLocSecond() const { return ColonLocSecond; }
 
  void setColonLocSecond(SourceLocation L) { ColonLocSecond = L; }
 
 
 
  SourceLocation getRBracketLoc() const { return RBracketLoc; }
 
  void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
 
 
 
  SourceLocation getExprLoc() const LLVM_READONLY {
 
    return getBase()->getExprLoc();
 
  }
 
 
 
  static bool classof(const Stmt *T) {
 
    return T->getStmtClass() == OMPArraySectionExprClass;
 
  }
 
 
 
  child_range children() {
 
    return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
 
  }
 
 
 
  const_child_range children() const {
 
    return const_child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
 
  }
 
};
 
 
 
/// An explicit cast in C or a C-style cast in C++, which uses the syntax
 
/// ([s1][s2]...[sn])expr. For example: @c ([3][3])f.
 
class OMPArrayShapingExpr final
 
    : public Expr,
 
      private llvm::TrailingObjects<OMPArrayShapingExpr, Expr *, SourceRange> {
 
  friend TrailingObjects;
 
  friend class ASTStmtReader;
 
  friend class ASTStmtWriter;
 
  /// Base node.
 
  SourceLocation LPLoc; /// The location of the left paren
 
  SourceLocation RPLoc; /// The location of the right paren
 
  unsigned NumDims = 0; /// Number of dimensions in the shaping expression.
 
 
 
  /// Construct full expression.
 
  OMPArrayShapingExpr(QualType ExprTy, Expr *Op, SourceLocation L,
 
                      SourceLocation R, ArrayRef<Expr *> Dims);
 
 
 
  /// Construct an empty expression.
 
  explicit OMPArrayShapingExpr(EmptyShell Shell, unsigned NumDims)
 
      : Expr(OMPArrayShapingExprClass, Shell), NumDims(NumDims) {}
 
 
 
  /// Sets the dimensions for the array shaping.
 
  void setDimensions(ArrayRef<Expr *> Dims);
 
 
 
  /// Sets the base expression for array shaping operation.
 
  void setBase(Expr *Op) { getTrailingObjects<Expr *>()[NumDims] = Op; }
 
 
 
  /// Sets source ranges for the brackets in the array shaping operation.
 
  void setBracketsRanges(ArrayRef<SourceRange> BR);
 
 
 
  unsigned numTrailingObjects(OverloadToken<Expr *>) const {
 
    // Add an extra one for the base expression.
 
    return NumDims + 1;
 
  }
 
 
 
  unsigned numTrailingObjects(OverloadToken<SourceRange>) const {
 
    return NumDims;
 
  }
 
 
 
public:
 
  static OMPArrayShapingExpr *Create(const ASTContext &Context, QualType T,
 
                                     Expr *Op, SourceLocation L,
 
                                     SourceLocation R, ArrayRef<Expr *> Dims,
 
                                     ArrayRef<SourceRange> BracketRanges);
 
 
 
  static OMPArrayShapingExpr *CreateEmpty(const ASTContext &Context,
 
                                          unsigned NumDims);
 
 
 
  SourceLocation getLParenLoc() const { return LPLoc; }
 
  void setLParenLoc(SourceLocation L) { LPLoc = L; }
 
 
 
  SourceLocation getRParenLoc() const { return RPLoc; }
 
  void setRParenLoc(SourceLocation L) { RPLoc = L; }
 
 
 
  SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; }
 
  SourceLocation getEndLoc() const LLVM_READONLY {
 
    return getBase()->getEndLoc();
 
  }
 
 
 
  /// Fetches the dimensions for array shaping expression.
 
  ArrayRef<Expr *> getDimensions() const {
 
    return llvm::ArrayRef(getTrailingObjects<Expr *>(), NumDims);
 
  }
 
 
 
  /// Fetches source ranges for the brackets os the array shaping expression.
 
  ArrayRef<SourceRange> getBracketsRanges() const {
 
    return llvm::ArrayRef(getTrailingObjects<SourceRange>(), NumDims);
 
  }
 
 
 
  /// Fetches base expression of array shaping expression.
 
  Expr *getBase() { return getTrailingObjects<Expr *>()[NumDims]; }
 
  const Expr *getBase() const { return getTrailingObjects<Expr *>()[NumDims]; }
 
 
 
  static bool classof(const Stmt *T) {
 
    return T->getStmtClass() == OMPArrayShapingExprClass;
 
  }
 
 
 
  // Iterators
 
  child_range children() {
 
    Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
 
    return child_range(Begin, Begin + NumDims + 1);
 
  }
 
  const_child_range children() const {
 
    Stmt *const *Begin =
 
        reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
 
    return const_child_range(Begin, Begin + NumDims + 1);
 
  }
 
};
 
 
 
/// Helper expressions and declaration for OMPIteratorExpr class for each
 
/// iteration space.
 
struct OMPIteratorHelperData {
 
  /// Internal normalized counter.
 
  VarDecl *CounterVD = nullptr;
 
  /// Normalized upper bound. Normalized loop iterates from 0 to Upper with
 
  /// step 1.
 
  Expr *Upper = nullptr;
 
  /// Update expression for the originally specified iteration variable,
 
  /// calculated as VD = Begin + CounterVD * Step;
 
  Expr *Update = nullptr;
 
  /// Updater for the internal counter: ++CounterVD;
 
  Expr *CounterUpdate = nullptr;
 
};
 
 
 
/// OpenMP 5.0 [2.1.6 Iterators]
 
/// Iterators are identifiers that expand to multiple values in the clause on
 
/// which they appear.
 
/// The syntax of the iterator modifier is as follows:
 
/// \code
 
/// iterator(iterators-definition)
 
/// \endcode
 
/// where iterators-definition is one of the following:
 
/// \code
 
/// iterator-specifier [, iterators-definition ]
 
/// \endcode
 
/// where iterator-specifier is one of the following:
 
/// \code
 
/// [ iterator-type ] identifier = range-specification
 
/// \endcode
 
/// where identifier is a base language identifier.
 
/// iterator-type is a type name.
 
/// range-specification is of the form begin:end[:step], where begin and end are
 
/// expressions for which their types can be converted to iterator-type and step
 
/// is an integral expression.
 
/// In an iterator-specifier, if the iterator-type is not specified then the
 
/// type of that iterator is of int type.
 
/// The iterator-type must be an integral or pointer type.
 
/// The iterator-type must not be const qualified.
 
class OMPIteratorExpr final
 
    : public Expr,
 
      private llvm::TrailingObjects<OMPIteratorExpr, Decl *, Expr *,
 
                                    SourceLocation, OMPIteratorHelperData> {
 
public:
 
  /// Iterator range representation begin:end[:step].
 
  struct IteratorRange {
 
    Expr *Begin = nullptr;
 
    Expr *End = nullptr;
 
    Expr *Step = nullptr;
 
  };
 
  /// Iterator definition representation.
 
  struct IteratorDefinition {
 
    Decl *IteratorDecl = nullptr;
 
    IteratorRange Range;
 
    SourceLocation AssignmentLoc;
 
    SourceLocation ColonLoc, SecondColonLoc;
 
  };
 
 
 
private:
 
  friend TrailingObjects;
 
  friend class ASTStmtReader;
 
  friend class ASTStmtWriter;
 
 
 
  /// Offset in the list of expressions for subelements of the ranges.
 
  enum class RangeExprOffset {
 
    Begin = 0,
 
    End = 1,
 
    Step = 2,
 
    Total = 3,
 
  };
 
  /// Offset in the list of locations for subelements of colon symbols
 
  /// locations.
 
  enum class RangeLocOffset {
 
    AssignLoc = 0,
 
    FirstColonLoc = 1,
 
    SecondColonLoc = 2,
 
    Total = 3,
 
  };
 
  /// Location of 'iterator' keyword.
 
  SourceLocation IteratorKwLoc;
 
  /// Location of '('.
 
  SourceLocation LPLoc;
 
  /// Location of ')'.
 
  SourceLocation RPLoc;
 
  /// Number of iterator definitions.
 
  unsigned NumIterators = 0;
 
 
 
  OMPIteratorExpr(QualType ExprTy, SourceLocation IteratorKwLoc,
 
                  SourceLocation L, SourceLocation R,
 
                  ArrayRef<IteratorDefinition> Data,
 
                  ArrayRef<OMPIteratorHelperData> Helpers);
 
 
 
  /// Construct an empty expression.
 
  explicit OMPIteratorExpr(EmptyShell Shell, unsigned NumIterators)
 
      : Expr(OMPIteratorExprClass, Shell), NumIterators(NumIterators) {}
 
 
 
  /// Sets basic declaration for the specified iterator definition.
 
  void setIteratorDeclaration(unsigned I, Decl *D);
 
 
 
  /// Sets the location of the assignment symbol for the specified iterator
 
  /// definition.
 
  void setAssignmentLoc(unsigned I, SourceLocation Loc);
 
 
 
  /// Sets begin, end and optional step expressions for specified iterator
 
  /// definition.
 
  void setIteratorRange(unsigned I, Expr *Begin, SourceLocation ColonLoc,
 
                        Expr *End, SourceLocation SecondColonLoc, Expr *Step);
 
 
 
  /// Sets helpers for the specified iteration space.
 
  void setHelper(unsigned I, const OMPIteratorHelperData &D);
 
 
 
  unsigned numTrailingObjects(OverloadToken<Decl *>) const {
 
    return NumIterators;
 
  }
 
 
 
  unsigned numTrailingObjects(OverloadToken<Expr *>) const {
 
    return NumIterators * static_cast<int>(RangeExprOffset::Total);
 
  }
 
 
 
  unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
 
    return NumIterators * static_cast<int>(RangeLocOffset::Total);
 
  }
 
 
 
public:
 
  static OMPIteratorExpr *Create(const ASTContext &Context, QualType T,
 
                                 SourceLocation IteratorKwLoc, SourceLocation L,
 
                                 SourceLocation R,
 
                                 ArrayRef<IteratorDefinition> Data,
 
                                 ArrayRef<OMPIteratorHelperData> Helpers);
 
 
 
  static OMPIteratorExpr *CreateEmpty(const ASTContext &Context,
 
                                      unsigned NumIterators);
 
 
 
  SourceLocation getLParenLoc() const { return LPLoc; }
 
  void setLParenLoc(SourceLocation L) { LPLoc = L; }
 
 
 
  SourceLocation getRParenLoc() const { return RPLoc; }
 
  void setRParenLoc(SourceLocation L) { RPLoc = L; }
 
 
 
  SourceLocation getIteratorKwLoc() const { return IteratorKwLoc; }
 
  void setIteratorKwLoc(SourceLocation L) { IteratorKwLoc = L; }
 
  SourceLocation getBeginLoc() const LLVM_READONLY { return IteratorKwLoc; }
 
  SourceLocation getEndLoc() const LLVM_READONLY { return RPLoc; }
 
 
 
  /// Gets the iterator declaration for the given iterator.
 
  Decl *getIteratorDecl(unsigned I);
 
  const Decl *getIteratorDecl(unsigned I) const {
 
    return const_cast<OMPIteratorExpr *>(this)->getIteratorDecl(I);
 
  }
 
 
 
  /// Gets the iterator range for the given iterator.
 
  IteratorRange getIteratorRange(unsigned I);
 
  const IteratorRange getIteratorRange(unsigned I) const {
 
    return const_cast<OMPIteratorExpr *>(this)->getIteratorRange(I);
 
  }
 
 
 
  /// Gets the location of '=' for the given iterator definition.
 
  SourceLocation getAssignLoc(unsigned I) const;
 
  /// Gets the location of the first ':' in the range for the given iterator
 
  /// definition.
 
  SourceLocation getColonLoc(unsigned I) const;
 
  /// Gets the location of the second ':' (if any) in the range for the given
 
  /// iteratori definition.
 
  SourceLocation getSecondColonLoc(unsigned I) const;
 
 
 
  /// Returns number of iterator definitions.
 
  unsigned numOfIterators() const { return NumIterators; }
 
 
 
  /// Fetches helper data for the specified iteration space.
 
  OMPIteratorHelperData &getHelper(unsigned I);
 
  const OMPIteratorHelperData &getHelper(unsigned I) const;
 
 
 
  static bool classof(const Stmt *T) {
 
    return T->getStmtClass() == OMPIteratorExprClass;
 
  }
 
 
 
  // Iterators
 
  child_range children() {
 
    Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
 
    return child_range(
 
        Begin, Begin + NumIterators * static_cast<int>(RangeExprOffset::Total));
 
  }
 
  const_child_range children() const {
 
    Stmt *const *Begin =
 
        reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
 
    return const_child_range(
 
        Begin, Begin + NumIterators * static_cast<int>(RangeExprOffset::Total));
 
  }
 
};
 
 
 
} // end namespace clang
 
 
 
#endif