xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/StmtOpenACC.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- StmtOpenACC.h - Classes for OpenACC directives  ----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// This file defines OpenACC AST classes for statement-level contructs.
10 ///
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_AST_STMTOPENACC_H
14 #define LLVM_CLANG_AST_STMTOPENACC_H
15 
16 #include "clang/AST/OpenACCClause.h"
17 #include "clang/AST/Stmt.h"
18 #include "clang/Basic/OpenACCKinds.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include <memory>
21 
22 namespace clang {
23 /// This is the base class for an OpenACC statement-level construct, other
24 /// construct types are expected to inherit from this.
25 class OpenACCConstructStmt : public Stmt {
26   friend class ASTStmtWriter;
27   friend class ASTStmtReader;
28   /// The directive kind. Each implementation of this interface should handle
29   /// specific kinds.
30   OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
31   /// The location of the directive statement, from the '#' to the last token of
32   /// the directive.
33   SourceRange Range;
34   /// The location of the directive name.
35   SourceLocation DirectiveLoc;
36 
37   /// The list of clauses.  This is stored here as an ArrayRef, as this is the
38   /// most convienient place to access the list, however the list itself should
39   /// be stored in leaf nodes, likely in trailing-storage.
40   MutableArrayRef<const OpenACCClause *> Clauses;
41 
42 protected:
OpenACCConstructStmt(StmtClass SC,OpenACCDirectiveKind K,SourceLocation Start,SourceLocation DirectiveLoc,SourceLocation End)43   OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
44                        SourceLocation Start, SourceLocation DirectiveLoc,
45                        SourceLocation End)
46       : Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {}
47 
48   // Used only for initialization, the leaf class can initialize this to
49   // trailing storage.
setClauseList(MutableArrayRef<const OpenACCClause * > NewClauses)50   void setClauseList(MutableArrayRef<const OpenACCClause *> NewClauses) {
51     assert(Clauses.empty() && "Cannot change clause list");
52     Clauses = NewClauses;
53   }
54 
55 public:
getDirectiveKind()56   OpenACCDirectiveKind getDirectiveKind() const { return Kind; }
57 
classof(const Stmt * S)58   static bool classof(const Stmt *S) {
59     return S->getStmtClass() >= firstOpenACCConstructStmtConstant &&
60            S->getStmtClass() <= lastOpenACCConstructStmtConstant;
61   }
62 
getBeginLoc()63   SourceLocation getBeginLoc() const { return Range.getBegin(); }
getEndLoc()64   SourceLocation getEndLoc() const { return Range.getEnd(); }
getDirectiveLoc()65   SourceLocation getDirectiveLoc() const { return DirectiveLoc; }
clauses()66   ArrayRef<const OpenACCClause *> clauses() const { return Clauses; }
67 
children()68   child_range children() {
69     return child_range(child_iterator(), child_iterator());
70   }
71 
children()72   const_child_range children() const {
73     return const_cast<OpenACCConstructStmt *>(this)->children();
74   }
75 };
76 
77 /// This is a base class for any OpenACC statement-level constructs that have an
78 /// associated statement. This class is not intended to be instantiated, but is
79 /// a convenient place to hold the associated statement.
80 class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
81   friend class ASTStmtWriter;
82   friend class ASTStmtReader;
83   template <typename Derived> friend class RecursiveASTVisitor;
84   Stmt *AssociatedStmt = nullptr;
85 
86 protected:
OpenACCAssociatedStmtConstruct(StmtClass SC,OpenACCDirectiveKind K,SourceLocation Start,SourceLocation DirectiveLoc,SourceLocation End,Stmt * AssocStmt)87   OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K,
88                                  SourceLocation Start,
89                                  SourceLocation DirectiveLoc,
90                                  SourceLocation End, Stmt *AssocStmt)
91       : OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End),
92         AssociatedStmt(AssocStmt) {}
93 
setAssociatedStmt(Stmt * S)94   void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; }
getAssociatedStmt()95   Stmt *getAssociatedStmt() { return AssociatedStmt; }
getAssociatedStmt()96   const Stmt *getAssociatedStmt() const {
97     return const_cast<OpenACCAssociatedStmtConstruct *>(this)
98         ->getAssociatedStmt();
99   }
100 
101 public:
classof(const Stmt * T)102   static bool classof(const Stmt *T) {
103     return false;
104   }
105 
children()106   child_range children() {
107     if (getAssociatedStmt())
108       return child_range(&AssociatedStmt, &AssociatedStmt + 1);
109     return child_range(child_iterator(), child_iterator());
110   }
111 
children()112   const_child_range children() const {
113     return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
114   }
115 };
116 
117 class OpenACCLoopConstruct;
118 /// This class represents a compute construct, representing a 'Kind' of
119 /// `parallel', 'serial', or 'kernel'. These constructs are associated with a
120 /// 'structured block', defined as:
121 ///
122 ///  in C or C++, an executable statement, possibly compound, with a single
123 ///  entry at the top and a single exit at the bottom
124 ///
125 /// At the moment there is no real motivation to have a different AST node for
126 /// those three, as they are semantically identical, and have only minor
127 /// differences in the permitted list of clauses, which can be differentiated by
128 /// the 'Kind'.
129 class OpenACCComputeConstruct final
130     : public OpenACCAssociatedStmtConstruct,
131       public llvm::TrailingObjects<OpenACCComputeConstruct,
132                                    const OpenACCClause *> {
133   friend class ASTStmtWriter;
134   friend class ASTStmtReader;
135   friend class ASTContext;
OpenACCComputeConstruct(unsigned NumClauses)136   OpenACCComputeConstruct(unsigned NumClauses)
137       : OpenACCAssociatedStmtConstruct(
138             OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
139             SourceLocation{}, SourceLocation{}, SourceLocation{},
140             /*AssociatedStmt=*/nullptr) {
141     // We cannot send the TrailingObjects storage to the base class (which holds
142     // a reference to the data) until it is constructed, so we have to set it
143     // separately here.
144     std::uninitialized_value_construct(
145         getTrailingObjects<const OpenACCClause *>(),
146         getTrailingObjects<const OpenACCClause *>() + NumClauses);
147     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
148                                   NumClauses));
149   }
150 
OpenACCComputeConstruct(OpenACCDirectiveKind K,SourceLocation Start,SourceLocation DirectiveLoc,SourceLocation End,ArrayRef<const OpenACCClause * > Clauses,Stmt * StructuredBlock)151   OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
152                           SourceLocation DirectiveLoc, SourceLocation End,
153                           ArrayRef<const OpenACCClause *> Clauses,
154                           Stmt *StructuredBlock)
155       : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
156                                        DirectiveLoc, End, StructuredBlock) {
157     assert(isOpenACCComputeDirectiveKind(K) &&
158            "Only parallel, serial, and kernels constructs should be "
159            "represented by this type");
160 
161     // Initialize the trailing storage.
162     std::uninitialized_copy(Clauses.begin(), Clauses.end(),
163                             getTrailingObjects<const OpenACCClause *>());
164 
165     setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
166                                   Clauses.size()));
167   }
168 
setStructuredBlock(Stmt * S)169   void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
170   // Serialization helper function that searches the structured block for 'loop'
171   // constructs that should be associated with this, and sets their parent
172   // compute construct to this one. This isn't necessary normally, since we have
173   // the ability to record the state during parsing.
174   void findAndSetChildLoops();
175 
176 public:
classof(const Stmt * T)177   static bool classof(const Stmt *T) {
178     return T->getStmtClass() == OpenACCComputeConstructClass;
179   }
180 
181   static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
182                                               unsigned NumClauses);
183   static OpenACCComputeConstruct *
184   Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
185          SourceLocation DirectiveLoc, SourceLocation EndLoc,
186          ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock,
187          ArrayRef<OpenACCLoopConstruct *> AssociatedLoopConstructs);
188 
getStructuredBlock()189   Stmt *getStructuredBlock() { return getAssociatedStmt(); }
getStructuredBlock()190   const Stmt *getStructuredBlock() const {
191     return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
192   }
193 };
194 /// This class represents a 'loop' construct.  The 'loop' construct applies to a
195 /// 'for' loop (or range-for loop), and is optionally associated with a Compute
196 /// Construct.
197 class OpenACCLoopConstruct final
198     : public OpenACCAssociatedStmtConstruct,
199       public llvm::TrailingObjects<OpenACCLoopConstruct,
200                                    const OpenACCClause *> {
201   // The compute construct this loop is associated with, or nullptr if this is
202   // an orphaned loop construct, or if it hasn't been set yet.  Because we
203   // construct the directives at the end of their statement, the 'parent'
204   // construct is not yet available at the time of construction, so this needs
205   // to be set 'later'.
206   const OpenACCComputeConstruct *ParentComputeConstruct = nullptr;
207 
208   friend class ASTStmtWriter;
209   friend class ASTStmtReader;
210   friend class ASTContext;
211   friend class OpenACCComputeConstruct;
212 
213   OpenACCLoopConstruct(unsigned NumClauses);
214 
215   OpenACCLoopConstruct(SourceLocation Start, SourceLocation DirLoc,
216                        SourceLocation End,
217                        ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
218   void setLoop(Stmt *Loop);
219 
setParentComputeConstruct(OpenACCComputeConstruct * CC)220   void setParentComputeConstruct(OpenACCComputeConstruct *CC) {
221     assert(!ParentComputeConstruct && "Parent already set?");
222     ParentComputeConstruct = CC;
223   }
224 
225 public:
classof(const Stmt * T)226   static bool classof(const Stmt *T) {
227     return T->getStmtClass() == OpenACCLoopConstructClass;
228   }
229 
230   static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C,
231                                            unsigned NumClauses);
232 
233   static OpenACCLoopConstruct *
234   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation DirLoc,
235          SourceLocation EndLoc, ArrayRef<const OpenACCClause *> Clauses,
236          Stmt *Loop);
237 
getLoop()238   Stmt *getLoop() { return getAssociatedStmt(); }
getLoop()239   const Stmt *getLoop() const {
240     return const_cast<OpenACCLoopConstruct *>(this)->getLoop();
241   }
242 
243   /// OpenACC 3.3 2.9:
244   /// An orphaned loop construct is a loop construct that is not lexically
245   /// enclosed within a compute construct. The parent compute construct of a
246   /// loop construct is the nearest compute construct that lexically contains
247   /// the loop construct.
isOrphanedLoopConstruct()248   bool isOrphanedLoopConstruct() const {
249     return ParentComputeConstruct == nullptr;
250   }
getParentComputeConstruct()251   const OpenACCComputeConstruct *getParentComputeConstruct() const {
252     return ParentComputeConstruct;
253   }
254 };
255 } // namespace clang
256 #endif // LLVM_CLANG_AST_STMTOPENACC_H
257