1 //===----- SemaOpenACC.h - Semantic Analysis for OpenACC constructs -------===// 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 declares semantic analysis for OpenACC constructs and 10 /// clauses. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_SEMA_SEMAOPENACC_H 15 #define LLVM_CLANG_SEMA_SEMAOPENACC_H 16 17 #include "clang/AST/DeclGroup.h" 18 #include "clang/AST/StmtOpenACC.h" 19 #include "clang/Basic/OpenACCKinds.h" 20 #include "clang/Basic/SourceLocation.h" 21 #include "clang/Sema/Ownership.h" 22 #include "clang/Sema/SemaBase.h" 23 #include <variant> 24 25 namespace clang { 26 class OpenACCClause; 27 28 class SemaOpenACC : public SemaBase { 29 private: 30 /// A collection of loop constructs in the compute construct scope that 31 /// haven't had their 'parent' compute construct set yet. Entires will only be 32 /// made to this list in the case where we know the loop isn't an orphan. 33 llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs; 34 /// Whether we are inside of a compute construct, and should add loops to the 35 /// above collection. 36 bool InsideComputeConstruct = false; 37 38 public: 39 // Redeclaration of the version in OpenACCClause.h. 40 using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>; 41 42 /// A type to represent all the data for an OpenACC Clause that has been 43 /// parsed, but not yet created/semantically analyzed. This is effectively a 44 /// discriminated union on the 'Clause Kind', with all of the individual 45 /// clause details stored in a std::variant. 46 class OpenACCParsedClause { 47 OpenACCDirectiveKind DirKind; 48 OpenACCClauseKind ClauseKind; 49 SourceRange ClauseRange; 50 SourceLocation LParenLoc; 51 52 struct DefaultDetails { 53 OpenACCDefaultClauseKind DefaultClauseKind; 54 }; 55 56 struct ConditionDetails { 57 Expr *ConditionExpr; 58 }; 59 60 struct IntExprDetails { 61 SmallVector<Expr *> IntExprs; 62 }; 63 64 struct VarListDetails { 65 SmallVector<Expr *> VarList; 66 bool IsReadOnly; 67 bool IsZero; 68 }; 69 70 struct WaitDetails { 71 Expr *DevNumExpr; 72 SourceLocation QueuesLoc; 73 SmallVector<Expr *> QueueIdExprs; 74 }; 75 76 struct DeviceTypeDetails { 77 SmallVector<DeviceTypeArgument> Archs; 78 }; 79 struct ReductionDetails { 80 OpenACCReductionOperator Op; 81 SmallVector<Expr *> VarList; 82 }; 83 84 std::variant<std::monostate, DefaultDetails, ConditionDetails, 85 IntExprDetails, VarListDetails, WaitDetails, DeviceTypeDetails, 86 ReductionDetails> 87 Details = std::monostate{}; 88 89 public: OpenACCParsedClause(OpenACCDirectiveKind DirKind,OpenACCClauseKind ClauseKind,SourceLocation BeginLoc)90 OpenACCParsedClause(OpenACCDirectiveKind DirKind, 91 OpenACCClauseKind ClauseKind, SourceLocation BeginLoc) 92 : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {} 93 getDirectiveKind()94 OpenACCDirectiveKind getDirectiveKind() const { return DirKind; } 95 getClauseKind()96 OpenACCClauseKind getClauseKind() const { return ClauseKind; } 97 getBeginLoc()98 SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); } 99 getLParenLoc()100 SourceLocation getLParenLoc() const { return LParenLoc; } 101 getEndLoc()102 SourceLocation getEndLoc() const { return ClauseRange.getEnd(); } 103 getDefaultClauseKind()104 OpenACCDefaultClauseKind getDefaultClauseKind() const { 105 assert(ClauseKind == OpenACCClauseKind::Default && 106 "Parsed clause is not a default clause"); 107 return std::get<DefaultDetails>(Details).DefaultClauseKind; 108 } 109 getConditionExpr()110 const Expr *getConditionExpr() const { 111 return const_cast<OpenACCParsedClause *>(this)->getConditionExpr(); 112 } 113 getConditionExpr()114 Expr *getConditionExpr() { 115 assert((ClauseKind == OpenACCClauseKind::If || 116 (ClauseKind == OpenACCClauseKind::Self && 117 DirKind != OpenACCDirectiveKind::Update)) && 118 "Parsed clause kind does not have a condition expr"); 119 120 // 'self' has an optional ConditionExpr, so be tolerant of that. This will 121 // assert in variant otherwise. 122 if (ClauseKind == OpenACCClauseKind::Self && 123 std::holds_alternative<std::monostate>(Details)) 124 return nullptr; 125 126 return std::get<ConditionDetails>(Details).ConditionExpr; 127 } 128 getNumIntExprs()129 unsigned getNumIntExprs() const { 130 assert((ClauseKind == OpenACCClauseKind::NumGangs || 131 ClauseKind == OpenACCClauseKind::NumWorkers || 132 ClauseKind == OpenACCClauseKind::Async || 133 ClauseKind == OpenACCClauseKind::VectorLength) && 134 "Parsed clause kind does not have a int exprs"); 135 136 // 'async' and 'wait' have an optional IntExpr, so be tolerant of that. 137 if ((ClauseKind == OpenACCClauseKind::Async || 138 ClauseKind == OpenACCClauseKind::Wait) && 139 std::holds_alternative<std::monostate>(Details)) 140 return 0; 141 return std::get<IntExprDetails>(Details).IntExprs.size(); 142 } 143 getQueuesLoc()144 SourceLocation getQueuesLoc() const { 145 assert(ClauseKind == OpenACCClauseKind::Wait && 146 "Parsed clause kind does not have a queues location"); 147 148 if (std::holds_alternative<std::monostate>(Details)) 149 return SourceLocation{}; 150 151 return std::get<WaitDetails>(Details).QueuesLoc; 152 } 153 getDevNumExpr()154 Expr *getDevNumExpr() const { 155 assert(ClauseKind == OpenACCClauseKind::Wait && 156 "Parsed clause kind does not have a device number expr"); 157 158 if (std::holds_alternative<std::monostate>(Details)) 159 return nullptr; 160 161 return std::get<WaitDetails>(Details).DevNumExpr; 162 } 163 getQueueIdExprs()164 ArrayRef<Expr *> getQueueIdExprs() const { 165 assert(ClauseKind == OpenACCClauseKind::Wait && 166 "Parsed clause kind does not have a queue id expr list"); 167 168 if (std::holds_alternative<std::monostate>(Details)) 169 return ArrayRef<Expr *>{std::nullopt}; 170 171 return std::get<WaitDetails>(Details).QueueIdExprs; 172 } 173 getIntExprs()174 ArrayRef<Expr *> getIntExprs() { 175 assert((ClauseKind == OpenACCClauseKind::NumGangs || 176 ClauseKind == OpenACCClauseKind::NumWorkers || 177 ClauseKind == OpenACCClauseKind::Async || 178 ClauseKind == OpenACCClauseKind::VectorLength) && 179 "Parsed clause kind does not have a int exprs"); 180 181 return std::get<IntExprDetails>(Details).IntExprs; 182 } 183 getIntExprs()184 ArrayRef<Expr *> getIntExprs() const { 185 return const_cast<OpenACCParsedClause *>(this)->getIntExprs(); 186 } 187 getReductionOp()188 OpenACCReductionOperator getReductionOp() const { 189 return std::get<ReductionDetails>(Details).Op; 190 } 191 getVarList()192 ArrayRef<Expr *> getVarList() { 193 assert((ClauseKind == OpenACCClauseKind::Private || 194 ClauseKind == OpenACCClauseKind::NoCreate || 195 ClauseKind == OpenACCClauseKind::Present || 196 ClauseKind == OpenACCClauseKind::Copy || 197 ClauseKind == OpenACCClauseKind::PCopy || 198 ClauseKind == OpenACCClauseKind::PresentOrCopy || 199 ClauseKind == OpenACCClauseKind::CopyIn || 200 ClauseKind == OpenACCClauseKind::PCopyIn || 201 ClauseKind == OpenACCClauseKind::PresentOrCopyIn || 202 ClauseKind == OpenACCClauseKind::CopyOut || 203 ClauseKind == OpenACCClauseKind::PCopyOut || 204 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 205 ClauseKind == OpenACCClauseKind::Create || 206 ClauseKind == OpenACCClauseKind::PCreate || 207 ClauseKind == OpenACCClauseKind::PresentOrCreate || 208 ClauseKind == OpenACCClauseKind::Attach || 209 ClauseKind == OpenACCClauseKind::DevicePtr || 210 ClauseKind == OpenACCClauseKind::Reduction || 211 ClauseKind == OpenACCClauseKind::FirstPrivate) && 212 "Parsed clause kind does not have a var-list"); 213 214 if (ClauseKind == OpenACCClauseKind::Reduction) 215 return std::get<ReductionDetails>(Details).VarList; 216 217 return std::get<VarListDetails>(Details).VarList; 218 } 219 getVarList()220 ArrayRef<Expr *> getVarList() const { 221 return const_cast<OpenACCParsedClause *>(this)->getVarList(); 222 } 223 isReadOnly()224 bool isReadOnly() const { 225 assert((ClauseKind == OpenACCClauseKind::CopyIn || 226 ClauseKind == OpenACCClauseKind::PCopyIn || 227 ClauseKind == OpenACCClauseKind::PresentOrCopyIn) && 228 "Only copyin accepts 'readonly:' tag"); 229 return std::get<VarListDetails>(Details).IsReadOnly; 230 } 231 isZero()232 bool isZero() const { 233 assert((ClauseKind == OpenACCClauseKind::CopyOut || 234 ClauseKind == OpenACCClauseKind::PCopyOut || 235 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 236 ClauseKind == OpenACCClauseKind::Create || 237 ClauseKind == OpenACCClauseKind::PCreate || 238 ClauseKind == OpenACCClauseKind::PresentOrCreate) && 239 "Only copyout/create accepts 'zero' tag"); 240 return std::get<VarListDetails>(Details).IsZero; 241 } 242 getDeviceTypeArchitectures()243 ArrayRef<DeviceTypeArgument> getDeviceTypeArchitectures() const { 244 assert((ClauseKind == OpenACCClauseKind::DeviceType || 245 ClauseKind == OpenACCClauseKind::DType) && 246 "Only 'device_type'/'dtype' has a device-type-arg list"); 247 return std::get<DeviceTypeDetails>(Details).Archs; 248 } 249 setLParenLoc(SourceLocation EndLoc)250 void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } setEndLoc(SourceLocation EndLoc)251 void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } 252 setDefaultDetails(OpenACCDefaultClauseKind DefKind)253 void setDefaultDetails(OpenACCDefaultClauseKind DefKind) { 254 assert(ClauseKind == OpenACCClauseKind::Default && 255 "Parsed clause is not a default clause"); 256 Details = DefaultDetails{DefKind}; 257 } 258 setConditionDetails(Expr * ConditionExpr)259 void setConditionDetails(Expr *ConditionExpr) { 260 assert((ClauseKind == OpenACCClauseKind::If || 261 (ClauseKind == OpenACCClauseKind::Self && 262 DirKind != OpenACCDirectiveKind::Update)) && 263 "Parsed clause kind does not have a condition expr"); 264 // In C++ we can count on this being a 'bool', but in C this gets left as 265 // some sort of scalar that codegen will have to take care of converting. 266 assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() || 267 ConditionExpr->getType()->isScalarType()) && 268 "Condition expression type not scalar/dependent"); 269 270 Details = ConditionDetails{ConditionExpr}; 271 } 272 setIntExprDetails(ArrayRef<Expr * > IntExprs)273 void setIntExprDetails(ArrayRef<Expr *> IntExprs) { 274 assert((ClauseKind == OpenACCClauseKind::NumGangs || 275 ClauseKind == OpenACCClauseKind::NumWorkers || 276 ClauseKind == OpenACCClauseKind::Async || 277 ClauseKind == OpenACCClauseKind::VectorLength) && 278 "Parsed clause kind does not have a int exprs"); 279 Details = IntExprDetails{{IntExprs.begin(), IntExprs.end()}}; 280 } setIntExprDetails(llvm::SmallVector<Expr * > && IntExprs)281 void setIntExprDetails(llvm::SmallVector<Expr *> &&IntExprs) { 282 assert((ClauseKind == OpenACCClauseKind::NumGangs || 283 ClauseKind == OpenACCClauseKind::NumWorkers || 284 ClauseKind == OpenACCClauseKind::Async || 285 ClauseKind == OpenACCClauseKind::VectorLength) && 286 "Parsed clause kind does not have a int exprs"); 287 Details = IntExprDetails{std::move(IntExprs)}; 288 } 289 setVarListDetails(ArrayRef<Expr * > VarList,bool IsReadOnly,bool IsZero)290 void setVarListDetails(ArrayRef<Expr *> VarList, bool IsReadOnly, 291 bool IsZero) { 292 assert((ClauseKind == OpenACCClauseKind::Private || 293 ClauseKind == OpenACCClauseKind::NoCreate || 294 ClauseKind == OpenACCClauseKind::Present || 295 ClauseKind == OpenACCClauseKind::Copy || 296 ClauseKind == OpenACCClauseKind::PCopy || 297 ClauseKind == OpenACCClauseKind::PresentOrCopy || 298 ClauseKind == OpenACCClauseKind::CopyIn || 299 ClauseKind == OpenACCClauseKind::PCopyIn || 300 ClauseKind == OpenACCClauseKind::PresentOrCopyIn || 301 ClauseKind == OpenACCClauseKind::CopyOut || 302 ClauseKind == OpenACCClauseKind::PCopyOut || 303 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 304 ClauseKind == OpenACCClauseKind::Create || 305 ClauseKind == OpenACCClauseKind::PCreate || 306 ClauseKind == OpenACCClauseKind::PresentOrCreate || 307 ClauseKind == OpenACCClauseKind::Attach || 308 ClauseKind == OpenACCClauseKind::DevicePtr || 309 ClauseKind == OpenACCClauseKind::FirstPrivate) && 310 "Parsed clause kind does not have a var-list"); 311 assert((!IsReadOnly || ClauseKind == OpenACCClauseKind::CopyIn || 312 ClauseKind == OpenACCClauseKind::PCopyIn || 313 ClauseKind == OpenACCClauseKind::PresentOrCopyIn) && 314 "readonly: tag only valid on copyin"); 315 assert((!IsZero || ClauseKind == OpenACCClauseKind::CopyOut || 316 ClauseKind == OpenACCClauseKind::PCopyOut || 317 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 318 ClauseKind == OpenACCClauseKind::Create || 319 ClauseKind == OpenACCClauseKind::PCreate || 320 ClauseKind == OpenACCClauseKind::PresentOrCreate) && 321 "zero: tag only valid on copyout/create"); 322 Details = 323 VarListDetails{{VarList.begin(), VarList.end()}, IsReadOnly, IsZero}; 324 } 325 setVarListDetails(llvm::SmallVector<Expr * > && VarList,bool IsReadOnly,bool IsZero)326 void setVarListDetails(llvm::SmallVector<Expr *> &&VarList, bool IsReadOnly, 327 bool IsZero) { 328 assert((ClauseKind == OpenACCClauseKind::Private || 329 ClauseKind == OpenACCClauseKind::NoCreate || 330 ClauseKind == OpenACCClauseKind::Present || 331 ClauseKind == OpenACCClauseKind::Copy || 332 ClauseKind == OpenACCClauseKind::PCopy || 333 ClauseKind == OpenACCClauseKind::PresentOrCopy || 334 ClauseKind == OpenACCClauseKind::CopyIn || 335 ClauseKind == OpenACCClauseKind::PCopyIn || 336 ClauseKind == OpenACCClauseKind::PresentOrCopyIn || 337 ClauseKind == OpenACCClauseKind::CopyOut || 338 ClauseKind == OpenACCClauseKind::PCopyOut || 339 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 340 ClauseKind == OpenACCClauseKind::Create || 341 ClauseKind == OpenACCClauseKind::PCreate || 342 ClauseKind == OpenACCClauseKind::PresentOrCreate || 343 ClauseKind == OpenACCClauseKind::Attach || 344 ClauseKind == OpenACCClauseKind::DevicePtr || 345 ClauseKind == OpenACCClauseKind::FirstPrivate) && 346 "Parsed clause kind does not have a var-list"); 347 assert((!IsReadOnly || ClauseKind == OpenACCClauseKind::CopyIn || 348 ClauseKind == OpenACCClauseKind::PCopyIn || 349 ClauseKind == OpenACCClauseKind::PresentOrCopyIn) && 350 "readonly: tag only valid on copyin"); 351 assert((!IsZero || ClauseKind == OpenACCClauseKind::CopyOut || 352 ClauseKind == OpenACCClauseKind::PCopyOut || 353 ClauseKind == OpenACCClauseKind::PresentOrCopyOut || 354 ClauseKind == OpenACCClauseKind::Create || 355 ClauseKind == OpenACCClauseKind::PCreate || 356 ClauseKind == OpenACCClauseKind::PresentOrCreate) && 357 "zero: tag only valid on copyout/create"); 358 Details = VarListDetails{std::move(VarList), IsReadOnly, IsZero}; 359 } 360 setReductionDetails(OpenACCReductionOperator Op,llvm::SmallVector<Expr * > && VarList)361 void setReductionDetails(OpenACCReductionOperator Op, 362 llvm::SmallVector<Expr *> &&VarList) { 363 assert(ClauseKind == OpenACCClauseKind::Reduction && 364 "reduction details only valid on reduction"); 365 Details = ReductionDetails{Op, std::move(VarList)}; 366 } 367 setWaitDetails(Expr * DevNum,SourceLocation QueuesLoc,llvm::SmallVector<Expr * > && IntExprs)368 void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc, 369 llvm::SmallVector<Expr *> &&IntExprs) { 370 assert(ClauseKind == OpenACCClauseKind::Wait && 371 "Parsed clause kind does not have a wait-details"); 372 Details = WaitDetails{DevNum, QueuesLoc, std::move(IntExprs)}; 373 } 374 setDeviceTypeDetails(llvm::SmallVector<DeviceTypeArgument> && Archs)375 void setDeviceTypeDetails(llvm::SmallVector<DeviceTypeArgument> &&Archs) { 376 assert((ClauseKind == OpenACCClauseKind::DeviceType || 377 ClauseKind == OpenACCClauseKind::DType) && 378 "Only 'device_type'/'dtype' has a device-type-arg list"); 379 Details = DeviceTypeDetails{std::move(Archs)}; 380 } 381 }; 382 383 SemaOpenACC(Sema &S); 384 385 /// Called after parsing an OpenACC Clause so that it can be checked. 386 OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses, 387 OpenACCParsedClause &Clause); 388 389 /// Called after the construct has been parsed, but clauses haven't been 390 /// parsed. This allows us to diagnose not-implemented, as well as set up any 391 /// state required for parsing the clauses. 392 void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc); 393 394 /// Called after the directive, including its clauses, have been parsed and 395 /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES 396 /// happen before any associated declarations or statements have been parsed. 397 /// This function is only called when we are parsing a 'statement' context. 398 bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); 399 400 /// Called after the directive, including its clauses, have been parsed and 401 /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES 402 /// happen before any associated declarations or statements have been parsed. 403 /// This function is only called when we are parsing a 'Decl' context. 404 bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); 405 /// Called when we encounter an associated statement for our construct, this 406 /// should check legality of the statement as it appertains to this Construct. 407 StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc, 408 OpenACCDirectiveKind K, StmtResult AssocStmt); 409 410 /// Called after the directive has been completely parsed, including the 411 /// declaration group or associated statement. 412 StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, 413 SourceLocation StartLoc, 414 SourceLocation DirLoc, 415 SourceLocation EndLoc, 416 ArrayRef<OpenACCClause *> Clauses, 417 StmtResult AssocStmt); 418 419 /// Called after the directive has been completely parsed, including the 420 /// declaration group or associated statement. 421 DeclGroupRef ActOnEndDeclDirective(); 422 423 /// Called when encountering an 'int-expr' for OpenACC, and manages 424 /// conversions and diagnostics to 'int'. 425 ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, 426 SourceLocation Loc, Expr *IntExpr); 427 428 /// Called when encountering a 'var' for OpenACC, ensures it is actually a 429 /// declaration reference to a variable of the correct type. 430 ExprResult ActOnVar(OpenACCClauseKind CK, Expr *VarExpr); 431 432 /// Called while semantically analyzing the reduction clause, ensuring the var 433 /// is the correct kind of reference. 434 ExprResult CheckReductionVar(Expr *VarExpr); 435 436 /// Called to check the 'var' type is a variable of pointer type, necessary 437 /// for 'deviceptr' and 'attach' clauses. Returns true on success. 438 bool CheckVarIsPointerType(OpenACCClauseKind ClauseKind, Expr *VarExpr); 439 440 /// Checks and creates an Array Section used in an OpenACC construct/clause. 441 ExprResult ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, 442 Expr *LowerBound, 443 SourceLocation ColonLocFirst, Expr *Length, 444 SourceLocation RBLoc); 445 446 /// Helper type for the registration/assignment of constructs that need to 447 /// 'know' about their parent constructs and hold a reference to them, such as 448 /// Loop needing its parent construct. 449 class AssociatedStmtRAII { 450 SemaOpenACC &SemaRef; 451 bool WasInsideComputeConstruct; 452 OpenACCDirectiveKind DirKind; 453 llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs; 454 455 public: 456 AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind); 457 ~AssociatedStmtRAII(); 458 }; 459 }; 460 461 } // namespace clang 462 463 #endif // LLVM_CLANG_SEMA_SEMAOPENACC_H 464