#pragma once #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //===- DeclOpenMP.h - Classes for representing OpenMP directives -*- 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 // //===----------------------------------------------------------------------===// /// /// \file /// This file defines OpenMP nodes for declarative directives. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLOPENMP_H #define LLVM_CLANG_AST_DECLOPENMP_H #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/Type.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/TrailingObjects.h" namespace clang { /// This is a basic class for representing single OpenMP declarative directive. /// template class OMPDeclarativeDirective : public U { friend class ASTDeclReader; friend class ASTDeclWriter; /// Get the clauses storage. MutableArrayRef getClauses() { if (!Data) return llvm::None; return Data->getClauses(); } protected: /// Data, associated with the directive. OMPChildren *Data = nullptr; /// Build instance of directive. template OMPDeclarativeDirective(Params &&... P) : U(std::forward(P)...) {} template static T *createDirective(const ASTContext &C, DeclContext *DC, ArrayRef Clauses, unsigned NumChildren, Params &&... P) { auto *Inst = new (C, DC, size(Clauses.size(), NumChildren)) T(DC, std::forward(P)...); Inst->Data = OMPChildren::Create(Inst + 1, Clauses, /*AssociatedStmt=*/nullptr, NumChildren); Inst->Data->setClauses(Clauses); return Inst; } template static T *createEmptyDirective(const ASTContext &C, unsigned ID, unsigned NumClauses, unsigned NumChildren, Params &&... P) { auto *Inst = new (C, ID, size(NumClauses, NumChildren)) T(nullptr, std::forward(P)...); Inst->Data = OMPChildren::CreateEmpty( Inst + 1, NumClauses, /*HasAssociatedStmt=*/false, NumChildren); return Inst; } static size_t size(unsigned NumClauses, unsigned NumChildren) { return OMPChildren::size(NumClauses, /*HasAssociatedStmt=*/false, NumChildren); } public: /// Get number of clauses. unsigned getNumClauses() const { if (!Data) return 0; return Data->getNumClauses(); } /// Returns specified clause. /// /// \param I Number of clause. /// OMPClause *getClause(unsigned I) const { return clauses()[I]; } ArrayRef clauses() const { if (!Data) return llvm::None; return Data->getClauses(); } }; /// This represents '#pragma omp threadprivate ...' directive. /// For example, in the following, both 'a' and 'A::b' are threadprivate: /// /// \code /// int a; /// #pragma omp threadprivate(a) /// struct A { /// static int b; /// #pragma omp threadprivate(b) /// }; /// \endcode /// class OMPThreadPrivateDecl final : public OMPDeclarativeDirective { friend class OMPDeclarativeDirective; virtual void anchor(); OMPThreadPrivateDecl(DeclContext *DC = nullptr, SourceLocation L = SourceLocation()) : OMPDeclarativeDirective(OMPThreadPrivate, DC, L) {} ArrayRef getVars() const { auto **Storage = reinterpret_cast(Data->getChildren().data()); return llvm::makeArrayRef(Storage, Data->getNumChildren()); } MutableArrayRef getVars() { auto **Storage = reinterpret_cast(Data->getChildren().data()); return llvm::makeMutableArrayRef(Storage, Data->getNumChildren()); } void setVars(ArrayRef VL); public: static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef VL); static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned N); typedef MutableArrayRef::iterator varlist_iterator; typedef ArrayRef::iterator varlist_const_iterator; typedef llvm::iterator_range varlist_range; typedef llvm::iterator_range varlist_const_range; unsigned varlist_size() const { return Data->getNumChildren(); } bool varlist_empty() const { return Data->getChildren().empty(); } varlist_range varlists() { return varlist_range(varlist_begin(), varlist_end()); } varlist_const_range varlists() const { return varlist_const_range(varlist_begin(), varlist_end()); } varlist_iterator varlist_begin() { return getVars().begin(); } varlist_iterator varlist_end() { return getVars().end(); } varlist_const_iterator varlist_begin() const { return getVars().begin(); } varlist_const_iterator varlist_end() const { return getVars().end(); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPThreadPrivate; } }; /// This represents '#pragma omp declare reduction ...' directive. /// For example, in the following, declared reduction 'foo' for types 'int' and /// 'float': /// /// \code /// #pragma omp declare reduction (foo : int,float : omp_out += omp_in) /// initializer (omp_priv = 0) /// \endcode /// /// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer. class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext { // This class stores some data in DeclContext::OMPDeclareReductionDeclBits // to save some space. Use the provided accessors to access it. public: enum InitKind { CallInit, // Initialized by function call. DirectInit, // omp_priv() CopyInit // omp_priv = }; private: friend class ASTDeclReader; /// Combiner for declare reduction construct. Expr *Combiner = nullptr; /// Initializer for declare reduction construct. Expr *Initializer = nullptr; /// In parameter of the combiner. Expr *In = nullptr; /// Out parameter of the combiner. Expr *Out = nullptr; /// Priv parameter of the initializer. Expr *Priv = nullptr; /// Orig parameter of the initializer. Expr *Orig = nullptr; /// Reference to the previous declare reduction construct in the same /// scope with the same name. Required for proper templates instantiation if /// the declare reduction construct is declared inside compound statement. LazyDeclPtr PrevDeclInScope; void anchor() override; OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, QualType Ty, OMPDeclareReductionDecl *PrevDeclInScope); void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) { PrevDeclInScope = Prev; } public: /// Create declare reduction node. static OMPDeclareReductionDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, QualType T, OMPDeclareReductionDecl *PrevDeclInScope); /// Create deserialized declare reduction node. static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// Get combiner expression of the declare reduction construct. Expr *getCombiner() { return Combiner; } const Expr *getCombiner() const { return Combiner; } /// Get In variable of the combiner. Expr *getCombinerIn() { return In; } const Expr *getCombinerIn() const { return In; } /// Get Out variable of the combiner. Expr *getCombinerOut() { return Out; } const Expr *getCombinerOut() const { return Out; } /// Set combiner expression for the declare reduction construct. void setCombiner(Expr *E) { Combiner = E; } /// Set combiner In and Out vars. void setCombinerData(Expr *InE, Expr *OutE) { In = InE; Out = OutE; } /// Get initializer expression (if specified) of the declare reduction /// construct. Expr *getInitializer() { return Initializer; } const Expr *getInitializer() const { return Initializer; } /// Get initializer kind. InitKind getInitializerKind() const { return static_cast(OMPDeclareReductionDeclBits.InitializerKind); } /// Get Orig variable of the initializer. Expr *getInitOrig() { return Orig; } const Expr *getInitOrig() const { return Orig; } /// Get Priv variable of the initializer. Expr *getInitPriv() { return Priv; } const Expr *getInitPriv() const { return Priv; } /// Set initializer expression for the declare reduction construct. void setInitializer(Expr *E, InitKind IK) { Initializer = E; OMPDeclareReductionDeclBits.InitializerKind = IK; } /// Set initializer Orig and Priv vars. void setInitializerData(Expr *OrigE, Expr *PrivE) { Orig = OrigE; Priv = PrivE; } /// Get reference to previous declare reduction construct in the same /// scope with the same name. OMPDeclareReductionDecl *getPrevDeclInScope(); const OMPDeclareReductionDecl *getPrevDeclInScope() const; static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPDeclareReduction; } static DeclContext *castToDeclContext(const OMPDeclareReductionDecl *D) { return static_cast(const_cast(D)); } static OMPDeclareReductionDecl *castFromDeclContext(const DeclContext *DC) { return static_cast( const_cast(DC)); } }; /// This represents '#pragma omp declare mapper ...' directive. Map clauses are /// allowed to use with this directive. The following example declares a user /// defined mapper for the type 'struct vec'. This example instructs the fields /// 'len' and 'data' should be mapped when mapping instances of 'struct vec'. /// /// \code /// #pragma omp declare mapper(mid: struct vec v) map(v.len, v.data[0:N]) /// \endcode class OMPDeclareMapperDecl final : public OMPDeclarativeDirective, public DeclContext { friend class OMPDeclarativeDirective; friend class ASTDeclReader; friend class ASTDeclWriter; /// Mapper variable, which is 'v' in the example above Expr *MapperVarRef = nullptr; /// Name of the mapper variable DeclarationName VarName; LazyDeclPtr PrevDeclInScope; void anchor() override; OMPDeclareMapperDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, QualType Ty, DeclarationName VarName, OMPDeclareMapperDecl *PrevDeclInScope) : OMPDeclarativeDirective(OMPDeclareMapper, DC, L, Name, Ty), DeclContext(OMPDeclareMapper), VarName(VarName), PrevDeclInScope(PrevDeclInScope) {} void setPrevDeclInScope(OMPDeclareMapperDecl *Prev) { PrevDeclInScope = Prev; } public: /// Creates declare mapper node. static OMPDeclareMapperDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, QualType T, DeclarationName VarName, ArrayRef Clauses, OMPDeclareMapperDecl *PrevDeclInScope); /// Creates deserialized declare mapper node. static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned N); using clauselist_iterator = MutableArrayRef::iterator; using clauselist_const_iterator = ArrayRef::iterator; using clauselist_range = llvm::iterator_range; using clauselist_const_range = llvm::iterator_range; unsigned clauselist_size() const { return Data->getNumClauses(); } bool clauselist_empty() const { return Data->getClauses().empty(); } clauselist_range clauselists() { return clauselist_range(clauselist_begin(), clauselist_end()); } clauselist_const_range clauselists() const { return clauselist_const_range(clauselist_begin(), clauselist_end()); } clauselist_iterator clauselist_begin() { return Data->getClauses().begin(); } clauselist_iterator clauselist_end() { return Data->getClauses().end(); } clauselist_const_iterator clauselist_begin() const { return Data->getClauses().begin(); } clauselist_const_iterator clauselist_end() const { return Data->getClauses().end(); } /// Get the variable declared in the mapper Expr *getMapperVarRef() { return cast_or_null(Data->getChildren()[0]); } const Expr *getMapperVarRef() const { return cast_or_null(Data->getChildren()[0]); } /// Set the variable declared in the mapper void setMapperVarRef(Expr *MapperVarRefE) { Data->getChildren()[0] = MapperVarRefE; } /// Get the name of the variable declared in the mapper DeclarationName getVarName() { return VarName; } /// Get reference to previous declare mapper construct in the same /// scope with the same name. OMPDeclareMapperDecl *getPrevDeclInScope(); const OMPDeclareMapperDecl *getPrevDeclInScope() const; static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPDeclareMapper; } static DeclContext *castToDeclContext(const OMPDeclareMapperDecl *D) { return static_cast(const_cast(D)); } static OMPDeclareMapperDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } }; /// Pseudo declaration for capturing expressions. Also is used for capturing of /// non-static data members in non-static member functions. /// /// Clang supports capturing of variables only, but OpenMP 4.5 allows to /// privatize non-static members of current class in non-static member /// functions. This pseudo-declaration allows properly handle this kind of /// capture by wrapping captured expression into a variable-like declaration. class OMPCapturedExprDecl final : public VarDecl { friend class ASTDeclReader; void anchor() override; OMPCapturedExprDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, QualType Type, TypeSourceInfo *TInfo, SourceLocation StartLoc) : VarDecl(OMPCapturedExpr, C, DC, StartLoc, StartLoc, Id, Type, TInfo, SC_None) { setImplicit(); } public: static OMPCapturedExprDecl *Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, QualType T, SourceLocation StartLoc); static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPCapturedExpr; } }; /// This represents '#pragma omp requires...' directive. /// For example /// /// \code /// #pragma omp requires unified_address /// \endcode /// class OMPRequiresDecl final : public OMPDeclarativeDirective { friend class OMPDeclarativeDirective; friend class ASTDeclReader; virtual void anchor(); OMPRequiresDecl(DeclContext *DC, SourceLocation L) : OMPDeclarativeDirective(OMPRequires, DC, L) {} public: /// Create requires node. static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef CL); /// Create deserialized requires node. static OMPRequiresDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned N); using clauselist_iterator = MutableArrayRef::iterator; using clauselist_const_iterator = ArrayRef::iterator; using clauselist_range = llvm::iterator_range; using clauselist_const_range = llvm::iterator_range; unsigned clauselist_size() const { return Data->getNumClauses(); } bool clauselist_empty() const { return Data->getClauses().empty(); } clauselist_range clauselists() { return clauselist_range(clauselist_begin(), clauselist_end()); } clauselist_const_range clauselists() const { return clauselist_const_range(clauselist_begin(), clauselist_end()); } clauselist_iterator clauselist_begin() { return Data->getClauses().begin(); } clauselist_iterator clauselist_end() { return Data->getClauses().end(); } clauselist_const_iterator clauselist_begin() const { return Data->getClauses().begin(); } clauselist_const_iterator clauselist_end() const { return Data->getClauses().end(); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPRequires; } }; /// This represents '#pragma omp allocate ...' directive. /// For example, in the following, the default allocator is used for both 'a' /// and 'A::b': /// /// \code /// int a; /// #pragma omp allocate(a) /// struct A { /// static int b; /// #pragma omp allocate(b) /// }; /// \endcode /// class OMPAllocateDecl final : public OMPDeclarativeDirective { friend class OMPDeclarativeDirective; friend class ASTDeclReader; virtual void anchor(); OMPAllocateDecl(DeclContext *DC, SourceLocation L) : OMPDeclarativeDirective(OMPAllocate, DC, L) {} ArrayRef getVars() const { auto **Storage = reinterpret_cast(Data->getChildren().data()); return llvm::makeArrayRef(Storage, Data->getNumChildren()); } MutableArrayRef getVars() { auto **Storage = reinterpret_cast(Data->getChildren().data()); return llvm::makeMutableArrayRef(Storage, Data->getNumChildren()); } void setVars(ArrayRef VL); public: static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ArrayRef VL, ArrayRef CL); static OMPAllocateDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned NVars, unsigned NClauses); typedef MutableArrayRef::iterator varlist_iterator; typedef ArrayRef::iterator varlist_const_iterator; typedef llvm::iterator_range varlist_range; typedef llvm::iterator_range varlist_const_range; using clauselist_iterator = MutableArrayRef::iterator; using clauselist_const_iterator = ArrayRef::iterator; using clauselist_range = llvm::iterator_range; using clauselist_const_range = llvm::iterator_range; unsigned varlist_size() const { return Data->getNumChildren(); } bool varlist_empty() const { return Data->getChildren().empty(); } unsigned clauselist_size() const { return Data->getNumClauses(); } bool clauselist_empty() const { return Data->getClauses().empty(); } varlist_range varlists() { return varlist_range(varlist_begin(), varlist_end()); } varlist_const_range varlists() const { return varlist_const_range(varlist_begin(), varlist_end()); } varlist_iterator varlist_begin() { return getVars().begin(); } varlist_iterator varlist_end() { return getVars().end(); } varlist_const_iterator varlist_begin() const { return getVars().begin(); } varlist_const_iterator varlist_end() const { return getVars().end(); } clauselist_range clauselists() { return clauselist_range(clauselist_begin(), clauselist_end()); } clauselist_const_range clauselists() const { return clauselist_const_range(clauselist_begin(), clauselist_end()); } clauselist_iterator clauselist_begin() { return Data->getClauses().begin(); } clauselist_iterator clauselist_end() { return Data->getClauses().end(); } clauselist_const_iterator clauselist_begin() const { return Data->getClauses().begin(); } clauselist_const_iterator clauselist_end() const { return Data->getClauses().end(); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPAllocate; } }; } // end namespace clang #endif #ifdef __GNUC__ #pragma GCC diagnostic pop #endif