885 lines
37 KiB
C++
885 lines
37 KiB
C++
//===- StmtOpenACC.h - Classes for OpenACC directives ----------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// This file defines OpenACC AST classes for statement-level contructs.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_AST_STMTOPENACC_H
|
|
#define LLVM_CLANG_AST_STMTOPENACC_H
|
|
|
|
#include "clang/AST/OpenACCClause.h"
|
|
#include "clang/AST/Stmt.h"
|
|
#include "clang/Basic/OpenACCKinds.h"
|
|
#include "clang/Basic/SourceLocation.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include <memory>
|
|
|
|
namespace clang {
|
|
/// This is the base class for an OpenACC statement-level construct, other
|
|
/// construct types are expected to inherit from this.
|
|
class OpenACCConstructStmt : public Stmt {
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
/// The directive kind. Each implementation of this interface should handle
|
|
/// specific kinds.
|
|
OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
|
|
/// The location of the directive statement, from the '#' to the last token of
|
|
/// the directive.
|
|
SourceRange Range;
|
|
/// The location of the directive name.
|
|
SourceLocation DirectiveLoc;
|
|
|
|
/// The list of clauses. This is stored here as an ArrayRef, as this is the
|
|
/// most convienient place to access the list, however the list itself should
|
|
/// be stored in leaf nodes, likely in trailing-storage.
|
|
MutableArrayRef<const OpenACCClause *> Clauses;
|
|
|
|
protected:
|
|
OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
|
|
SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End)
|
|
: Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {}
|
|
|
|
// Used only for initialization, the leaf class can initialize this to
|
|
// trailing storage.
|
|
void setClauseList(MutableArrayRef<const OpenACCClause *> NewClauses) {
|
|
assert(Clauses.empty() && "Cannot change clause list");
|
|
Clauses = NewClauses;
|
|
}
|
|
|
|
public:
|
|
OpenACCDirectiveKind getDirectiveKind() const { return Kind; }
|
|
|
|
static bool classof(const Stmt *S) {
|
|
return S->getStmtClass() >= firstOpenACCConstructStmtConstant &&
|
|
S->getStmtClass() <= lastOpenACCConstructStmtConstant;
|
|
}
|
|
|
|
SourceLocation getBeginLoc() const { return Range.getBegin(); }
|
|
SourceLocation getEndLoc() const { return Range.getEnd(); }
|
|
SourceLocation getDirectiveLoc() const { return DirectiveLoc; }
|
|
ArrayRef<const OpenACCClause *> clauses() const { return Clauses; }
|
|
|
|
child_range children() {
|
|
return child_range(child_iterator(), child_iterator());
|
|
}
|
|
|
|
const_child_range children() const {
|
|
return const_cast<OpenACCConstructStmt *>(this)->children();
|
|
}
|
|
};
|
|
|
|
/// This is a base class for any OpenACC statement-level constructs that have an
|
|
/// associated statement. This class is not intended to be instantiated, but is
|
|
/// a convenient place to hold the associated statement.
|
|
class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
template <typename Derived> friend class RecursiveASTVisitor;
|
|
Stmt *AssociatedStmt = nullptr;
|
|
|
|
protected:
|
|
OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K,
|
|
SourceLocation Start,
|
|
SourceLocation DirectiveLoc,
|
|
SourceLocation End, Stmt *AssocStmt)
|
|
: OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End),
|
|
AssociatedStmt(AssocStmt) {}
|
|
|
|
void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; }
|
|
Stmt *getAssociatedStmt() { return AssociatedStmt; }
|
|
const Stmt *getAssociatedStmt() const {
|
|
return const_cast<OpenACCAssociatedStmtConstruct *>(this)
|
|
->getAssociatedStmt();
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return false;
|
|
}
|
|
|
|
child_range children() {
|
|
if (getAssociatedStmt())
|
|
return child_range(&AssociatedStmt, &AssociatedStmt + 1);
|
|
return child_range(child_iterator(), child_iterator());
|
|
}
|
|
|
|
const_child_range children() const {
|
|
return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
|
|
}
|
|
};
|
|
|
|
/// This class represents a compute construct, representing a 'Kind' of
|
|
/// `parallel', 'serial', or 'kernel'. These constructs are associated with a
|
|
/// 'structured block', defined as:
|
|
///
|
|
/// in C or C++, an executable statement, possibly compound, with a single
|
|
/// entry at the top and a single exit at the bottom
|
|
///
|
|
/// At the moment there is no real motivation to have a different AST node for
|
|
/// those three, as they are semantically identical, and have only minor
|
|
/// differences in the permitted list of clauses, which can be differentiated by
|
|
/// the 'Kind'.
|
|
class OpenACCComputeConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCComputeConstruct,
|
|
const OpenACCClause *> {
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
friend class ASTContext;
|
|
friend TrailingObjects;
|
|
OpenACCComputeConstruct(unsigned NumClauses)
|
|
: OpenACCAssociatedStmtConstruct(
|
|
OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
|
|
SourceLocation{}, SourceLocation{}, SourceLocation{},
|
|
/*AssociatedStmt=*/nullptr) {
|
|
// We cannot send the TrailingObjects storage to the base class (which holds
|
|
// a reference to the data) until it is constructed, so we have to set it
|
|
// separately here.
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
|
|
SourceLocation DirectiveLoc, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock)
|
|
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
|
|
DirectiveLoc, End, StructuredBlock) {
|
|
assert(isOpenACCComputeDirectiveKind(K) &&
|
|
"Only parallel, serial, and kernels constructs should be "
|
|
"represented by this type");
|
|
|
|
// Initialize the trailing storage.
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCComputeConstructClass;
|
|
}
|
|
|
|
static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCComputeConstruct *
|
|
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
|
|
SourceLocation DirectiveLoc, SourceLocation EndLoc,
|
|
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
|
|
|
|
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
|
|
const Stmt *getStructuredBlock() const {
|
|
return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
|
|
}
|
|
};
|
|
/// This class represents a 'loop' construct. The 'loop' construct applies to a
|
|
/// 'for' loop (or range-for loop), and is optionally associated with a Compute
|
|
/// Construct.
|
|
class OpenACCLoopConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCLoopConstruct,
|
|
const OpenACCClause *> {
|
|
// The compute/combined construct kind this loop is associated with, or
|
|
// invalid if this is an orphaned loop construct.
|
|
OpenACCDirectiveKind ParentComputeConstructKind =
|
|
OpenACCDirectiveKind::Invalid;
|
|
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
friend class ASTContext;
|
|
friend class OpenACCAssociatedStmtConstruct;
|
|
friend class OpenACCCombinedConstruct;
|
|
friend class OpenACCComputeConstruct;
|
|
friend TrailingObjects;
|
|
|
|
OpenACCLoopConstruct(unsigned NumClauses);
|
|
|
|
OpenACCLoopConstruct(OpenACCDirectiveKind ParentKind, SourceLocation Start,
|
|
SourceLocation DirLoc, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCLoopConstructClass;
|
|
}
|
|
|
|
static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
|
|
static OpenACCLoopConstruct *
|
|
Create(const ASTContext &C, OpenACCDirectiveKind ParentKind,
|
|
SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation EndLoc,
|
|
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
|
|
|
|
Stmt *getLoop() { return getAssociatedStmt(); }
|
|
const Stmt *getLoop() const {
|
|
return const_cast<OpenACCLoopConstruct *>(this)->getLoop();
|
|
}
|
|
|
|
/// OpenACC 3.3 2.9:
|
|
/// An orphaned loop construct is a loop construct that is not lexically
|
|
/// enclosed within a compute construct. The parent compute construct of a
|
|
/// loop construct is the nearest compute construct that lexically contains
|
|
/// the loop construct.
|
|
bool isOrphanedLoopConstruct() const {
|
|
return ParentComputeConstructKind == OpenACCDirectiveKind::Invalid;
|
|
}
|
|
|
|
OpenACCDirectiveKind getParentComputeConstructKind() const {
|
|
return ParentComputeConstructKind;
|
|
}
|
|
};
|
|
|
|
// This class represents a 'combined' construct, which has a bunch of rules
|
|
// shared with both loop and compute constructs.
|
|
class OpenACCCombinedConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCCombinedConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCCombinedConstruct(unsigned NumClauses)
|
|
: OpenACCAssociatedStmtConstruct(
|
|
OpenACCCombinedConstructClass, OpenACCDirectiveKind::Invalid,
|
|
SourceLocation{}, SourceLocation{}, SourceLocation{},
|
|
/*AssociatedStmt=*/nullptr) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCCombinedConstruct(OpenACCDirectiveKind K, SourceLocation Start,
|
|
SourceLocation DirectiveLoc, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock)
|
|
: OpenACCAssociatedStmtConstruct(OpenACCCombinedConstructClass, K, Start,
|
|
DirectiveLoc, End, StructuredBlock) {
|
|
assert(isOpenACCCombinedDirectiveKind(K) &&
|
|
"Only parallel loop, serial loop, and kernels loop constructs "
|
|
"should be represented by this type");
|
|
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCCombinedConstructClass;
|
|
}
|
|
|
|
static OpenACCCombinedConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCCombinedConstruct *
|
|
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation Start,
|
|
SourceLocation DirectiveLoc, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock);
|
|
Stmt *getLoop() { return getAssociatedStmt(); }
|
|
const Stmt *getLoop() const {
|
|
return const_cast<OpenACCCombinedConstruct *>(this)->getLoop();
|
|
}
|
|
};
|
|
|
|
// This class represents a 'data' construct, which has an associated statement
|
|
// and clauses, but is otherwise pretty simple.
|
|
class OpenACCDataConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCDataConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCDataConstruct(unsigned NumClauses)
|
|
: OpenACCAssociatedStmtConstruct(
|
|
OpenACCDataConstructClass, OpenACCDirectiveKind::Data,
|
|
SourceLocation{}, SourceLocation{}, SourceLocation{},
|
|
/*AssociatedStmt=*/nullptr) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock)
|
|
: OpenACCAssociatedStmtConstruct(OpenACCDataConstructClass,
|
|
OpenACCDirectiveKind::Data, Start,
|
|
DirectiveLoc, End, StructuredBlock) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCDataConstructClass;
|
|
}
|
|
|
|
static OpenACCDataConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCDataConstruct *Create(const ASTContext &C, SourceLocation Start,
|
|
SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock);
|
|
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
|
|
const Stmt *getStructuredBlock() const {
|
|
return const_cast<OpenACCDataConstruct *>(this)->getStructuredBlock();
|
|
}
|
|
};
|
|
// This class represents a 'enter data' construct, which JUST has clauses.
|
|
class OpenACCEnterDataConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCEnterDataConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCEnterDataConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCEnterDataConstructClass,
|
|
OpenACCDirectiveKind::EnterData, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
OpenACCEnterDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCEnterDataConstructClass,
|
|
OpenACCDirectiveKind::EnterData, Start,
|
|
DirectiveLoc, End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCEnterDataConstructClass;
|
|
}
|
|
static OpenACCEnterDataConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCEnterDataConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
// This class represents a 'exit data' construct, which JUST has clauses.
|
|
class OpenACCExitDataConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCExitDataConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCExitDataConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCExitDataConstructClass,
|
|
OpenACCDirectiveKind::ExitData, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
OpenACCExitDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCExitDataConstructClass,
|
|
OpenACCDirectiveKind::ExitData, Start,
|
|
DirectiveLoc, End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCExitDataConstructClass;
|
|
}
|
|
static OpenACCExitDataConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCExitDataConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
// This class represents a 'host_data' construct, which has an associated
|
|
// statement and clauses, but is otherwise pretty simple.
|
|
class OpenACCHostDataConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCHostDataConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCHostDataConstruct(unsigned NumClauses)
|
|
: OpenACCAssociatedStmtConstruct(
|
|
OpenACCHostDataConstructClass, OpenACCDirectiveKind::HostData,
|
|
SourceLocation{}, SourceLocation{}, SourceLocation{},
|
|
/*AssociatedStmt=*/nullptr) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
OpenACCHostDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock)
|
|
: OpenACCAssociatedStmtConstruct(OpenACCHostDataConstructClass,
|
|
OpenACCDirectiveKind::HostData, Start,
|
|
DirectiveLoc, End, StructuredBlock) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCHostDataConstructClass;
|
|
}
|
|
static OpenACCHostDataConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCHostDataConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *StructuredBlock);
|
|
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
|
|
const Stmt *getStructuredBlock() const {
|
|
return const_cast<OpenACCHostDataConstruct *>(this)->getStructuredBlock();
|
|
}
|
|
};
|
|
|
|
// This class represents a 'wait' construct, which has some expressions plus a
|
|
// clause list.
|
|
class OpenACCWaitConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCWaitConstruct, Expr *,
|
|
OpenACCClause *> {
|
|
// FIXME: We should be storing a `const OpenACCClause *` to be consistent with
|
|
// the rest of the constructs, but TrailingObjects doesn't allow for mixing
|
|
// constness in its implementation of `getTrailingObjects`.
|
|
|
|
friend TrailingObjects;
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
// Locations of the left and right parens of the 'wait-argument'
|
|
// expression-list.
|
|
SourceLocation LParenLoc, RParenLoc;
|
|
// Location of the 'queues' keyword, if present.
|
|
SourceLocation QueuesLoc;
|
|
|
|
// Number of the expressions being represented. Index '0' is always the
|
|
// 'devnum' expression, even if it not present.
|
|
unsigned NumExprs = 0;
|
|
|
|
OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCWaitConstructClass,
|
|
OpenACCDirectiveKind::Wait, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}),
|
|
NumExprs(NumExprs) {
|
|
assert(NumExprs >= 1 &&
|
|
"NumExprs should always be >= 1 because the 'devnum' "
|
|
"expr is represented by a null if necessary");
|
|
std::uninitialized_value_construct_n(getExprPtr(), NumExprs);
|
|
std::uninitialized_value_construct_n(getTrailingObjects<OpenACCClause *>(),
|
|
NumClauses);
|
|
setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
|
|
getTrailingObjects<OpenACCClause *>()),
|
|
NumClauses));
|
|
}
|
|
|
|
OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation LParenLoc, Expr *DevNumExpr,
|
|
SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
|
|
SourceLocation RParenLoc, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCWaitConstructClass,
|
|
OpenACCDirectiveKind::Wait, Start, DirectiveLoc,
|
|
End),
|
|
LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc),
|
|
NumExprs(QueueIdExprs.size() + 1) {
|
|
assert(NumExprs >= 1 &&
|
|
"NumExprs should always be >= 1 because the 'devnum' "
|
|
"expr is represented by a null if necessary");
|
|
|
|
llvm::uninitialized_copy(ArrayRef(DevNumExpr), getExprPtr());
|
|
llvm::uninitialized_copy(QueueIdExprs, getExprPtr() + 1);
|
|
std::uninitialized_copy(const_cast<OpenACCClause **>(Clauses.begin()),
|
|
const_cast<OpenACCClause **>(Clauses.end()),
|
|
getTrailingObjects<OpenACCClause *>());
|
|
setClauseList(MutableArrayRef(const_cast<const OpenACCClause **>(
|
|
getTrailingObjects<OpenACCClause *>()),
|
|
Clauses.size()));
|
|
}
|
|
|
|
size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; }
|
|
size_t numTrailingObjects(OverloadToken<const OpenACCClause *>) const {
|
|
return clauses().size();
|
|
}
|
|
|
|
Expr **getExprPtr() const {
|
|
return const_cast<Expr**>(getTrailingObjects<Expr *>());
|
|
}
|
|
|
|
ArrayRef<Expr *> getExprs() const { return {getExprPtr(), NumExprs}; }
|
|
|
|
ArrayRef<Expr *> getExprs() { return {getExprPtr(), NumExprs}; }
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCWaitConstructClass;
|
|
}
|
|
|
|
static OpenACCWaitConstruct *
|
|
CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses);
|
|
|
|
static OpenACCWaitConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc,
|
|
ArrayRef<Expr *> QueueIdExprs, SourceLocation RParenLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
|
|
|
|
SourceLocation getLParenLoc() const { return LParenLoc; }
|
|
SourceLocation getRParenLoc() const { return RParenLoc; }
|
|
bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
|
|
SourceLocation getQueuesLoc() const { return QueuesLoc; }
|
|
|
|
bool hasDevNumExpr() const { return getExprs()[0]; }
|
|
Expr *getDevNumExpr() const { return getExprs()[0]; }
|
|
ArrayRef<Expr *> getQueueIdExprs() { return getExprs().drop_front(); }
|
|
ArrayRef<Expr *> getQueueIdExprs() const { return getExprs().drop_front(); }
|
|
|
|
child_range children() {
|
|
Stmt **Begin = reinterpret_cast<Stmt **>(getExprPtr());
|
|
return child_range(Begin, Begin + NumExprs);
|
|
}
|
|
|
|
const_child_range children() const {
|
|
Stmt *const *Begin =
|
|
reinterpret_cast<Stmt *const *>(getExprPtr());
|
|
return const_child_range(Begin, Begin + NumExprs);
|
|
}
|
|
};
|
|
|
|
class OpenACCCacheConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCCacheConstruct, Expr *> {
|
|
friend TrailingObjects;
|
|
friend class ASTStmtWriter;
|
|
friend class ASTStmtReader;
|
|
// Locations of the left and right parens of the 'var-list'
|
|
// expression-list.
|
|
SourceRange ParensLoc;
|
|
SourceLocation ReadOnlyLoc;
|
|
|
|
unsigned NumVars = 0;
|
|
|
|
OpenACCCacheConstruct(unsigned NumVars)
|
|
: OpenACCConstructStmt(OpenACCCacheConstructClass,
|
|
OpenACCDirectiveKind::Cache, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}),
|
|
NumVars(NumVars) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumVars);
|
|
}
|
|
OpenACCCacheConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation LParenLoc, SourceLocation ReadOnlyLoc,
|
|
ArrayRef<Expr *> VarList, SourceLocation RParenLoc,
|
|
SourceLocation End)
|
|
: OpenACCConstructStmt(OpenACCCacheConstructClass,
|
|
OpenACCDirectiveKind::Cache, Start, DirectiveLoc,
|
|
End),
|
|
ParensLoc(LParenLoc, RParenLoc), ReadOnlyLoc(ReadOnlyLoc),
|
|
NumVars(VarList.size()) {
|
|
|
|
llvm::uninitialized_copy(VarList, getTrailingObjects());
|
|
}
|
|
|
|
public:
|
|
ArrayRef<Expr *> getVarList() const { return getTrailingObjects(NumVars); }
|
|
|
|
MutableArrayRef<Expr *> getVarList() { return getTrailingObjects(NumVars); }
|
|
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCCacheConstructClass;
|
|
}
|
|
|
|
static OpenACCCacheConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumVars);
|
|
static OpenACCCacheConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation LParenLoc, SourceLocation ReadOnlyLoc,
|
|
ArrayRef<Expr *> VarList, SourceLocation RParenLoc,
|
|
SourceLocation End);
|
|
|
|
SourceLocation getLParenLoc() const { return ParensLoc.getBegin(); }
|
|
SourceLocation getRParenLoc() const { return ParensLoc.getEnd(); }
|
|
bool hasReadOnly() const { return !ReadOnlyLoc.isInvalid(); }
|
|
SourceLocation getReadOnlyLoc() const { return ReadOnlyLoc; }
|
|
|
|
child_range children() {
|
|
Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects());
|
|
return child_range(Begin, Begin + NumVars);
|
|
}
|
|
|
|
const_child_range children() const {
|
|
Stmt *const *Begin = reinterpret_cast<Stmt *const *>(getTrailingObjects());
|
|
return const_child_range(Begin, Begin + NumVars);
|
|
}
|
|
};
|
|
|
|
// This class represents an 'init' construct, which has just a clause list.
|
|
class OpenACCInitConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCInitConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCInitConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCInitConstructClass,
|
|
OpenACCDirectiveKind::Init, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
OpenACCInitConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCInitConstructClass,
|
|
OpenACCDirectiveKind::Init, Start, DirectiveLoc,
|
|
End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCInitConstructClass;
|
|
}
|
|
static OpenACCInitConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCInitConstruct *Create(const ASTContext &C, SourceLocation Start,
|
|
SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
|
|
// This class represents a 'shutdown' construct, which has just a clause list.
|
|
class OpenACCShutdownConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCShutdownConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCShutdownConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCShutdownConstructClass,
|
|
OpenACCDirectiveKind::Shutdown, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
OpenACCShutdownConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCShutdownConstructClass,
|
|
OpenACCDirectiveKind::Shutdown, Start,
|
|
DirectiveLoc, End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCShutdownConstructClass;
|
|
}
|
|
static OpenACCShutdownConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCShutdownConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
|
|
// This class represents a 'set' construct, which has just a clause list.
|
|
class OpenACCSetConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCSetConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCSetConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCSetConstructClass,
|
|
OpenACCDirectiveKind::Set, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCSetConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCSetConstructClass,
|
|
OpenACCDirectiveKind::Set, Start, DirectiveLoc,
|
|
End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCSetConstructClass;
|
|
}
|
|
static OpenACCSetConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCSetConstruct *Create(const ASTContext &C, SourceLocation Start,
|
|
SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
// This class represents an 'update' construct, which has just a clause list.
|
|
class OpenACCUpdateConstruct final
|
|
: public OpenACCConstructStmt,
|
|
private llvm::TrailingObjects<OpenACCUpdateConstruct,
|
|
const OpenACCClause *> {
|
|
friend TrailingObjects;
|
|
OpenACCUpdateConstruct(unsigned NumClauses)
|
|
: OpenACCConstructStmt(OpenACCUpdateConstructClass,
|
|
OpenACCDirectiveKind::Update, SourceLocation{},
|
|
SourceLocation{}, SourceLocation{}) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCUpdateConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses)
|
|
: OpenACCConstructStmt(OpenACCUpdateConstructClass,
|
|
OpenACCDirectiveKind::Update, Start, DirectiveLoc,
|
|
End) {
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCUpdateConstructClass;
|
|
}
|
|
static OpenACCUpdateConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCUpdateConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses);
|
|
};
|
|
|
|
// This class represents the 'atomic' construct, which has an associated
|
|
// statement, but no clauses.
|
|
class OpenACCAtomicConstruct final
|
|
: public OpenACCAssociatedStmtConstruct,
|
|
private llvm::TrailingObjects<OpenACCAtomicConstruct,
|
|
const OpenACCClause *> {
|
|
|
|
friend class ASTStmtReader;
|
|
friend TrailingObjects;
|
|
OpenACCAtomicKind AtomicKind = OpenACCAtomicKind::None;
|
|
|
|
OpenACCAtomicConstruct(unsigned NumClauses)
|
|
: OpenACCAssociatedStmtConstruct(
|
|
OpenACCAtomicConstructClass, OpenACCDirectiveKind::Atomic,
|
|
SourceLocation{}, SourceLocation{}, SourceLocation{},
|
|
/*AssociatedStmt=*/nullptr) {
|
|
std::uninitialized_value_construct_n(getTrailingObjects(), NumClauses);
|
|
setClauseList(getTrailingObjects(NumClauses));
|
|
}
|
|
|
|
OpenACCAtomicConstruct(SourceLocation Start, SourceLocation DirectiveLoc,
|
|
OpenACCAtomicKind AtKind, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses,
|
|
Stmt *AssociatedStmt)
|
|
: OpenACCAssociatedStmtConstruct(OpenACCAtomicConstructClass,
|
|
OpenACCDirectiveKind::Atomic, Start,
|
|
DirectiveLoc, End, AssociatedStmt),
|
|
AtomicKind(AtKind) {
|
|
// Initialize the trailing storage.
|
|
llvm::uninitialized_copy(Clauses, getTrailingObjects());
|
|
|
|
setClauseList(getTrailingObjects(Clauses.size()));
|
|
}
|
|
|
|
void setAssociatedStmt(Stmt *S) {
|
|
OpenACCAssociatedStmtConstruct::setAssociatedStmt(S);
|
|
}
|
|
|
|
public:
|
|
static bool classof(const Stmt *T) {
|
|
return T->getStmtClass() == OpenACCAtomicConstructClass;
|
|
}
|
|
|
|
static OpenACCAtomicConstruct *CreateEmpty(const ASTContext &C,
|
|
unsigned NumClauses);
|
|
static OpenACCAtomicConstruct *
|
|
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc,
|
|
OpenACCAtomicKind AtKind, SourceLocation End,
|
|
ArrayRef<const OpenACCClause *> Clauses, Stmt *AssociatedStmt);
|
|
|
|
OpenACCAtomicKind getAtomicKind() const { return AtomicKind; }
|
|
const Stmt *getAssociatedStmt() const {
|
|
return OpenACCAssociatedStmtConstruct::getAssociatedStmt();
|
|
}
|
|
Stmt *getAssociatedStmt() {
|
|
return OpenACCAssociatedStmtConstruct::getAssociatedStmt();
|
|
}
|
|
|
|
// A struct to represent a broken-down version of the associated statement,
|
|
// providing the information specified in OpenACC3.3 Section 2.12.
|
|
struct SingleStmtInfo {
|
|
// Holds the entire expression for this. In the case of a normal
|
|
// read/write/update, this should just be the associated statement. in the
|
|
// case of an update, this is going to be the sub-expression this
|
|
// represents.
|
|
const Expr *WholeExpr;
|
|
const Expr *V;
|
|
const Expr *X;
|
|
// Listed as 'expr' in the standard, this is typically a generic expression
|
|
// as a component.
|
|
const Expr *RefExpr;
|
|
// If this is an 'update', records whether this is a post-fix
|
|
// increment/decrement. In the case where we have a single-line variant of
|
|
// 'capture' we have to form the IR differently if this is the case to make
|
|
// sure the old value is 'read' in the 2nd step.
|
|
bool IsPostfixIncDec = false;
|
|
static SingleStmtInfo Empty() {
|
|
return {nullptr, nullptr, nullptr, nullptr, false};
|
|
}
|
|
|
|
static SingleStmtInfo createRead(const Expr *WholeExpr, const Expr *V,
|
|
const Expr *X) {
|
|
return {WholeExpr, V, X, /*RefExpr=*/nullptr};
|
|
}
|
|
static SingleStmtInfo createWrite(const Expr *WholeExpr, const Expr *X,
|
|
const Expr *RefExpr) {
|
|
return {WholeExpr, /*V=*/nullptr, X, RefExpr};
|
|
}
|
|
static SingleStmtInfo createUpdate(const Expr *WholeExpr, const Expr *X,
|
|
bool PostfixIncDec) {
|
|
return {WholeExpr, /*V=*/nullptr, X, /*RefExpr=*/nullptr, PostfixIncDec};
|
|
}
|
|
};
|
|
|
|
struct StmtInfo {
|
|
enum class StmtForm {
|
|
Read,
|
|
Write,
|
|
Update,
|
|
ReadWrite,
|
|
ReadUpdate,
|
|
UpdateRead
|
|
} Form;
|
|
SingleStmtInfo First, Second;
|
|
|
|
static StmtInfo createUpdateRead(SingleStmtInfo First,
|
|
SingleStmtInfo Second) {
|
|
return {StmtForm::UpdateRead, First, Second};
|
|
}
|
|
static StmtInfo createReadWrite(SingleStmtInfo First,
|
|
SingleStmtInfo Second) {
|
|
return {StmtForm::ReadWrite, First, Second};
|
|
}
|
|
static StmtInfo createReadUpdate(SingleStmtInfo First,
|
|
SingleStmtInfo Second) {
|
|
return {StmtForm::ReadUpdate, First, Second};
|
|
}
|
|
};
|
|
|
|
const StmtInfo getAssociatedStmtInfo() const;
|
|
};
|
|
|
|
} // namespace clang
|
|
#endif // LLVM_CLANG_AST_STMTOPENACC_H
|