brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.2 KiB · ec8ceb9 Raw
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