596 lines · cpp
1//===--- StmtOpenACC.cpp - Classes 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the subclasses of Stmt class declared in StmtOpenACC.h10//11//===----------------------------------------------------------------------===//12 13#include "clang/AST/StmtOpenACC.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/ExprCXX.h"16#include "clang/AST/StmtCXX.h"17 18using namespace clang;19 20OpenACCComputeConstruct *21OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) {22 void *Mem = C.Allocate(23 OpenACCComputeConstruct::totalSizeToAlloc<const OpenACCClause *>(24 NumClauses));25 auto *Inst = new (Mem) OpenACCComputeConstruct(NumClauses);26 return Inst;27}28 29OpenACCComputeConstruct *OpenACCComputeConstruct::Create(30 const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,31 SourceLocation DirLoc, SourceLocation EndLoc,32 ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock) {33 void *Mem = C.Allocate(34 OpenACCComputeConstruct::totalSizeToAlloc<const OpenACCClause *>(35 Clauses.size()));36 auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, DirLoc, EndLoc,37 Clauses, StructuredBlock);38 return Inst;39}40 41OpenACCLoopConstruct::OpenACCLoopConstruct(unsigned NumClauses)42 : OpenACCAssociatedStmtConstruct(43 OpenACCLoopConstructClass, OpenACCDirectiveKind::Loop,44 SourceLocation{}, SourceLocation{}, SourceLocation{},45 /*AssociatedStmt=*/nullptr) {46 std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);47 setClauseList(getTrailingObjects(NumClauses));48}49 50OpenACCLoopConstruct::OpenACCLoopConstruct(51 OpenACCDirectiveKind ParentKind, SourceLocation Start,52 SourceLocation DirLoc, SourceLocation End,53 ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop)54 : OpenACCAssociatedStmtConstruct(OpenACCLoopConstructClass,55 OpenACCDirectiveKind::Loop, Start, DirLoc,56 End, Loop),57 ParentComputeConstructKind(ParentKind) {58 // accept 'nullptr' for the loop. This is diagnosed somewhere, but this gives59 // us some level of AST fidelity in the error case.60 assert((Loop == nullptr || isa<ForStmt, CXXForRangeStmt>(Loop)) &&61 "Associated Loop not a for loop?");62 // Initialize the trailing storage.63 llvm::uninitialized_copy(Clauses, getTrailingObjects());64 65 setClauseList(getTrailingObjects(Clauses.size()));66}67 68OpenACCLoopConstruct *OpenACCLoopConstruct::CreateEmpty(const ASTContext &C,69 unsigned NumClauses) {70 void *Mem =71 C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc<const OpenACCClause *>(72 NumClauses));73 auto *Inst = new (Mem) OpenACCLoopConstruct(NumClauses);74 return Inst;75}76 77OpenACCLoopConstruct *OpenACCLoopConstruct::Create(78 const ASTContext &C, OpenACCDirectiveKind ParentKind,79 SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation EndLoc,80 ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop) {81 void *Mem =82 C.Allocate(OpenACCLoopConstruct::totalSizeToAlloc<const OpenACCClause *>(83 Clauses.size()));84 auto *Inst = new (Mem)85 OpenACCLoopConstruct(ParentKind, BeginLoc, DirLoc, EndLoc, Clauses, Loop);86 return Inst;87}88 89OpenACCCombinedConstruct *90OpenACCCombinedConstruct::CreateEmpty(const ASTContext &C,91 unsigned NumClauses) {92 void *Mem = C.Allocate(93 OpenACCCombinedConstruct::totalSizeToAlloc<const OpenACCClause *>(94 NumClauses));95 auto *Inst = new (Mem) OpenACCCombinedConstruct(NumClauses);96 return Inst;97}98 99OpenACCCombinedConstruct *OpenACCCombinedConstruct::Create(100 const ASTContext &C, OpenACCDirectiveKind DK, SourceLocation BeginLoc,101 SourceLocation DirLoc, SourceLocation EndLoc,102 ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop) {103 void *Mem = C.Allocate(104 OpenACCCombinedConstruct::totalSizeToAlloc<const OpenACCClause *>(105 Clauses.size()));106 auto *Inst = new (Mem)107 OpenACCCombinedConstruct(DK, BeginLoc, DirLoc, EndLoc, Clauses, Loop);108 return Inst;109}110 111OpenACCDataConstruct *OpenACCDataConstruct::CreateEmpty(const ASTContext &C,112 unsigned NumClauses) {113 void *Mem =114 C.Allocate(OpenACCDataConstruct::totalSizeToAlloc<const OpenACCClause *>(115 NumClauses));116 auto *Inst = new (Mem) OpenACCDataConstruct(NumClauses);117 return Inst;118}119 120OpenACCDataConstruct *121OpenACCDataConstruct::Create(const ASTContext &C, SourceLocation Start,122 SourceLocation DirectiveLoc, SourceLocation End,123 ArrayRef<const OpenACCClause *> Clauses,124 Stmt *StructuredBlock) {125 void *Mem =126 C.Allocate(OpenACCDataConstruct::totalSizeToAlloc<const OpenACCClause *>(127 Clauses.size()));128 auto *Inst = new (Mem)129 OpenACCDataConstruct(Start, DirectiveLoc, End, Clauses, StructuredBlock);130 return Inst;131}132 133OpenACCEnterDataConstruct *134OpenACCEnterDataConstruct::CreateEmpty(const ASTContext &C,135 unsigned NumClauses) {136 void *Mem = C.Allocate(137 OpenACCEnterDataConstruct::totalSizeToAlloc<const OpenACCClause *>(138 NumClauses));139 auto *Inst = new (Mem) OpenACCEnterDataConstruct(NumClauses);140 return Inst;141}142 143OpenACCEnterDataConstruct *OpenACCEnterDataConstruct::Create(144 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,145 SourceLocation End, ArrayRef<const OpenACCClause *> Clauses) {146 void *Mem = C.Allocate(147 OpenACCEnterDataConstruct::totalSizeToAlloc<const OpenACCClause *>(148 Clauses.size()));149 auto *Inst =150 new (Mem) OpenACCEnterDataConstruct(Start, DirectiveLoc, End, Clauses);151 return Inst;152}153 154OpenACCExitDataConstruct *155OpenACCExitDataConstruct::CreateEmpty(const ASTContext &C,156 unsigned NumClauses) {157 void *Mem = C.Allocate(158 OpenACCExitDataConstruct::totalSizeToAlloc<const OpenACCClause *>(159 NumClauses));160 auto *Inst = new (Mem) OpenACCExitDataConstruct(NumClauses);161 return Inst;162}163 164OpenACCExitDataConstruct *OpenACCExitDataConstruct::Create(165 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,166 SourceLocation End, ArrayRef<const OpenACCClause *> Clauses) {167 void *Mem = C.Allocate(168 OpenACCExitDataConstruct::totalSizeToAlloc<const OpenACCClause *>(169 Clauses.size()));170 auto *Inst =171 new (Mem) OpenACCExitDataConstruct(Start, DirectiveLoc, End, Clauses);172 return Inst;173}174 175OpenACCHostDataConstruct *176OpenACCHostDataConstruct::CreateEmpty(const ASTContext &C,177 unsigned NumClauses) {178 void *Mem = C.Allocate(179 OpenACCHostDataConstruct::totalSizeToAlloc<const OpenACCClause *>(180 NumClauses));181 auto *Inst = new (Mem) OpenACCHostDataConstruct(NumClauses);182 return Inst;183}184 185OpenACCHostDataConstruct *OpenACCHostDataConstruct::Create(186 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,187 SourceLocation End, ArrayRef<const OpenACCClause *> Clauses,188 Stmt *StructuredBlock) {189 void *Mem = C.Allocate(190 OpenACCHostDataConstruct::totalSizeToAlloc<const OpenACCClause *>(191 Clauses.size()));192 auto *Inst = new (Mem) OpenACCHostDataConstruct(Start, DirectiveLoc, End,193 Clauses, StructuredBlock);194 return Inst;195}196 197OpenACCWaitConstruct *OpenACCWaitConstruct::CreateEmpty(const ASTContext &C,198 unsigned NumExprs,199 unsigned NumClauses) {200 void *Mem = C.Allocate(201 OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>(202 NumExprs, NumClauses));203 204 auto *Inst = new (Mem) OpenACCWaitConstruct(NumExprs, NumClauses);205 return Inst;206}207 208OpenACCWaitConstruct *OpenACCWaitConstruct::Create(209 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,210 SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc,211 ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc, SourceLocation End,212 ArrayRef<const OpenACCClause *> Clauses) {213 214 assert(!llvm::is_contained(QueueIdExprs, nullptr));215 216 void *Mem = C.Allocate(217 OpenACCWaitConstruct::totalSizeToAlloc<Expr *, OpenACCClause *>(218 QueueIdExprs.size() + 1, Clauses.size()));219 220 auto *Inst = new (Mem)221 OpenACCWaitConstruct(Start, DirectiveLoc, LParenLoc, DevNumExpr,222 QueuesLoc, QueueIdExprs, RParenLoc, End, Clauses);223 return Inst;224}225OpenACCInitConstruct *OpenACCInitConstruct::CreateEmpty(const ASTContext &C,226 unsigned NumClauses) {227 void *Mem =228 C.Allocate(OpenACCInitConstruct::totalSizeToAlloc<const OpenACCClause *>(229 NumClauses));230 auto *Inst = new (Mem) OpenACCInitConstruct(NumClauses);231 return Inst;232}233 234OpenACCInitConstruct *235OpenACCInitConstruct::Create(const ASTContext &C, SourceLocation Start,236 SourceLocation DirectiveLoc, SourceLocation End,237 ArrayRef<const OpenACCClause *> Clauses) {238 void *Mem =239 C.Allocate(OpenACCInitConstruct::totalSizeToAlloc<const OpenACCClause *>(240 Clauses.size()));241 auto *Inst =242 new (Mem) OpenACCInitConstruct(Start, DirectiveLoc, End, Clauses);243 return Inst;244}245OpenACCShutdownConstruct *246OpenACCShutdownConstruct::CreateEmpty(const ASTContext &C,247 unsigned NumClauses) {248 void *Mem = C.Allocate(249 OpenACCShutdownConstruct::totalSizeToAlloc<const OpenACCClause *>(250 NumClauses));251 auto *Inst = new (Mem) OpenACCShutdownConstruct(NumClauses);252 return Inst;253}254 255OpenACCShutdownConstruct *OpenACCShutdownConstruct::Create(256 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,257 SourceLocation End, ArrayRef<const OpenACCClause *> Clauses) {258 void *Mem = C.Allocate(259 OpenACCShutdownConstruct::totalSizeToAlloc<const OpenACCClause *>(260 Clauses.size()));261 auto *Inst =262 new (Mem) OpenACCShutdownConstruct(Start, DirectiveLoc, End, Clauses);263 return Inst;264}265 266OpenACCSetConstruct *OpenACCSetConstruct::CreateEmpty(const ASTContext &C,267 unsigned NumClauses) {268 void *Mem = C.Allocate(269 OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>(NumClauses));270 auto *Inst = new (Mem) OpenACCSetConstruct(NumClauses);271 return Inst;272}273 274OpenACCSetConstruct *275OpenACCSetConstruct::Create(const ASTContext &C, SourceLocation Start,276 SourceLocation DirectiveLoc, SourceLocation End,277 ArrayRef<const OpenACCClause *> Clauses) {278 void *Mem =279 C.Allocate(OpenACCSetConstruct::totalSizeToAlloc<const OpenACCClause *>(280 Clauses.size()));281 auto *Inst = new (Mem) OpenACCSetConstruct(Start, DirectiveLoc, End, Clauses);282 return Inst;283}284 285OpenACCUpdateConstruct *286OpenACCUpdateConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) {287 void *Mem = C.Allocate(288 OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>(289 NumClauses));290 auto *Inst = new (Mem) OpenACCUpdateConstruct(NumClauses);291 return Inst;292}293 294OpenACCUpdateConstruct *295OpenACCUpdateConstruct::Create(const ASTContext &C, SourceLocation Start,296 SourceLocation DirectiveLoc, SourceLocation End,297 ArrayRef<const OpenACCClause *> Clauses) {298 void *Mem = C.Allocate(299 OpenACCUpdateConstruct::totalSizeToAlloc<const OpenACCClause *>(300 Clauses.size()));301 auto *Inst =302 new (Mem) OpenACCUpdateConstruct(Start, DirectiveLoc, End, Clauses);303 return Inst;304}305 306OpenACCAtomicConstruct *307OpenACCAtomicConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) {308 void *Mem = C.Allocate(309 OpenACCAtomicConstruct::totalSizeToAlloc<const OpenACCClause *>(310 NumClauses));311 auto *Inst = new (Mem) OpenACCAtomicConstruct(NumClauses);312 return Inst;313}314 315OpenACCAtomicConstruct *OpenACCAtomicConstruct::Create(316 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,317 OpenACCAtomicKind AtKind, SourceLocation End,318 ArrayRef<const OpenACCClause *> Clauses, Stmt *AssociatedStmt) {319 void *Mem = C.Allocate(320 OpenACCAtomicConstruct::totalSizeToAlloc<const OpenACCClause *>(321 Clauses.size()));322 auto *Inst = new (Mem) OpenACCAtomicConstruct(Start, DirectiveLoc, AtKind,323 End, Clauses, AssociatedStmt);324 return Inst;325}326 327static std::optional<std::pair<const Expr *, const Expr *>>328getBinaryAssignOpArgs(const Expr *Op, bool &IsCompoundAssign) {329 if (const auto *BO = dyn_cast<BinaryOperator>(Op)) {330 if (!BO->isAssignmentOp())331 return std::nullopt;332 IsCompoundAssign = BO->isCompoundAssignmentOp();333 return std::pair<const Expr *, const Expr *>(BO->getLHS(), BO->getRHS());334 }335 336 if (const auto *OO = dyn_cast<CXXOperatorCallExpr>(Op)) {337 if (!OO->isAssignmentOp())338 return std::nullopt;339 IsCompoundAssign = OO->getOperator() != OO_Equal;340 return std::pair<const Expr *, const Expr *>(OO->getArg(0), OO->getArg(1));341 }342 return std::nullopt;343}344static std::optional<std::pair<const Expr *, const Expr *>>345getBinaryAssignOpArgs(const Expr *Op) {346 bool IsCompoundAssign;347 return getBinaryAssignOpArgs(Op, IsCompoundAssign);348}349 350static std::optional<std::pair<const Expr *, bool>>351getUnaryOpArgs(const Expr *Op) {352 if (const auto *UO = dyn_cast<UnaryOperator>(Op))353 return {{UO->getSubExpr(), UO->isPostfix()}};354 355 if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(Op)) {356 // Post-inc/dec have a second unused argument to differentiate it, so we357 // accept -- or ++ as unary, or any operator call with only 1 arg.358 if (OpCall->getNumArgs() == 1 || OpCall->getOperator() == OO_PlusPlus ||359 OpCall->getOperator() == OO_MinusMinus)360 return {{OpCall->getArg(0), /*IsPostfix=*/OpCall->getNumArgs() == 1}};361 }362 363 return std::nullopt;364}365 366// Read is of the form `v = x;`, where both sides are scalar L-values. This is a367// BinaryOperator or CXXOperatorCallExpr.368static std::optional<OpenACCAtomicConstruct::SingleStmtInfo>369getReadStmtInfo(const Expr *E, bool ForAtomicComputeSingleStmt = false) {370 std::optional<std::pair<const Expr *, const Expr *>> BinaryArgs =371 getBinaryAssignOpArgs(E);372 373 if (!BinaryArgs)374 return std::nullopt;375 376 // We want the L-value for each side, so we ignore implicit casts.377 auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createRead(378 E, BinaryArgs->first->IgnoreImpCasts(),379 BinaryArgs->second->IgnoreImpCasts());380 381 // The atomic compute single-stmt variant has to do a 'fixup' step for the 'X'382 // value, since it is dependent on the RHS. So if we're in that version, we383 // skip the checks on X.384 if ((!ForAtomicComputeSingleStmt &&385 (!Res.X->isLValue() || !Res.X->getType()->isScalarType())) ||386 !Res.V->isLValue() || !Res.V->getType()->isScalarType())387 return std::nullopt;388 389 return Res;390}391 392// Write supports only the format 'x = expr', where the expression is scalar393// type, and 'x' is a scalar l value. As above, this can come in 2 forms;394// Binary Operator or CXXOperatorCallExpr.395static std::optional<OpenACCAtomicConstruct::SingleStmtInfo>396getWriteStmtInfo(const Expr *E) {397 std::optional<std::pair<const Expr *, const Expr *>> BinaryArgs =398 getBinaryAssignOpArgs(E);399 if (!BinaryArgs)400 return std::nullopt;401 // We want the L-value for ONLY the X side, so we ignore implicit casts. For402 // the right side (the expr), we emit it as an r-value so we need to403 // maintain implicit casts.404 auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createWrite(405 E, BinaryArgs->first->IgnoreImpCasts(), BinaryArgs->second);406 407 if (!Res.X->isLValue() || !Res.X->getType()->isScalarType())408 return std::nullopt;409 return Res;410}411 412static std::optional<OpenACCAtomicConstruct::SingleStmtInfo>413getUpdateStmtInfo(const Expr *E) {414 std::optional<std::pair<const Expr *, bool>> UnaryArgs = getUnaryOpArgs(E);415 if (UnaryArgs) {416 auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createUpdate(417 E, UnaryArgs->first->IgnoreImpCasts(), UnaryArgs->second);418 419 if (!Res.X->isLValue() || !Res.X->getType()->isScalarType())420 return std::nullopt;421 422 return Res;423 }424 425 bool IsRHSCompoundAssign = false;426 std::optional<std::pair<const Expr *, const Expr *>> BinaryArgs =427 getBinaryAssignOpArgs(E, IsRHSCompoundAssign);428 if (!BinaryArgs)429 return std::nullopt;430 431 auto Res = OpenACCAtomicConstruct::SingleStmtInfo::createUpdate(432 E, BinaryArgs->first->IgnoreImpCasts(), /*PostFixIncDec=*/false);433 434 if (!Res.X->isLValue() || !Res.X->getType()->isScalarType())435 return std::nullopt;436 437 // 'update' has to be either a compound-assignment operation, or438 // assignment-to-a-binary-op. Return nullopt if these are not the case.439 // If we are already compound-assign, we're done!440 if (IsRHSCompoundAssign)441 return Res;442 443 // else we have to check that we have a binary operator.444 const Expr *RHS = BinaryArgs->second->IgnoreImpCasts();445 446 if (isa<BinaryOperator>(RHS)) {447 return Res;448 } else if (const auto *OO = dyn_cast<CXXOperatorCallExpr>(RHS)) {449 if (OO->isInfixBinaryOp())450 return Res;451 }452 453 return std::nullopt;454}455 456/// The statement associated with an atomic capture comes in 1 of two forms: A457/// compound statement containing two statements, or a single statement. In458/// either case, the compound/single statement is decomposed into 2 separate459/// operations, eihter a read/write, read/update, or update/read. This function460/// figures out that information in the form listed in the standard (filling in461/// V, X, or Expr) for each of these operations.462static OpenACCAtomicConstruct::StmtInfo463getCaptureStmtInfo(const Stmt *AssocStmt) {464 465 if (const auto *CmpdStmt = dyn_cast<CompoundStmt>(AssocStmt)) {466 // We checked during Sema to ensure we only have 2 statements here, and467 // that both are expressions, we can look at these to see what the valid468 // options are.469 const Expr *Stmt1 = cast<Expr>(*CmpdStmt->body().begin())->IgnoreImpCasts();470 const Expr *Stmt2 =471 cast<Expr>(*(CmpdStmt->body().begin() + 1))->IgnoreImpCasts();472 473 // The compound statement form allows read/write, read/update, or474 // update/read. First we get the information for a 'Read' to see if this is475 // one of the former two.476 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Read =477 getReadStmtInfo(Stmt1);478 479 if (Read) {480 // READ : WRITE481 // v = x; x = expr482 // READ : UPDATE483 // v = x; x binop = expr484 // v = x; x = x binop expr485 // v = x; x = expr binop x486 // v = x; x++487 // v = x; ++x488 // v = x; x--489 // v = x; --x490 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Update =491 getUpdateStmtInfo(Stmt2);492 // Since we already know the first operation is a read, the second is493 // either an update, which we check, or a write, which we can assume next.494 if (Update)495 return OpenACCAtomicConstruct::StmtInfo::createReadUpdate(*Read,496 *Update);497 498 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Write =499 getWriteStmtInfo(Stmt2);500 return OpenACCAtomicConstruct::StmtInfo::createReadWrite(*Read, *Write);501 }502 // UPDATE: READ503 // x binop = expr; v = x504 // x = x binop expr; v = x505 // x = expr binop x ; v = x506 // ++ x; v = x507 // x++; v = x508 // --x; v = x509 // x--; v = x510 // Otherwise, it is one of the above forms for update/read.511 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Update =512 getUpdateStmtInfo(Stmt1);513 Read = getReadStmtInfo(Stmt2);514 515 return OpenACCAtomicConstruct::StmtInfo::createUpdateRead(*Update, *Read);516 } else {517 // All of the forms that can be done in a single line fall into 2518 // categories: update/read, or read/update. The special cases are the519 // postfix unary operators, which we have to make sure we do the 'read'520 // first. However, we still parse these as the RHS first, so we have a521 // 'reversing' step. READ: UPDATE v = x++; v = x--; UPDATE: READ v = ++x; v522 // = --x; v = x binop=expr v = x = x binop expr v = x = expr binop x523 524 const Expr *E = cast<const Expr>(AssocStmt);525 526 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Read =527 getReadStmtInfo(E, /*ForAtomicComputeSingleStmt=*/true);528 std::optional<OpenACCAtomicConstruct::SingleStmtInfo> Update =529 getUpdateStmtInfo(Read->X);530 531 // Fixup this, since the 'X' for the read is the result after write, but is532 // the same value as the LHS-most variable of the update(its X).533 Read->X = Update->X;534 535 // Postfix is a read FIRST, then an update.536 if (Update->IsPostfixIncDec)537 return OpenACCAtomicConstruct::StmtInfo::createReadUpdate(*Read, *Update);538 539 return OpenACCAtomicConstruct::StmtInfo::createUpdateRead(*Update, *Read);540 }541 return {};542}543 544const OpenACCAtomicConstruct::StmtInfo545OpenACCAtomicConstruct::getAssociatedStmtInfo() const {546 // This ends up being a vastly simplified version of SemaOpenACCAtomic, since547 // it doesn't have to worry about erroring out, but we should do a lot of548 // asserts to ensure we don't get off into the weeds.549 assert(getAssociatedStmt() && "invalid associated stmt?");550 551 switch (AtomicKind) {552 case OpenACCAtomicKind::Read:553 return OpenACCAtomicConstruct::StmtInfo{554 OpenACCAtomicConstruct::StmtInfo::StmtForm::Read,555 *getReadStmtInfo(cast<const Expr>(getAssociatedStmt())),556 OpenACCAtomicConstruct::SingleStmtInfo::Empty()};557 558 case OpenACCAtomicKind::Write:559 return OpenACCAtomicConstruct::StmtInfo{560 OpenACCAtomicConstruct::StmtInfo::StmtForm::Write,561 *getWriteStmtInfo(cast<const Expr>(getAssociatedStmt())),562 OpenACCAtomicConstruct::SingleStmtInfo::Empty()};563 564 case OpenACCAtomicKind::None:565 case OpenACCAtomicKind::Update:566 return OpenACCAtomicConstruct::StmtInfo{567 OpenACCAtomicConstruct::StmtInfo::StmtForm::Update,568 *getUpdateStmtInfo(cast<const Expr>(getAssociatedStmt())),569 OpenACCAtomicConstruct::SingleStmtInfo::Empty()};570 571 case OpenACCAtomicKind::Capture:572 return getCaptureStmtInfo(getAssociatedStmt());573 }574 575 llvm_unreachable("unknown OpenACC atomic kind");576}577 578OpenACCCacheConstruct *OpenACCCacheConstruct::CreateEmpty(const ASTContext &C,579 unsigned NumVars) {580 void *Mem =581 C.Allocate(OpenACCCacheConstruct::totalSizeToAlloc<Expr *>(NumVars));582 auto *Inst = new (Mem) OpenACCCacheConstruct(NumVars);583 return Inst;584}585 586OpenACCCacheConstruct *OpenACCCacheConstruct::Create(587 const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,588 SourceLocation LParenLoc, SourceLocation ReadOnlyLoc,589 ArrayRef<Expr *> VarList, SourceLocation RParenLoc, SourceLocation End) {590 void *Mem = C.Allocate(591 OpenACCCacheConstruct::totalSizeToAlloc<Expr *>(VarList.size()));592 auto *Inst = new (Mem) OpenACCCacheConstruct(593 Start, DirectiveLoc, LParenLoc, ReadOnlyLoc, VarList, RParenLoc, End);594 return Inst;595}596