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