//===- StmtOpenACC.h - Classes for OpenACC 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 OpenACC AST classes for statement-level contructs. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_STMTOPENACC_H #define LLVM_CLANG_AST_STMTOPENACC_H #include "clang/AST/OpenACCClause.h" #include "clang/AST/Stmt.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/STLExtras.h" #include namespace clang { /// This is the base class for an OpenACC statement-level construct, other /// construct types are expected to inherit from this. class OpenACCConstructStmt : public Stmt { friend class ASTStmtWriter; friend class ASTStmtReader; /// The directive kind. Each implementation of this interface should handle /// specific kinds. OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid; /// The location of the directive statement, from the '#' to the last token of /// the directive. SourceRange Range; /// The location of the directive name. SourceLocation DirectiveLoc; /// The list of clauses. This is stored here as an ArrayRef, as this is the /// most convienient place to access the list, however the list itself should /// be stored in leaf nodes, likely in trailing-storage. MutableArrayRef Clauses; protected: OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End) : Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {} // Used only for initialization, the leaf class can initialize this to // trailing storage. void setClauseList(MutableArrayRef NewClauses) { assert(Clauses.empty() && "Cannot change clause list"); Clauses = NewClauses; } public: OpenACCDirectiveKind getDirectiveKind() const { return Kind; } static bool classof(const Stmt *S) { return S->getStmtClass() >= firstOpenACCConstructStmtConstant && S->getStmtClass() <= lastOpenACCConstructStmtConstant; } SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } SourceLocation getDirectiveLoc() const { return DirectiveLoc; } ArrayRef clauses() const { return Clauses; } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_cast(this)->children(); } }; /// This is a base class for any OpenACC statement-level constructs that have an /// associated statement. This class is not intended to be instantiated, but is /// a convenient place to hold the associated statement. class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt { friend class ASTStmtWriter; friend class ASTStmtReader; template friend class RecursiveASTVisitor; Stmt *AssociatedStmt = nullptr; protected: OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, Stmt *AssocStmt) : OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End), AssociatedStmt(AssocStmt) {} void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; } Stmt *getAssociatedStmt() { return AssociatedStmt; } const Stmt *getAssociatedStmt() const { return const_cast(this) ->getAssociatedStmt(); } public: static bool classof(const Stmt *T) { return false; } child_range children() { if (getAssociatedStmt()) return child_range(&AssociatedStmt, &AssociatedStmt + 1); return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_cast(this)->children(); } }; /// This class represents a compute construct, representing a 'Kind' of /// `parallel', 'serial', or 'kernel'. These constructs are associated with a /// 'structured block', defined as: /// /// in C or C++, an executable statement, possibly compound, with a single /// entry at the top and a single exit at the bottom /// /// At the moment there is no real motivation to have a different AST node for /// those three, as they are semantically identical, and have only minor /// differences in the permitted list of clauses, which can be differentiated by /// the 'Kind'. class OpenACCComputeConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { friend class ASTStmtWriter; friend class ASTStmtReader; friend class ASTContext; friend TrailingObjects; OpenACCComputeConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid, SourceLocation{}, SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) { // We cannot send the TrailingObjects storage to the base class (which holds // a reference to the data) until it is constructed, so we have to set it // separately here. std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start, DirectiveLoc, End, StructuredBlock) { assert(isOpenACCComputeDirectiveKind(K) && "Only parallel, serial, and kernels constructs should be " "represented by this type"); // Initialize the trailing storage. llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCComputeConstructClass; } static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCComputeConstruct * Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, SourceLocation DirectiveLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *StructuredBlock); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { return const_cast(this)->getStructuredBlock(); } }; /// This class represents a 'loop' construct. The 'loop' construct applies to a /// 'for' loop (or range-for loop), and is optionally associated with a Compute /// Construct. class OpenACCLoopConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { // The compute/combined construct kind this loop is associated with, or // invalid if this is an orphaned loop construct. OpenACCDirectiveKind ParentComputeConstructKind = OpenACCDirectiveKind::Invalid; friend class ASTStmtWriter; friend class ASTStmtReader; friend class ASTContext; friend class OpenACCAssociatedStmtConstruct; friend class OpenACCCombinedConstruct; friend class OpenACCComputeConstruct; friend TrailingObjects; OpenACCLoopConstruct(unsigned NumClauses); OpenACCLoopConstruct(OpenACCDirectiveKind ParentKind, SourceLocation Start, SourceLocation DirLoc, SourceLocation End, ArrayRef Clauses, Stmt *Loop); public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCLoopConstructClass; } static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCLoopConstruct * Create(const ASTContext &C, OpenACCDirectiveKind ParentKind, SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *Loop); Stmt *getLoop() { return getAssociatedStmt(); } const Stmt *getLoop() const { return const_cast(this)->getLoop(); } /// OpenACC 3.3 2.9: /// An orphaned loop construct is a loop construct that is not lexically /// enclosed within a compute construct. The parent compute construct of a /// loop construct is the nearest compute construct that lexically contains /// the loop construct. bool isOrphanedLoopConstruct() const { return ParentComputeConstructKind == OpenACCDirectiveKind::Invalid; } OpenACCDirectiveKind getParentComputeConstructKind() const { return ParentComputeConstructKind; } }; // This class represents a 'combined' construct, which has a bunch of rules // shared with both loop and compute constructs. class OpenACCCombinedConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { friend TrailingObjects; OpenACCCombinedConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCCombinedConstructClass, OpenACCDirectiveKind::Invalid, SourceLocation{}, SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCCombinedConstruct(OpenACCDirectiveKind K, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCCombinedConstructClass, K, Start, DirectiveLoc, End, StructuredBlock) { assert(isOpenACCCombinedDirectiveKind(K) && "Only parallel loop, serial loop, and kernels loop constructs " "should be represented by this type"); llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCCombinedConstructClass; } static OpenACCCombinedConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCCombinedConstruct * Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock); Stmt *getLoop() { return getAssociatedStmt(); } const Stmt *getLoop() const { return const_cast(this)->getLoop(); } }; // This class represents a 'data' construct, which has an associated statement // and clauses, but is otherwise pretty simple. class OpenACCDataConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { friend TrailingObjects; OpenACCDataConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCDataConstructClass, OpenACCDirectiveKind::Data, SourceLocation{}, SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCDataConstructClass, OpenACCDirectiveKind::Data, Start, DirectiveLoc, End, StructuredBlock) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCDataConstructClass; } static OpenACCDataConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCDataConstruct *Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { return const_cast(this)->getStructuredBlock(); } }; // This class represents a 'enter data' construct, which JUST has clauses. class OpenACCEnterDataConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCEnterDataConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCEnterDataConstructClass, OpenACCDirectiveKind::EnterData, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCEnterDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCEnterDataConstructClass, OpenACCDirectiveKind::EnterData, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCEnterDataConstructClass; } static OpenACCEnterDataConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCEnterDataConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents a 'exit data' construct, which JUST has clauses. class OpenACCExitDataConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCExitDataConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCExitDataConstructClass, OpenACCDirectiveKind::ExitData, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCExitDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCExitDataConstructClass, OpenACCDirectiveKind::ExitData, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCExitDataConstructClass; } static OpenACCExitDataConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCExitDataConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents a 'host_data' construct, which has an associated // statement and clauses, but is otherwise pretty simple. class OpenACCHostDataConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { friend TrailingObjects; OpenACCHostDataConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCHostDataConstructClass, OpenACCDirectiveKind::HostData, SourceLocation{}, SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCHostDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCHostDataConstructClass, OpenACCDirectiveKind::HostData, Start, DirectiveLoc, End, StructuredBlock) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCHostDataConstructClass; } static OpenACCHostDataConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCHostDataConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses, Stmt *StructuredBlock); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { return const_cast(this)->getStructuredBlock(); } }; // This class represents a 'wait' construct, which has some expressions plus a // clause list. class OpenACCWaitConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { // FIXME: We should be storing a `const OpenACCClause *` to be consistent with // the rest of the constructs, but TrailingObjects doesn't allow for mixing // constness in its implementation of `getTrailingObjects`. friend TrailingObjects; friend class ASTStmtWriter; friend class ASTStmtReader; // Locations of the left and right parens of the 'wait-argument' // expression-list. SourceLocation LParenLoc, RParenLoc; // Location of the 'queues' keyword, if present. SourceLocation QueuesLoc; // Number of the expressions being represented. Index '0' is always the // 'devnum' expression, even if it not present. unsigned NumExprs = 0; OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses) : OpenACCConstructStmt(OpenACCWaitConstructClass, OpenACCDirectiveKind::Wait, SourceLocation{}, SourceLocation{}, SourceLocation{}), NumExprs(NumExprs) { assert(NumExprs >= 1 && "NumExprs should always be >= 1 because the 'devnum' " "expr is represented by a null if necessary"); std::uninitialized_value_construct_n(getExprPtr(), NumExprs); std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(MutableArrayRef(const_cast( getTrailingObjects()), NumClauses)); } OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef QueueIdExprs, SourceLocation RParenLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCWaitConstructClass, OpenACCDirectiveKind::Wait, Start, DirectiveLoc, End), LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc), NumExprs(QueueIdExprs.size() + 1) { assert(NumExprs >= 1 && "NumExprs should always be >= 1 because the 'devnum' " "expr is represented by a null if necessary"); llvm::uninitialized_copy(ArrayRef(DevNumExpr), getExprPtr()); llvm::uninitialized_copy(QueueIdExprs, getExprPtr() + 1); std::uninitialized_copy(const_cast(Clauses.begin()), const_cast(Clauses.end()), getTrailingObjects()); setClauseList(MutableArrayRef(const_cast( getTrailingObjects()), Clauses.size())); } size_t numTrailingObjects(OverloadToken) const { return NumExprs; } size_t numTrailingObjects(OverloadToken) const { return clauses().size(); } Expr **getExprPtr() const { return const_cast(getTrailingObjects()); } ArrayRef getExprs() const { return {getExprPtr(), NumExprs}; } ArrayRef getExprs() { return {getExprPtr(), NumExprs}; } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCWaitConstructClass; } static OpenACCWaitConstruct * CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses); static OpenACCWaitConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef QueueIdExprs, SourceLocation RParenLoc, SourceLocation End, ArrayRef Clauses); SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); } SourceLocation getQueuesLoc() const { return QueuesLoc; } bool hasDevNumExpr() const { return getExprs()[0]; } Expr *getDevNumExpr() const { return getExprs()[0]; } ArrayRef getQueueIdExprs() { return getExprs().drop_front(); } ArrayRef getQueueIdExprs() const { return getExprs().drop_front(); } child_range children() { Stmt **Begin = reinterpret_cast(getExprPtr()); return child_range(Begin, Begin + NumExprs); } const_child_range children() const { Stmt *const *Begin = reinterpret_cast(getExprPtr()); return const_child_range(Begin, Begin + NumExprs); } }; class OpenACCCacheConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; friend class ASTStmtWriter; friend class ASTStmtReader; // Locations of the left and right parens of the 'var-list' // expression-list. SourceRange ParensLoc; SourceLocation ReadOnlyLoc; unsigned NumVars = 0; OpenACCCacheConstruct(unsigned NumVars) : OpenACCConstructStmt(OpenACCCacheConstructClass, OpenACCDirectiveKind::Cache, SourceLocation{}, SourceLocation{}, SourceLocation{}), NumVars(NumVars) { std::uninitialized_value_construct_n(getTrailingObjects(), NumVars); } OpenACCCacheConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation LParenLoc, SourceLocation ReadOnlyLoc, ArrayRef VarList, SourceLocation RParenLoc, SourceLocation End) : OpenACCConstructStmt(OpenACCCacheConstructClass, OpenACCDirectiveKind::Cache, Start, DirectiveLoc, End), ParensLoc(LParenLoc, RParenLoc), ReadOnlyLoc(ReadOnlyLoc), NumVars(VarList.size()) { llvm::uninitialized_copy(VarList, getTrailingObjects()); } public: ArrayRef getVarList() const { return getTrailingObjects(NumVars); } MutableArrayRef getVarList() { return getTrailingObjects(NumVars); } static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCCacheConstructClass; } static OpenACCCacheConstruct *CreateEmpty(const ASTContext &C, unsigned NumVars); static OpenACCCacheConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation LParenLoc, SourceLocation ReadOnlyLoc, ArrayRef VarList, SourceLocation RParenLoc, SourceLocation End); SourceLocation getLParenLoc() const { return ParensLoc.getBegin(); } SourceLocation getRParenLoc() const { return ParensLoc.getEnd(); } bool hasReadOnly() const { return !ReadOnlyLoc.isInvalid(); } SourceLocation getReadOnlyLoc() const { return ReadOnlyLoc; } child_range children() { Stmt **Begin = reinterpret_cast(getTrailingObjects()); return child_range(Begin, Begin + NumVars); } const_child_range children() const { Stmt *const *Begin = reinterpret_cast(getTrailingObjects()); return const_child_range(Begin, Begin + NumVars); } }; // This class represents an 'init' construct, which has just a clause list. class OpenACCInitConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCInitConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCInitConstructClass, OpenACCDirectiveKind::Init, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCInitConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCInitConstructClass, OpenACCDirectiveKind::Init, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCInitConstructClass; } static OpenACCInitConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCInitConstruct *Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents a 'shutdown' construct, which has just a clause list. class OpenACCShutdownConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCShutdownConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCShutdownConstructClass, OpenACCDirectiveKind::Shutdown, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCShutdownConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCShutdownConstructClass, OpenACCDirectiveKind::Shutdown, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCShutdownConstructClass; } static OpenACCShutdownConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCShutdownConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents a 'set' construct, which has just a clause list. class OpenACCSetConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCSetConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCSetConstructClass, OpenACCDirectiveKind::Set, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCSetConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCSetConstructClass, OpenACCDirectiveKind::Set, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCSetConstructClass; } static OpenACCSetConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCSetConstruct *Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents an 'update' construct, which has just a clause list. class OpenACCUpdateConstruct final : public OpenACCConstructStmt, private llvm::TrailingObjects { friend TrailingObjects; OpenACCUpdateConstruct(unsigned NumClauses) : OpenACCConstructStmt(OpenACCUpdateConstructClass, OpenACCDirectiveKind::Update, SourceLocation{}, SourceLocation{}, SourceLocation{}) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCUpdateConstruct(SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses) : OpenACCConstructStmt(OpenACCUpdateConstructClass, OpenACCDirectiveKind::Update, Start, DirectiveLoc, End) { llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCUpdateConstructClass; } static OpenACCUpdateConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCUpdateConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, SourceLocation End, ArrayRef Clauses); }; // This class represents the 'atomic' construct, which has an associated // statement, but no clauses. class OpenACCAtomicConstruct final : public OpenACCAssociatedStmtConstruct, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; OpenACCAtomicKind AtomicKind = OpenACCAtomicKind::None; OpenACCAtomicConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCAtomicConstructClass, OpenACCDirectiveKind::Atomic, SourceLocation{}, SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) { std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses); setClauseList(getTrailingObjects(NumClauses)); } OpenACCAtomicConstruct(SourceLocation Start, SourceLocation DirectiveLoc, OpenACCAtomicKind AtKind, SourceLocation End, ArrayRef Clauses, Stmt *AssociatedStmt) : OpenACCAssociatedStmtConstruct(OpenACCAtomicConstructClass, OpenACCDirectiveKind::Atomic, Start, DirectiveLoc, End, AssociatedStmt), AtomicKind(AtKind) { // Initialize the trailing storage. llvm::uninitialized_copy(Clauses, getTrailingObjects()); setClauseList(getTrailingObjects(Clauses.size())); } void setAssociatedStmt(Stmt *S) { OpenACCAssociatedStmtConstruct::setAssociatedStmt(S); } public: static bool classof(const Stmt *T) { return T->getStmtClass() == OpenACCAtomicConstructClass; } static OpenACCAtomicConstruct *CreateEmpty(const ASTContext &C, unsigned NumClauses); static OpenACCAtomicConstruct * Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, OpenACCAtomicKind AtKind, SourceLocation End, ArrayRef Clauses, Stmt *AssociatedStmt); OpenACCAtomicKind getAtomicKind() const { return AtomicKind; } const Stmt *getAssociatedStmt() const { return OpenACCAssociatedStmtConstruct::getAssociatedStmt(); } Stmt *getAssociatedStmt() { return OpenACCAssociatedStmtConstruct::getAssociatedStmt(); } // A struct to represent a broken-down version of the associated statement, // providing the information specified in OpenACC3.3 Section 2.12. struct SingleStmtInfo { // Holds the entire expression for this. In the case of a normal // read/write/update, this should just be the associated statement. in the // case of an update, this is going to be the sub-expression this // represents. const Expr *WholeExpr; const Expr *V; const Expr *X; // Listed as 'expr' in the standard, this is typically a generic expression // as a component. const Expr *RefExpr; // If this is an 'update', records whether this is a post-fix // increment/decrement. In the case where we have a single-line variant of // 'capture' we have to form the IR differently if this is the case to make // sure the old value is 'read' in the 2nd step. bool IsPostfixIncDec = false; static SingleStmtInfo Empty() { return {nullptr, nullptr, nullptr, nullptr, false}; } static SingleStmtInfo createRead(const Expr *WholeExpr, const Expr *V, const Expr *X) { return {WholeExpr, V, X, /*RefExpr=*/nullptr}; } static SingleStmtInfo createWrite(const Expr *WholeExpr, const Expr *X, const Expr *RefExpr) { return {WholeExpr, /*V=*/nullptr, X, RefExpr}; } static SingleStmtInfo createUpdate(const Expr *WholeExpr, const Expr *X, bool PostfixIncDec) { return {WholeExpr, /*V=*/nullptr, X, /*RefExpr=*/nullptr, PostfixIncDec}; } }; struct StmtInfo { enum class StmtForm { Read, Write, Update, ReadWrite, ReadUpdate, UpdateRead } Form; SingleStmtInfo First, Second; static StmtInfo createUpdateRead(SingleStmtInfo First, SingleStmtInfo Second) { return {StmtForm::UpdateRead, First, Second}; } static StmtInfo createReadWrite(SingleStmtInfo First, SingleStmtInfo Second) { return {StmtForm::ReadWrite, First, Second}; } static StmtInfo createReadUpdate(SingleStmtInfo First, SingleStmtInfo Second) { return {StmtForm::ReadUpdate, First, Second}; } }; const StmtInfo getAssociatedStmtInfo() const; }; } // namespace clang #endif // LLVM_CLANG_AST_STMTOPENACC_H